As of CDM version 4.3, dates are no longer handled by the udunits library. This allows handling non-standard Calendars. This change only affects datetime coordinate handling, called time coordinates in CF. For all dimensional units, the udunits package is still used.
The CDM library allows datetime coordinates to be specified in the following forms:
CDM 4.3 supports the following values of the calendar attribute, which is attached to the datetime coordinate:
The calendar attribute none is currently ignored by the CDM, but is available to the application to process. None of these calendars handle leap seconds, but with enough effort one could define, eg, a UTC or TAI calendar.
These calendars are implemented in the CDM with classes from Jon Blower's uk.ac.rdg.resc.edal.time package.
The CDM library version 4.3 and after continues to accept udunits for time coordinate units, but it doesn't use the udunit library to process them.
The udunit date grammar is difficult to understand. Heres an approximate regular expression:
period SINCE [-]Y[Y[Y[Y]]]-MM-DD[(T| )hh[:mm[:ss[.sss*]]][ [+|-]hh[[:]mm]]]
The following specifies the CDM udunit date grammar:
udunitDate = period SINCE reference_date period = "millisec" | "msec" | "second" | "sec" | "s" | "minute" | "min" | "hour" | "hr" | "day" | "week" | "month" | "mon" | "year" | "yr" period = period + "s" (plural form) reference_date = iso8601 formatted date as described below SINCE = literal (case insensitive)
where
udunits defines the periods as fixed multiples of seconds. The non-obvious ones are:
The udunit package has some other periods that are no longer supported by CDM udunit date grammar, such as "sidereal day", "lunar month", "fortnight", "eon", etc. Also CDM doesnt support the full menagerie of udunit prefixes like "nano", "mega", "kilo", and so on. Contact us if this is a problem.
CF and CDM agree that one should not use month or year as the period in a udunit, in order to avoid the following sort of problems:
0 months since 1930-01-01 == 1930-01-01T00:00:00Z 1 months since 1930-01-01 == 1930-01-31T10:29:03Z 2 months since 1930-01-01 == 1930-03-02T20:58:07Z 3 months since 1930-01-01 == 1930-04-02T07:27:11Z 4 months since 1930-01-01 == 1930-05-02T17:56:15Z 5 months since 1930-01-01 == 1930-06-02T04:25:19Z 6 months since 1930-01-01 == 1930-07-02T14:54:22Z 7 months since 1930-01-01 == 1930-08-02T01:23:26Z 8 months since 1930-01-01 == 1930-09-01T11:52:30Z 9 months since 1930-01-01 == 1930-10-01T22:21:34Z 10 months since 1930-01-01 == 1930-11-01T08:50:38Z 11 months since 1930-01-01 == 1930-12-01T19:19:42Z
0 years since 1850-01-01 == 1850-01-01T00:00:00Z 10 years since 1850-01-01 == 1860-01-01T10:07:39Z 20 years since 1850-01-01 == 1869-12-31T20:15:19Z 30 years since 1850-01-01 == 1880-01-01T06:22:59Z 40 years since 1850-01-01 == 1889-12-31T16:30:38Z 50 years since 1850-01-01 == 1900-01-01T02:38:18Z 60 years since 1850-01-01 == 1910-01-01T12:45:58Z 70 years since 1850-01-01 == 1920-01-01T22:53:38Z 80 years since 1850-01-01 == 1930-01-01T09:01:17Z 90 years since 1850-01-01 == 1940-01-01T19:08:57Z
The CDM accepts an extended form of udunit grammar, called a calendar field unit:
CALENDAR period SINCE reference_date
The presence of "CALENDAR" (case insensitive) means that the CDM library manipulates the calendar field directly, rather than converting the period to a fixed multiple of seconds. The actual result depends on the calendar used. Note that values of the period must be an integer.
For example:
1 calendar months since 1930-01-01 00:00:00Z == 1930-02-01T00:00:00.000Z 2 calendar months since 1930-01-01 00:00:00Z == 1930-03-01T00:00:00.000Z 3 calendar months since 1930-01-01 00:00:00Z == 1930-04-01T00:00:00.000Z 4 calendar months since 1930-01-01 00:00:00Z == 1930-05-01T00:00:00.000Z 5 calendar months since 1930-01-01 00:00:00Z == 1930-06-01T00:00:00.000Z 6 calendar months since 1930-01-01 00:00:00Z == 1930-07-01T00:00:00.000Z 7 calendar months since 1930-01-01 00:00:00Z == 1930-08-01T00:00:00.000Z 8 calendar months since 1930-01-01 00:00:00Z == 1930-09-01T00:00:00.000Z 9 calendar months since 1930-01-01 00:00:00Z == 1930-10-01T00:00:00.000Z 10 calendar months since 1930-01-01 00:00:00Z == 1930-11-01T00:00:00.000Z 11 calendar months since 1930-01-01 00:00:00Z == 1930-12-01T00:00:00.000Z 12 calendar months since 1930-01-01 00:00:00Z == 1931-01-01T00:00:00.000Z
1 calendar years since 1930-01-01 00:00:00Z == 1931-01-01T00:00:00.000Z 2 calendar years since 1930-01-01 00:00:00Z == 1932-01-01T00:00:00.000Z 3 calendar years since 1930-01-01 00:00:00Z == 1933-01-01T00:00:00.000Z 4 calendar years since 1930-01-01 00:00:00Z == 1934-01-01T00:00:00.000Z 5 calendar years since 1930-01-01 00:00:00Z == 1935-01-01T00:00:00.000Z 6 calendar years since 1930-01-01 00:00:00Z == 1936-01-01T00:00:00.000Z 7 calendar years since 1930-01-01 00:00:00Z == 1937-01-01T00:00:00.000Z 8 calendar years since 1930-01-01 00:00:00Z == 1938-01-01T00:00:00.000Z 9 calendar years since 1930-01-01 00:00:00Z == 1939-01-01T00:00:00.000Z 10 calendar years since 1930-01-01 00:00:00Z == 1940-01-01T00:00:00.000Z 11 calendar years since 1930-01-01 00:00:00Z == 1941-01-01T00:00:00.000Z 12 calendar years since 1930-01-01 00:00:00Z == 1942-01-01T00:00:00.000ZNote that invalid dates are decremented until valid:
0 calendar months since 1930-01-31 00:00:00Z == 1930-01-31T00:00:00.000Z 1 calendar months since 1930-01-31 00:00:00Z == 1930-02-28T00:00:00.000Z 2 calendar months since 1930-01-31 00:00:00Z == 1930-03-31T00:00:00.000Z 3 calendar months since 1930-01-31 00:00:00Z == 1930-04-30T00:00:00.000Z 4 calendar months since 1930-01-31 00:00:00Z == 1930-05-31T00:00:00.000Z 5 calendar months since 1930-01-31 00:00:00Z == 1930-06-30T00:00:00.000Z 6 calendar months since 1930-01-31 00:00:00Z == 1930-07-31T00:00:00.000Z 7 calendar months since 1930-01-31 00:00:00Z == 1930-08-31T00:00:00.000Z 8 calendar months since 1930-01-31 00:00:00Z == 1930-09-30T00:00:00.000Z 9 calendar months since 1930-01-31 00:00:00Z == 1930-10-31T00:00:00.000Z 10 calendar months since 1930-01-31 00:00:00Z == 1930-11-30T00:00:00.000Z 11 calendar months since 1930-01-31 00:00:00Z == 1930-12-31T00:00:00.000Z 12 calendar months since 1930-01-31 00:00:00Z == 1931-01-31T00:00:00.000Zand:
0 calendar years since 2008-02-29 00:00:00Z == 2008-02-29T00:00:00.000Z 1 calendar years since 2008-02-29 00:00:00Z == 2009-02-28T00:00:00.000Z 2 calendar years since 2008-02-29 00:00:00Z == 2010-02-28T00:00:00.000Z 3 calendar years since 2008-02-29 00:00:00Z == 2011-02-28T00:00:00.000Z 4 calendar years since 2008-02-29 00:00:00Z == 2012-02-29T00:00:00.000Z 5 calendar years since 2008-02-29 00:00:00Z == 2013-02-28T00:00:00.000Z 6 calendar years since 2008-02-29 00:00:00Z == 2014-02-28T00:00:00.000Z 7 calendar years since 2008-02-29 00:00:00Z == 2015-02-28T00:00:00.000Z 8 calendar years since 2008-02-29 00:00:00Z == 2016-02-29T00:00:00.000Z 9 calendar years since 2008-02-29 00:00:00Z == 2017-02-28T00:00:00.000Z 10 calendar years since 2008-02-29 00:00:00Z == 2018-02-28T00:00:00.000Z 11 calendar years since 2008-02-29 00:00:00Z == 2019-02-28T00:00:00.000Z 12 calendar years since 2008-02-29 00:00:00Z == 2020-02-29T00:00:00.000Z 13 calendar years since 2008-02-29 00:00:00Z == 2021-02-28T00:00:00.000Z 14 calendar years since 2008-02-29 00:00:00Z == 2022-02-28T00:00:00.000Z
The CDM uses the W3C profile of ISO 8601 formatting for reading and writing calendar dates:
The formats defined by the W3C profile of ISO 8601 are as follows. Exactly the components shown here must be present, with exactly this punctuation. Note that the "T" appears literally in the string, to indicate the beginning of the time element, as specified in ISO 8601.
Year: YYYY (eg 1997) Year and month: YYYY-MM (eg 1997-07) Complete date: YYYY-MM-DD (eg 1997-07-16) Complete date plus hours and minutes: YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00) Complete date plus hours, minutes and seconds: YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00) Complete date plus hours, minutes, seconds and a decimal fraction of a second YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)where:
YYYY = four-digit year MM = two-digit month (01=January, etc.) DD = two-digit day of month (01 through 31) hh = two digits of hour (00 through 23) (am/pm NOT allowed) mm = two digits of minute (00 through 59) ss = two digits of second (00 through 59) s = one or more digits representing a decimal fraction of a second TZD = time zone designator (Z or +hh:mm or -hh:mm)
with the following differences, to allow backwards compatibility with udunits:
In addition, the following must be done:
N [calendar] UNITS since DATE // current N [calendar] UNITS since 65500 BCE // assume we mean 0Z on 1 Jan. always calendar years N [calendar] UNITS since 65500k BCE N [calendar] UNITS since 65M BCE N calendar Myears before 1980-01-01
in CalendarDate class:
public static CalendarDate of(Calendar cal, int year, int monthOfYear, int dayOfMonth, int hourOfDay, int minuteOfHour, int secondOfMinute);
in CalendarDateFormatter class:
public static CalendarDate isoStringToCalendarDate(Calendar calt, String iso) throws IllegalArgumentException;