001/* 002 * Units of Measurement Implementation for Java SE 003 * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. 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-363 nor the names of its 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 tec.uom.se.quantity.time; 031 032import static tec.uom.se.unit.Units.DAY; 033import static tec.uom.se.unit.Units.HOUR; 034import static tec.uom.se.unit.Units.MINUTE; 035import static tec.uom.se.unit.Units.SECOND; 036 037import java.util.Objects; 038import java.math.BigDecimal; 039import java.math.MathContext; 040import java.time.Duration; 041import java.time.temporal.ChronoUnit; 042import java.time.temporal.TemporalAmount; 043import java.time.temporal.TemporalUnit; 044 045import javax.measure.IncommensurableException; 046import javax.measure.Quantity; 047import javax.measure.UnconvertibleException; 048import javax.measure.Unit; 049import javax.measure.UnitConverter; 050import javax.measure.quantity.Time; 051 052import tec.uom.se.AbstractQuantity; 053import tec.uom.se.ComparableQuantity; 054import tec.uom.se.quantity.Quantities; 055 056/** 057 * Class that represents {@link TemporalUnit} in Unit-API 058 * 059 * @author keilw 060 * @since 1.0 061 */ 062public final class TemporalQuantity extends AbstractQuantity<Time> { 063 /** 064 * 065 */ 066 private static final long serialVersionUID = 6835738653744691425L; 067 068 private final TemporalUnit timeUnit; 069 private final Integer value; 070 private final TemporalAmount amount; 071 072 /** 073 * creates the {@link TemporalQuantity} using {@link TemporalUnit} and {@link Integer} 074 * 075 * @param timeUnit 076 * - time to be used 077 * @param value 078 * - value to be used 079 */ 080 TemporalQuantity(Integer value, TemporalUnit timeUnit) { 081 super(toUnit(timeUnit)); 082 this.timeUnit = timeUnit; 083 this.amount = Duration.of(value, timeUnit); 084 this.value = value; 085 } 086 087 /** 088 * creates the {@link TemporalQuantity} using {@link TemporalUnit} and {@link Integer} 089 * 090 * @param value 091 * - value to be used 092 * @param timeUnit 093 * - time to be used 094 */ 095 public static TemporalQuantity of(Integer number, TemporalUnit timeUnit) { 096 return new TemporalQuantity(Objects.requireNonNull(number), Objects.requireNonNull(timeUnit)); 097 } 098 099 /** 100 * Creates a {@link TemporalQuantity} based a {@link Quantity<Time>} converted to {@link Units#SECOND}. 101 * 102 * @param quantity 103 * - quantity to be used 104 * @return the {@link TemporalQuantity} converted be quantity in seconds. 105 */ 106 public static TemporalQuantity of(Quantity<Time> quantity) { 107 Quantity<Time> seconds = Objects.requireNonNull(quantity).to(SECOND); 108 return new TemporalQuantity(seconds.getValue().intValue(), ChronoUnit.SECONDS); 109 } 110 111 /** 112 * get to {@link TemporalAmount} 113 * 114 * @return the TemporalAmount 115 */ 116 public TemporalAmount getTemporalAmount() { 117 return amount; 118 } 119 120 /** 121 * get to {@link TemporalUnit} 122 * 123 * @return the TemporalUnit 124 */ 125 public TemporalUnit getTemporalUnit() { 126 return timeUnit; 127 } 128 129 /** 130 * get value expressed in {@link Integer} 131 * 132 * @return the value 133 */ 134 public Integer getValue() { 135 return value; 136 } 137 138 /** 139 * converts the {@link TemporalUnit} to {@link Unit} 140 * 141 * @return the {@link TemporalQuantity#getTemporalUnit()} converted to Unit 142 */ 143 public Unit<Time> toUnit() { 144 return toUnit(timeUnit); 145 } 146 147 /** 148 * Converts the {@link TemporalQuantity} to {@link Quantity<Time>} 149 * 150 * @return this class converted to Quantity 151 */ 152 public Quantity<Time> toQuantity() { 153 return Quantities.getQuantity(value, toUnit()); 154 } 155 156 public TemporalQuantity to(TemporalUnit timeUnit) { 157 Quantity<Time> time = toQuantity().to(toUnit(timeUnit)); 158 return new TemporalQuantity(time.getValue().intValue(), timeUnit); 159 } 160 161 private static Unit<Time> toUnit(TemporalUnit timeUnit) { 162 if (timeUnit instanceof ChronoUnit) { 163 ChronoUnit chronoUnit = (ChronoUnit) timeUnit; 164 switch (chronoUnit) { 165 case MICROS: 166 return TimeQuantities.MICROSECOND; 167 case MILLIS: 168 return TimeQuantities.MILLISECOND; 169 case NANOS: 170 return TimeQuantities.NANOSECOND; 171 case SECONDS: 172 return SECOND; 173 case MINUTES: 174 return MINUTE; 175 case HOURS: 176 return HOUR; 177 case DAYS: 178 return DAY; 179 default: 180 throw new IllegalArgumentException("TemporalQuantity only supports DAYS, HOURS, MICROS, MILLIS, MINUTES, NANOS, SECONDS "); 181 } 182 } else { 183 throw new IllegalArgumentException("TemporalQuantity only supports temporal units of type ChronoUnit"); 184 185 } 186 } 187 188 @Override 189 public int hashCode() { 190 return Objects.hash(timeUnit, value); 191 } 192 193 @Override 194 public boolean equals(Object obj) { 195 if (this == obj) { 196 return true; 197 } 198 if (TemporalQuantity.class.isInstance(obj)) { 199 TemporalQuantity other = TemporalQuantity.class.cast(obj); 200 return Objects.equals(timeUnit, other.timeUnit) && Objects.equals(value, other.value); 201 } 202 if (obj instanceof Quantity<?>) { 203 Quantity<?> that = (Quantity<?>) obj; 204 return Objects.equals(getUnit(), that.getUnit()) && Equalizer.hasEquality(value, that.getValue()); 205 } 206 return super.equals(obj); 207 } 208 209 @Override 210 public String toString() { 211 return "Temporal unit:" + timeUnit + " value: " + value; 212 } 213 214 @Override 215 public ComparableQuantity<Time> add(Quantity<Time> that) { 216 if (getUnit().equals(that.getUnit())) { 217 return TimeQuantities.getQuantity(value + that.getValue().intValue(), timeUnit); 218 } 219 Quantity<Time> converted = that.to(getUnit()); 220 return TimeQuantities.getQuantity(value + converted.getValue().intValue(), timeUnit); 221 } 222 223 @Override 224 public ComparableQuantity<Time> subtract(Quantity<Time> that) { 225 if (getUnit().equals(that.getUnit())) { 226 return TimeQuantities.getQuantity(value - that.getValue().intValue(), timeUnit); 227 } 228 Quantity<Time> converted = that.to(getUnit()); 229 return TimeQuantities.getQuantity(value - converted.getValue().intValue(), timeUnit); 230 } 231 232 @Override 233 public ComparableQuantity<?> divide(Quantity<?> that) { 234 if (getUnit().equals(that.getUnit())) { 235 return TimeQuantities.getQuantity(value / that.getValue().intValue(), timeUnit); 236 } 237 Unit<?> divUnit = getUnit().divide(that.getUnit()); 238 UnitConverter conv; 239 try { 240 conv = getUnit().getConverterToAny(divUnit); 241 return TimeQuantities.getQuantity(value / conv.convert(that.getValue()).intValue(), timeUnit); 242 } catch (UnconvertibleException e) { 243 // TODO Auto-generated catch block 244 e.printStackTrace(); 245 return TimeQuantities.getQuantity(value / that.getValue().intValue(), timeUnit); 246 } catch (IncommensurableException e) { 247 // TODO Auto-generated catch block 248 e.printStackTrace(); 249 return TimeQuantities.getQuantity(value / that.getValue().intValue(), timeUnit); 250 } 251 } 252 253 @Override 254 public ComparableQuantity<Time> divide(Number that) { 255 return TimeQuantities.getQuantity(value / that.intValue(), timeUnit); 256 } 257 258 @Override 259 public ComparableQuantity<?> multiply(Quantity<?> multiplier) { 260 if (getUnit().equals(multiplier.getUnit())) { 261 return TimeQuantities.getQuantity(value * multiplier.getValue().intValue(), timeUnit); 262 } 263 Unit<?> mulUnit = getUnit().multiply(multiplier.getUnit()); 264 UnitConverter conv; 265 try { 266 conv = getUnit().getConverterToAny(mulUnit); 267 return TimeQuantities.getQuantity(value * conv.convert(multiplier.getValue()).intValue(), timeUnit); 268 } catch (UnconvertibleException e) { 269 // TODO Auto-generated catch block 270 e.printStackTrace(); 271 return TimeQuantities.getQuantity(value * multiplier.getValue().intValue(), timeUnit); 272 } catch (IncommensurableException e) { 273 // TODO Auto-generated catch block 274 e.printStackTrace(); 275 return TimeQuantities.getQuantity(value * multiplier.getValue().intValue(), timeUnit); 276 } 277 } 278 279 @Override 280 public ComparableQuantity<Time> multiply(Number multiplier) { 281 return TimeQuantities.getQuantity(value * multiplier.intValue(), timeUnit); 282 } 283 284 @Override 285 public ComparableQuantity<?> inverse() { 286 return TimeQuantities.getQuantity(1 / value, timeUnit); 287 } 288 289 @Override 290 public boolean isBig() { 291 return true; // Duration backed by BigDecimal/BigInteger 292 } 293 294 @Override 295 public BigDecimal decimalValue(Unit<Time> unit, MathContext ctx) throws ArithmeticException { 296 return BigDecimal.valueOf(value.doubleValue()); 297 } 298 299 @Override 300 public double doubleValue(Unit<Time> unit) throws ArithmeticException { 301 return value.doubleValue(); 302 } 303}