1 package org.djunits.unit; 2 3 import static org.djunits.unit.unitsystem.UnitSystem.OTHER; 4 5 import java.util.GregorianCalendar; 6 7 import org.djunits.unit.unitsystem.UnitSystem; 8 9 /** 10 * Standard absolute time units. Note that when the offset of a stored absolute Time becomes large, precision of a float or 11 * double might not be enough for the required resolution of a Time. A float has around 7 significant digits (23 bit mantissa), 12 * whereas a double has around 16 significant digits (52 bit mantissa). This means that when we need to have a float time that 13 * is precise to microseconds, the Time value should not go above 2^22 = 4.0E6. This is <b>not</b> enough to store Epoch values! 14 * So feeding System.TimeInMillis() to a FloatTime with TimeUnit.BASE as its unit is not having the required precision. For a 15 * (double) Time with TimeUnit.BASE as its unit, the largest value where the ms precision is reached is 2^51 = 2.3E15, which is 16 * around 71000 years. This is sufficient to store a date on an Epoch level precise to a ms. 17 * <p> 18 * Copyright (c) 2015-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br> 19 * BSD-style license. See <a href="http://djunits.org/docs/license.html">DJUNITS License</a>. 20 * <p> 21 * $LastChangedDate: 2018-01-28 03:17:44 +0100 (Sun, 28 Jan 2018) $, @version $Revision: 256 $, by $Author: averbraeck $, 22 * initial version May 15, 2014 <br> 23 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a> 24 */ 25 public class TimeUnit extends AbsoluteLinearUnit<TimeUnit, DurationUnit> 26 { 27 /** */ 28 private static final long serialVersionUID = 20140607L; 29 30 /** 31 * The base unit for time with an artifical "zero" point. 32 */ 33 public static final TimeUnit BASE; 34 35 /** 36 * The base unit for time with an artifical "zero" point with a calculation in seconds. Note that when the offset becomes 37 * large, precision of a float or double might not be enough for the required resolution of a Time. A float has around 7 38 * significant digits (23 bit mantissa), whereas a double has around 16 significant digits (52 bit mantissa). This means 39 * that when we need to have a float time that is precise to microseconds, the Time value should not go above 2^22 = 4.0E6. 40 * This is <b>not</b> enough to store Epoch values! So feeding System.TimeInMillis() to a FloatTime with TimeUnit.BASE as 41 * its unit is not having the required precision. For a (double) Time with TimeUnit.BASE as its unit, the largest value 42 * where the ms precision is reached is 2^51 = 2.3E15, which is around 71000 years. This is sufficient to store a date on an 43 * Epoch level precise to a ms. 44 */ 45 public static final TimeUnit BASE_SECOND; 46 47 /** The base unit for time with an artifical "zero" point with a calculation in microseconds. */ 48 public static final TimeUnit BASE_MICROSECOND; 49 50 /** The base unit for time with an artifical "zero" point with a calculation in milliseconds. */ 51 public static final TimeUnit BASE_MILLISECOND; 52 53 /** The base unit for time with an artifical "zero" point with a calculation in minutes. */ 54 public static final TimeUnit BASE_MINUTE; 55 56 /** The base unit for time with an artifical "zero" point with a calculation in hours. */ 57 public static final TimeUnit BASE_HOUR; 58 59 /** The base unit for time with an artifical "zero" point with a calculation in days. */ 60 public static final TimeUnit BASE_DAY; 61 62 /** The base unit for time with an artifical "zero" point with a calculation in weeks. */ 63 public static final TimeUnit BASE_WEEK; 64 65 /** 66 * The POSIX and Gregorian Epoch: January 1, 1970 at 00:00 UTC with a calculation in seconds. The base should be taken in 67 * such a way that a resolution of a millisecond is still 'visible' on a date in, say, 2020. When 1-1-1970 is used as the 68 * origin, 1-1-2020 has a value of 1,577,836,800,000 milliseconds = 1.6E12 ms. If we want to be precise on the ms level, we 69 * need 12 significant digits. A float has around 7 significant digits (23 bit mantissa), whereas a double has around 16 70 * significant digits (52 bit mantissa). This means that a float time with an offset of 1-1-1970 is at best precise to a 71 * minute level. A double time is precise to microseconds. Therefore, avoid using float times that use the EPOCH. 72 */ 73 public static final TimeUnit EPOCH; 74 75 /** The POSIX and Gregorian Epoch: January 1, 1970 at 00:00 UTC with a calculation in seconds. */ 76 public static final TimeUnit EPOCH_SECOND; 77 78 /** The POSIX and Gregorian Epoch: January 1, 1970 at 00:00 UTC with a calculation in microseconds. */ 79 public static final TimeUnit EPOCH_MICROSECOND; 80 81 /** The POSIX and Gregorian Epoch: January 1, 1970 at 00:00 UTC with a calculation in milliseconds. */ 82 public static final TimeUnit EPOCH_MILLISECOND; 83 84 /** The POSIX and Gregorian Epoch: January 1, 1970 at 00:00 UTC with a calculation in minutes. */ 85 public static final TimeUnit EPOCH_MINUTE; 86 87 /** The POSIX and Gregorian Epoch: January 1, 1970 at 00:00 UTC with a calculation in hours. */ 88 public static final TimeUnit EPOCH_HOUR; 89 90 /** The POSIX and Gregorian Epoch: January 1, 1970 at 00:00 UTC with a calculation in days. */ 91 public static final TimeUnit EPOCH_DAY; 92 93 /** The POSIX and Gregorian Epoch: January 1, 1970 at 00:00 UTC with a calculation in weeks. */ 94 public static final TimeUnit EPOCH_WEEK; 95 96 /** 97 * The Epoch with 0001-01-01 AD at 00:00 as the origin with a calculation in seconds. When 1-1-0001 is used as the origin, 98 * 1-1-2020 has a value of around 6.4E13 ms. If we want to be precise on the ms level, we need 13 significant digits. A 99 * float has around 7 significant digits (23 bit mantissa), whereas a double has around 16 significant digits (52 bit 100 * mantissa). This means that a float time with an offset of 1-1-0001 is at best precise to an hour level. A double time is 101 * precise to microseconds. Therefore, avoid using float times that use the EPOCH_YEAR_1. 102 */ 103 public static final TimeUnit EPOCH_YEAR_1; 104 105 /** 106 * The Epoch with J2000.0 as the origin, which is The Gregorian date January 1, 2000 at 12:00 GMT (noon) with a calculation 107 * in seconds. When 1-1-2000 is used as the origin, 1-1-2020 has a value of around 6.3E11 ms. If we want to be precise on 108 * the ms level, we need 11 significant digits. A float has around 7 significant digits (23 bit mantissa), whereas a double 109 * has around 16 significant digits (52 bit mantissa). This means that a float time with an offset of 1-1-2000 is at best 110 * precise to a minute level. A double time is precise to fractions of microseconds. Therefore, avoid using float times that 111 * use the EPOCH_J2000_1. 112 */ 113 public static final TimeUnit EPOCH_J2000_1; 114 115 static 116 { 117 BASE = new TimeUnit("TimeUnit.epoch.second", "TimeUnit.epoch.s", OTHER, 1.0, 0.0, true, DurationUnit.SECOND); 118 EPOCH = BASE; 119 EPOCH_SECOND = BASE; 120 BASE_SECOND = EPOCH_SECOND; 121 EPOCH_MICROSECOND = new TimeUnit("TimeUnit.epoch.microsecond", "TimeUnit.epoch.mus", OTHER, 1E-6, 0.0, true, 122 DurationUnit.MICROSECOND); 123 BASE_MICROSECOND = EPOCH_MICROSECOND; 124 EPOCH_MILLISECOND = new TimeUnit("TimeUnit.epoch.millisecond", "TimeUnit.epoch.ms", OTHER, 1E-3, 0.0, true, 125 DurationUnit.MILLISECOND); 126 BASE_MILLISECOND = EPOCH_MILLISECOND; 127 EPOCH_MINUTE = new TimeUnit("TimeUnit.epoch.minute", "TimeUnit.epoch.m", OTHER, 60.0, 0.0, true, DurationUnit.MINUTE); 128 BASE_MINUTE = EPOCH_MINUTE; 129 EPOCH_HOUR = new TimeUnit("TimeUnit.epoch.hour", "TimeUnit.epoch.h", OTHER, 3600.0, 0.0, true, DurationUnit.HOUR); 130 BASE_HOUR = EPOCH_HOUR; 131 EPOCH_DAY = new TimeUnit("TimeUnit.epoch.day", "TimeUnit.epoch.d", OTHER, 3600 * 24.0, 0.0, true, DurationUnit.DAY); 132 BASE_DAY = EPOCH_DAY; 133 EPOCH_WEEK = 134 new TimeUnit("TimeUnit.epoch.week", "TimeUnit.epoch.w", OTHER, 3600 * 24 * 7.0, 0.0, true, DurationUnit.WEEK); 135 BASE_WEEK = EPOCH_WEEK; 136 137 double seconds00010101 = new GregorianCalendar(1, 0, 1, 0, 0, 0).getTimeInMillis() / 1000.0; 138 EPOCH_YEAR_1 = 139 new TimeUnit("TimeUnit.epoch_1", "TimeUnit.epoch_1", OTHER, 1.0, seconds00010101, false, DurationUnit.SECOND); 140 141 double seconds20000101 = new GregorianCalendar(2000, 0, 1, 12, 0, 0).getTimeInMillis() / 1000.0; 142 EPOCH_J2000_1 = new TimeUnit("TimeUnit.epoch_j2000", "TimeUnit.epoch_j2000", OTHER, 1.0, seconds20000101, false, 143 DurationUnit.SECOND); 144 } 145 146 /** 147 * Build a TimeUnit with a scale factor and offset to the base TimeUnit. 148 * @param nameOrNameKey if standardUnit: the key to the locale file for the long name of the unit, otherwise the name itself 149 * @param abbreviationOrAbbreviationKey if standardUnit: the key to the locale file for the abbreviation of the unit, 150 * otherwise the abbreviation itself 151 * @param unitSystem the unit system, e.g. SI or Imperial 152 * @param scaleFactor multiply a value in this unit by the factor to convert to the given reference unit 153 * @param offset the offset to the reference unit to add to convert to the standard (e.g., BASE) unit 154 * @param standardUnit indicates whether it is a standard unit with a definition in the locale, or a user-defined unit 155 * @param relativeUnit the corresponding relative unit belonging to this absolute unit 156 */ 157 private TimeUnit(final String nameOrNameKey, final String abbreviationOrAbbreviationKey, final UnitSystem unitSystem, 158 final double scaleFactor, final double offset, final boolean standardUnit, final DurationUnit relativeUnit) 159 { 160 super(nameOrNameKey, abbreviationOrAbbreviationKey, unitSystem, scaleFactor, offset, standardUnit, relativeUnit); 161 } 162 163 /** 164 * Build a user-defined TimeUnit with a scale factor and offset to the base TimeUnit. 165 * @param name the long name of the unit 166 * @param abbreviation the abbreviation of the unit 167 * @param unitSystem the unit system, e.g. SI or Imperial 168 * @param scaleFactor multiply a value in this unit by the factor to convert to the given reference unit 169 * @param offset the offset to the reference unit to add to convert to the standard (e.g., BASE) unit 170 * @param relativeUnit the corresponding relative unit belonging to this absolute unit 171 */ 172 public TimeUnit(final String name, final String abbreviation, final UnitSystem unitSystem, final double scaleFactor, 173 final double offset, final DurationUnit relativeUnit) 174 { 175 this(name, abbreviation, unitSystem, scaleFactor, offset, false, relativeUnit); 176 } 177 178 /** {@inheritDoc} */ 179 @Override 180 public final TimeUnit getStandardUnit() 181 { 182 return BASE; 183 } 184 185 /** {@inheritDoc} */ 186 @Override 187 public final String getSICoefficientsString() 188 { 189 return "s"; 190 } 191 }