ZetCode

Python datetime Formatting with f-strings

last modified May 11, 2025

This tutorial explores formatting datetime objects using Python's f-strings, a concise and readable approach introduced in Python 3.6. F-strings simplify date and time formatting while offering advantages over legacy methods.

Effectively formatting date and time information is crucial in many applications, from generating human-readable timestamps in logs and reports to preparing date strings for APIs and databases. Python's built-in datetime module provides a comprehensive set of tools for date and time manipulation, including classes for representing dates, times, and time intervals.

While older methods like strftime() have long been used for datetime formatting, f-strings (formatted string literals) offer a more modern, intuitive, and often more performant way to achieve the same results. F-strings allow embedding expressions inside string literals by prefixing the string with an 'f' and placing expressions in curly braces {}. When an expression is a datetime object, you can include a format specifier after a colon to control its string representation. This makes the code cleaner and easier to understand at a glance.

Throughout this tutorial, we will delve into various aspects of datetime formatting using f-strings. We will cover common formatting codes, how to extract and display specific components of a datetime object (like year, month, day, hour, minute), and how to handle more advanced scenarios such as locale-specific formatting and timezone conversions. All examples leverage the power and flexibility of the datetime module combined with the syntactic sugar of f-strings.

We'll cover essential datetime formatting techniques with f-strings, including custom formats, localization, and timezone management. All examples utilize Python's built-in datetime module, which provides robust tools for handling and manipulating date and time data.

Datetime Format Specifiers in Python

Python's strftime and f-string formatting provide a flexible way to represent date and time values. Format specifiers define how datetime objects are displayed, making it easy to adjust output for different applications, locales, and readability preferences.

The table below lists common format specifiers supported by Python's datetime module:

SpecifierDescriptionExample
%YYear with century (0000-9999)2025
%yYear without century (zero-padded, 00-99)25
%mMonth as zero-padded decimal (01-12)02
%BFull month name (locale-dependent)February
%bAbbreviated month name (locale-dependent)Feb
%dDay of the month (zero-padded, 01-31)09
%AFull weekday name (locale-dependent)Monday
%aAbbreviated weekday name (locale-dependent)Mon
%wWeekday as decimal (0-6, Sunday=0)1
%uISO 8601 weekday (1-7, Monday=1)2
%HHour (24-hour format, zero-padded, 00-23)14
%IHour (12-hour format, zero-padded, 01-12)02
%pAM/PM marker (locale-dependent)PM
%MMinute (zero-padded, 00-59)05
%SSecond (zero-padded, 00-59)07
%fMicrosecond (zero-padded, 000000-999999)123456
%zUTC offset in ±HHMM[SS[.ffffff]] format (empty if naive)+0100
%ZTime zone name (empty if naive)CET
%jDay of the year (zero-padded, 001-366)040
%UWeek number (Sunday as start of week, 00-53)06
%WWeek number (Monday as start of week, 00-53)06
%VISO 8601 week number (01-53)07
%GISO 8601 week-based year (0000-9999)2025
%cLocale's full date and time representationTue Feb 15 14:30:45 2025
%xLocale's date format02/15/25
%XLocale's time format14:30:45
%%Literal % character%

Using these format specifiers, you can customize datetime output for various use cases, such as logging, reporting, and localization. Python's f-strings provide a convenient way to apply these specifiers dynamically within formatted strings.

Basic datetime formatting with f-strings

The simplest way to format a datetime object with f-strings is to use the default string representation. This shows the date and time in ISO format. The example below demonstrates basic formatting.

main.py
from datetime import datetime

now = datetime.now()
print(f"Current datetime: {now}")
print(f"Date only: {now:%Y-%m-%d}")
print(f"Time only: {now:%H:%M:%S}")

This code shows three different f-string formats. The first uses the default string representation. The second formats just the date portion. The third formats only the time portion. The format specifiers after the colon define the output format.

$ python main.py
Current datetime: 2025-02-15 14:30:45.123456
Date only: 2025-02-15
Time only: 14:30:45

Custom date formats with f-strings

F-strings allow complete control over datetime formatting. You can combine any valid format codes to create custom date and time displays. The example shows several common formatting options.

main.py
from datetime import datetime

now = datetime.now()
print(f"Full month name: {now:%B %d, %Y}")
print(f"Short month name: {now:%b %d, %Y}")
print(f"Weekday name: {now:%A, %B %d}")
print(f"12-hour clock: {now:%I:%M %p}")

This example demonstrates different date and time formatting options. %B shows the full month name, %b the abbreviated month name. %A displays the full weekday name. %I formats hours in 12-hour clock with %p for AM/PM.

$ python main.py
Full month name: February 15, 2025
Short month name: Feb 15, 2025
Weekday name: Saturday, February 15
12-hour clock: 02:30 PM

Formatting datetime components individually

You can access individual components of a datetime object directly in f-strings. This provides flexibility when you need to combine date parts with other text. The example shows how to format components separately.

main.py
from datetime import datetime

now = datetime.now()
print(f"Today is {now.year}/{now.month:02d}/{now.day:02d}")
print(f"The time is {now.hour:02d}:{now.minute:02d}:{now.second:02d}")
print(f"Day of year: {now.timetuple().tm_yday}")
print(f"Week number: {now.isocalendar().week}")

This code accesses year, month, and day attributes directly. The :02d format ensures two-digit formatting with leading zeros. We also show the day of year and week number using additional datetime methods.

$ python main.py
Today is 2025/02/15
The time is 14:30:45
Day of year: 46
Week number: 7

Combining datetime with other variables

F-strings make it easy to combine datetime formatting with other variables. You can mix date formatting with string text and other variable values. This example shows several combinations.

main.py
from datetime import datetime

now = datetime.now()
user = "John"
items = 3
total = 45.50

print(f"Receipt for {user} on {now:%Y-%m-%d %H:%M}")
print(f"Order #{12345:06d} - {now:%A %B %d}")
print(f"{items} items purchased for ${total:.2f} at {now:%I:%M %p}")

This example combines datetime formatting with string variables, integers, and floats. The f-string automatically converts all values to strings. Number formatting (:06d for zero-padded int, :.2f for currency) works alongside datetime formatting.

$ python main.py
Receipt for John on 2025-02-15 14:30
Order #012345 - Saturday February 15
3 items purchased for $45.50 at 02:30 PM

Formatting timedelta objects

Timedelta objects represent durations and can also be formatted with f-strings. This is useful for displaying time differences or elapsed time. The example shows several formatting options.

main.py
from datetime import datetime, timedelta

start = datetime(2025, 2, 15, 9, 0)
end = datetime.now()
duration = end - start

print(f"Elapsed time: {duration}")
print(f"Hours: {duration.total_seconds()/3600:.1f}")
print(f"Working time: {duration.seconds//3600}h {(duration.seconds%3600)//60}m")
print(f"Days: {duration.days}, Seconds: {duration.seconds}")

This code calculates the duration between two datetime objects. We show the raw timedelta, total hours, formatted hours and minutes, and access to individual components. Note the difference between total_seconds() and seconds attribute.

$ python main.py
Elapsed time: 5:30:45.123456
Hours: 5.5
Working time: 5h 30m
Days: 0, Seconds: 19845

Locale-aware datetime formatting

For international applications, you may need locale-specific formatting. While f-strings don't directly support locales, you can combine them with strftime. This example shows locale-aware formatting.

main.py
from datetime import datetime
import locale

now = datetime.now()

# Set to German locale
locale.setlocale(locale.LC_TIME, 'de_DE')
print(f"German format: {now:%A, %d. %B %Y}")

# Set to French locale
locale.setlocale(locale.LC_TIME, 'fr_FR')
print(f"French format: {now:%A %d %B %Y}")

# Reset to default
locale.setlocale(locale.LC_TIME, '')
print(f"Local format: {now:%x %X}")

This example demonstrates locale-specific date formatting. The locale module changes how month and day names appear. %x and %X are locale- specific date and time formats. Note that locale availability depends on the system.

$ python main.py
German format: Samstag, 15. Februar 2025
French format: samedi 15 février 2025
Local format: 02/15/2025 02:30:45 PM

Timezone-aware datetime formatting

When working with timezones, f-strings can format aware datetime objects. This example uses the zoneinfo module (Python 3.9+) for timezone handling.

main.py
from datetime import datetime
from zoneinfo import ZoneInfo

utc_time = datetime.now(ZoneInfo('UTC'))
ny_time = utc_time.astimezone(ZoneInfo('America/New_York'))
tokyo_time = utc_time.astimezone(ZoneInfo('Asia/Tokyo'))

print(f"UTC: {utc_time:%Y-%m-%d %H:%M %Z}")
print(f"New York: {ny_time:%Y-%m-%d %I:%M %p %Z}")
print(f"Tokyo: {tokyo_time:%Y年%m月%d日 %H時%M分}")

This code shows the same moment in time in three different timezones. Each f-string includes the timezone abbreviation (%Z). The Tokyo format demonstrates using f-strings with non-ASCII characters in format specs.

$ python main.py
UTC: 2025-02-15 14:30 UTC
New York: 2025-02-15 09:30 AM EST
Tokyo: 2025年02月15日 23時30分

Formatting datetime in logging messages

F-strings are particularly useful for including timestamps in log messages. This example shows how to create formatted log entries with datetime.

main.py
from datetime import datetime

def log_message(level, message):
    now = datetime.now()
    print(f"[{now:%Y-%m-%d %H:%M:%S.%f}] [{level.upper():<7}] {message}")

log_message("info", "System started")
log_message("warning", "Low disk space")
log_message("error", "Connection failed")

This logging function uses f-strings to format consistent log messages. The timestamp includes microseconds (%f). The log level is left-aligned and padded to 7 characters. This creates neatly aligned log output.

$ python main.py
[2025-02-15 14:30:45.123456] [INFO   ] System started
[2025-02-15 14:30:45.123456] [WARNING] Low disk space
[2025-02-15 14:30:45.123456] [ERROR  ] Connection failed

Advanced datetime formatting with conditionals

F-strings can include conditional expressions for dynamic formatting. This example shows how to change the format based on datetime values.

main.py
from datetime import datetime, time

now = datetime.now()
current_time = now.time()

greeting = (
    f"Good {'morning' if time(5,0) <= current_time < time(12,0) else 'afternoon' "
    f"if time(12,0) <= current_time < time(18,0) else 'evening'}"
)

print(f"{greeting}! It's {now:%A, %B %d}")
print(f"{'🌞' if current_time.hour < 18 else '🌜'} {now:%I:%M %p}")

This code determines the appropriate greeting based on the time of day. It uses nested conditional expressions within the f-string. The second line shows an emoji based on whether it's daytime or evening.

$ python main.py
Good afternoon! It's Saturday, February 15
🌞 02:30 PM

Formatting datetime in data structures

F-strings work well when formatting datetime objects in lists or dictionaries. This example shows formatting multiple dates in a loop.

main.py
from datetime import datetime, timedelta

today = datetime.now()
dates = [today + timedelta(days=i) for i in range(-2, 3)]

print("Upcoming dates:")
for date in dates:
    print(f"- {date:%a %b %d}: {'Past' if date < today else 'Today' if date == today else 'Future'}")

events = {
    "Meeting": today.replace(hour=14, minute=0),
    "Deadline": today + timedelta(days=2),
    "Reminder": today.replace(hour=9, minute=0) + timedelta(days=1)
}

print("\nEvents:")
for name, when in events.items():
    print(f"{name:<10} {when:%Y-%m-%d %I:%M %p} ({'Today' if when.date() == today.date() else when.strftime('%A')})")

This example demonstrates datetime formatting in loops and dictionaries. The first part shows relative date descriptions. The second part formats events with different datetime formats based on whether they're today.

$ python main.py
Upcoming dates:
- Thu Feb 13: Past
- Fri Feb 14: Past
- Sat Feb 15: Today
- Sun Feb 16: Future
- Mon Feb 17: Future

Events:
Meeting    2025-02-15 02:00 PM (Today)
Deadline   2025-02-17 02:30 PM (Monday)
Reminder   2025-02-16 09:00 AM (Sunday)

Parsing date strings and formatting

Often, you receive dates as strings and need to convert them into datetime objects before you can format them. Python's datetime.strptime() method is used for this parsing. Once parsed, you can format the datetime object using f-strings.

main.py
from datetime import datetime

date_string = "2024-07-26 10:30:00"
dt_object = datetime.strptime(date_string, "%Y-%m-%d %H:%M:%S")

print(f"Parsed datetime: {dt_object}")
print(f"Formatted date: {dt_object:%A, %B %d, %Y}")
print(f"Formatted time: {dt_object:%I:%M %p}")

another_date_string = "15/Mar/2023"
dt_object_date_only = datetime.strptime(another_date_string, "%d/%b/%Y").date()
print(f"Parsed date object: {dt_object_date_only}")
print(f"Formatted: {dt_object_date_only:%d %B, %Y}")

The first example parses a full datetime string, and the second parses a string into a date object. strptime requires a format string that matches the input string's structure.

$ python main.py
Parsed datetime: 2024-07-26 10:30:00
Formatted date: Friday, July 26, 2024
Formatted time: 10:30 AM
Parsed date object: 2023-03-15
Formatted: 15 March, 2023

Formatting date and time objects

The datetime module also provides separate date and time objects. These can be created and formatted independently if you only need to work with dates or times. F-strings handle these objects just as well.

main.py
from datetime import date, time

today_date = date(2025, 8, 15)
specific_time = time(16, 45, 30)

print(f"Date: {today_date:%A, %d %B %Y}")
print(f"ISO Date: {today_date:%Y-%m-%d}")

print(f"Time: {specific_time:%I:%M:%S %p}")
print(f"24-hour Time: {specific_time:%H.%M}")

This example shows creating specific date and time objects and formatting them using various f-string directives.

$ python main.py
Date: Friday, 15 August 2025
ISO Date: 2025-08-15
Time: 04:45:30 PM
24-hour Time: 16.45

Working with Unix timestamps

Unix timestamps (seconds since the epoch, January 1, 1970, UTC) are a common way to represent time. Python's datetime module can convert timestamps to datetime objects and vice versa. These datetime objects can then be formatted using f-strings.

main.py
from datetime import datetime

timestamp = 1678886400  # Represents 2023-03-15 12:00:00 UTC

# Convert timestamp to datetime object (UTC)
dt_object_utc = datetime.utcfromtimestamp(timestamp)
# For local time, use fromtimestamp()
dt_object_local = datetime.fromtimestamp(timestamp)


print(f"UTC from timestamp: {dt_object_utc:%Y-%m-%d %H:%M:%S %Z}")
print(f"Local from timestamp: {dt_object_local:%Y-%m-%d %H:%M:%S %Z%z}") # %Z%z for timezone info

# Convert datetime object back to timestamp
now = datetime.now()
current_timestamp = now.timestamp()
print(f"Current datetime: {now:%Y-%m-%d %H:%M:%S}")
print(f"Current timestamp: {current_timestamp}")

This code demonstrates converting a Unix timestamp to a datetime object (both UTC and local time) and then formatting it. It also shows converting a current datetime object back to a timestamp. Note that %Z might be empty for naive objects on some systems; using timezone-aware objects is better for full timezone name display.

$ python main.py
UTC from timestamp: 2023-03-15 12:00:00 UTC
Local from timestamp: 2023-03-15 13:00:00 CET+0100 
Current datetime: 2025-02-15 14:30:45 
Current timestamp: 1739629845.123456

Source

Python datetime - Documentation

This tutorial has shown various ways to format datetime objects using Python's f-strings. F-strings provide a clean, readable syntax for datetime formatting that's often more intuitive than traditional methods.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Python tutorials.