Skip to content

Datetime formats

ITk needs to define a consistent way of ensure that users follow a consistent datetime specification and do't give confusing results to the database.

The ITk Production database is following the ISO8601 format for datetime strings. This means that test run results should be uploaded with the appropriate format and the database should be returning results with datetime strings in this same format.

Interpretation

The standard does not assign any specific meaning to elements of the date/time to be represented; the meaning will depend on the context of its use.

Note however that the ISO8601 format is first, and foremost, a formatting specification. It also contains a specification on how one should interpret a datetime string consistently, but that is not as strictly (or easily) enforced. For this project, there is an agreement to require the timezone information to be included explicitly in an expanded format.

Recommendation

The recommendation is to use the explicit timezone offset in ISO8601 formatted strings. Zulu designation (Z) is acceptable if one is not able to provide an offset-formatted string. Most modern libraries should be able to provide timezone-offsetted strings by default.

The best formatted example of a datetime following the recommendations is

1
2021-06-04T08:43:04.264-07:00

which is an expanded datetime format (contains colons and dashes), with T designation for time, and an explicit timezone offset at the end -07:00. The following should not be accepted due to: using microseconds and not milliseconds, implicitly meaning UTC, or not including a timezone offset at all:

1
2
3
4
2021-06-04T08:43:04.264792-07:00
2021-06-04T15:43:04.264792Z
2021-06-04T15:43:04.264
2021-06-04T15:43:04

In these two cases, they are meant to represent local time and should not be uploaded to the database. They would need to be converted to UTC, or have the timezone offset explicitly added such as:

  • 2021-06-04T15:43:04.264Z: addition of Z states that the time is represented in UTC
  • 2021-06-04T15:43:04+00:00: addition of timezone offset states that the time is represented in UTC

This is what is meant by not implicitly assuming a timezone (which can be dangerous if the datetime library you're using is not enforcing this consistently). Otherwise, the following datetime formats should be accepted:

1
2
3
4
5
6
2021-06-04T08:43:04.264-07:00
2021-06-04T08:43:04-07:00
2021-06-04T08:43:04-0700
2021-06-04T15:43:04.264Z
2021-06-04T15:43:04Z
2021-06-04T15:43Z

Please note that all of the correct solutions do not require Zulu. In fact, this is by far the default that generally happens with most standard libraries these days as the Zulu identifier does not add any additional information.

Zulu time

The addition of Zulu to satisfy the stricter format required by the database is discouraged unless you know that your datetime string is in UTC. It is always recommended to add an offset.

There are cases where simply added the Z (for Zulu time) identifier does not automatically make a datetime string valid as it could still be represented in the wrong timezone.

Code Snippets

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from datetime import datetime, timezone

# CORRECT (UTC to ISO8601 with timezone information)
datetime.now(timezone.utc).isoformat(timespec='milliseconds')
# '2021-06-08T15:13:35.179+00:00'

# CORRECT (local time to ISO8601 without timezone information)
datetime.now().isoformat(timespec='milliseconds')
# '2021-06-08T08:13:37.858'

# CORRECT (local time to ISO8601 with timezone information)
datetime.now().astimezone().isoformat(timespec='milliseconds')
# '2021-06-08T08:13:46.012-07:00'

# INCORRECT (UTC to ISO8601 without timezone information
datetime.utcnow().isoformat(timespec='milliseconds')
# '2021-06-08T15:13:49.927'

# INCORRECT (UTC to ISO8601 with wrong timezone information)
datetime.utcnow().astimezone().isoformat(timespec='milliseconds')
# '2021-06-08T15:13:52.447-07:00'

arrow is a 3rd-party python library that is available via pip install arrow.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import arrow

# CORRECT (local time to ISO8601 with timezone information)
arrow.now().isoformat(timespec='milliseconds')
# '2021-06-08T08:25:58.337-07:00'

# CORRECT (local time to ISO8601 with timezone information)
arrow.now().dehumanize("in 2 hours").isoformat(timespec='milliseconds')
# '2021-06-08T10:30:24.540-07:00'

# CORRECT (local time to ISO8601 with timezone information)
arrow.now().dehumanize("2 hours ago").isoformat(timespec='milliseconds')
# '2021-06-08T06:30:31.289-07:00'

# CORRECT (UTC to ISO8601 with timezone information)
arrow.utcnow().isoformat(timespec='milliseconds')
# '2021-06-08T15:31:09.854+00:00'
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <time.h>

int main ()
{
  time_t rawtime;
  struct tm * timeinfo;
  char buffer [80];

  time (&rawtime);
  timeinfo = localtime (&rawtime);

  strftime (buffer,80,"%Y-%m-%dT%H:%M:%S%z.",timeinfo);
  puts (buffer);

  return 0;
}
// 2021-06-08T16:35:04+0000
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function toIsoString(date) {
  var tzo = -date.getTimezoneOffset(),
      dif = tzo >= 0 ? '+' : '-',
      pad = function(num) {
          var norm = Math.floor(Math.abs(num));
          return (norm < 10 ? '0' : '') + norm;
      };

  return date.getFullYear() +
      '-' + pad(date.getMonth() + 1) +
      '-' + pad(date.getDate()) +
      'T' + pad(date.getHours()) +
      ':' + pad(date.getMinutes()) +
      ':' + pad(date.getSeconds()) +
      dif + pad(tzo / 60) +
      ':' + pad(tzo % 60);
}

const event = new Date()

console.log(event.toISOString());
// "2021-06-04T16:08:16.340Z"

console.log(toIsoString(event));
// "2021-06-04T09:08:16-07:00"

Additional Notes

The 2004 document had widely known issues with the interpretation and the 2019 had to clarify it further into two separate documents which are hard to access. If you want to see a similar profile online without access -- the RFC3339 is similar and the only difference is that RFC3339 mandates the requirement of the T character for indication of times.

Time precision

There is no strict requirement on how precise the datetime can be. The default supported in ISO8601 is acceptable for our purposes. In many cases however, one should discourage only dates. Having at least minute-level precision is encouraged.

Thus a date 2021-06-04Z is generally discouraged but 2021-06-04T15:45Z and 2021-06-04T15:45-07:00 are acceptable.

JavaScript really only supports up to millisecond precision so we will disallow microsecond precision for datetime strings.