# Python : Core Library : Dates & Times
**Standard Library**
\[ [calendar](https://docs.python.org/3/library/calendar.html) | [datetime](https://docs.python.org/3/library/datetime.html) | [time](https://docs.python.org/3/library/time.html) | [zoneinfo](https://docs.python.org/3/library/zoneinfo.html) ]
**Third-Party**
\[ python-dateutil -> [PyPI](https://pypi.org/project/python-dateutil/) | [src](https://github.com/dateutil/dateutil/) | [docs](https://dateutil.readthedocs.io/en/stable/) ]
[[Tech/Data/Dates & Times|ISO 8601]]
## Standard Library
#### calendar
Useful for creating calendar displays.
```python
Calendar( firstweekday=0 ) # 0 == Monday
calendar.Day # enum
calendar.MONDAY ...
calendar.Month # enum
calendar.JANUARY ...
```
```bash
$ python -m calendar 2000
```
#### datetime
- *aware* — includes tz context
- *naive* — doesn't include tz context
- all four types are immutable (`date`, `datetime`, `time`, `timedelta`)
- for types with a `tzinfo` attribute (`datetime` and `time`), set it to an instance of a subclass of the abstract base class `datetime.tzinfo` — such as `datetime.timezone` and `zoneinfo.ZoneInfo`
- for methods with a `timespec` parameter (`datetime` and `time`), it indicates the truncation point
- options: `auto`, `hours`, `minutes`, `seconds`, `milliseconds`, `microseconds`
###### Formatting Codes
```
%a weekday, abbrev Sun..Sat
%A weekday, full Sunday..Saturday
%w weekday, number 0..6
%d day of month 01..31
%b month, abbrev Jan..Dec
%B month, full January..December
%m month, number 01..12
%y year, short 00..99
%Y year, full 0001..9999
%H hour (24hr clock) 00..23
%I hour (12hr clock) 00..12
%p AM/PM
%M minute 00..59
%S second 00.59
%f microsecond 000000..999999
%z offset "" or ±HHMM[SS[.ffffff]]
%Z time zone "", UTC, GMT, ...
%j day of year 001..366
%U week number (Sun) 00..53
%W week number (Mon) 00..53
%c localized datetime ex: Tue Aug 16 21:30:00 1988
%x localized date ex: 08/16/88, 08/16/1988
%X localized time ex: 21:30:00
%% literal '%'
```
###### API
```python
# supports comparison operators with itself
date( year, month (1-12), day (1-31) )
# Class Attributes
.today() # current local date
.fromtimestamp( timestamp ) # takes a float representing POSIX time (seconds since 1970)
.fromisoformat( datestring )
# Instance Attributes
.__format__/.strftime( format )
.__str__/.isoformat() # "YYYY-MM-DD"
.isoweekday() # 1 (Mon) .. 7 (Sun)
.replace( year, month, day )
.weekday() # 0 (Mon) .. 6 (Sun)
# subclass of `date`
# fold := the first or second time through the hour (because of DST shifts)
# supports comparison operators with itself if both operands are aware or both are naive
datetime( year, month (1-12), day (1-31),
hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0 (0-1) )
# Class Attributes
.fromisoformat( datetimestring )
.fromtimestamp( timestamp, tz=None ) # takes a float representing POSIX time (seconds since 1970)
.now( tz=None ) # same as today() unless tz passed
.strptime( datetimestring, format )
.today() # current local datetime
.utcfromtimestamp( timestamp ) # deprecated in favor of fromtimestamp( tz=timezone.utc )
.utcnow() # deprecated in favor of now( tz=timezone.utc )
# Instance Attributes
__format__/strftime( format )
__str__() # equiv to isoformat( " " )
astimezone( tz=None ) # if no tz, assumes local time
date()
isoformat( sep="T", timespec="auto" ) # YYYY-MM-DDTHH:MM:SS if microsecond is 0
# YYYY-MM-DDTHH:MM:SS.ffffff if microsecond is not 0
# +HH:MM if tzinfo
isoweekday() # 1 (Mon) .. 7 (Sun)
replace( ... )
time() # without tzinfo
timestamp() # returns POSIX time as float (seconds since 1970)
tztime() # with tzinfo
weekday() # 0 (Mon) .. 6 (Sun)
# supports comparisons with itself if both operands are naive or both are aware
time( hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0 )
# Class Attributes
.fromisoformat( timestring )
# Instance Attributes
.__format__/.strftime( format )
.__str__() # equiv to isoformat()
.isoformat( timespec="auto" )
.replace( ... )
# only stores days, seconds and microseconds - the rest get converted to those three units
# supports math operations with itself as well as date and datetime
# supports comparison operations with itself
timedelta( days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0 )
# Instance Attributes
.total_seconds()
tzinfo # ABC
timezone < tzinfo
# Class Attributes
.utc
UTC -> datetime.timezone.utc # type: datetime.timezone
```
#### time
```python
process_time() # seconds of time consumed by process so far
sleep( seconds )
time() # current POSIX datetime (float)
tzname() # returns tuple: ( non-dst name, dst name )
```
#### zoneinfo
[tz database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)
```python
ZoneInfo < datetime.tzinfo
ZoneInfo( key ) # key is path relative to TZPATH
# ex: "America/Los_Angeles", "America/Chicago", "America/New_York"
key/__str__()
available_timezones() # returns set
TZPATH # Ubuntu: /usr/share/zoneinfo
```
## python-dateutil
```python
from dateutil.relativedelta import relativedelta
# Supports math operations with datetimes:
# - relative values are added or subtracted from current
# - absolute values replace current
# Two construction methods:
d = relativedelta( dt1, dt2 )
d = relativedelta(
years, months, weeks, days, hours, minutes, seconds, microseconds, # relative values
year, month, day, hour, minute, second, microsecond, # absolute values
)
# Example:
d = datetime.now() + relativedelta( days=1, hour=10 ) # tomorrow at 10am
```
Also `dateutil.rrule`, which implements the recurrence rules from [RFC 5545](https://datatracker.ietf.org/doc/html/rfc5545) ([iCalendar](https://icalendar.org/)).
```python
import dateutil.rrule as dr
import dateutil.parser as dp
import dateutil.relativedelta as drel
start = dp.parse( "19/02/2010" ) # 3rd Fri in 2010-Feb
rr = dr.rrule( dr.MONTHLY, byweekday = drel.FR( 3 ), dtstart=start, count=10 ) # 3rd Fri/ea month
print map( str, rr )
-> [ "2010-02-19 00:00:00" ... "2010-11-19 00:00:00" ]
print [ d.strftime( "%d/%m/%Y" ) for d in rr[ ::2 ] ]
-> [ "19/02/2010", "16/04/2010", "18/06/2010", "20/08/2010", "15/10/2010" ]
```