Python
logging
time format
customization
programming

How to Customize the time format for Python logging?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Python logging timestamps come from the formatter, not from the logger itself. To customize the time format, include %(asctime)s in the log format and pass a datefmt string, or override the formatter's time conversion behavior if you need something more specialized.

Basic datefmt Usage

The standard way to control the timestamp is logging.Formatter.

python
1import logging
2
3logger = logging.getLogger("demo")
4logger.setLevel(logging.INFO)
5
6handler = logging.StreamHandler()
7formatter = logging.Formatter(
8    fmt="%(asctime)s | %(levelname)s | %(message)s",
9    datefmt="%Y/%m/%d %H:%M:%S",
10)
11handler.setFormatter(formatter)
12logger.addHandler(handler)
13
14logger.info("Application started")

The datefmt argument uses strftime directives. That lets you switch between formats such as:

  • '%Y-%m-%d %H:%M:%S'
  • '%d/%m/%Y %I:%M:%S %p'
  • '%H:%M:%S'

If %(asctime)s is not present in the format string, the customized time format will not appear.

Customizing basicConfig

If your application uses logging.basicConfig, you can still provide the same parameters directly there.

python
1import logging
2
3logging.basicConfig(
4    level=logging.INFO,
5    format="%(asctime)s %(name)s %(levelname)s %(message)s",
6    datefmt="%Y-%m-%dT%H:%M:%S",
7)
8
9logging.info("Using basicConfig")

This is the quickest approach for scripts and small applications.

Including Milliseconds

A common requirement is to keep milliseconds in the output. The default formatter uses a comma-separated millisecond suffix, but you can format it more explicitly.

python
1import logging
2
3formatter = logging.Formatter(
4    fmt="%(asctime)s.%(msecs)03d %(levelname)s %(message)s",
5    datefmt="%Y-%m-%d %H:%M:%S",
6)

This produces a timestamp shaped like 2026-03-07 14:05:09.123.

Using UTC Instead of Local Time

By default, logging formats timestamps in local time. If you want UTC, set the formatter's converter to time.gmtime.

python
1import logging
2import time
3
4formatter = logging.Formatter(
5    fmt="%(asctime)sZ %(levelname)s %(message)s",
6    datefmt="%Y-%m-%dT%H:%M:%S",
7)
8formatter.converter = time.gmtime

This is useful for logs that are aggregated across servers in different time zones.

dictConfig and Application-Wide Formatting

Larger applications often configure logging with logging.config.dictConfig instead of building handlers inline. The same timestamp controls still apply there.

python
1import logging.config
2
3logging.config.dictConfig({
4    "version": 1,
5    "formatters": {
6        "standard": {
7            "format": "%(asctime)s %(levelname)s %(name)s %(message)s",
8            "datefmt": "%Y-%m-%d %H:%M:%S",
9        }
10    },
11    "handlers": {
12        "console": {
13            "class": "logging.StreamHandler",
14            "formatter": "standard",
15        }
16    },
17    "root": {
18        "level": "INFO",
19        "handlers": ["console"],
20    },
21})

This is the cleanest way to keep a consistent timestamp format across modules, worker processes, or framework components.

Full Control With a Custom Formatter

If datefmt is not enough, override formatTime. That lets you generate ISO 8601 strings, timezone-aware values, or any other custom representation.

python
1import logging
2from datetime import datetime, timezone
3
4class IsoUtcFormatter(logging.Formatter):
5    def formatTime(self, record, datefmt=None):
6        dt = datetime.fromtimestamp(record.created, tz=timezone.utc)
7        return dt.isoformat(timespec="milliseconds")
8
9
10handler = logging.StreamHandler()
11handler.setFormatter(IsoUtcFormatter("%(asctime)s %(levelname)s %(message)s"))
12
13logger = logging.getLogger("iso")
14logger.setLevel(logging.INFO)
15logger.addHandler(handler)
16
17logger.info("Structured timestamp")

This approach is ideal when you want a precise API-friendly format and do not want to depend on strftime limitations.

Watch Out for Multiple Handlers

Each handler has its own formatter. If your console logs and file logs need different timestamp formats, configure them separately.

python
1console = logging.StreamHandler()
2console.setFormatter(logging.Formatter("%(asctime)s %(message)s", "%H:%M:%S"))
3
4file_handler = logging.FileHandler("app.log")
5file_handler.setFormatter(logging.Formatter(
6    "%(asctime)s %(levelname)s %(message)s",
7    "%Y-%m-%d %H:%M:%S"
8))

This is often cleaner than trying to force one global format everywhere.

Common Pitfalls

The most common mistake is setting datefmt but forgetting %(asctime)s in the main format string. Without %(asctime)s, the timestamp field is never emitted.

Another issue is expecting datefmt alone to control milliseconds. If you want a custom millisecond style, combine %(asctime)s with %(msecs)03d or override formatTime.

Developers also sometimes use local time unintentionally in distributed systems. If the logs will be merged from several machines, UTC is usually safer.

Finally, if logs are duplicated, the problem is probably multiple handlers or logger propagation, not the time format itself.

Summary

  • Use logging.Formatter with %(asctime)s and datefmt for normal timestamp customization.
  • 'basicConfig supports the same formatting options for simple setups.'
  • Add %(msecs)03d if you want explicit milliseconds.
  • Set formatter.converter = time.gmtime for UTC output.
  • Override formatTime when you need full control over the timestamp format.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.