1 package org.djunits.unit;
2
3 import java.util.GregorianCalendar;
4
5 import org.djunits.quantity.Quantity;
6 import org.djunits.unit.scale.OffsetLinearScale;
7 import org.djunits.unit.si.SIPrefixes;
8 import org.djunits.unit.unitsystem.UnitSystem;
9
10 /**
11 * Standard absolute time units. Note that when the offset of a stored absolute Time becomes large, precision of a float or
12 * double might not be enough for the required resolution of a Time. A float has around 7 significant digits (23 bit mantissa),
13 * whereas a double has around 16 significant digits (52 bit mantissa). This means that when we need to have a float time that
14 * 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!
15 * So feeding System.TimeInMillis() to a FloatTime with TimeUnit.BASE as its unit is not having the required precision. For a
16 * (double) Time with TimeUnit.BASE as its unit, the largest value where the ms precision is reached is 2^51 = 2.3E15, which is
17 * around 71000 years. This is sufficient to store a date on an Epoch level precise to a ms.
18 * <p>
19 * Copyright (c) 2015-2025 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
20 * BSD-style license. See <a href="https://djunits.org/docs/license.html">DJUNITS License</a>.
21 * </p>
22 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
23 */
24 public class TimeUnit extends AbsoluteLinearUnit<TimeUnit, DurationUnit>
25 {
26 /** */
27 private static final long serialVersionUID = 20140607L;
28
29 /** The base, with "m2" as the SI signature. */
30 public static final Quantity<TimeUnit> BASE = new Quantity<>("Time", "s");
31
32 /**
33 * The base unit for time with an artifical "zero" point with a calculation in seconds. Note that when the offset becomes
34 * large, precision of a float or double might not be enough for the required resolution of a Time. A float has around 7
35 * significant digits (23 bit mantissa), whereas a double has around 16 significant digits (52 bit mantissa). This means
36 * 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.
37 * This is <b>not</b> enough to store Epoch values! So feeding System.TimeInMillis() to a FloatTime with TimeUnit.BASE as
38 * its unit is not having the required precision. For a (double) Time with TimeUnit.BASE as its unit, the largest value
39 * 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
40 * Epoch level precise to a ms.
41 */
42 public static final TimeUnit BASE_SECOND = new TimeUnit().build(new AbsoluteLinearUnit.Builder<TimeUnit, DurationUnit>()
43 .setQuantity(BASE).setId("s").setName("second").setUnitSystem(UnitSystem.SI_DERIVED)
44 .setSiPrefixes(SIPrefixes.UNIT, 1.0).setRelativeUnit(DurationUnit.SECOND).setScale(new OffsetLinearScale(1.0, 0.0))
45 .setDefaultDisplayAbbreviation("s").setDefaultTextualAbbreviation("s").setAdditionalAbbreviations("sec"));
46
47 /** The default unit for time is BASE_SECOND. */
48 public static final TimeUnit DEFAULT = BASE_SECOND;
49
50 /** The base unit for time with an artificial "zero" point with a calculation in microseconds. */
51 public static final TimeUnit BASE_MICROSECOND = BASE_SECOND.deriveLinearOffset(1.0E-6, 0.0, DurationUnit.MICROSECOND, "mus",
52 "microsecond", UnitSystem.SI_DERIVED, "\u03BCs", "mus", "\u03BCsec", "musec");
53
54 /** The base unit for time with an artificial "zero" point with a calculation in milliseconds. */
55 public static final TimeUnit BASE_MILLISECOND = BASE_SECOND.deriveLinearOffset(1.0E-3, 0.0, DurationUnit.MILLISECOND, "ms",
56 "millisecond", UnitSystem.SI_DERIVED, "ms", "ms", "msec");
57
58 /** The base unit for time with an artificial "zero" point with a calculation in minutes. */
59 public static final TimeUnit BASE_MINUTE = BASE_SECOND.deriveLinearOffset(60.0, 0.0, DurationUnit.MINUTE, "min", "minute",
60 UnitSystem.SI_DERIVED, "min", "min");
61
62 /** The base unit for time with an artificial "zero" point with a calculation in hours. */
63 public static final TimeUnit BASE_HOUR = BASE_SECOND.deriveLinearOffset(3600.0, 0.0, DurationUnit.HOUR, "h", "hour",
64 UnitSystem.SI_DERIVED, "h", "h", "hr", "hour");
65
66 /** The base unit for time with an artificial "zero" point with a calculation in days. */
67 public static final TimeUnit BASE_DAY = BASE_SECOND.deriveLinearOffset(24.0 * 3600.0, 0.0, DurationUnit.DAY, "day", "day",
68 UnitSystem.SI_DERIVED, "day", "day");
69
70 /** The base unit for time with an artificial "zero" point with a calculation in weeks. */
71 public static final TimeUnit BASE_WEEK = BASE_SECOND.deriveLinearOffset(7.0 * 24.0 * 3600.0, 0.0, DurationUnit.WEEK, "wk",
72 "week", UnitSystem.SI_DERIVED, "wk", "wk", "week");
73
74 /**
75 * The POSIX and Gregorian Epoch: January 1, 1970 at 00:00 UTC with a calculation in seconds. The base should be taken in
76 * 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
77 * origin, 1-1-2021 has a value of 1,577,836,800,000 milliseconds = 1.6E12 ms. If we want to be precise on the ms level, we
78 * need 12 significant digits. A float has around 7 significant digits (23 bit mantissa), whereas a double has around 16
79 * significant digits (52 bit mantissa). This means that a float time with an offset of 1-1-1970 is at best precise to a
80 * minute level. A double time is precise to microseconds. Therefore, avoid using float times that use the EPOCH.
81 */
82 public static final TimeUnit EPOCH_SECOND = BASE_SECOND.deriveLinearOffset(1.0, 0.0, DurationUnit.SECOND, "s(Y1970)",
83 "seconds since 1/1/70", UnitSystem.OTHER, "s(Y1970)", "s(Y1970)", "sec(Y1970)");
84
85 /** The POSIX and Gregorian Epoch: January 1, 1970 at 00:00 UTC with a calculation in microseconds. */
86 public static final TimeUnit EPOCH_MICROSECOND =
87 BASE_SECOND.deriveLinearOffset(1.0E-6, 0.0, DurationUnit.MICROSECOND, "mus(Y1970)", "microseconds since 1/1/70",
88 UnitSystem.OTHER, "\u03BCs(Y1970)", "mus(Y1970)", "\u03BCsec(Y1970)", "musec(Y1970)");
89
90 /** The POSIX and Gregorian Epoch: January 1, 1970 at 00:00 UTC with a calculation in milliseconds. */
91 public static final TimeUnit EPOCH_MILLISECOND = BASE_SECOND.deriveLinearOffset(1.0E-3, 0.0, DurationUnit.MILLISECOND,
92 "ms(Y1970)", "milliseconds since 1/1/70", UnitSystem.OTHER, "ms(Y1970)", "ms(Y1970)", "msec(Y1970)");
93
94 /** The POSIX and Gregorian Epoch: January 1, 1970 at 00:00 UTC with a calculation in minutes. */
95 public static final TimeUnit EPOCH_MINUTE = BASE_SECOND.deriveLinearOffset(60.0, 0.0, DurationUnit.MINUTE, "min(Y1970)",
96 "minutes since 1/1/70", UnitSystem.OTHER, "min(Y1970)", "min(Y1970)");
97
98 /** The POSIX and Gregorian Epoch: January 1, 1970 at 00:00 UTC with a calculation in hours. */
99 public static final TimeUnit EPOCH_HOUR = BASE_SECOND.deriveLinearOffset(3600.0, 0.0, DurationUnit.HOUR, "h(Y1970)",
100 "hours since 1/1/70", UnitSystem.OTHER, "h(Y1970)", "h(Y1970)", "hour(Y1970)", "hr(Y1970)");
101
102 /** The POSIX and Gregorian Epoch: January 1, 1970 at 00:00 UTC with a calculation in days. */
103 public static final TimeUnit EPOCH_DAY = BASE_SECOND.deriveLinearOffset(24.0 * 3600.0, 0.0, DurationUnit.DAY, "day(Y1970)",
104 "days since 1/1/70", UnitSystem.OTHER, "day(Y1970)", "day(Y1970)");
105
106 /** The POSIX and Gregorian Epoch: January 1, 1970 at 00:00 UTC with a calculation in weeks. */
107 public static final TimeUnit EPOCH_WEEK = BASE_SECOND.deriveLinearOffset(7.0 * 24.0 * 3600.0, 0.0, DurationUnit.WEEK,
108 "wk(Y1970)", "weeks since 1/1/70", UnitSystem.OTHER, "wk(Y1970)", "wk(Y1970)", "week(Y1970)");
109
110 /**
111 * 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,
112 * 1-1-2021 has a value of around 6.4E13 ms. If we want to be precise on the ms level, we need 13 significant digits. A
113 * float has around 7 significant digits (23 bit mantissa), whereas a double has around 16 significant digits (52 bit
114 * 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
115 * precise to microseconds. Therefore, avoid using float times that use the EPOCH_YEAR1_SECOND.
116 */
117 public static final TimeUnit EPOCH_YEAR1_SECOND = EPOCH_SECOND.deriveLinearOffset(1.0,
118 new GregorianCalendar(1, 0, 1, 0, 0, 0).getTimeInMillis() / 1000.0, DurationUnit.SECOND, "s(Y1)",
119 "seconds since 1-1-0001 00:00", UnitSystem.OTHER, "s(Y1)", "s(Y1)", "sec(Y1)");
120
121 /**
122 * The Epoch with J2000.0 as the origin, which is The Gregorian date January 1, 2000 at 12:00 GMT (noon) with a calculation
123 * in seconds. When 1-1-2000 is used as the origin, 1-1-2021 has a value of around 6.3E11 ms. If we want to be precise on
124 * the ms level, we need 11 significant digits. A float has around 7 significant digits (23 bit mantissa), whereas a double
125 * has around 16 significant digits (52 bit mantissa). This means that a float time with an offset of 1-1-2000 is at best
126 * precise to a minute level. A double time is precise to fractions of microseconds. Therefore, avoid using float times that
127 * use the EPOCH_J2000_SECOND.
128 */
129 public static final TimeUnit EPOCH_J2000_SECOND = EPOCH_SECOND.deriveLinearOffset(1.0,
130 new GregorianCalendar(2000, 0, 1, 12, 0, 0).getTimeInMillis() / 1000.0, DurationUnit.SECOND, "s(Y2000)",
131 "seconds since 1-1-2000 12:00 GMT", UnitSystem.OTHER, "s(Y2000)", "s(Y2000)", "sec(Y2000)");
132
133 }