001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2021, Jean-Marie Dautelle, Werner Keil, Otavio Santana. 004 * 005 * All rights reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without modification, 008 * are permitted provided that the following conditions are met: 009 * 010 * 1. Redistributions of source code must retain the above copyright notice, 011 * this list of conditions and the following disclaimer. 012 * 013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions 014 * and the following disclaimer in the documentation and/or other materials provided with the distribution. 015 * 016 * 3. Neither the name of JSR-385, Indriya nor the names of their contributors may be used to endorse or promote products 017 * derived from this software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package tech.units.indriya.quantity.time; 031 032import static tech.units.indriya.unit.Units.DAY; 033import static tech.units.indriya.unit.Units.HOUR; 034import static tech.units.indriya.unit.Units.MINUTE; 035import static tech.units.indriya.unit.Units.SECOND; 036 037import java.util.Objects; 038import java.util.concurrent.TimeUnit; 039import java.util.function.BinaryOperator; 040 041import javax.measure.Quantity; 042import javax.measure.Unit; 043import javax.measure.UnitConverter; 044import javax.measure.quantity.Frequency; 045import javax.measure.quantity.Time; 046 047import tech.units.indriya.AbstractQuantity; 048import tech.units.indriya.ComparableQuantity; 049import tech.units.indriya.function.Calculus; 050import tech.units.indriya.internal.function.Calculator; 051import tech.units.indriya.quantity.Quantities; 052 053/** 054 * Class that represents {@link TimeUnit} in Unit-API 055 * 056 * @author Otavio Santana 057 * @author Werner Keil 058 * @author Andi Huber 059 * @version 1.2 060 * @since 1.0 061 */ 062public final class TimeUnitQuantity extends AbstractQuantity<Time> { 063 064 /** 065 * 066 */ 067 private static final long serialVersionUID = -5840251813363744230L; 068 069 private final TimeUnit timeUnit; 070 071 private final Number value; 072 073 /** 074 * creates the {@link TimeUnitQuantity} using {@link TimeUnit} and {@link Long} 075 * 076 * @param timeUnit 077 * - time to be used 078 * @param value 079 * - value to be used 080 */ 081 TimeUnitQuantity(TimeUnit timeUnit, Number value) { 082 super(toUnit(timeUnit)); 083 this.timeUnit = timeUnit; 084 this.value = value; 085 } 086 087 /** 088 * creates the {@link TimeUnitQuantity} using {@link TimeUnit} and {@link Long} 089 * 090 * @param timeUnit 091 * - time to be used 092 * @param value 093 * - value to be used 094 * @since 1.0.9 095 */ 096 public static TimeUnitQuantity of(Number number, TimeUnit timeUnit) { 097 return new TimeUnitQuantity(Objects.requireNonNull(timeUnit), Objects.requireNonNull(number)); 098 } 099 100 /** 101 * Creates a {@link TimeUnitQuantity} based a {@link Quantity<Time>} converted to {@link SI#SECOND}. 102 * 103 * @param quantity 104 * - quantity to be used 105 * @return the {@link TimeUnitQuantity} converted be quantity in seconds. 106 * @since 1.0 107 */ 108 public static TimeUnitQuantity of(Quantity<Time> quantity) { 109 Quantity<Time> seconds = Objects.requireNonNull(quantity).to(SECOND); 110 return new TimeUnitQuantity(TimeUnit.SECONDS, seconds.getValue()); 111 } 112 113 /** 114 * get to {@link TimeUnit} 115 * 116 * @return the TimeUnit 117 * @since 1.0 118 */ 119 public TimeUnit getTimeUnit() { 120 return timeUnit; 121 } 122 123 /** 124 * get value expressed in {@link Number} 125 * 126 * @return the value 127 * @since 1.0 128 */ 129 public Number getValue() { 130 return value; 131 } 132 133 /** 134 * converts the {@link TimeUnit} to {@link Unit} 135 * 136 * @return the {@link TimeUnitQuantity#getTimeUnit()} converted to Unit 137 * @since 1.0 138 */ 139 public Unit<Time> toUnit() { 140 return toUnit(timeUnit); 141 } 142 143 /** 144 * Converts the {@link TimeUnitQuantity} to {@link Quantity<Time>} 145 * 146 * @return this class converted to Quantity 147 * @since 1.0 148 */ 149 public Quantity<Time> toQuantity() { 150 return Quantities.getQuantity(value, toUnit()); 151 } 152 153 public TimeUnitQuantity to(TimeUnit aTimeUnit) { 154 Quantity<Time> time = toQuantity().to(toUnit(aTimeUnit)); 155 return new TimeUnitQuantity(aTimeUnit, time.getValue().longValue()); 156 } 157 158 private static Unit<Time> toUnit(TimeUnit timeUnit) { 159 switch (timeUnit) { 160 case MICROSECONDS: 161 return TimeQuantities.MICROSECOND; 162 case MILLISECONDS: 163 return TimeQuantities.MILLISECOND; 164 case NANOSECONDS: 165 return TimeQuantities.NANOSECOND; 166 case SECONDS: 167 return SECOND; 168 case MINUTES: 169 return MINUTE; 170 case HOURS: 171 return HOUR; 172 case DAYS: 173 return DAY; 174 default: 175 throw new IllegalStateException("In TimeUnitQuantity just supports DAYS, HOURS, MICROSECONDS, MILLISECONDS, MINUTES, NANOSECONDS, SECONDS "); 176 } 177 } 178 179 /** 180 * @since 1.0 181 */ 182 @Override 183 public int hashCode() { 184 return Objects.hash(timeUnit, value); 185 } 186 187 /** 188 * @since 1.0 189 */ 190 @Override 191 public boolean equals(Object obj) { 192 if (this == obj) { 193 return true; 194 } 195 if (TimeUnitQuantity.class.isInstance(obj)) { 196 TimeUnitQuantity other = TimeUnitQuantity.class.cast(obj); 197 return Objects.equals(timeUnit, other.timeUnit) && Objects.equals(value, other.value); 198 } 199 if (obj instanceof Quantity<?>) { 200 Quantity<?> that = (Quantity<?>) obj; 201 return Objects.equals(getUnit(), that.getUnit()) && 202 Calculus.currentNumberSystem().compare(value, that.getValue()) == 0; 203 204 } 205 return super.equals(obj); 206 } 207 208 @Override 209 public String toString() { 210 return "Time unit:" + timeUnit + " value: " + value; 211 } 212 213 /** 214 * @since 1.0.1 215 */ 216 @Override 217 public ComparableQuantity<Time> add(Quantity<Time> that) { 218 final UnitConverter thisToThat = this.getUnit().getConverterTo(that.getUnit()); 219 final boolean thatUnitIsSmaller = 220 Calculus.currentNumberSystem().compare(thisToThat.convert(1.), 1.)>0; 221 222 final Unit<Time> preferedUnit = thatUnitIsSmaller ? that.getUnit() : this.getUnit(); 223 224 final Number thisValueInPreferedUnit = convertedQuantityValue(this, preferedUnit); 225 final Number thatValueInPreferedUnit = convertedQuantityValue(that, preferedUnit); 226 227 final Number resultValueInPreferedUnit = Calculator.of(thisValueInPreferedUnit) 228 .add(thatValueInPreferedUnit) 229 .peek(); 230 231 return Quantities.getQuantity(resultValueInPreferedUnit, preferedUnit); 232 } 233 234 /** 235 * @since 1.0.1 236 */ 237 @Override 238 public ComparableQuantity<Time> subtract(Quantity<Time> that) { 239 return add(that.negate()); 240 } 241 242 /** 243 * @since 1.0.1 244 */ 245 @Override 246 public ComparableQuantity<?> divide(Quantity<?> that) { 247 return applyMultiplicativeQuantityOperation( 248 that, (a, b)->Calculator.of(a).divide(b).peek(), Unit::divide); 249 } 250 251 /** 252 * @since 1.0.1 253 */ 254 @Override 255 public ComparableQuantity<Time> divide(Number that) { 256 return applyMultiplicativeNumberOperation( 257 that, (a, b)->Calculator.of(a).divide(b).peek()); 258 } 259 260 /** 261 * @since 1.0.1 262 */ 263 @Override 264 public ComparableQuantity<?> multiply(Quantity<?> that) { 265 return applyMultiplicativeQuantityOperation( 266 that, (a, b)->Calculator.of(a).multiply(b).peek(), Unit::multiply); 267 } 268 269 /** 270 * @since 1.0.1 271 */ 272 @Override 273 public ComparableQuantity<Time> multiply(Number that) { 274 return applyMultiplicativeNumberOperation( 275 that, (a, b)->Calculator.of(a).multiply(b).peek()); 276 } 277 278 /** 279 * @since 1.0.1 280 */ 281 @Override 282 public ComparableQuantity<Frequency> inverse() { 283 return Quantities.getQuantity( 284 Calculator.of(value).reciprocal().peek(), 285 toUnit(timeUnit).inverse()).asType(Frequency.class); 286 } 287 288 /** 289 * @since 1.0.2 290 */ 291 @Override 292 public Quantity<Time> negate() { 293 return of( 294 Calculator.of(value).negate().peek(), 295 getTimeUnit()); 296 } 297 298 // -- HELPER 299 300 private static <R extends Quantity<R>> Number quantityValue(Quantity<R> that) { 301 return convertedQuantityValue(that, that.getUnit()); 302 } 303 304 private static <R extends Quantity<R>> Number convertedQuantityValue(Quantity<R> that, Unit<R> unit) { 305 return that.getUnit().getConverterTo(unit).convert(that.getValue()); 306 } 307 308 private ComparableQuantity<?> applyMultiplicativeQuantityOperation( 309 Quantity<?> that, 310 BinaryOperator<Number> valueOperator, 311 BinaryOperator<Unit<?>> unitOperator) { 312 313 final Number thisValue = quantityValue(this); 314 final Number thatValue = quantityValue(that); 315 final Number result = valueOperator.apply(thisValue, thatValue); 316 final Unit<?> resultUnit = unitOperator.apply(getUnit(), that.getUnit()); 317 return Quantities.getQuantity(result, resultUnit); 318 } 319 320 private ComparableQuantity<Time> applyMultiplicativeNumberOperation(Number that, 321 BinaryOperator<Number> valueOperator) { 322 final Number thisValue = this.getValue(); 323 final Number thatValue = that; 324 final Number result = valueOperator.apply(thisValue, thatValue); 325 return Quantities.getQuantity(result, getUnit()); 326 } 327}