Version 0.1 - Working Draft
This informal specification lays out a way to represent time series information using JSON. The objective is to enable cross-platform sharing of a wide variety of regular and irregular time series data.
The format puts no hard limits on observation frequency, but library support may vary.
Dates are represented using strings. The format for date strings is derived from ISO 8601, subject to a few minor modifications.
As with ISO 8601, dates are represented in the following format:
[Year]-[Month]-[Day]T[Hour]:[Minute]:[Second].[SubSecond][TimeZone]
-
[Year]is the four-digit year (0000-9999) -
[Month]is the two-digit month (01-12) -
[Day]is the two-digit day of the month (01-31) -
[Hour]is the two-digit hour in 24-hour format (00-23) -
[Minute]is the two-digit minute (00-59) -
[Second]is the two-digit second (00-59) -
[SubSecond]is expressed in milliseconds (000-999), microseconds (000000-999999), or to an arbitrary degree of precision with digits added in groups of three -
[TimeZone]is one of the following:-
Z- indicates UTC -
+HH:MM- indicates a positive offset from UTC -
-HH:MM- indicates a negative offset from UTC
-
For example, to millisecond precision:
2000-01-01T00:00:00.000Z
As with ISO 8601, higher-precision date elements may be omitted. Unlike ISO
8601, a stand-alone year of the form YYYY is considered a valid date.
For the purpose of this format, dates should be understood to refer to specific instants in time, not intervals of time, irrespective of the precision inherent in the date expression.
Lower-precision dates should be understood as follows:
-
YYYYshould be understood asYYYY-01-01T00:00:00.000 -
YYYY-MMshould be understood asYYYY-MM-01T00:00:00.000 -
YYYY-MM-DDshould be understood asYYYY-MM-DDT00:00:00.000 -
YYYY-MM-DDTHHshould be understood asYYYY-MM-DDTHH:00:00.000 -
YYYY-MM-DDTHH:NNshould be understood asYYYY-MM-DDTHH:NN:00.000 -
YYYY-MM-DDTHH:NN:SSshould be understood asYYYY-MM-DDTHH:NN:SS.000
The date 2019 should therefore be understood to represent midnight on January
1st, not the year 2019 as a whole.
As with ISO 8601, the time zone may be omitted, in which case the date is understood to refer to local time.
Unlike ISO 8601, a time zone specification is permitted even if there are no
time elements in the date string. For example, 2000Z, 2000-01Z, and
2000-01-01Z all represent midnight on January 1, 2000, UTC.
Other ISO 8601 representations like YYYY-WXX and YYYY-DDD are not permitted.
Irregular time series are represented using JSON objects of the following form:
{
"JsonTs": "irregular",
"Observations": ...
}-
The
JsonTsparameter (required string) is"irregular"to indicate the nature of the time series. The value is not case-sensitive. -
The
Observationsparameter (required array) contains the time series observations in chronological order. It may be empty, which indicates that there are no obsevations.Each element of
Observationsmust take one of two forms:-
[Start, Value]Representing an observation in this form indicates that the
Startof the following observation should serve as theEndof the current one. The final observation must not take this form.-
Start(date string) specifies the beginning of the time interval to whichValueapplies. The instant represented byStartis considered part of the observation, while the instant represented by theStartof the following observation is considered part of the next observation.For the first observation in a series, any
Startis valid.If following an observation of type (1),
Startmust be strictly later than theStartof the preceding observation.If following an observation of type (2),
Startmust be later than or equal to theEndof the preceding observation. -
Value(any JSON value) specifies the value of the observation.
-
-
[Start, Value, End]Representing an observation in this form allows for an explicit
Enddate, which can be used to represent gaps in the data. The final observation must take this form.-
Start(date string) specifies the beginning of the time interval to whichValueapplies. The instant represented byStartis considered part of the observation.For the first observation in the series, any
Startis valid.If following an observation of type (1),
Startmust be strictly later than theStartof the preceding observation.If following an observation of type (2),
Startmust be later than or equal to theEndof the preceding observation. -
Value(any JSON value) specifies the value of the observation. -
End(date string) specifies the end of the time interval to which theValueapplies. The instant represented byEndis not considered part of the observation.Endmust be strictly later thanStart.
-
-
-
An irregular time series containing string values from midnight UTC on January 1, 2000 until midnight UTC on January 10, 2000, with no gaps in the data.
{ "JsonTs": "irregular", "Observations": [ ["2000Z", "value1"], ["2000-01-03T04:00:10Z", "value2"], ["2000-01-08T23:40:20Z", "value3", "2000-01-10Z"] ] }
-
An irregular time series containing string values from midnight UTC on January 1, 2000 until midnight UTC on January 10, 2000, with a gap in the data.
{ "JsonTs": "irregular", "Observations": [ ["2000Z", "value1"], ["2000-01-03T04:00:10Z", "value2", "2000-01-04T07:15:30Z"], ["2000-01-08T23:40:20Z", "value3", "2000-01-10Z"] ] }
Regular time series can in principle be represented using the irregular format, but that would discard information about the repetitive structure of the time series, which is often relevant when interpreting and modifying the data. The regular time series format is designed to retain this information.
Regular time series are represented by JSON objects of the following form:
{
"JsonTs": "regular",
"BasePeriod": ...,
"Anchor": ...,
"SubPeriods": ...,
"Observations": ...
}-
The
JsonTsparameter (required string) is"regular"to indicate the nature of the time series. The value is not case-sensitive. -
The
BasePeriodparameter (required array) specifies the base periodicity of the series. Base periods can be broken into higher frequency observations using theSubPeriodsparameter.The
BasePeriodparameter must take the following form...[BasePeriodNumber, BasePeriodType]Where...
-
BasePeriodNumber(positive integer) specifies the number ofBasePeriodTypes that constitute a base period. -
BasePeriodType(string) must be one of:y- Yearsm- Monthsw- Weeksd- Daysh- Hoursn- Minutess- Secondsms- Millisecondse-#- Arbitrarily high frequency
The
e-#base period type enables the representation of time series with arbitrarily high frequency.#must be a positive multiple of 3. The expression uses scientific notation to indicate the length of the base period in terms of seconds, soe-3is equivalent tomsande-6indicates microsecond precision. There is no format-prescribed limit on#, but library support varies.The
BasePeriodTypeis not case-sensitive.
Examples:
[1, "Y"]indicates a base period of one year[5, "n"]indicates a base period of five minutes
-
-
The
Anchorparameter (optional date string) specifies the starting instant of one base period and, indirectly, the starting instants of all other base periods. TheAnchorparameter allows an entire series to be shifted forward or backward in time.For example, if
BasePeriodis[1, "y"]andAnchoris"2000-01Z", then each base period will run from the start of January 1st UTC through the end of December 31st UTC. IfBasePeriodis[1, "y"]andAnchoris"2000-07Z"then each base period will run from the start of July 1st UTC through the end of June 30th UTC of the next year.If the
Anchorparameter is not specified...-
If
BasePeriodTypeis"w", thenAnchormust default to midnight UTC on a Monday. For example,"2000-01-03T00:00:00Z". -
If
BasePeriodTypeis anything else, thenAnchormust default to midnight UTC on a January 1st. For example,"2000-01-01T00:00:00Z".
-
-
The
SubPeriodsparameter (optional positive integer) specifies the number of observations within eachBasePeriod.For example, a time series with business-day frequency would have
BasePeriodset to[1, "w"]andSubPeriodsset to5.
If theSubPeriodsparameter is not specified, it must default to1. -
The
Observationsparameter (required array) contains the time series observations in chronological order. It may be empty, which indicates that there are no obsevations.Each element of
Observationsmust take one of three forms:-
[BasePeriodDate, SubPeriodNumber, Value]Representing an observation in this form allows its base period and sub period to be specified explicitly.
BasePeriodDate(date string) indicates the base period to which the observation is being assigned. It may reference any instant falling within the base period, as determined by the boundary calculation procedure below.SubPeriodNumber(positive integer) specifies the sub period to whichValueis being assigned. Sub periods are indexed beginning at1, soSubPeriodNumbermust fall between1andSubPeriods.Value(any JSON value) is the value of the observation.Observations represented in this form must be ordered chronologically...
-
If adjacent observations reference different base periods, the base period referenced by the second observation must be later than the base period referenced by the first.
-
If adjacent observations reference the same base period, the second observation must have a strictly greater
SubPeriodNumber.
-
-
[BasePeriodDate, Value]Representing an observation in this form is equivalent to
[BasePeriodDate, 1, Value]. Observations may only be represented in this form ifSubPeriodsis 1. -
[Value]Representing an observation in this form indicates that it occupies the sub period immediately following the previous observation. If the previous observation had a
SubPeriodNumberequal toSubPeriods, the observation will occupy the first sub period of the next base period.The first observation must not take this form.
Value(any JSON value) is the value of the observation.
-
Base period boundaries are determined by adding and subtracting the interval
specified in BasePeriod to the Anchor, which by definition is the beginning
of a base period.
To calculate the boundaries of base periods after the anchor:
-
The first base period after the anchor starts at
Anchorand ends immediately prior toAnchor + BasePeriod. -
The second base period after the anchor starts at
Anchor + BasePeriodand ends immediately prior toAnchor + 2 * BasePeriod. -
And so on...
To calculate the boundaries of base periods before the anchor:
-
The first base period before the anchor starts at
Anchor - BasePeriodand ends immediately prior toAnchor. -
The second base period before the anchor starts at
Anchor - 2 * BasePeriodand ends immediately prior toAnchor - BasePeriod. -
And so on...
When adding to or subtracting from a date element on the anchor, less-granular date elements should be rolled forward or backward as appropriate and more-granular date elements should be left unchanged. When the anchor lies on the 29th, 30th, or 31st of the month and the month resulting from a boundary calculation does not contain that day, the calculation should substitute the last day of that month.
Sub periods are indexed ordinally within each base period, but the time boundaries of each sub period within its base period are not prescribed by the format. For maximum flexibility, this is left to the application/library.
-
A monthly time series containing numerical values for the first three months of the year 2000.
{ "JsonTs": "regular", "BasePeriod": [1, "m"], "Observations": [ ["2000-01", 1], [2], [3] ] }
-
A time series with ten-minute frequency containing string values for the first and last twenty minutes of 2019
{ "JsonTs": "regular", "BasePeriod": [10, "n"], "Observations": [ ["2019-01-01T00:00:00Z", "A"], ["B"], ["2019-12-31T23:40:00Z", "Y"], ["Z"] ] }
-
A time series containing numerical fiscal quarter observations for one fiscal year ending October 31.
{ "JsonTs": "regular", "BasePeriod": [1, "q"], "Anchor": "2000-11-01", "Observations": [ ["2000-11-01", 100], [200], [300], [400] ] }
-
A weekly time series with five weeks of boolean observations, where weeks start on Sunday and end on Saturday.
{ "JsonTs": "regular", "BasePeriod": [1, "w"], "Anchor": "2019-01-06", "Observations": [ ["2019-01-06", 1, true], [false], [true], [false], [true] ] }
-
A business week time series with one week of numerical data.
{ "JsonTs": "regular", "BasePeriod": [1, "w"], "SubPeriods": 5, "Observations": [ ["2000-01-03", 1, 1], [2], [3], [4], [5] ] }
-
A business week time series with data for Monday, Tuesday, Thursday, and Friday. Note that the observation for Thursday references Monday, January 3rd as the base period, but could equivalently reference Thursday, January 6th, as both fall within the same weekly base period.
{ "JsonTs": "regular", "BasePeriod": [1, "w"], "SubPeriods": 5, "Observations": [ ["2000-01-03", 1, 1], [2], ["2000-01-03", 4, 4], [5] ] }
-
A time series with millisecond frequency containing two string observations in the middle of the first second of 2000.
{ "JsonTs": "regular", "BasePeriod": [1, "e-3"], "Observations": [ ["2019-01-01T00:00:00.499Z", "first"], ["second"] ] }