Python API

Manipulating sequences of dates

Sequences of dates are represented by the Sequence class. Specific types of sequence are defined as subclasses:

A sequence object can be created by invoking the corresponding constructor:

from earthkit.time import WeeklySequence
from earthkit.time.calendar import MONDAY, WEDNESDAY
seq = WeeklySequence([MONDAY, WEDNESDAY])

It can also be loaded from a dictionary using Sequence.from_dict, or from a preset file using Sequence.from_resource.

For convenience, calling the create_sequence() function will dispatch to the appropriate constructor or factory method.

Sequence examples

Example

Description

DailySequence()

Sequence recurring every day

DailySequence(excludes=[31])

Sequence recurring every day, except the 31st

WeeklySequence([MONDAY, THURSDAY])

Sequence recurring every Monday and Thursday

MonthlySequence([1, 15])

Sequence recurring every 1st and 15th of the month

MonthlySequence([1, 8, 15, 22, 29], excludes=[(2, 29)])

Sequence recurring every 7 days each month, skipping the 29th February

YearlySequence((12, 25))

Sequence recurring every year on the 25th December

Sequence.from_resource("ecmwf-4days")

Pre-defined sequence (equivalent to MonthlySequence(range(1, 30, 4), excludes=[(2, 29)]))

create_sequence("daily")

Equivalent to DailySequence()

create_sequence("resource", "ecmwf-2days")

Equivalent to Sequence.from_resource("ecmwf-2days")

Computing individual dates

To get the previous or next date in a sequence, use Sequence.previous or Sequence.next:

>>> seq = WeeklySequence([WEDNESDAY, FRIDAY])
>>> seq.previous(date(2024, 5, 12))
datetime.date(2024, 5, 10)
>>> seq.next(date(2024, 5, 10))
datetime.date(2024, 5, 15)
>>> seq.next(date(2024, 5, 10), strict=False)
datetime.date(2024, 5, 10)

If the given date is in the sequence, the default behaviour is to skip to the previous or next one. To keep it, pass strict=False.

Similarly, the sequence date closest to a given date can be computed using Sequence.nearest:

>>> seq = MonthlySequence([1, 15])
>>> seq.nearest(date(2024, 7, 4))
datetime.date(2024, 7, 1)
>>> seq.nearest(date(2024, 3, 20))
datetime.date(2024, 3, 15)
>>> seq.nearest(date(2024, 8, 8))
datetime.date(2024, 8, 1)
>>> seq.nearest(date(2024, 8, 8), resolve="next")
datetime.date(2024, 8, 15)

If there is a tie, meaning that the given date is equidistant from the previous and next date in the sequence, the previous date is returned. This behaviour can be explicitly controlled by passing resolve="previous" or resolve="next".

Computing sets of dates

To find all the sequence dates falling within a range, use Sequence.range:

>>> print_dates = lambda dates: print(", ".join(d.strftime("%Y%m%d") for d in dates))
>>> seq = WeeklySequence([0, 2, 4])
>>> print_dates(seq.range(date(2024, 12, 1), date(2024, 12, 16)))
20241202, 20241204, 20241206, 20241209, 20241211, 20241213, 20241216
>>> print_dates(seq.range(date(2024, 12, 1), date(2024, 12, 16), include_end=False))
20241202, 20241204, 20241206, 20241209, 20241211, 20241213
>>> print_dates(seq.range(date(2024, 12, 2), date(2024, 12, 16), include_start=False))
20241204, 20241206, 20241209, 20241211, 20241213, 20241216

By default, ranges include the given start and end dates. The include_start and include_end arguments control this behaviour.

To get a given number of dates around one reference, use Sequence.bracket:

>>> seq = WeeklySequence(SATURDAY)
>>> print_dates(seq.bracket(date(1999, 11, 27)))
19991120, 19991204
>>> print_dates(seq.bracket(date(1999, 11, 27), strict=False))
19991120, 19991127, 19991204
>>> print_dates(seq.bracket(date(2006, 5, 28), 3))
20060513, 20060520, 20060527, 20060603, 20060610, 20060617
>>> print_dates(seq.bracket(date(2015, 4, 3), (1, 2)))
20150328, 20150404, 20150411
>>> print_dates(seq.bracket(date(1993, 7, 17), (2, 1), strict=False))
19930703, 19930710, 19930717, 19930724

The optional num argument represents the number of dates to output, respectively before and after the reference date. If an integer is given, the same number of dates either side is returned. If strict=False is passed and the reference date is in the sequence, it is printed as well (but not counted towards the numbers requested).

Sets of dates for model climates

To get one date per year on the same day as a given reference, use date_range():

>>> from earthkit.time import date_range
>>> print_dates(date_range(date(2006, 10, 23), 2000, 2005))
20001023, 20011023, 20021023, 20031023, 20041023, 20051023
>>> print_dates(date_range(date(2005, 6, 2), date(2002, 6, 8), date(2004, 7, 1)))
20030602, 20040602
>>> from earthkit.time import RelativeYear
>>> print_dates(date_range(date(2010, 8, 5), RelativeYear(-3), RelativeYear(-1)))
20070805, 20080805, 20090805

To combine yearly dates with multiple reference dates taken from a sequence, use model_climate_dates():

>>> from earthkit.time import model_climate_dates
>>> seq = Sequence.from_resource("ecmwf-mon-thu")
>>> print_dates(model_climate_dates(date(2023, 8, 6), 2018, 2020, 7, 7, seq))
20180731, 20180803, 20180807, 20180810, 20190731, 20190803, 20190807, 20190810, 20200731, 20200803, 20200807, 20200810
>>> print_dates(model_climate_dates(date(2023, 1, 1), RelativeYear(-7), RelativeYear(-4), 5, 5, seq))
20151229, 20160102, 20160105, 20161229, 20170102, 20170105, 20171229, 20180102, 20180105, 20181229, 20190102, 20190105