View Javadoc
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 }