diff --git a/.github/workflows/adoc_build.yml b/.github/workflows/adoc_build.yml index 2871aece..2659dfe8 100644 --- a/.github/workflows/adoc_build.yml +++ b/.github/workflows/adoc_build.yml @@ -18,24 +18,41 @@ # https://github.com/Analog-inc/asciidoctor-action # https://github.com/actions/upload-artifact # https://github.com/actions/download-artifact +# https://github.com/action-badges/create-orphan-branch # +# Custom workflow for pages deployment +# name: Asciidoctor Build Workflow on: # manually run workflow workflow_dispatch: - # trigger on PR event against main (will not run publish job) + + # trigger on PR event against default branch (i.e. main) (will not run publish job) pull_request: branches: [ main ] - # Trigger on a push to main (a PR is merged), or when a release is + # Trigger on a push to default branch (i.e. main) (a PR is merged), or when a release is + # published on github. These will run the publish job. push: - branches: - - main + branches: [ main ] # Trigger when a GitHub release is published. release: types: - published -jobs: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: write + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: # Job to build cf-conventions.html, cf-conventions.pdf build_conventions_and_conformance: name: Build cf-conventions and conformance html and pdf @@ -75,12 +92,35 @@ jobs: if: github.event_name != 'pull_request' # Wait for the build artifacts to become available needs: [build_conventions_and_conformance] + +# # Grant GITHUB_TOKEN the permissions required to make a Pages deployment +# permissions: +# pages: write # to deploy to Pages +# id-token: write # to verify the deployment originates from an appropriate source + +# # Deploy to the github-pages environment +# environment: +# name: github-pages +# url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest steps: + # Checkout repo + - uses: actions/checkout@v4 + # create a new orphan branch if a branch with the given name does not already exist + - name: Create Orphan Branch + uses: action-badges/create-orphan-branch@0.1.1 + with: + branch-name: 'gh-pages' # Checkout gh-pages branch - uses: actions/checkout@v4 with: ref: 'gh-pages' + - name: Add .nojekyll file if it doesn't exist + run: | + if [ ! -f .nojekyll ]; then + touch .nojekyll + fi # Will new docs go into root, or into a directory named after the # release? - name: Determine where the new documents should live @@ -102,10 +142,10 @@ jobs: if: github.event_name == 'release' run: mkdir -p ${{ env.TARGET_DIR }} # If we are not doing a release, let's clean out the previous images - # directory in the root directory + # directory in the root directory (OLD TO BE DEPRECATED) - name: Remove old images directory if: github.event_name != 'release' - run: rm -rf ${{ env.TARGET_DIR }}/images + run: sudo rm -rf ${{ env.TARGET_DIR }}/images - name: Copy conventions and conformance documents run: | cp -p build/cf-conventions.html ${{ env.TARGET_DIR }}/ diff --git a/.gitignore b/.gitignore index 662b639a..50afdd97 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ conventions_build/ conformance.html conformance.pdf conformance_build/ +build/ .vscode/ diff --git a/appa.adoc b/appa.adoc index 1eaa8ee9..ed0da1cd 100644 --- a/appa.adoc +++ b/appa.adoc @@ -386,8 +386,8 @@ In cases where there is a strong constraint on dataset size, it is allowed to pa | **`units_metadata`** | S | C, D, BI -| <> -| Specifies the interpretation (on-scale, difference or unknown) of the unit of temperature appearing in the **`units`** attribute. +| <>, and <> +| Specifies the interpretation of a unit of measure appearing in the **`units`** attribute. | **`valid_max`** | N diff --git a/ch01.adoc b/ch01.adoc index 7fa20950..215a2528 100644 --- a/ch01.adoc +++ b/ch01.adoc @@ -71,6 +71,8 @@ The netCDF utilities ncdump and ncgen use this format (see link:$$https://docs.unidata.ucar.edu/nug/current/_c_d_l.html$$[NUG section on CDL syntax]). All examples in this document use CDL syntax. +calendar:: A CF calendar defines an ordered set of valid datetimes with integer seconds. + cell:: A region in one or more dimensions whose boundary can be described by a set of vertices. The term __interval__ is sometimes used for one-dimensional cells. @@ -81,6 +83,8 @@ The coordinate values must be in strict monotonic order (all values are differen Missing values are not allowed in coordinate variables. To avoid confusion with coordinate variables, CF does not permit a one-dimensional string-valued variable to have the same name as its dimension. +datetime:: The set of numbers which together identify an instant of time, namely its year, month, day, hour, minute and second, where the second may have a fraction but the others are all integer. + grid mapping variable:: A variable used as a container for attributes that define a specific grid mapping. The type of the variable is arbitrary since it contains no data. diff --git a/ch02.adoc b/ch02.adoc index a0e569bf..03f6b2ea 100644 --- a/ch02.adoc +++ b/ch02.adoc @@ -176,7 +176,7 @@ If it is observational, **`source`** should characterize it (e.g., "**`surface o **`history`**:: Provides an audit trail for modifications to the original data. Well-behaved generic netCDF filters will automatically append their name and the parameters with which they were invoked to the global history attribute of an input netCDF file. -We recommend that each line begin with a timestamp indicating the date and time of day that the program was executed. +We recommend that each line begin by indicating the date and time of day that the program was executed. **`references`**:: Published or web-based references that describe the data or methods used to produce it. diff --git a/ch03.adoc b/ch03.adoc index 9e54fce0..f1f3f386 100644 --- a/ch03.adoc +++ b/ch03.adoc @@ -165,6 +165,12 @@ A standard name contains no whitespace and is case sensitive. canonical units:: Representative units of the physical quantity. Unless it is dimensionless, a variable with a **`standard_name`** attribute must have units which are physically equivalent (not necessarily identical) to the canonical units, possibly modified by an operation specified by the standard name modifier (see below and <>) or by the **`cell_methods`** attribute (see <> and <>) or both. +Units of time coordinates (<>), whose **`units`** attribute includes the word **`since`**, are _not_ physically equivalent to time units that do not include **`since`** in the **`units`**. +To mark this distinction, the canonical unit given for quantities used for time coordinates is **`s since 1958-1-1`**. +The reference datetime in the canonical unit (the beginning of the day i.e. midnight on 1st January 1958 at 0 `degrees_east`) is not restrictive; the time coordinate variable's own **`units`** may contain any reference datetime (after **`since`**) that is valid in its calendar. +(We use `1958-1-1` because it is the beginning of International Atomic Time, and a valid datetime in all CF calendars; see also <>.) +In both kinds of time **`units`** attribute (with or without **`since`**), any unit for measuring time can be used i.e. any unit which is physically equivalent to the SI base unit of time, namely the second. + description:: The description is meant to clarify the qualifiers of the fundamental quantities such as which surface a quantity is defined on or what the flux sign conventions are. We don't attempt to provide precise definitions of fundumental physical quantities (e.g., temperature) which may be found in the literature. The description may define rules on the variable type, attributes and coordinates which must be complied with by any variable carrying that standard name (such as in Example 3.5). diff --git a/ch04.adoc b/ch04.adoc index 7763f730..f957f718 100644 --- a/ch04.adoc +++ b/ch04.adoc @@ -1,5 +1,7 @@ [[coordinate-types, Chapter 4, Coordinate Types]] -== Coordinate Types +== Coordinate Types +:doc-part: 4 +:figure: 0 The commonest use of coordinate variables is to locate the data in space and time, but coordinates may be provided for any other continuous geophysical quantity (e.g. density, temperature, radiation wavelength, zenith angle of radiance, sea surface wave frequency) or discrete category (see <>, e.g. area type, model level number, ensemble member number) on which the data variable depends. @@ -185,97 +187,323 @@ The `computed_standard_name` attribute indicates that the values in variable [[time-coordinate, Section 4.4, "Time Coordinate"]] === Time Coordinate -Variables representing reference time must always explicitly include the **`units`** attribute; there is no default value. -The **`units`** attribute takes a string value that follows the formatting requirements of the <> package. These requirements can best be described by an example with explanatory comments: +A time coordinate is a number which identifies an instant along the continuous physical dimension of time, whether in reality or in a model. +The instant can equivalently be identified by its datetime, which is a set of numbers comprising year, month, day, hour, minute and second, where the second may have a fraction but the others are all integer. +The time coordinate and the datetime are interconvertible given the **`calendar`** attribute of the time coordinate variable (<>) and its **`units`** attribute (containing the time unit of the coordinate values and the reference datetime, <>). -The time unit specification **`seconds since 1992-10-8 15:15:42.5 -6:00`** indicates seconds since October 8th, 1992 at 3 hours, 15 minutes and 42.5 seconds in the afternoon in the time zone which is six hours to the west of Coordinated Universal Time (i.e. Mountain Daylight Time). -The time zone specification can also be written without a colon using one or two digits (indicating hours) or three or four digits (indicating hours and minutes). - -The acceptable units for time are given by the UDUNITS package. -The most commonly used of these strings (and their abbreviations) includes **`day`** (**`d`**), **`hour`** (**`hr`**, **`h`**), **`minute`** (**`min`**) and **`second`** (**`sec`**, **`s`**). -Plural forms are also acceptable. - -UDUNITS permits a number of alternatives to the word **`since`** in the units of time coordinates. All the alternatives have exactly the same meaning in UDUNITS. For compatibility with other software, CF strongly recommends that `since` should be used. - -The reference date/time string (appearing after the identifier **`since`**) is required. -It may include date alone, or date and time, or date, time and time zone. -If the time zone is omitted the default is UTC, and if both time and time zone are omitted the default is 00:00:00 UTC. - -UDUNITS defines a **`year`** to be exactly 365.242198781 days (the interval between 2 successive passages of the sun through vernal equinox). -__It is not a calendar year.__ UDUNITS defines a **`month`** to be exactly **`year/12`**, which is __not a calendar month__. -The CF standard follows UDUNITS in the definition of units, but we recommend that **`year`** and **`month`** should not be used, because of the potential for mistakes and confusion. +Variables containing time coordinates must always explicitly include the **`units`** attribute, formatted as described in <>. +There is no default value for the **`units`**. +A coordinate variable is identifiable as a time coordinate variable from its **`units`** alone. +Optionally, a time coordinate variable may be indicated additionally by providing the **`standard_name`** attribute with an appropriate value, and/or the **`axis`** attribute with the value **`T`**. [[time-axis-ex]] [caption="Example 4.4. "] -.Time axis +.Example of a time coordinate variable ==== ---- double time(time) ; - time:long_name = "time" ; - time:units = "days since 1990-1-1 0:0:0" ; + time:axis = "T"; // optional + time:standard_name = "time" ; // optional + time:units = "days since 1990-1-1 0:0:0" ; // mandatory ---- ==== -A reference time coordinate is identifiable from its units string alone. -Optionally, the time coordinate may be indicated additionally by providing the **`standard_name`** attribute with an appropriate value, and/or the **`axis`** attribute with the value **`T`**. +[[time-coordinate-units, Section 4.4.1, "Time Coordinate Units"]] +==== Time Coordinate Units + +The **`units`** attribute of a time coordinate variable takes a string value that follows the formatting requirements of the <> package (e.g. <>). +It must comprise a unit of measure that is physically equivalent to the SI base unit of time (i.e. the second), followed by the word **`since`** and a reference datetime. +The format of the **`units`** string implies that the time coordinate equals the length of the time interval from the instant identified by the reference datetime to the instant identified by the time coordinate. +This is exactly true in all cases except when leap seconds occur between the two intervals in the **`standard`**, **`proleptic_gregorian`**, and **`julian`** calendars. +See <>. + +The acceptable units of measure for time are given by UDUNITS. +The most commonly used of these strings (and their abbreviations) are **`day`** (**`d`**), **`hour`** (**`hr`**, **`h`**), **`minute`** (**`min`**) and **`second`** (**`sec`**, **`s`**). +Plural forms are also acceptable. + +UDUNITS defines a **`year`** to be exactly 365.242198781 days (the interval between 2 successive passages of the sun through vernal equinox). +__It is not a calendar year.__ UDUNITS defines a **`month`** to be exactly **`year/12`**, which is __not a calendar month__. +The CF standard follows UDUNITS in the definition of units, but we recommend that **`year`** and **`month`** should not be used, because of the potential for mistakes and confusion. + +UDUNITS defines a **`minute`** as 60 **`seconds`**, an **`hour`** as 3600 **`seconds`** and a **`day`** as 86400 **`seconds`**. +These are not calendar units. +When a leap second is inserted into UTC, the minute, hour and day affected differ by one second from their usual durations according to clock time, but the UDUNITS and CF **`minute`**, **`hour`** and **`day`** do not; they are fixed units of measure. +See also <>. + +UDUNITS permits a number of alternatives to the word **`since`** in the units of time coordinates. +All the alternatives have exactly the same meaning in UDUNITS. +For compatibility with other software, CF strongly recommends that `since` should be used. + +The reference datetime string (appearing after the identifier **`since`**) is required. +It may include date alone, or date and time, or date, time and time zone offset. +Its format is __y__-__m__-__d__ [__H__:__M__:__S__ [__Z__]], where [...] indicates an optional element, + +* _y_ is year, _m_ month, _d_ day, _H_ hour and _M_ minute, which are all integers of one or more digits, and _y_ may be prefixed with a sign (but note that some CF calendars do not permit negative years; see <>), + +* _S_ is second, which may be integer or floating point (see <> regarding __S__>59), + +* _Z_ is the time zone offset with respect to UTC. +This is an interval of time, specified in one of the formats described below. +Only numbers (digits, `+`, `-` and `:`) are allowed in _Z_, not time zone names or acronyms. + +The default time zone offset is zero. +In a time zone with zero offset, time (approximately) equals mean solar time for 0 `degrees_east` of longitude. +(Although this may be exact in a model, in reality the time with zero time zone offset differs by some seconds from mean solar time; see the discussion of UTC and leap seconds in <>.) +If both time and time zone offset are omitted the time is 00:00:00 (the beginning of the day i.e. midnight at 0 `degrees_east`). +Thus, **`units = "days since 1990-1-1"`** means the same as **`units = "days since 1990-1-1 0:0:0"`**. + +The time zone offset _Z_ must be in one of the following four formats, any of which may be prefixed with a sign: + +** _H_, the hour alone, of one or two digits e.g. **`-6`**, **`2`**, **`+11`**, which is sufficient for many time zones. + +** __H__:__M__, where _H_ is hour and _M_ minute, each of one or two digits, e.g. **`5:30`**. -[[calendar, Section 4.4.1, "Calendar"]] +** four digits, of which the first pair are the hours and the second the minutes e.g. **`0530`**. + +** three digits, of which the first is the hour (0--9) e.g. **`530`**. + +For example, **`seconds since 1992-10-8 15:15:42.5 -6:00`** indicates seconds since October 8th, 1992 at 3 hours, 15 minutes and 42.5 seconds in the afternoon, in a time zone where the datetime is six hours behind the default. +Subtracting the time zone offset from a given datetime converts it to the equivalent datetime with zero time zone offset e.g. **`1989-12-31 18:00:00 -6`** identifies the same instant as **`1990-1-1 0:0:0`**. + + +[[calendar, Section 4.4.2, "Calendar"]] ==== Calendar -A date/time is the set of numbers which together identify an instant of time, namely its year, month, day, hour, minute and second, where the second may have a fraction but the others are all integer. -A time coordinate value represents a date/time. -In order to calculate a time coordinate value from a date/time, or the reverse, one must know the **`units`** attribute of the time coordinate variable (containing the time unit of the coordinate values and the reference date/time) and the calendar. -The choice of calendar defines the set of dates (year-month-day combinations) which are permitted, and therefore it specifies the number of days between the times of **`0:0:0`** (midnight) on any two dates. -Date/times which are not permitted in a given calendar are prohibited in both the encoded time coordinate values, and in the reference date/time string. +The calendar defines the set of valid datetimes and their order. +Note that the CF meaning of "calendar" refers to datetimes, not to dates alone. +Datetimes which are not permitted in a given calendar are prohibited both in the time coordinate values and in the reference datetime string in the **`units`**. It is recommended that the calendar be specified by the **`calendar`** attribute of the time coordinate variable. +The values currently defined for **`calendar`** are listed below. -When a time coordinate value is calculated from a date/time, or the reverse, it is assumed that the coordinate value increases by exactly 60 seconds from the start of any minute (identified by year, month, day, hour, minute, all being integers) to the start of the next minute, with no leap seconds, in all CF calendars. -This assumption has various consequences when real-world date/times from calendars which do contain leap seconds (such as UTC) are stored in time coordinate variables: +Because the calendars have different sets of valid dates, and different treatments of leap seconds (see below in this section, and <>), a given time coordinate value with given **`units`** can represent different datetimes in different calendars; conversely, a given datetime is represented by different time coordinate values in different calendars. +Moreover, in different calendars a given datetime can identify a different instant in the continuous physical dimension of time. +// Examples of these situations are shown in the table of *Appendix ???*. -* Any date/times between the end of the 60th second of the last minute of one hour and the start of the first second of the next hour cannot be represented by time coordinates e.g. **`2016-12-31 23:59:60.5`** cannot be represented. -* A time coordinate value must not be interpreted as representing a date/time in the excluded range. -For instance, **`60 seconds after 23:59`** means **`00:00`** on the next day. -* A date/time in the excluded range must not be used as a reference date/time e.g. **`seconds since 2016-12-31 23:59:60`** is not a permitted value for **`units`**. -* It is important to realise that a time coordinate value does not necessarily exactly equal the actual length of the interval of time between the reference date/time and the date/time it represents. +The lengths of the months in the Gregorian calendar are used in all calendars except **`360_day`**, **`none`** (see <>) and explicitly defined calendars (see <>). +The calendars differ in their treatment of leap years (when there are 29 days in February instead of 28). -The values currently defined for **`calendar`** are listed below. -In all calendars except **`360_day`** and **`none`**, the lengths of the months are the same as in the Gregorian calendar for leap years and non-leap years. -In the **`julian`** and the default **`standard`** mixed Gregorian/Julian calendar, dates in years before year 0 (i.e. before 0-1-1 0:0:0) are not allowed, and the year in the reference date/time of the units must not be negative. +Leap seconds are adjustments made at irregular and unpredictable intervals in Coordinated Universal Time (link:$$https://en.wikipedia.org/wiki/Coordinated_Universal_Time$$[UTC]). +In response to slight variations in the Earth's rotation speed, positive or negative leap seconds are inserted in order to keep UTC close to mean solar time at 0 `degrees_east` i.e. the time zone with the default (zero) time zone offset in UDUNITS and CF (see <>). +When a single positive leap second is introduced at the end of a minute, that minute contains 61 seconds. +The net number of leap seconds added to UTC between 1958-1-1 and 2025-1-1 is 37. +The CF calendars differ in their treatment of leap seconds (see <>). + +In the **`julian`** and the default **`standard`** calendar, dates in years before year 0 (i.e. before 0-1-1 0:0:0) are not allowed, and the year in the reference datetime of the units must not be negative. In these calendars, year zero has a special use to indicate a climatology (see <>), but this use of year zero is deprecated. -In other calendars, years before year 1 are allowed. +In other calendars, year 0 is the year before year 1, and negative years are allowed. **`standard`**:: Mixed Gregorian/Julian calendar as defined by UDUNITS. This is the default. A deprecated alternative name for this calendar is **`gregorian`**. -In this calendar, date/times after (and including) 1582-10-15 0:0:0 are in the Gregorian calendar, in which a year is a leap year if either (i) it is divisible by 4 but not by 100 or (ii) it is divisible by 400. -Date/times before (and excluding) 1582-10-5 0:0:0 are in the Julian calendar. +The Gregorian and Julian calendars have the same lengths of their months; they differ only in respect of the rules that decide which years are leap years. +In the **`standard`** calendar, datetimes after and including 1582-10-15 0:0:0 are in the Gregorian calendar, in which a year is a leap year if either (i) it is divisible by 4 but not by 100 or (ii) it is divisible by 400. +Datetimes before (and excluding) 1582-10-5 0:0:0 are in the Julian calendar, in which any year that is divisible by 4 is a leap year. Year 1 AD or CE in the **`standard`** calendar is also year 1 of the **`julian`** calendar. -In the **`standard`** calendar, 1582-10-15 0:0:0 is exactly 1 day later than 1582-10-4 0:0:0 and the intervening dates are undefined. -Therefore it is recommended that date/times in the range from (and including) 1582-10-5 0:0:0 until (but excluding) 1582-10-15 0:0:0 should not be used as reference in **`units`**, and that a time coordinate variable should not include any date/times in this range, because their interpretation is unclear. -It is also recommended that a reference date/time before the discontinuity should not be used for date/times after the discontinuity, and vice-versa. +Negative years are invalid in time coordinates and reference datetimes in the **`standard`** calendar. +In the **`standard`** calendar, 1582-10-15 0:0:0 is exactly 1 day later than 1582-10-4 0:0:0. +Therefore datetimes in the range from (and including) 1582-10-5 0:0:0 until (but excluding) 1582-10-15 0:0:0 are invalid, and must not be used as reference in **`units`**. +It is recommended that a reference datetime before the discontinuity should not be used for datetimes after the discontinuity, and vice-versa. +See also <>. -**`proleptic_gregorian`**:: A calendar with the Gregorian rules for leap-years extended to dates before 1582-10-15. +**`proleptic_gregorian`**:: A calendar with the Gregorian rules for leap years extended to dates before 1582-10-15. All dates consistent with these rules are allowed, both before and after 1582-10-15 0:0:0. +See also <>. **`julian`**:: Julian calendar, in which a year is a leap year if it is divisible by 4, even if it is also divisible by 100. +Year 1 AD or CE in the **`julian`** calendar is also year 1 of the **`standard`** calendar. +Negative years are invalid in time coordinates and reference datetimes in the **`julian`** calendar. +See also <>. + +**`utc`**:: A Gregorian calendar __with__ leap seconds as prescribed by UTC. +Datetimes before 1958-01-01 0:0:0 are not allowed in this calendar. +Datetimes in the future are not allowed in this calendar, because it is unknown when future leap seconds will occur. +When a datetime is converted to a time coordinate value or vice-versa in this calendar, any leap seconds (positive or negative) must be counted that occurred in the interval between the datetime and the reference datetime in the **`units`**. +For any given instant, the **`utc`** datetime is behind the **`tai`** datetime, where "behind" means the same as it does when describing a timezone to the west as being behind one to the east. +The difference between the two datetimes for a given instant of time is the net number of leap seconds introduced since 1958-01-01. +The difference was zero on that instant, when both calendars began. +This means that a given datetime in the **`utc`** calendar represents an instant that is earlier than the same datetime in the **`tai`** calendar. +See also <>. + +**`tai`**:: A Gregorian calendar __without__ leap seconds that is based on International Atomic Time (TAI). +Datetimes before 1958-01-01 0:0:0 are not allowed in this calendar. +For any given instant, the **`tai`** datetime is ahead of the **`utc`** datetime, where "ahead" means the same as it does when describing a timezone to the east as being ahead of one to the west. +The difference between the two datetimes for a given instant of time is the net number of leap seconds introduced since 1958-01-01. +The difference was zero on that instant, when both calendars began. +This means that a given datetime in the **`tai`** calendar represents an instant that is later than the same datetime in the **`utc`** calendar. +See also <>. + +**`noleap`** or **`365_day`**:: A calendar with no leap years, i.e., all years are 365 days long, and there are no leap seconds. + +**`all_leap`** or **`366_day`**:: A calendar in which every year is a leap year, i.e., all years are 366 days long, and there are no leap seconds. + +**`360_day`**:: A calendar in which all years are 360 days, and divided into 30 day months, and there are no leap seconds. + +**`none`**:: To be used when there is no annual cycle. See <>. + +Any other value may be given to the **`calendar`** attribute to describe an explicitly defined calendar. See <>. + + +[[leap-seconds, Section 4.4.3, "Leap Seconds"]] +==== Leap Seconds + +This section describes how to deal properly with leap seconds. +Most people ignore the existence of leap seconds, including many data producers and the CF standard before version 1.12. +As a result, the time coordinates of two real-world observational datasets could disagree by some number of seconds if one has taken leap seconds into account and the other has not. +Practically speaking, this means that if you are working with real-world data, and if it's important for your time coordinates to be accurate to the second, you need to care about leap seconds. +Otherwise, you need only to be aware that the difference between two time coordinates might not exactly equal the duration of the time interval between the two instants, but could be inaccurate by a number of seconds, if leap seconds are involved. +Relatedly, two instants with the same time of day on different days, which would always be separated by a multiple of 86400 seconds if there were no leap seconds, will have a few more seconds between them if leap seconds intervene. + +Each calendar defines a set of valid combinations of the six numbers year-month-day-hour-minute-second. +We refer to this set as the calendar's "set of datetimes". +Fractions of seconds are allowed in all calendars in addition to the integer number of seconds. +In this section, we use the word _timeline_ to mean "continuous physical dimension of time". +The valid datetimes identify discrete instants along the timeline, in that sense. + +You need to know the set of datetimes defined by the calendar in order to compute time coordinate values from datetimes and vice-versa. +Ignoring fractional seconds in datetimes, a time coordinate value expressed in seconds equals the number of valid (integer-second) datetimes _after_ (not including) the reference datetime in the **`units`** _up to_ (and including) the datetime that the time coordinate represents. +For instance, in **`units`** of **`seconds since 2024-9-14 11:12:00`**, the time coordinate for the datetime **`2024-9-14 11:12:03`** is **`3`**, because there are three datetimes (**`2024-9-14 11:12:01`**, **`2024-9-14 11:12:02`**, **`2024-9-14 11:12:03`**) following **`2024-9-14 11:12:00`** up to and including **`2024-9-14 11:12:03`**. +The coordinate for **`2024-9-14 11:11:58`** is **`-2`**, because there are two valid datetimes (**`2024-9-14 11:11:59`**, **`2024-9-14 11:11:58`**) from **`2024-9-14 11:12:00`** to (and including) **`2024-9-14 11:11:58`**, and the count is negative because it goes backwards. +The signed difference between the fractional seconds of the datetime and the reference is added to the time coordinate after counting the seconds. +This paragraph may appear to be excessively elaborate in describing a usually obvious procedure, but it is necessary to be very careful about it when there are leap seconds. + +The **`utc`** calendar is the _only_ calendar which includes leap seconds in its set of datetimes. +In all other calendars, datetimes within leap seconds are not valid. +Therefore reference datetimes in the **`units`** attribute must not contain seconds equal to or greater than 60 unless the **`calendar`** is **`utc`**. + +The **`standard`**, **`proleptic_gregorian`**, and **`julian`** calendars each have two variants. +In one variant the timeline does not include leap seconds. +In the other variant, the timeline includes leap seconds, even though they are _not_ included in the valid set of datetimes. +To resolve the ambiguity between the variants of these calendars, the **`units_metadata`** attribute should be defined as well as the **`calendar`** attribute, as described later in this section. + +For **`standard`**, **`proleptic_gregorian`**, and **`julian`** calendars, there are the following cases: + +1. **The calendar is being used for a timeline in which leap seconds do not exist.** + This is the case for a model simulation that defines every day as having a constant length of 86400 seconds. + +2. **The calendar is being used for a timeline in which leap seconds exist, and they are correctly accounted for in the datetimes represented by the time coordinates.** + This could be the case for observations from a platform with equipment which records UTC datetimes and has prior knowledge of when new leap seconds are to be introduced, so that it is able to apply a new leap second at the appropriate time. + It could equally be the case for model whose timesteps include leap seconds. + +3. **The calendar is being used for a timeline in which leap seconds exist, but some or all leap seconds might not have not been correctly accounted for in the datetimes.** + This could be the case for observations from a platform whose time recording equipment has a delay in applying a new leap second. + +4. **It may be unknown whether leap seconds exist in the timeline.** + +Except in the **`utc`** calendar, when a time coordinate value is calculated from a datetime, or the reverse, it is assumed that the coordinate value increases by exactly 60 seconds from the start of any minute (identified by year, month, day, hour, minute, all being integers) to the start of the next minute, because leap seconds are not valid datetimes. +In other words, leap seconds (positive or negative) are never counted in the **`standard`**, **`proleptic_gregorian`**, and **`julian`** calendars. +When these calendars are being be used for timelines _with_ leap seconds (i.e. cases 2 and 3 and perhaps case 4), the assumption of 60-second minutes has the following consequences: + +* It is impossible to identify any instant during a leap second (i.e. between the end of the 60th second of the last minute of one hour and the start of the first second of the next hour) by a time coordinate e.g. **`2016-12-31 23:59:60.5`** cannot be represented by a time coordinate value. + +* A datetime in the excluded range must not be used as a reference datetime e.g. **`seconds since 2016-12-31 23:59:60`** is not a permitted value for **`units`**. + +* The coordinate value does not count any leap seconds which occurred between the reference datetime and the datetime represented by the coordinate. + For instance, 60 **`seconds after 23:59:00`** always means 00:00:00 on the next day, even if there is a leap second at 23:59:60, which makes the actual interval 61 seconds between 23:59:00 and 00:00:00 on the next day. + +Because of the last point, the difference between two coordinate values with the same **`units`** string does not exactly equal the length of the interval between instants they represent if there were any leap seconds between them. +This discrepancy can happen in cases 2, 3 and 4 of the **`standard`**, **`proleptic_gregorian`**, and **`julian`** calendars. +By contrast, in case 1 of those calendars (i.e. a timeline without leap seconds), and in all other calendars, the difference between two time coordinate values with the same **`units`** string is always equal to the length of time between the instants they represent. +Furthermore, an inaccuracy results from converting a time coordinate to a datetime if the interval includes leap seconds which were _not_ known when the time coordinate was calculated (possible in case 3 or 4). +It is important to be aware of these disadvantages of the **`standard`**, **`proleptic_gregorian`** and **`julian`** calendars when used with timelines including leap seconds. + +If it is essential for leap seconds to be counted in time coordinates, so that they exactly equal time intervals, you must use the **`utc`** calendar. +For many applications of the **`standard`**, **`proleptic_gregorian`**, and **`julian`** calendars, these inaccuracies are too small to matter, but there are some applications where it is necessary to know about them. +Therefore it is recommended that for the **`standard`**, **`proleptic_gregorian`**, and **`julian`** calendars the appropriate treatment of leap seconds should be indicated by giving the time coordinate variable a **`units_metadata`** attribute containing a **`leap_seconds`** keyword with one of the permitted values **`none`**, **`utc**` or **`unknown`**. +**`none`** means that leap seconds do not exist in the timeline (i.e. case 1), **`utc`** means that leap seconds exist in the timeline and the time coordinates correctly represent the datetimes (i.e. case 2), and **`unknown`** means that the data-writer did not know or did not record whether the leap seconds exist in the timeline, nor how they are treated if they did exist (i.e. cases 3 and 4). +If the **`units_metadata`** attribute is not present, or does not contain the `leap_seconds` keyword, the data-reader should assume **`leap_seconds: unknown`**. +A variable's **`units_metadata`** attribute may only contain the **`leap_seconds`** keyword if the variable's calendar is one of **`standard`** , **`proleptic_gregorian`**, or **`julian`**. -**`noleap`** or **`365_day`**:: A calendar with no leap years, i.e., all years are 365 days long. +[[units-metadata-leap-seconds-ex]] +[caption="Example 4.5. "] +.Use of **`units_metadata`** and **`calendar`** to define the treatment of leap seconds +==== -**`all_leap`** or **`366_day`**:: A calendar in which every year is a leap year, i.e., all years are 366 days long. +---- +variables: + float time_tai ; + time_tai:standard_name = "time" ; + time_tai:long_name = "Satellite data" ; + time_tai:calendar = "tai" ; + time_tai:units = "seconds since 2016-12-31 23:59:58" ; + float time_stdnone ; + time_stdnone:standard_name = "time" ; + time_stdnone:long_name = "Model data with no leap seconds" ; + time_stdnone:calendar = "standard" ; + time_stdnone:units = "seconds since 2016-12-31 23:59:58" ; + time_stdnone:units_metadata = "leap_seconds: none" ; + float time_stdutc ; + time_stdutc:standard_name = "time" ; + time_stdutc:long_name = "Model data with leap seconds or obs data with accurate UTC" ; + time_stdutc:calendar = "standard" ; + time_stdutc:units = "seconds since 2016-12-31 23:59:58" ; + time_stdutc:units_metadata = "leap_seconds: utc" ; + float time_utc ; + time_utc:standard_name = "time" ; + time_utc:long_name = "Time signal from UK National Physical Laboratory" ; + time_utc:calendar = "utc" ; + time_utc:units = "seconds since 2016-12-31 23:59:58" ; + float time_unknown ; + time_unknown:standard_name = "time" ; + time_unknown:long_name = "Obs data with unreliable information on leap seconds" ; + time_unknown:calendar = "standard" ; + time_unknown:units = "seconds since 2016-12-31 23:59:58" ; + time_unknown:units_metadata = "leap_seconds: unknown" ; +data: // time coordinate variable and the datetime it represents + time_tai = 2; // 2017-1-1 0:0:0 because no leap seconds in the timeline + time_stdnone = 2; // 2017-1-1 0:0:0 because no leap seconds in the timeline + time_stdutc = 2; // 2017-1-1 0:0:0 because the leap second is not counted + time_utc = 2; // leap second 2016-12-31 23:59:60 + time_unknown = 2; // unknown whether 2016-12-31 23:59:60 or 2017-1-1 0:0:0 +---- -**`360_day`**:: A calendar in which all years are 360 days, and divided into 30 day months. +This example shows five scalar time coordinate variables. +Although they all have the value 2 and the same **`units`** attribute, they do not all refer to the same datetime, as shown in the comments on their data values, because they have different treatments of the leap second that was added to the UTC calendar at the end of 2016. +The first four of them correspond to the instants marked 2 **`seconds since 2016-12-31 23:59:58`** in <>. -**`none`**:: No calendar. +The value of **`2`** seconds for **`time_stdnone`**, **`time_utc`** and **`time_tai`** can be correctly interpreted as the length of the interval from the reference datetime 2016-12-31 23:59:58 to the datetime indicated in the comment. +In both **`time_stdnone`** and **`time_stdutc`**, the time coordinate represents 2017-1-1 0:0:0, because 2016-12-31 23:59:60 is not permitted in the **`standard`** calendar, hence only two valid datetimes with integer seconds are counted (2016-12-31 23:59:59 and 2017-1-1 0:0:0). +However, the _timeline_ for **`time_stdutc`** _does_ include the leap second, so the time interval from the reference datetime 2016-12-31 23:59:58 to 2017-1-1 0:0:0 is actually three seconds, not two as indicated by the time coordinate value. +This is an example of the **`standard`** calendar not counting a leap second in the coordinate value, with the consequence that the difference between time coordinates does not exactly equal the duration of the interval. +An application may choose either to ignore this inaccuracy or to correct for it when calculating the length of intervals which include the leap second. +In the case of **`time_unknown`**, we cannot convert the time coordinate to a datetime with certainty, because we do not know whether 2017-1-1 0:0:0 is two or three seconds after 2016-12-31 23:59:58. +==== + +[[leap-second-timelines]] +[caption="Figure {doc-part}.{counter:figure}. ", reftext=Figure {doc-part}.{figure}] +.Illustration of the equivalence between datetimes and time coordinate values with **`units="seconds since 2016-12-31 23:59:58"`** for various choices of the **`calendar`** attribute and **`leap_seconds`** keyword. +==== +image::images/leap-second-timelines.svg[,70%,pdfwidth=50vw,align="center"] +This illustration shows that a given time coordinate value (the numbers in columns at the bottom right) can represent different datetimes in different calendars. +However, the illustration cannot show another important point to keep in mind, that a given datetime may identify different instants in different calendars. + +The diagonal lines depict the timelines of the calendars. +Along each line, a filled circle marks the instant on the timeline that begins each second in the set of datetimes allowed by the calendar. +There is no meaning in the slight left-right displacement of the circles at each second, which is done only so they can all be seen; they are supposed to be exactly coincident. +As explained in the text of this section, the time coordinate in seconds is the count of valid datetimes (= the number of circles) that occur along the timeline _after_ the reference datetime **`2016-12-31 23:59:58`** (which is the first circle on the line in every case, hence with a count of zero as shown in the column below its group of circles), up to and including the datetime represented. +The instants marked 2 **`seconds since 2016-12-31 23:59:58`** are the ones represented by the first four time coordinate variables of Example 4.5. + +A leap second was added to the UTC calendar at the end of 2016. +The duration of the leap second is shown by the shading. +The **`utc`** calendar is the only one in which datetimes in the leap second are valid; hence the black circle is the only marker of **`2016-12-31 23:59:60`**. +The grey timeline of the **`utc`** variant of the **`standard`** calendar includes the the leap second as well, but datetimes in the leap second are not valid in that calendar, so there is no grey circle for it. +The leap second does not appear in the timelines of the **`tai`** calendar and the *`none`* variant of the *`standard`* calendar. +Their timelines (red and purple) skip over the leap second, and they have no circle for it. +For those timelines, please imagine the digram having the shaded rectangle cut out, and the cut edges joined, making the red and purple lines continuous, passing smoothly from 2016-12-31 23:59:00 to 2017-1-1 00:00:00 as for all the other seconds. +==== + + +[[none-calendar, Section 4.4.4, "Time Coordinates with no Annual Cycle"]] +==== Time Coordinates with no Annual Cycle The **`calendar`** attribute may be set to **`none`** in climate experiments that simulate a fixed time of year. The time of year is indicated by the date in the reference time of the **`units`** attribute. The time coordinates that might apply in a perpetual July experiment are given in the following example. [[perpetual-time-axis-ex]] -[caption="Example 4.5. "] +[caption="Example 4.6. "] .Perpetual time axis ==== @@ -294,12 +522,16 @@ data: Here, all days simulate the conditions of 15th July, so it does not make sense to give them different dates. The time coordinates are interpreted as 0, 1, 2, etc. days since the start of the experiment. -If none of the calendars defined above applies (e.g., calendars appropriate to a different paleoclimate era), a non-standard calendar can be defined. -The lengths of each month are explicitly defined with the **`month_lengths`** attribute of the time axis: + +[[explicit-calendar, Section 4.4.5, "Explicitly Defined Calendar"]] +==== Explicitly Defined Calendar + +If none of the calendars defined in <> applies (e.g., calendars appropriate to a different paleoclimate era), a calendar can be explicitly defined, in terms of permissible year-month-day combinations. +To do this, the lengths of each month are explicitly defined with the **`month_lengths`** attribute of the time axis: **`month_lengths`**:: A vector of size 12, specifying the number of days in the months from January to December (in a non-leap year). -If leap years are included, then two other attributes of the time axis should also be defined: +If leap years are included, then two other attributes of the time axis must also be defined: **`leap_year`**:: An example of a leap year. It is assumed that all years that differ from this year by a multiple of four are also leap years. @@ -309,12 +541,10 @@ If this attribute is absent, it is assumed there are no leap years. If this attribute is not present, February (2) is assumed. This attribute is ignored if **`leap_year`** is not specified. -The **`calendar`** attribute is not required when a non-standard calendar is being used. -It is sufficient to define the calendar using the **`month_lengths`** attribute, along with **`leap_year`**, and **`leap_month`** as appropriate. -However, the **`calendar`** attribute is allowed to take non-standard values and in that case defining the non-standard calendar using the appropriate attributes is required. +When an explicitly defined calendar is being used, the calendar may be described by giving a value not defined in <> to the **`calendar`** attribute; alternatively, the attribute may be omitted. [[paleoclimate-time-axis-ex]] -[caption="Example 4.6. "] +[caption="Example 4.7. "] .Paleoclimate time axis ==== @@ -328,6 +558,7 @@ double time(time) ; ==== + [[discrete-axis, Section 4.5, "Discrete Axis"]] === Discrete Axis @@ -337,4 +568,3 @@ Consequently such an axis may be called {ldquo}discrete{rdquo}. A discrete axis has a dimension but might not have a coordinate variable. Instead, there might be one or more auxiliary coordinate variables with this dimension (see preamble to section 5). Following sections define various applications of discrete axes, for instance section 6.1.1 {ldquo}Geographical regions{rdquo}, section 7.3.3 {ldquo}Statistics applying to portions of cells{rdquo}, section 9.3 {ldquo}Representation of collections of features in data variables{rdquo}. - diff --git a/ch07.adoc b/ch07.adoc index d71db454..fa87308d 100644 --- a/ch07.adoc +++ b/ch07.adoc @@ -488,7 +488,7 @@ Instead, it has a **`climatology`** attribute, which names a variable with dimen Using the units and calendar of the time coordinate variable, element (i,0) of the climatology variable specifies the beginning of the first subinterval and element (i,1) the end of the last subinterval used to evaluate the climatological statistics with index i in the time dimension. The time coordinates should be values that are representative of the climatological time intervals, such that an application which does not recognise climatological time will nonetheless be able to make a reasonable interpretation. -For compatibility with the COARDS standard, a climatological time coordinate in the default **`standard`** and **`julian`** calendars may be indicated by setting the date/time reference string in the time coordinate's **`units`** attribute to midnight on 1 January in year 0 (i.e., **`since 0-1-1`**). +For compatibility with the COARDS standard, a climatological time coordinate in the default **`standard`** and **`julian`** calendars may be indicated by setting the datetime reference string in the time coordinate's **`units`** attribute to midnight at 0 `degrees_east` on 1 January in year 0 (i.e., **`since 0-1-1`**). This convention is deprecated because it does not provide any information about the intervals used to compute the climatology, and there may be inconsistencies among software packages in the interpretation of the time coordinates with a reference time of year 0. Use of year 0 for this purpose is impossible in all other calendars, because year 0 is a valid year. @@ -539,7 +539,7 @@ variables: time:climatology="climatology_bounds"; time:units="days since 1960-1-1"; double climatology_bounds(time,nv); -data: // time coordinates translated to date/time format +data: // time coordinates translated to datetime format time="1960-4-16", "1960-7-16", "1960-10-16", "1961-1-16" ; climatology_bounds="1960-3-1", "1990-6-1", "1960-6-1", "1990-9-1", @@ -565,7 +565,7 @@ variables: time:climatology="climatology_bounds"; time:units="days since 1901-1-1"; double climatology_bounds(time,nv); -data: // time coordinates translated to date/time format +data: // time coordinates translated to datetime format time="1965-1-15", "1975-1-15", "1985-1-15" ; climatology_bounds="1961-1-1", "1970-2-1", "1971-1-1", "1980-2-1", @@ -591,7 +591,7 @@ variables: time:climatology="climatology_bounds"; time:units="hours since 1997-4-1"; double climatology_bounds(time,nv); -data: // time coordinates translated to date/time format +data: // time coordinates translated to datetime format time="1997-4-1 0:30", "1997-4-1 1:30", ... "1997-4-1 23:30" ; climatology_bounds="1997-4-1 0:00", "1997-4-30 1:00", "1997-4-1 1:00", "1997-4-30 2:00", @@ -625,7 +625,7 @@ variables: time:climatology="climatology_bounds"; time:units="days since 2000-6-1"; double climatology_bounds(time,nv); -data: // time coordinates translated to date/time format +data: // time coordinates translated to datetime format time="2008-1-16 6:00"; climatology_bounds="2007-12-1 6:00", "2008-3-1 6:00"; threshold=0.; @@ -649,7 +649,7 @@ variables: time:climatology="climatology_bounds"; time:units="days since 1961-1-1"; double climatology_bounds(time,nv); -data: // time coordinates translated to date/time format +data: // time coordinates translated to datetime format time="1961-4-1 0:30", "1961-4-1 1:30", ..., "1961-4-1 23:30" ; climatology_bounds="1961-4-1 0:00", "1990-4-30 1:00", "1961-4-1 1:00", "1990-4-30 2:00", @@ -678,7 +678,7 @@ variables: time:climatology="climatology_bounds"; time:units="days since 2000-6-1"; double climatology_bounds(time,nv); -data: // time coordinates translated to date/time format +data: // time coordinates translated to datetime format time="2000-6-16", "2000-7-16", "2000-8-16" ; climatology_bounds="2000-6-1 6:00:00", "2000-7-1 6:00:00", "2000-7-1 6:00:00", "2000-8-1 6:00:00", diff --git a/conformance.adoc b/conformance.adoc index 4e490ab9..8f831964 100644 --- a/conformance.adoc +++ b/conformance.adoc @@ -144,11 +144,11 @@ References can be absolute, relative or with no path, in which case, the variabl * The type of the **`units`** attribute is a string that must be recognizable by the UDUNITS package. Exceptions are the units **`level`**, **`layer`**, and **`sigma_level`**. * Dimensionless units for volume fractions defined by UDUNITS (**`ppv`**, **`ppmv`**, **`ppbv`**, **`pptv`**, **`ppqv`**) are not allowed in the **`units`** attribute of any variable which also has a **`standard_name`** attribute. -* If present, the **`units_metadata`** attribute must have one of these values: `temperature: on_scale`, `temperature: difference`, `temperature: unknown`. +* If present, the **`units_metadata`** attribute must have one of these values: `temperature: on_scale`, `temperature: difference`, `temperature: unknown`, `leap_seconds: none`, `leap_seconds: utc`, or `leap_seconds: unknown`. * The **`units`** of a variable that specifies a **`standard_name`** must be physically equivalent to the canonical units given in the standard name table, as modified by the **`standard_name`** modifier, if there is one, according to Appendix C, and then modified by all the methods listed in order by the **`cell_methods`** attribute, if one is present, according to Appendix E. * If the **`standard_name`** attribute includes the `standard_error` modifier, the **`units_metadata`** attribute, if present, must have the value `temperature: difference`. -* If the **`cell_methods`** attribute includes any entry with any of the methods `range`, `standard_deviation` or `variance`, the **`units_metadata`** attribute, if present, must have the value `temperature: difference`. -* A variable must not have a **`units_metadata`** attribute if it has no **`units`** attribute or if its **`units`** do not involve a temperature unit. +* If a variable has a **`units`** attribute that involves a temperature unit, and has a **`cell_methods`** attribute includes any entry with any of the methods `range`, `standard_deviation` or `variance`, then the **`units_metadata`** attribute, if present, must have the value `temperature: difference`. +* A variable must not have a **`units_metadata`** attribute if it has no **`units`** attribute, or if its **`units`** do not involve a temperature unit or a reference time unit. *Recommendations:* @@ -237,39 +237,59 @@ The values of **`var`** must be variables that exist in the file. [[section-13]] [[time-coordinate]] -=== 4.4 Time Coordinate +=== 4.4.1 Time Coordinate Units *Requirements:* -* The time **`units`** of a time coordinate variable must contain a reference date/time. -* The reference date/time of a time coordinate variable must be a legal date/time in the specified calendar. -* The reference date/time in time **`units`** is not allowed to contain seconds equal to or greater than 60. +* The time **`units`** of a time coordinate variable must contain a reference datetime. *Recommendations:* -* The use of time coordinates in year 0 and reference date/times in year 0 to indicate climatological time is deprecated. * Units of **`year`** and **`month`** and any equivalent units should be used with caution. * UDUNITS permits a number of alternatives to the word **`since`** in the units of time coordinates. All the alternatives have exactly the same meaning in UDUNITS. For compatibility with other software, CF strongly recommends that **`since`** should be used. [[section-14]] [[calendar]] -=== 4.4.1 Calendar +=== 4.4.2 Calendar *Requirements:* -* The attributes **`calendar`**, **`month_lengths`**, **`leap_year`**, and **`leap_month`** may only be attached to time coordinate variables. -* The standardized values (case insensitive) of the **`calendar`** attribute are **`standard`**, **`gregorian`** (deprecated), **`proleptic_gregorian`**, **`noleap`**, **`365_day`**, **`all_leap`**, **`366_day`**, **`360_day`**, **`julian`**, and **`none`**. -If the **`calendar`** attribute is given a non-standard value, then the attribute **`month_lengths`** is required, along with **`leap_year`** and **`leap_month`** as appropriate. +* The **`calendar`** attribute may only be attached to time coordinate variables. +* If present, the value of the **`calendar`** attribute must be one of the standardized values (case insensitive) detailed in this section, unless the **`month_length`** attribute is present, in which case the **`calendar`** attribute must _not_ take one of the standardized values. +* The reference datetime of a time coordinate variable must be a legal datetime in the specified calendar. + +*Recommendations:* + +* A time coordinate variable should have a **`calendar`** attribute. +* If the **`calendar`** attribute is **`standard`**, **`gregorian**` (deprecated) or **`julian`** or absent, the use of time coordinates in year 0 and reference datetimes in year 0 is deprecated. +* The value **`standard`** should be used instead of **`gregorian`** in the **`calendar`** attribute. +* The time coordinate should not cross the date 1582-10-15 when the default mixed Gregorian/Julian calendar is in use. + +[[leap-seconds]] +=== 4.4.3 Leap Seconds + +*Requirements:* + +* The reference datetime in time **`units`** is not allowed to contain seconds equal to or greater than 60, except for valid leap seconds if the **`calendar`** is **`utc`**. +* A time coordinate variable must not have a **`units_metadata`** attribute if it has a **`calendar`** attribute with a value _other than_ one of the following values: `standard`, `gregorian` (deprecated), `proleptic_gregorian`, `julian`. +* If a time coordinate variable has a **`units_metadata`** attribute then it must have one of these values: `leap_seconds: none`, `leap_seconds: utc`, or `leap_seconds: unknown`. + +*Recommendations:* + +* A time coordinate variable should have a **`units_metadata`** attribute if it has no **`calendar`** attribute, or if it has a **`calendar`** attribute with one of the following values: `standard`, `gregorian` (deprecated), `proleptic_gregorian`, `julian`. + +[[explicitly-defined-calendar]] +=== 4.4.5 Explicitly Defined Calendar + +* The **`month_lengths`**, **`leap_year`**, and **`leap_month`** attributes may only be attached to time coordinate variables. +* If the **`calendar`** attribute of a time coordinate variable is given a non-standard value, then the attribute **`month_lengths`** is required, along with **`leap_year`** and **`leap_month`** as appropriate. * The type of the **`month_lengths`** attribute must be an integer array of size 12. * The values of the **`leap_month`** attribute must be in the range 1-12. * The values of the **`leap_year`** and **`leap_month`** attributes are integer scalars. *Recommendations:* -* A time coordinate variable should have a **`calendar`** attribute. -* The value **`standard`** should be used instead of **`gregorian`** in the **`calendar`** attribute. * The attribute **`leap_month`** should not appear unless the attribute **`leap_year`** is present. -* The time coordinate should not cross the date 1582-10-15 when the default mixed Gregorian/Julian calendar is in use. [[section-15]] [[coordinate-systems]] diff --git a/history.adoc b/history.adoc index bfca341c..aa2c20ef 100644 --- a/history.adoc +++ b/history.adoc @@ -7,6 +7,8 @@ === Working version (most recent first) +* {issues}542{Issue #542}: Clarify and rearrange text of section 4.4 about time coordinate units and calendars; introduce new text and a diagram explaining leap-seconds in existing calendars; define leap_second keyword of units_metadata attribute; define utc and tai calendars; define "datetime" in section 1.3. +* {issues}166{Issue #166}: Clarify that time coordinate variables must have **`units`** containing **`since`** and a reference time; distinguish between canonical units of time with and without **`since`**. * {issues}367[Issue #367]: Remove the AMIP and GRIB columns from the standard name table format defined by Appendix B. * {issues}403[Issue #403]: Metadata to encode quantization properties * {issues}530[Issue #530]: Define "the most rapidly varying dimension", and use this phrase consistently with the clarification "(the last dimension in CDL order)". diff --git a/images/leap-second-timelines.odg b/images/leap-second-timelines.odg new file mode 100644 index 00000000..dd75ee08 Binary files /dev/null and b/images/leap-second-timelines.odg differ diff --git a/images/leap-second-timelines.pdf b/images/leap-second-timelines.pdf new file mode 100644 index 00000000..5b8d1400 Binary files /dev/null and b/images/leap-second-timelines.pdf differ diff --git a/images/leap-second-timelines.svg b/images/leap-second-timelines.svg new file mode 100644 index 00000000..80529262 --- /dev/null +++ b/images/leap-second-timelines.svg @@ -0,0 +1,540 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2017-1-1 00:00:022017-1-1 00:00:012017-1-1 00:00:002016-12-31 23:59:602016-12-31 23:59:592016-12-31 23:59:58 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0000 + + + + + + 1111 + + + + + + 222 + + + + + + 4434 + + + + + + 3323 + + + + + + calendar taistandardstandardutc + + + + + + seconds since2016-12-31 23:59:58 + + + + + + + + + + + + date/time + + + + + + leap second + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + leap_secondsnoneutc + + + + + + + + \ No newline at end of file diff --git a/toc-extra.adoc b/toc-extra.adoc index e73da712..a8494495 100644 --- a/toc-extra.adoc +++ b/toc-extra.adoc @@ -16,8 +16,9 @@ K.2. <> **List of Figures** [%hardbreaks] -7.1. <> -7.2. <> +7.1. <> +7.2. <> +4.1. <> 8.1. <> 8.2. <> 8.3. <> @@ -49,8 +50,9 @@ J.5. <> 4.2. <> 4.3. <> 4.4. <> -4.5. <> -4.6. <> +4.5. <> +4.6. <> +4.7. <> 5.1. <> 5.2. <> 5.3. <>