API tour
A guided tour of everything IsoWeek and IsoWeekDate can do, grouped by
kind of operation. Every output on this page is generated by running the code shown.
If you are new to the library, work through the quickstart first. For signatures, argument types and
raised exceptions, see the API reference pages for IsoWeek and
IsoWeekDate.
The two classes share most of their behaviour through their common parent class BaseIsoWeek, so this page covers the
shared operations first and the class specific ones afterwards.
Both classes are available from the top-level module:
from datetime import date, datetime
from iso_week_date import IsoWeek, IsoWeekDate
iw = IsoWeek("2023-W01")
iwd = IsoWeekDate("2023-W01-1")
print(iw, iwd)
2023-W01 2023-W01-1
str() returns the value, while repr() also reports the offset:
print(str(iw))
print(repr(iw))
2023-W01
IsoWeek(2023-W01) with offset 0:00:00
Parsing from other types
An instance can be initialized from several types:
print(IsoWeek("2023-W01"))
print(IsoWeekDate("2023-W01-1"))
2023-W01
2023-W01-1
print(IsoWeek.from_string("2023-W01"))
print(IsoWeekDate.from_string("2023-W01-1"))
2023-W01
2023-W01-1
print(IsoWeek.from_compact("2023W01"))
print(IsoWeekDate.from_compact("2023W011"))
2023-W01
2023-W01-1
print(IsoWeek.from_date(date(2023, 1, 2)))
print(IsoWeekDate.from_date(date(2023, 1, 2)))
2023-W01
2023-W01-1
print(IsoWeek.from_datetime(datetime(2023, 1, 2, 12)))
print(IsoWeekDate.from_datetime(datetime(2023, 1, 2, 12)))
2023-W01
2023-W01-1
print(IsoWeek.from_values(year=2023, week=1))
print(IsoWeekDate.from_values(year=2023, week=1, weekday=1))
2023-W01
2023-W01-1
print(IsoWeek.from_today() == IsoWeek.from_date(date.today()))
True
The compact format has no separators
The compact format drops every separator: IsoWeekDate.from_compact expects YYYYWNND (e.g. "2023W011"),
not "2023W01-1". from_today also accepts an optional time_zone argument.
Converting to other types
In the opposite direction, an instance can be converted to multiple types:
print(iw.to_string())
print(iwd.to_string())
2023-W01
2023-W01-1
print(iw.to_compact())
print(iwd.to_compact())
2023W01
2023W011
print(iw.to_date())
print(iwd.to_date())
2023-01-02
2023-01-02
print(iw.to_datetime())
print(iwd.to_datetime())
2023-01-02 00:00:00
2023-01-02 00:00:00
print(iw.to_values()) # (year, week)
print(iwd.to_values()) # (year, week, weekday)
(2023, 1)
(2023, 1, 1)
IsoWeek to date/datetime
IsoWeek.to_date and
IsoWeek.to_datetime accept an optional weekday
argument, which defaults to 1 (first weekday), and can be used to get the date of a specific day of the week:
print(iw.to_date(2))
print(iw.to_datetime(3))
2023-01-03
2023-01-04 00:00:00
IsoWeekDate already carries a weekday, so its to_date and to_datetime take no argument.
Properties
Both classes expose the components of their value as integers, plus the class name:
print(iw.year, iwd.year)
2023 2023
print(iw.week, iwd.week)
1 1
print(iw.quarter, iwd.quarter)
print(IsoWeek("2023-W40").quarter)
1 1
4
print(iw.name, iwd.name)
IsoWeek IsoWeekDate
Comparison operations
Both classes implement all the comparison operators (==, !=, <, <=, >, >=) for instances of the same class:
print(iw == IsoWeek("2023-W01"))
print(iw < IsoWeek("2023-W02"))
print(iwd > IsoWeekDate("2023-W02-2"))
True
True
False
Comparing across classes is rejected, because an IsoWeek and an IsoWeekDate do not represent the same kind of
quantity:
print(iw == iwd) # equality is False rather than an error
try:
iw < iwd
except TypeError as e:
print(f"TypeError: {e}")
False
TypeError: Cannot compare `IsoWeek` with type `<class 'iso_week_date.isoweekdate.IsoWeekDate'>`, comparison is supported only with other `IsoWeek` objects
Ordering works by first checking that both operands share the same class and the same offset, then comparing their string values, which is correct because the ISO week date format is lexicographically ordered. See why iso-week-date? for why that holds.
Predicates
The comparison operators also come in a named form, which reads better inside filters, and include a bounded check:
print(iw.is_before(IsoWeek("2023-W02")))
print(iw.is_after(IsoWeek("2022-W52")))
True
True
print(iw.is_between(IsoWeek("2022-W52"), IsoWeek("2023-W02")))
print(iw.is_between(IsoWeek("2023-W01"), IsoWeek("2023-W02"), inclusive="neither"))
True
False
is_between accepts inclusive="both" (the default), "left", "right" or "neither".
Addition and subtraction
operations with ints
The two classes treat the int type differently in addition and subtraction:
- for
IsoWeekit is interpreted as weeks - for
IsoWeekDateit is interpreted as days
Adding an int shifts the value; adding an iterable of ints returns a generator of shifted values:
print(iw + 1)
print(tuple(iw + (1, 2, 3)))
print(iwd + 1)
2023-W02
(IsoWeek(2023-W02) with offset 0:00:00, IsoWeek(2023-W03) with offset 0:00:00, IsoWeek(2023-W04) with offset 0:00:00)
2023-W01-2
print(iw - 1)
print(iw - IsoWeek("2022-W52")) # distance as int
print(tuple(iw - (1, 2, 3)))
print(iwd - 1)
print(iwd - IsoWeekDate("2022-W52-3"))
2022-W52
1
(IsoWeek(2022-W52) with offset 0:00:00, IsoWeek(2022-W51) with offset 0:00:00, IsoWeek(2022-W50) with offset 0:00:00)
2022-W52-7
5
Subtracting another instance of the same class returns the distance between the two as an int: weeks for IsoWeek,
days for IsoWeekDate.
The operators are also available as the named methods add and sub, which accept exactly the same arguments and are
handier when passed around as callables:
print(iw.add(2))
print(iw.sub(2))
print(tuple(iw.add((1, 2))))
2023-W03
2022-W51
(IsoWeek(2023-W02) with offset 0:00:00, IsoWeek(2023-W03) with offset 0:00:00)
Stepping by one
For the common case of moving a single step, use next and previous:
print(iw.next(), iw.previous())
print(iwd.next(), iwd.previous())
2023-W02 2022-W52
2023-W01-2 2022-W52-7
Both classes also implement __next__, so the next() builtin works on an instance. It returns a new object rather
than advancing the existing one:
print(next(iw), iw)
2023-W02 2023-W01
Arithmetic is bounded by ISO years 0001 and 9999
Values are backed by datetime.date, so stepping past either end raises the standard library's
own error rather than a domain one: OverflowError from the timedelta paths (next,
previous, +, -, weeksout, daysout) and ValueError from the strptime ones (days,
nth, to_date, to_datetime). Guard with except (OverflowError, ValueError) if you work near
the bounds. This is deliberate: a bounds check on every arithmetic call would cost every caller
something to protect a range essentially nobody reaches.
9999-W52 is the last representable week and a partial one, since it runs into year 10000 from
its sixth day on:
from iso_week_date import IsoWeek
print(IsoWeek("9999-W52").nth(5))
try:
IsoWeek("9999-W52").nth(6)
except (OverflowError, ValueError) as e:
print(f"day 6: {type(e).__name__}")
9999-12-31
day 6: ValueError
Replacing components
replace returns a new instance with some components swapped out, leaving the others untouched. Its arguments are
keyword-only:
print(iw.replace(year=2024))
print(iwd.replace(week=2, weekday=5))
2024-W01
2023-W02-5
Ranges
range is a classmethod that generates every value between two endpoints, with a configurable step and inclusiveness.
Endpoints can be passed as strings, dates, datetimes or instances:
_range = IsoWeek.range(
start="2023-W01", end="2023-W07", step=2, inclusive="both", as_str=True
)
print(tuple(_range))
('2023-W01', '2023-W03', '2023-W05', '2023-W07')
_range = IsoWeekDate.range(
start="2023-W01-1", end="2023-W03-3", step=3, inclusive="left", as_str=True
)
print(tuple(_range))
('2023-W01-1', '2023-W01-4', '2023-W01-7', '2023-W02-3', '2023-W02-6', '2023-W03-2')
as_str=False yields class instances instead of strings, and inclusive accepts the same four values as is_between.
The generated values always sit on a grid anchored at start, and inclusive removes the endpoints
from that grid rather than shifting it. With a step greater than 1 the grid may skip over end
entirely, in which case there is no end for inclusive to keep or drop:
for inclusive in ("both", "left", "right", "neither"):
weeks = IsoWeek.range(start="2023-W01", end="2023-W05", step=2, inclusive=inclusive)
print(f"{inclusive:8} {tuple(weeks)}")
both ('2023-W01', '2023-W03', '2023-W05')
left ('2023-W01', '2023-W03')
right ('2023-W03', '2023-W05')
neither ('2023-W03',)
IsoWeek specific
days property and nth method
days returns the tuple of dates in the week, and nth picks one of them (1-indexed, Monday first):
print(iw.days)
print(iw.nth(1), iw.nth(7))
(datetime.date(2023, 1, 2), datetime.date(2023, 1, 3), datetime.date(2023, 1, 4), datetime.date(2023, 1, 5), datetime.date(2023, 1, 6), datetime.date(2023, 1, 7), datetime.date(2023, 1, 8))
2023-01-02 2023-01-08
weeksout method
weeksout generates the weeks that are up to n_weeks after the given week:
print(tuple(iw.weeksout(3)))
print(tuple(iw.weeksout(6, step=2, as_str=False)))
('2023-W02', '2023-W03', '2023-W04')
(IsoWeek(2023-W02) with offset 0:00:00, IsoWeek(2023-W04) with offset 0:00:00, IsoWeek(2023-W06) with offset 0:00:00)
contains method and in operator
contains checks whether a week, string, date or datetime (or an iterable of them) falls inside the given week:
print(iw.contains("2023-W01"))
print(iw.contains(date(2023, 1, 1)))
print(iw.contains((IsoWeek("2023-W01"), date(2023, 1, 1), date(2023, 1, 2))))
True
False
(True, False, True)
A single value is also accepted by the in operator, via __contains__:
print(date(2023, 1, 1) in iw)
print(date(2023, 1, 2) in iw)
False
True
IsoWeekDate specific
weekday and isoweek properties
print(iwd.weekday) # 1 is Monday, 7 is Sunday
print(iwd.isoweek) # the week this date belongs to, as a string
1
2023-W01
day is a deprecated alias
IsoWeekDate.day still works as an alias of weekday, kept for backward compatibility. Prefer weekday in new
code.
daysout method
daysout generates the dates that are up to n_days after the given date:
print(tuple(iwd.daysout(3)))
print(tuple(iwd.daysout(6, step=3, as_str=False)))
('2023-W01-2', '2023-W01-3', '2023-W01-4')
(IsoWeekDate(2023-W01-2) with offset 0:00:00, IsoWeekDate(2023-W01-5) with offset 0:00:00)
Where to next
- Weeks that do not start on Monday: change the day a week starts on.
- Working with dataframes: apply these conversions to whole series.
- Working with Pydantic: validate ISO week strings on model fields.