datetime.strftime / strptime
One directive table, two directions: strftime ("format") turns a date into text, strptime ("parse") turns text into a datetime. The C89 directives are portable; flags like %-d depend on your platform.
Demo
from datetime import datetime datetime.fromisoformat('2026-09-05T14:05:09').strftime('%Y-%m-%d %H:%M:%S')
strftime directives this page lists as portable give the same text on every platform. For the rest the demo follows Linux (glibc): there %-d gives "5", while Windows raises ValueError: Invalid format string (Windows spells it %#d); %s is refused because it depends on the local timezone. In the round trip, fields missing from the format come back as defaults — 1900-01-01 for the date, 00:00 for the time.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| format | str | yes | Text with %-directives (table below). Everything else is copied literally; %% is a literal percent sign. |
Return value
str — strftime: the formatted text. (strptime returns a datetime — naive, or aware when the format has %z.)
Attributes
| Attribute | Type | Meaning |
|---|---|---|
| %a / %A | 'Sat' / 'Saturday' | Weekday name, abbreviated / full (locale names; English unless locale.setlocale changed LC_TIME). |
| %w | '6' | Weekday number, 0 = Sunday … 6 = Saturday. |
| %d | '05' | Day of the month, zero-padded. |
| %b / %B | 'Sep' / 'September' | Month name, abbreviated / full (locale). |
| %m | '09' | Month number, zero-padded. |
| %y / %Y | '26' / '2026' | Year without / with century. strptime maps %y 00–68 to 2000–2068 and 69–99 to 1969–1999. |
| %H / %I | '14' / '02' | Hour, 24-hour / 12-hour clock, zero-padded. |
| %p | 'PM' | AM/PM (locale). With strptime it only changes the hour when %I is used, not %H. |
| %M | '05' | Minute, zero-padded. |
| %S | '09' | Second, zero-padded. |
| %f | '250000' | Microsecond, 6 digits. strptime accepts 1 to 6 digits. Handled by Python itself, so it works everywhere. |
| %z | '+0200' | UTC offset; empty for naive objects. strptime also accepts Z, +02:00 and seconds, and returns an aware datetime. |
| %:z | '+02:00' | UTC offset with colons (Python 3.12+, strftime only). |
| %Z | 'UTC+02:00' | tzinfo.tzname(); empty for naive. strptime only accepts UTC, GMT and the local zone names in time.tzname — and the result stays naive. |
| %j | '248' | Day of the year, 001–366. |
| %U / %W | '35' / '35' | Week of the year, weeks starting Sunday / Monday; days before the first one are week 00. |
| %G / %V / %u | '2026' / '36' / '6' | ISO 8601 year, week (01–53) and weekday (1 = Monday). In strptime %G and %V need each other plus a weekday directive. |
| %c / %x / %X | 'Sat Sep 5 14:05:09 2026' / '09/05/26' / '14:05:09' | Locale date+time / date / time. Shown for the C locale; the layout changes with the locale — avoid in data formats. |
| %% | '%' | A literal percent sign. |
| %e %F %T %D %R %C %g | ' 5' '2026-09-05' '14:05:09' … | Accepted by strftime on Linux (glibc) and on Windows (UCRT); not in the C89 set Python documents. strptime rejects them. |
| %-d %-m %-I | '5' '9' '2' | No zero padding — glibc only. Windows raises ValueError: Invalid format string; its own flag is %#d. strptime rejects both. |
| %s | seconds since epoch | glibc only, computed as LOCAL time, ignoring tzinfo. Use dt.timestamp() instead. |
Common patterns
from datetime import datetime label = f"Saved {datetime(2026, 9, 29, 14, 5):%d %b %Y at %H:%M}"
from datetime import datetime def parse_any(text, formats=('%Y-%m-%d', '%d/%m/%Y', '%d %b %Y')): for fmt in formats: try: return datetime.strptime(text, fmt) except ValueError: pass raise ValueError(f'unrecognised date: {text!r}')
from datetime import datetime day = datetime.strptime('29.09.2026', '%d.%m.%Y').date()
label = f"{dt.day} {dt:%B %Y}" # '5 September 2026' on every platform
Examples
Pitfalls
from datetime import datetime datetime(2026, 9, 29, 14, 5).strftime('%Y-%M-%d')
from datetime import datetime datetime(2026, 9, 29, 14, 5).strftime('%Y-%m-%d')
from datetime import datetime datetime.strptime('29/09/2026', '%m/%d/%Y')
from datetime import datetime datetime.strptime('29/09/2026', '%d/%m/%Y')
from datetime import datetime datetime.strptime('29 Feb', '%d %b')
from datetime import datetime datetime.strptime('29 Feb 2028', '%d %b %Y')
from datetime import datetime datetime.strptime('2026-09-29 14:30 UTC', '%Y-%m-%d %H:%M %Z').tzinfo is None
from datetime import datetime datetime.strptime('2026-09-29 14:30 +0000', '%Y-%m-%d %H:%M %z').tzinfo
When to use
- Human-readable output: reports, UI labels, file names
- Parsing a known, fixed input layout (CSV exports, log lines)
- ISO 8601 text → isoformat() / fromisoformat(): faster, exact, offset-aware
- Locale-sensitive display for many languages → babel or the platform formatter
- Guessing unknown formats → dateutil.parser (third-party)
Notes
FAQ
strftime = "string format time": an object method that turns a date, time or datetime into text. strptime = "string parse time": a datetime class method that turns text into a datetime. Both use the same %-directives, so the format that wrote a string can read it back.