---
myst:
html_meta:
description: >-
Copy-pasteable recipes for common tasks: current time, time zone conversion,
parsing ISO 8601, rounding, ages, countdowns, and DST-safe scheduling.
---
(examples)=
# Examples
```{eval-rst}
.. currentmodule:: whenever
```
Short, copy-pasteable recipes for the things you'll reach for most often.
For the reasoning behind them, refer to the {ref}`guide`.
## Get the current time in UTC
```python
>>> from whenever import Instant
>>> Instant.now()
Instant("2025-04-19 19:02:56.39569Z")
```
## Convert UTC to the system time zone
```python
>>> from whenever import Instant, SYSTEM_TZ
>>> i = Instant.now()
>>> i.to_tz(SYSTEM_TZ)
ZonedDateTime("2025-04-19 21:02:56.39569+02:00[Europe/Berlin]")
```
## Convert from one time zone to another
```python
>>> from whenever import ZonedDateTime
>>> d = ZonedDateTime(2025, 4, 19, hour=15, tz="America/New_York")
>>> d.to_tz("Europe/Berlin")
ZonedDateTime("2025-04-19 21:00:00+02:00[Europe/Berlin]")
```
## Convert a date to datetime
```python
>>> from whenever import Date, Time
>>> date = Date(2023, 10, 1)
>>> date.at(Time(12, 30))
PlainDateTime("2023-10-01 12:30:00")
```
## Calculate somebody's age
```python
>>> from whenever import Date
>>> birth_date = Date(2000, 11, 2)
>>> today = Date(2026, 3, 10)
>>> today.since(birth_date, total="years") # scalar totals may be fractional
25.350684931506848
>>> years, months, days = today.since(
... birth_date, in_units=("years", "months", "days")
... ).values()
>>> years # completed calendar years
25
>>> months, days # optional remainder
(4, 8)
```
## Assign a time zone to a datetime
```python
>>> from whenever import PlainDateTime
>>> datetime = PlainDateTime(2023, 10, 1, 12, 30)
>>> datetime.assume_tz("America/New_York")
ZonedDateTime("2023-10-01 12:30:00-04:00[America/New_York]")
```
## Integrate with the standard library
```python
>>> import datetime
>>> py_dt = datetime.datetime.now(datetime.UTC)
>>> from whenever import Instant
>>> # create an Instant from any aware datetime
>>> i = Instant(py_dt)
Instant("2025-04-19 19:02:56.39569Z")
>>> zdt = i.to_tz("America/New_York")
ZonedDateTime("2025-04-19 15:02:56.39569-04:00[America/New_York]")
>>> # convert back to the standard library
>>> zdt.to_stdlib()
datetime.datetime(2025, 4, 19, 15, 2, 56, 395690, tzinfo=zoneinfo.ZoneInfo(key='America/New_York'))
```
## Parse an ISO 8601 string
```python
>>> from whenever import Instant
>>> Instant("2025-04-19T19:02+04:00")
Instant("2025-04-19 15:02:00Z")
```
Or, if you want to keep the offset value:
```python
>>> from whenever import OffsetDateTime
>>> OffsetDateTime("2025-04-19T19:02+04:00")
OffsetDateTime("2025-04-19 19:02:00+04:00")
```
## Determine the start of the hour
```python
>>> d = ZonedDateTime.now("America/New_York")
ZonedDateTime("2025-04-19 15:46:41-04:00[America/New_York]")
>>> d.start_of("hour")
ZonedDateTime("2025-04-19 15:00:00-04:00[America/New_York]")
```
The {meth}`~whenever.ZonedDateTime.start_of` method also works with
other units like ``"day"``, ``"minute"``, and more.
See its documentation for more details.
## Determine the end of the day
```python
>>> d = ZonedDateTime.now("America/New_York")
ZonedDateTime("2025-04-19 15:46:41-04:00[America/New_York]")
>>> d.end_of("day")
ZonedDateTime("2025-04-19 23:59:59.999999999-04:00[America/New_York]")
```
## Get the current timestamp
```python
>>> from whenever import Instant
>>> i = Instant.now()
>>> i.timestamp()
1745090505
```
Note that this is always in whole seconds.
If you need additional precision:
```python
>>> i.timestamp(unit="millisecond")
1745090505629
>>> i.timestamp(unit="nanosecond")
1745090505629346833
```
## Get a date and time from a timestamp
```python
>>> from whenever import Instant
>>> Instant.from_timestamp(1745090505).to_tz("America/New_York")
ZonedDateTime("2025-04-19 15:21:45-04:00[America/New_York]")
```
## Find the duration between two datetimes
```python
>>> from whenever import ZonedDateTime
>>> d = ZonedDateTime(2025, 1, 3, hour=15, tz="America/New_York")
>>> d2 = ZonedDateTime(2025, 1, 5, hour=8, minute=24, tz="Europe/Paris")
>>> d2 - d
TimeDelta("PT35h24m")
```
## Move a date by six months
```python
>>> from whenever import Date
>>> date = Date(2023, 10, 31)
>>> date.add(months=6)
Date("2024-04-30")
```
## Discard fractional seconds
```python
>>> from whenever import Instant
>>> i = Instant.now()
Instant("2025-04-19 19:02:56.39569Z")
>>> i.round()
Instant("2025-04-19 19:02:56Z")
```
Use the arguments of {meth}`~whenever.Instant.round` to customize the rounding behavior.
## Handling ambiguous datetimes
Due to daylight saving time, some date and time values don't exist,
or occur twice in a given time zone.
In the example below, the clock was set forward by one hour at 2:00 AM,
so the time 2:30 AM doesn't exist.
```python
>>> from whenever import PlainDateTime, ZonedDateTime
>>> # set up the date and time for the example
>>> dt = PlainDateTime(2023, 3, 26, hour=2, minute=30)
```
For a repeated or skipped local time, choose the desired policy explicitly.
The `"compatible"` policy follows established libraries and RFC 5545:
```python
>>> zoned = dt.assume_tz("Europe/Berlin", disambiguation="compatible")
ZonedDateTime("2023-03-26 03:30:00+02:00[Europe/Berlin]")
```
You can instead choose the earlier or later interpretation:
```python
>>> zoned = dt.assume_tz("Europe/Berlin", disambiguation="earlier")
ZonedDateTime("2023-03-26 01:30:00+01:00[Europe/Berlin]")
```
Or, you can even reject ambiguous datetimes altogether:
```python
>>> dt.assume_tz("Europe/Berlin", disambiguation="raise")
Traceback (most recent call last):
...
whenever.SkippedTime: 2023-03-26 02:30:00 is skipped in time zone 'Europe/Berlin'
```
## "Same time tomorrow" across DST
Adding a day keeps the local time, even when a DST transition
makes the day shorter or longer than 24 hours:
```python
>>> from whenever import ZonedDateTime
>>> # The night before Spring Forward in Amsterdam
>>> eve = ZonedDateTime(2025, 3, 30, hour=1, tz="Europe/Amsterdam")
>>> eve.add(days=1) # same local time
ZonedDateTime("2025-03-31 01:00:00+02:00[Europe/Amsterdam]")
>>> eve.add(hours=24) # exactly 24 hours — one hour later on the clock
ZonedDateTime("2025-03-31 02:00:00+02:00[Europe/Amsterdam]")
```
## Countdown to New Year's
```python
>>> from whenever import ZonedDateTime
>>> now = ZonedDateTime(2025, 12, 28, hour=14, tz="America/New_York")
>>> new_year = ZonedDateTime(2026, 1, 1, tz="America/New_York")
>>> days, hours = new_year.since(now, in_units=("days", "hours")).values()
(3, 10)
```
## Flight itinerary across time zones
```python
>>> from whenever import OffsetDateTime, hours
>>> departure = OffsetDateTime(2025, 7, 1, hour=9, offset=-hours(4)) # New York
>>> arrival = OffsetDateTime(2025, 7, 1, hour=22, offset=hours(2)) # Amsterdam
>>> flight_time = arrival - departure
>>> flight_time.total("hours")
7.0
```
## Recurring monthly event
When a monthly recurrence lands on a day that doesn't exist in the
target month, the date is clamped to the last valid day:
```python
>>> from whenever import Date
>>> meeting = Date(2025, 1, 31)
>>> meeting.add(months=1) # February doesn't have 31 days
Date("2025-02-28")
>>> meeting.add(months=2)
Date("2025-03-31")
```
## Sort a list of datetimes
All *exact types* can be compared and sorted amongst each other:
```python
>>> from whenever import Instant, ZonedDateTime, OffsetDateTime, hours
>>> times = [
... ZonedDateTime(2025, 6, 1, hour=12, tz="Asia/Tokyo"),
... Instant.from_utc(2025, 6, 1, hour=2),
... OffsetDateTime(2025, 6, 1, hour=6, offset=hours(4)),
... ]
>>> sorted(times) # all represent the same moment—sorted by the underlying instant
[...]
```
"Plain" datetimes cannot be mixed with exact types.
This will be flagged by type checking.
## Format with a pattern
For formats beyond ISO 8601, use pattern strings:
```python
>>> from whenever import Date, PlainDateTime, OffsetDateTime
>>> Date.parse("15 Mar 2024", pattern="DD MMM YYYY")
Date("2024-03-15")
>>> PlainDateTime.parse("03/15/2024 02:30 PM", pattern="MM/DD/YYYY ii:mm aa")
PlainDateTime("2024-03-15 14:30:00")
>>> OffsetDateTime.parse("2024-03-15 14:30+02:00", pattern="YYYY-MM-DD HH:mmxxx")
OffsetDateTime("2024-03-15 14:30:00+02:00")
```
If your input doesn't include an offset or time zone, parse with
{meth}`PlainDateTime.parse` and convert:
```python
>>> from whenever import PlainDateTime
>>> pdt = PlainDateTime.parse("2024-03-15 14:30", pattern="YYYY-MM-DD HH:mm")
>>> pdt.assume_utc()
Instant("2024-03-15 14:30:00Z")
```
It also integrates nicely with the standard library's formatting protocol
(`__format__`), so you can use pattern strings in f-strings:
```python
>>> from whenever import Date
>>> d = Date(2024, 3, 15)
>>> f"{d:DD/MM/YYYY}"
'15/03/2024'
>>> f"{d}" # empty spec falls back to str()
'2024-03-15'
```
## Roundtrip: datetime → string → datetime
Every `whenever` type has an ISO-compatible reversible string representation:
```python
>>> from whenever import ZonedDateTime
>>> d = ZonedDateTime(2025, 6, 15, hour=14, minute=30, tz="Europe/Amsterdam")
>>> s = str(d)
>>> s
'2025-06-15T14:30:00+02:00[Europe/Amsterdam]'
>>> ZonedDateTime(s) == d
True
```