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-2024 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 }