2.2. Datetime Parsing and Formatting

2.2.2. Date format in USA

Formal date format in USA []:

4/12/61
April 12, 1961

2.2.3. Date format in Japan

Formal date format in Japan []:

20/12/31

2.2.4. Date format in Germany

Formal date format in Germany:

12.04.1961

2.2.5. Date format in Poland

12.4.1961
12.04.1961

12 IV 1961
12.IV.1961

12/4/1961
12/04/1961

12 kwietnia 1961
12 kwiecień 1961

2.2.6. Time formats

2.2.7. 24 and 12 hour clock

  • What AM stands for?

  • What PM stands for?

17:00
5:00 PM

2.2.8. Noon and Midnight

  • Which time is a midnight?

  • Which time is a noon?

  • Confusion at noon and midnight

  • Is 12:00 a noon (in 24h format), or someone just simply forgot to put AM/PM?

12:00 am
12:00 pm

12:00
24:00

00:00
0:00

2.2.9. Times after 24:00

23:59:59
23:59:60
24:00
24:01
25:00
27:45
14:00-30:00

2.2.10. Military time

1200J
1200Z

2.2.11. ISO 8601 Standard

2.2.12. Dates

1961-04-12

2.2.13. Date and time

  • "Z" (Zulu) means UTC

  • "T" separates date and time

Date and time:

1961-04-12T06:07:00Z
1961-04-12T06:07:00.123Z
1961-04-12T06:07:00.123456Z

2.2.14. Noon and Midnight

  • "00:00" - midnight, at the beginning of a day

  • "24:00" - midnight, at the end of a day (not recommended)

  • "2007-04-05T24:00" is equal to "2007-04-06T00:00"

2.2.15. Weeks

Note year/month changes during the week:

2009-W01            # First week of 2009
2009-W01-1          # Monday 29 December 2008
2009-W53-7          # Sunday 3 January 2010

2.2.16. Timezone

  • "Z" (Zulu) means UTC

Time zone notation:

<time>UTC
<time>Z
<time>±hh:mm
<time>±hhmm
<time>±hh

2.2.17. Duration

  • Format: P[n]Y[n]M[n]DT[n]H[n]M[n]S

Table 2.1. Duration format

Format

Designator

Description

P

duration (period)

placed at the start of the duration representation

Y

year

number of years

M

month

number of months

W

week

number of weeks

D

day

number of days

T

time

precedes the time components of the representation

H

hour

number of hours

M

minute

number of minutes

S

second

number of seconds

Example:

P8Y3M8DT20H49M15S

Period of:

  • 8 years

  • 3 months

  • 8 days

  • 20 hours

  • 49 minutes

  • 15 seconds

2.2.18. Date and time parsing and formatting parameters

Almost any programming language has very similar date formatting parameters. There are only some minor differences like in JavaScript minutes are i, not M.

Table 2.2. Date and time parsing and formatting parameters

Directive

Example

Meaning

%a

Sun, Mon, …, Sat

Weekday as locale's abbreviated name

%A

Sunday, Monday, …, Saturday (en_US)

Weekday as locale's full name

%w

0, 1, …, 6

Weekday as a decimal number, where 0 is Sunday and 6 is Saturday

%d

01, 02, …, 31

Day of the month as a zero-padded decimal number

%b

Jan, Feb, …, Dec (en_US)

Month as locale's abbreviated name

%B

January, February, …, December (en_US)

Month as locale’s full name

%m

01, 02, …, 12

Month as a zero-padded decimal number

%y

00, 01, …, 99

Year without century as a zero-padded decimal number

%Y

0001, 0002, …, 2013, 2014, …, 9998, 9999

Year with century as a decimal number

%H

00, 01, …, 23

Hour (24-hour clock) as a zero-padded decimal number

%I

01, 02, …, 12

Hour (12-hour clock) as a zero-padded decimal number

%p

AM, PM (en_US)

Locale’s equivalent of either AM or PM

%M

00, 01, …, 59

Minute as a zero-padded decimal number

%S

00, 01, …, 59

Second as a zero-padded decimal number

%f

000000, 000001, …, 999999

Microsecond as a decimal number, zero-padded on the left

%z

(empty), +0000, -0400, +1030

UTC offset in the form +HHMM or -HHMM (empty string if the object is naive)

%Z

(empty), UTC, EST, CST

Time zone name (empty string if the object is naive)

%j

001, 002, …, 366

Day of the year as a zero-padded decimal number

%U

00, 01, …, 53

Week number of the year (Sunday as the first day of the week) as a zero padded decimal number. All days in a new year preceding the first Sunday are considered to be in week 0

%W

00, 01, …, 53

Week number of the year (Monday as the first day of the week) as a decimal number. All days in a new year preceding the first Monday are considered to be in week 0

%c

Tue Aug 16 21:30:00 1988 (en_US)

Locale’s appropriate date and time representation

%x

08/16/1988 (en_US); 16.08.1988 (de_DE)

Locale’s appropriate date representation

%X

21:30:00

Locale’s appropriate time representation

%%

%

A literal % character

%G

0001, 0002, …, 2013, 2014, …, 9998, 9999

ISO 8601 year with century representing the year that contains the greater part of the ISO week (%V)

%u

1, 2, …, 7

ISO 8601 weekday as a decimal number where 1 is Monday

%V

01, 02, …, 53

ISO 8601 week as a decimal number with Monday as the first day of the week. Week 01 is the week containing Jan 4

Todo

Convert table into smaller parts, based on categories: months, day, hour etc.

2.2.19. Date formatting

2.2.20. ISO Format

Datetime formatting to ISO format:

from datetime import datetime

dt = datetime(1969, 7, 21, 2, 56, 15)

dt.isoformat()
# 1969-07-21T02:56:15

Date formatting to ISO format:

from datetime import date

d = date(1969, 7, 21)

d.isoformat()
# 1969-07-21

2.2.21. f-string formatting

Datetime formatting as string with f'...':

from datetime import datetime

gagarin = datetime(1961, 4, 12, 6, 7)

print(f'Gagarin launched on {gagarin:%Y-%m-%d}')
# Gagarin launched on 1961-04-12

Datetime formatting as string with f'...':

from datetime import datetime

gagarin = datetime(1961, 4, 12, 6, 7)

print(f'Gagarin launched on {gagarin:%Y-%m-%d %H:%M}')
# Gagarin launched on 1961-04-12 06:07

Datetime formatting as string with f'...':

from datetime import datetime

gagarin = datetime(1961, 4, 12, 6, 7)
format = '%Y-%m-%d %H:%M'

print(f'Gagarin launched on {gagarin:{format}}')
# Gagarin launched on 1961-04-12 06:07

2.2.22. Format to string

Datetime formatting as string with .strftime():

from datetime import datetime

gagarin = datetime(1961, 4, 12, 6, 7)
formatted = gagarin.strftime('%Y-%m-%d %H:%M')

print(f'Gagarin launched on {formatted}')
# Gagarin launched on 1961-04-12 06:07

2.2.23. Parsing dates

  • Parsing - analyze (a sentence) into its parts and describe their syntactic roles.

Datetime parsing from string:

from datetime import datetime

sputnik = '4 October 1957, 19:28:34 [UTC]'

result = datetime.strptime(sputnik, '%d %B %Y, %H:%M:%S [%Z]')
# datetime.datetime(1957, 10, 4, 19, 28, 34)

print(result)
# 1957-10-04 19:28:34

2.2.24. Examples

from datetime import datetime


log = '1969-07-21T02:56:15.123 [WARNING] First step on the Moon'

date, level, message = log.split(maxsplit=2)
format = '%Y-%m-%dT%H:%M:%S.%f'
date = datetime.strptime(date, format)

print(date)
# 1969-07-21 02:56:15.123000

print(level)
# [WARNING]

print(message)
# First step on the Moon

2.2.25. Assignments

Code 2.3. Solution
"""
* Assignment: Datetime Parse ISO
* Complexity: easy
* Lines of code: 1 lines
* Time: 3 min

English:
    1. Use data from "Given" section (see below)
    2. The date and time is given in ISO format:
    3. Convert it to `datetime` object

Polish:
    1. Użyj danych z sekcji "Given" (patrz poniżej)
    2. Dana jest data w formacie ISO
    3. Przedstaw datę jako obiekt `datetime`

Tests:
    >>> type(result)
    <class 'datetime.datetime'>
    >>> result
    datetime.datetime(1969, 7, 21, 2, 56, 15, 123000)
"""


# Given
from datetime import datetime

DATA = '1969-07-21T02:56:15.123Z'


Code 2.4. Solution
"""
* Assignment: Datetime Parse Local
* Complexity: easy
* Lines of code: 3 lines
* Time: 3 min

English:
    1. Use data from "Given" section (see below)
    2. Create `datetime` object by parsing the given date
    3. Using formatting parameters print the date and time in ISO format
    4. Compare result with "Tests" section (see below)

Polish:
    1. Użyj danych z sekcji "Given" (patrz poniżej)
    2. Podaną datę przekonwertuj do obiektu `datetime`
    3. Używając parametrów formatujących wyświetl datę i czas w formacie ISO
    4. Porównaj wyniki z sekcją "Tests" (patrz poniżej)

Hints:
    * Add string `local time` to format statement

Tests:
    >>> type(result)
    <class 'str'>
    >>> result
    '1961-04-12T06:07:00.000000Z'
"""


# Given
from datetime import datetime


DATA = 'April 12, 1961 6:07 local time'


Code 2.5. Solution
"""
* Assignment: Datetime Parse US
* Complexity: easy
* Lines of code: 5 lines
* Time: 3 min

English:
    1. Use data from "Given" section (see below)
    3. Create `datetime` object by parsing `DATA`
    4. Using date formatting converts `DATA` to string and assign to `result`
       in american short date format (np. '07/21/69 2:56 AM')
    5. Make sure, that hour is without leading zero
    6. Compare result with "Tests" section (see below)

Polish:
    1. Użyj danych z sekcji "Given" (patrz poniżej)
    3. Stwórz obiekt `datetime` parsując `DATA`
    4. Używając parametrów formatowania daty przekonwertuj `DATA` do stringa
       i zapisz do `result` w formacie amerykańskim krótkim (np. '07/21/69 2:56 AM')
    5. Upewnij się, że godzina jest bez wiodącego zera
    6. Porównaj wyniki z sekcją "Tests" (patrz poniżej)

Hints:
    * Add quote sign `"` like normal text to `fmt` parameter of `.strptime()`
    * `%dst`
    * Use `%-I` or `%_I` on \*nix systems (macOS, BSD, Linux) to remove leading zero
    * Use `%#I` on Windows to remove leading zero

Tests:
    >>> type(result)
    <class 'str'>
    >>> result
    '07/21/69 2:56 AM'
"""


# Given
from datetime import datetime


DATA = '"July 21st, 1969 2:56:15 AM UTC"'
result = ''


Code 2.6. Solution
"""
* Assignment: Datetime Parse Logs
* Complexity: medium
* Lines of code: 15 lines
* Time: 13 min

English:
    1. Use data from "Given" section (see below)
    2. Save input data to file `apollo11-timeline.log`
    3. Extract `datetime` object, level name and message from each line
    4. Collect data to `result: list[dict]`
    6. Compare result with "Tests" section (see below)

Polish:
    1. Użyj danych z sekcji "Given" (patrz poniżej)
    2. Zapisz dane wejściowe do pliku `apollo11-timeline.log`
    3. Wyciągnij obiekt `datetime`, poziom logowania oraz wiadomość z każdej linii
    4. Zbierz dane do `result: list[dict]`
    6. Porównaj wyniki z sekcją "Tests" (patrz poniżej)

References:
    * Apollo 11 timeline https://history.nasa.gov/SP-4029/Apollo_11i_Timeline.htm

Hints:
    * `str.splitlines()`
    * `str.split(maxsplit)`
    * ` try ... except ValueError: ...`

Tests:
    >>> result  # doctest: +NORMALIZE_WHITESPACE
    [{'date': datetime.datetime(1969, 7, 14, 21, 0), 'level': 'INFO', 'message': 'Terminal countdown started'},
     {'date': datetime.datetime(1969, 7, 16, 13, 31, 53), 'level': 'WARNING', 'message': 'S-IC engine ignition (#5)'},
     {'date': datetime.datetime(1969, 7, 16, 13, 33, 23), 'level': 'DEBUG', 'message': 'Maximum dynamic pressure (735.17 lb/ft^2)'},
     {'date': datetime.datetime(1969, 7, 16, 13, 34, 44), 'level': 'WARNING', 'message': 'S-II ignition'},
     {'date': datetime.datetime(1969, 7, 16, 13, 35, 17), 'level': 'DEBUG', 'message': 'Launch escape tower jettisoned'},
     {'date': datetime.datetime(1969, 7, 16, 13, 39, 40), 'level': 'DEBUG', 'message': 'S-II center engine cutoff'},
     {'date': datetime.datetime(1969, 7, 16, 16, 22, 13), 'level': 'INFO', 'message': 'Translunar injection'},
     {'date': datetime.datetime(1969, 7, 16, 16, 56, 3), 'level': 'INFO', 'message': 'CSM docked with LM/S-IVB'},
     {'date': datetime.datetime(1969, 7, 16, 17, 21, 50), 'level': 'INFO', 'message': 'Lunar orbit insertion ignition'},
     {'date': datetime.datetime(1969, 7, 16, 21, 43, 36), 'level': 'INFO', 'message': 'Lunar orbit circularization ignition'},
     {'date': datetime.datetime(1969, 7, 20, 17, 44), 'level': 'INFO', 'message': 'CSM/LM undocked'},
     {'date': datetime.datetime(1969, 7, 20, 20, 5, 5), 'level': 'WARNING', 'message': 'LM powered descent engine ignition'},
     {'date': datetime.datetime(1969, 7, 20, 20, 10, 22), 'level': 'ERROR', 'message': 'LM 1202 alarm'},
     {'date': datetime.datetime(1969, 7, 20, 20, 14, 18), 'level': 'ERROR', 'message': 'LM 1201 alarm'},
     {'date': datetime.datetime(1969, 7, 20, 20, 17, 39), 'level': 'WARNING', 'message': 'LM lunar landing'},
     {'date': datetime.datetime(1969, 7, 21, 2, 39, 33), 'level': 'DEBUG', 'message': 'EVA started (hatch open)'},
     {'date': datetime.datetime(1969, 7, 21, 2, 56, 15), 'level': 'WARNING', 'message': '1st step taken lunar surface (CDR)'},
     {'date': datetime.datetime(1969, 7, 21, 2, 56, 15), 'level': 'WARNING', 'message': "That's one small step for [a] man... one giant leap for mankind"},
     {'date': datetime.datetime(1969, 7, 21, 3, 5, 58), 'level': 'DEBUG', 'message': 'Contingency sample collection started (CDR)'},
     {'date': datetime.datetime(1969, 7, 21, 3, 15, 16), 'level': 'INFO', 'message': 'LMP on lunar surface'},
     {'date': datetime.datetime(1969, 7, 21, 5, 11, 13), 'level': 'DEBUG', 'message': 'EVA ended (hatch closed)'},
     {'date': datetime.datetime(1969, 7, 21, 17, 54), 'level': 'WARNING', 'message': 'LM lunar liftoff ignition (LM APS)'},
     {'date': datetime.datetime(1969, 7, 21, 21, 35), 'level': 'INFO', 'message': 'CSM/LM docked'},
     {'date': datetime.datetime(1969, 7, 22, 4, 55, 42), 'level': 'WARNING', 'message': 'Transearth injection ignition (SPS)'},
     {'date': datetime.datetime(1969, 7, 24, 16, 21, 12), 'level': 'INFO', 'message': 'CM/SM separation'},
     {'date': datetime.datetime(1969, 7, 24, 16, 35, 5), 'level': 'WARNING', 'message': 'Entry'},
     {'date': datetime.datetime(1969, 7, 24, 16, 50, 35), 'level': 'WARNING', 'message': 'Splashdown (went to apex-down)'},
     {'date': datetime.datetime(1969, 7, 24, 17, 29), 'level': 'INFO', 'message': 'Crew egress'}]
"""


# Given
from datetime import datetime


DATA = """1969-07-14, 21:00:00, INFO, Terminal countdown started
1969-07-16, 13:31:53, WARNING, S-IC engine ignition (#5)
1969-07-16, 13:33:23, DEBUG, Maximum dynamic pressure (735.17 lb/ft^2)
1969-07-16, 13:34:44, WARNING, S-II ignition
1969-07-16, 13:35:17, DEBUG, Launch escape tower jettisoned
1969-07-16, 13:39:40, DEBUG, S-II center engine cutoff
1969-07-16, 16:22:13, INFO, Translunar injection
1969-07-16, 16:56:03, INFO, CSM docked with LM/S-IVB
1969-07-16, 17:21:50, INFO, Lunar orbit insertion ignition
1969-07-16, 21:43:36, INFO, Lunar orbit circularization ignition
1969-07-20, 17:44:00, INFO, CSM/LM undocked
1969-07-20, 20:05:05, WARNING, LM powered descent engine ignition
1969-07-20, 20:10:22, ERROR, LM 1202 alarm
1969-07-20, 20:14:18, ERROR, LM 1201 alarm
1969-07-20, 20:17:39, WARNING, LM lunar landing
1969-07-21, 02:39:33, DEBUG, EVA started (hatch open)
1969-07-21, 02:56:15, WARNING, 1st step taken lunar surface (CDR)
1969-07-21, 02:56:15, WARNING, That's one small step for [a] man... one giant leap for mankind
1969-07-21, 03:05:58, DEBUG, Contingency sample collection started (CDR)
1969-07-21, 03:15:16, INFO, LMP on lunar surface
1969-07-21, 05:11:13, DEBUG, EVA ended (hatch closed)
1969-07-21, 17:54:00, WARNING, LM lunar liftoff ignition (LM APS)
1969-07-21, 21:35:00, INFO, CSM/LM docked
1969-07-22, 04:55:42, WARNING, Transearth injection ignition (SPS)
1969-07-24, 16:21:12, INFO, CM/SM separation
1969-07-24, 16:35:05, WARNING, Entry
1969-07-24, 16:50:35, WARNING, Splashdown (went to apex-down)
1969-07-24, 17:29, INFO, Crew egress"""

result: list