metomi / isodatetime

:date: :watch: Python ISO 8601 date time parser and data model/manipulation utilities
GNU Lesser General Public License v3.0
38 stars 20 forks source link
datetime iso8601 python

isodatetime

Test codecov DOI PYPI Badge

Python ISO8601 (2004) full-specification parser and data model/manipulation utilities. Intended to be used in a similar way to Python's datetime module.

Installation

Install from PyPI:

$ pip install metomi-isodatetime

Or with conda: see https://github.com/conda-forge/metomi-isodatetime-feedstock

Usage

Python API:

>>> import metomi.isodatetime.parsers as parse
>>> import metomi.isodatetime.dumpers as dump

# Dates and times
>>> date_time = parse.TimePointParser().parse('2000-01-01T00:00Z')
>>> date_time.month_of_year
1

# Durations
>>> duration = parse.DurationParser().parse('P1YT3H')
>>> duration.get_days_and_seconds()
(365.0, 10800.0)
>>> date_time + duration
<metomi.isodatetime.data.TimePoint: 2001-01-01T03:00:00Z>

# Recurrences
>>> recurrence = parse.TimeRecurrenceParser().parse('R/1999/P1Y')
>>> recurrence.get_next(date_time)
<metomi.isodatetime.data.TimePoint: 2001-01-01T00:00:00Z>

# Output
>>> dump.TimePointDumper().strftime(date_time, '%d/%M/%Y %H:%M:%S')
'01/00/2000 00:00:00'

CLI:

$ isodatetime
2000-01-01T00:00:00Z
$ isodatetime 1066
1066
$ isodatetime 1066 --offset P1Y
1067
$ isodatetime R/2000/P1Y --max 3
2000-01-01T00:00:00Z
2001-01-01T00:00:00Z
2002-01-01T00:00:00Z

Copyright and Terms of Use

Copyright (C) 2013-2024 British Crown (Met Office) & Contributors.

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this program. If not, see GNU licenses.

ISO 8601

ISO 8601 (2004) is an international standard for writing down date/time information.

It is the correct, internationally-friendly, computer-sortable way to numerically represent date/time information.

Good reading material:

Reference material:

Dates and times

How do I write the year, month-of-year, and day-of-month down?

Syntax Example
CCYYMMDD 20151231
CCYY-MM-DD 2015-12-31

How about writing down the year, week-of-year, and day-of-week?

Syntax Example
CCYYWwwD 2015W534
CCYY-Www-D 2015-W53-4

How about writing down the year and day-of-year?

Syntax Example
CCYYDDD 2015365
CCYY-DDD 2015-365

How do I write just the year?

Either: CCYY or +XCCYY

+X stands for a plus or minus sign (+ or -), followed by a fixed, agreed number of expanded year digits (X). For example, if we agree to have 2 expanded year digits, we can represent years from -999999 to +999999 (1000000 BC to 999999 AD). Note that 1 BC is the year 0 in the proleptic Gregorian calendar used by ISO 8601.

For example, you can write the year 1995 AD as: 1995 or +001995 (using 2 expanded year digits).

Note: writing just the year where you mean a proper date implies Day 1 of Month 1 in that year - 1995 implies 1995-01 => 1995-01-01 => 1995-01-01T00 => 1995-01-01T00:00 => 1995-01-01T00:00:00.

How do I write just the year and month-of-year?

Either: CCYY-MM or +XCCYY-MM (+ standing in here for a + or - sign)

(not allowed: CCYYMM or +XCCYYMM).

How do I write dates past the year 9999 and before 0000?

Syntax Example (2 expanded year digits)
+XCCYYMMDD +0020151231
+XCCYY-MM-DD +002015-12-31
+XCCYYWwwD +002015W534
+XCCYY-Www-D +002015-W53-4
+XCCYYDDD +002015365
+XCCYY-DDD +002015-365

How do I write down time information by itself?

Syntax Example
hhmmss 083000
hhmm 0830
hh:mm:ss 17:45:01
hh:mm 17:45
hh 08

How do I write down time information at a date in ISO 8601?

Write the time after the date, separated with a T:

Syntax Example
CCYYMMDDThhmmss 20151231T063101
CCYY-MM-DDThh:mm:ss 2015-12-31T06:31:01
CCYYWwwDThhmmss 2015W534T063101
CCYY-Www-DThh:mm:ss 2015-W53-4T06:31:01
CCYYDDDThhmmss 2015365T063101
CCYY-DDDThh:mm:ss 2015-365T06:31:01

What about just the hour and minute at a date?

Syntax Example
CCYYWwwDThhmm 2015W534T0631
CCYY-Www-DThh:mm 2015-W53-4T06:31

What about just the hour at a date?

Syntax Example
CCYYMMDDThh 20151231T06
CCYY-MM-DDThh 2015-12-31T06

What about decimal parts of the hour or minute or second?

Use a comma or period to delimit the decimal part, and don't include any smaller units:

Syntax Example
CCYYMMDDThh,ii 20151231T06,5
CCYYMMDDThh.ii 20151231T06.5
CCYYMMDDThhmm,nn 20151231T0631,3333
CCYYMMDDThhmm.nn 20151231T0631.3333
CCYYMMDDThhmmss,tt 20151231T063101,25671
CCYYMMDDThhmmss.tt 20151231T063101.25671

How do I specify a time zone?

If the time zone is UTC, use "Z" - otherwise, use a numeric representation of the hours and minutes difference from UTC.

Note that this difference is (TIMEZONE - UTC) - so longitudes east of 0 tend to have positive differences, and west of 0 usually have negative differences.

Syntax Example
CCYYMMDDThhmmssZ 20151231T063101Z
CCYY-MM-DDThh:mm:ssZ 2015-12-31T06:31:01Z
CCYYMMDDThhmmss-hh 20151231T013101-05
CCYY-MM-DDThh:mm:ss-hh 2015-12-31T01:31:01-05
CCYYMMDDThhmmss+hh 20151231T083101+02
CCYY-MM-DDThh:mm:ss+hh 2015-12-31T08:31:01+02
CCYYMMDDThhmmss-hhmm 20151230T203101-1000
CCYY-MM-DDThh:mm:ss-hh:mm 2015-12-30T20:31:01-10:00
CCYYMMDDThhmmss+hhmm 20151231T193101+1300
CCYY-MM-DDThh:mm:ss+hh:mm 2015-12-31T19:31:01+13:00

Durations

How do I write down a certain period of time in X units?

A "P" followed by the number of units (optionally including a decimal part) followed by a designator to mark the units:

Unit type Unit designator
years Y
months M
weeks W
days D
hours H
minutes M
seconds S

If the unit is one of hours, minutes, or seconds, you need a leading "T" to delimit time from date:

Syntax Example Meaning
PnY P2Y 2 years
PTnM PT7M 7 minutes (note the 'T')
PnM P10M 10 months
PnDTnH P5DT6H 5 days and 6 hours
PTn,oH PT5,5H 5 and a half hours
PTn.oH PT5.5H 5 and a half hours
PnW P2W 2 weeks

Combining any other unit with weeks is not allowed. Decimals may only be used for hours, minutes and seconds.

Note that years and months are "nominal" durations, whose exact length of time depends on their position in the calendar. E.g., a duration of 1 calendar year starts on a particular day of a particular month and ends on the same day of the same month in the following calendar year, and may be different to 365 days in the Gregorian calendar due to leap years.

Conversely, weeks, days, hours, minutes and seconds are exact units, so P1W == P7D, P1D == PT24H and PT1H == PT60M etc. are always true. (Although ISO 8601 specifies that weeks and days are nominal durations, there is no case where they are not exact in our implementation.)

A supplementary format (which has to be agreed in advance) is to specify a date-time-like duration (PCCYY-MM-DDThh:mm:ss) where the numbers given for years, months, days, hours, minutes, and seconds are used literally (P1995-00-00T00:10:00 = P1995YT10M).

Recurring date-time series

1. Recur with a duration given by the difference between a start date and a subsequent date

Example Syntax Example Meaning
R/CCYY/CCYY R/2010/2014 Repeat every 1461 days (≈ 4 years*), starting at 2010-01-01
R/CCYY-MM/CCYY-DDD R/2010-01/2012-045 Repeat every 774 days (≈ 2 years and 44 days*), starting at 2010-01-01
Rn/CCYY-Www-D/CCYY-Www-D R5/2015-W05-2/2015-W07-3 Repeat every 15 days (= 2 weeks and 1 day), five times, starting at 2015-W05-2
Rn/CCYY-MM-DDThh/CCYY-MM-DDThh R1/1925-02-11T00Z/2027-06-01T00Z Repeat once at 1925-02-11T00Z (note the end date-time is ignored)

*See the previous section as to why only an approximate equivalent number of years are given.

2. Recur with a specified duration, starting at a context date-time

(You have to supply the context somewhere else)

Example Syntax Example Meaning
R/PnMnDTnM R/P10M3DT45M Repeat every 10 months, 3 days, and 45 minutes from a context start date-time.
Rn/PnY R2/P4Y Repeat every 4 years, for a total of 2 times, from a context start date-time.

3. Recur with a specified duration starting at a particular date-time

Example Syntax Example Meaning
R/CCYYMMDDThhZ/PTnH R/20201231T00Z/PT12H Repeat every 12 hours starting at 2020-12-31T00Z
R/CCYY-Www-D/PnW R/2012-W02-1/P1W Repeat weekly starting at Monday in the second ISO week of 2012
R/CCYYDDDThhmm/PnD R/1996291T0630+0100/P2D Repeat every 2 days starting on the 291st day of 1996 at 06:30, UTC + 1
Rn/CCYY-MM-DDThh:mm/PTnH R2/19900201T06Z/PT12H Repeat every 12 hours, for a total of 2 repetitions, starting at 1990-02-01T06Z
Rn/CCYY-Www-D/PnW R5/2012-W02-1/P1W Repeat weekly, for a total of 5 repetitions, starting at Monday in the second ISO week of 2012
Rn/CCYYDDDThhmm/PnD R1/1996291T0630Z/P2D Repeat once on the 291st day of 1996 at 06:30 (note the duration is ignored)

4. Recur with a specified duration ending at a particular date-time

The starting date-time of the recurrence is calculated from the specified duration.

Example Syntax Example Meaning
R/PTnH/CCYY-MM-DDThhZ R/PT1H/2012-01-02T00Z Repeat hourly, ending at 2012-01-02T00Z (therefore repeats on the hour)
R/PnY/CCYY R/P3Y/2000 Repeat every 3 years, ending at 2000-01-01 (therefore repeats at 00:00 January 1st)
R/PTnS/+XCCYYDDDThhmm R/PT5s/-002500012T1800 Repeat every 5 seconds, ending on the 12th day in 2501 BC at 18:00 (using 2 expanded year digits)
Rn/PnYTnM/CCYY-MM-DDThhZ R5/P1YT5M/2012-01-02T00Z Repeat every year and 5 minutes, five times, ending at 2012-01-02T00Z
Rn/PnM/CCYY-MM R4/P1M/2000-05 Repeat monthly, four times, ending at 2000-05-01 (therefore repeats on the first of the month)