65

Is it possible and how to set the logging timezone to GMT?

(i.e. the %(asctime)s parameter in the format)

vvvvv
  • 25,404
  • 19
  • 49
  • 81
Jonathan Livni
  • 101,334
  • 104
  • 266
  • 359

7 Answers7

90
logging.Formatter.converter = time.gmtime

(documented in the docstring of logging.Formatter.formatTime)

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • 2
    And I've now also updated the official HTML documentation - should show up soon for 3.2 and 3.3, and in a few days for 2.7. – Vinay Sajip Jun 12 '11 at 10:52
  • 7
    Described [here](http://docs.python.org/2/library/logging.html#logging.Formatter). If you want to attach formatter to a handler, you first need to create a formatter with **formatter = logging.Formatter(fmt)**, then do **formatter.converter = time.gmtime**, then **myHandler.setFormatter(formatter)** – Sergey M Mar 15 '14 at 04:46
  • 1
    @VinaySajip How to set it in a logging dictConfig? I use Django that uses a logging.dictConfig to configure the logging part. Thanks – Michael Oct 18 '14 at 20:02
  • @YAmikep see the answer by rakslice for one way to do it. – Vinay Sajip Oct 19 '14 at 11:00
  • @VinaySajip Ok thanks, I had to set ```'()' : 'my.package.customFormatterFactory',``` We cannot set the ```'class': 'my.package.customFormatterFactory' ``` for a formatter. – Michael Oct 19 '14 at 14:46
  • Any idea on how to make it work as well for django.request logger? https://stackoverflow.com/questions/62314586/how-to-convert-django-request-logger-time-to-utc – ivanleoncz Jun 11 '20 at 00:30
  • 1
    @ivanleoncz setting `logging.Formatter.converter = time.gmtime` will work for any formatter that inherits from the `logging.Formatter` class. Just check whether Django formatter is inheriting from Python's main Formatter class, which I bet it does. – Renato Byrro Jan 10 '21 at 12:35
7

From the python 3 docs:

import time

class UTCFormatter(logging.Formatter):
    converter = time.gmtime

https://docs.python.org/3/howto/logging-cookbook.html#formatting-times-using-utc-gmt-via-configuration

dcordz
  • 160
  • 3
  • 8
7

Just setting logging.Formatter.converter = time.gmtime is ineffective for me in Python 2.5.

So I created a child class with it set, and use that in place of logging.Formatter:

class UTCFormatter(logging.Formatter):
    converter = time.gmtime
rakslice
  • 8,742
  • 4
  • 53
  • 57
  • Worked for me in Python 2.7. Added a suggested edit showing the YAML syntax for instantiation, since it's a bit tricky. (There's no need for a `__init__()` method, as my first edit suggested.) – evadeflow Feb 09 '15 at 15:30
3

Here is code example:

import logging, logging.handlers
import time

logit = logging.getLogger('logit')
handler = logging.handlers.RotatingFileHandler("file.log", maxBytes=20000, backupCount=5)
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s %(levelname)8s: %(message)s')
handler.setFormatter(formatter)
logging.Formatter.converter = time.gmtime
logit.addHandler(handler)

logit.info("test log message")

Output:

2019-11-14 16:34:22,967     INFO: test log message
Vlad Gulin
  • 171
  • 2
  • 4
1

I had problems getting the popular answers from this post and similar posts related to using time.gmtime with the logging converter. I stumbled across this helpful post about logging timestamps in iso8601 which sent me in the right direction to eventually solve my issue.

This solution works in Python 3.10.8. It involved setting the converter = time.gmtime and overriding the formatTime. This may be unnecessary in future releases of Python and there may be an easier way to do it as well. Note, setting converter = time.gmtime() will not work and results in an error.

import logging
import time

class UtcIsoFormatter(logging.Formatter):
  """Custom logging.Formatter class for logging UTC time in ISO8601 format
  """
  
  # Use gmtime or universal coordinated time or utc
  converter = time.gmtime # must not include '()'
  
  # Format the time for this log event
  def formatTime(self, record, datefmt=None):
    ct = self.converter(record.created)
    if datefmt:
      s = time.strftime(datefmt, ct)
    else:
      # Default UTC ISO8601 format of "YYYY-mm-ddTHH:MM:SS.fffZ"
      t = time.strftime("%Y-%m-%dT%H:%M:%S", ct)
      s = f"{t}.{record.msecs:03.0f}Z"
    return s

logger = logging.getLogger(__name__)
logger.setLevel(level="DEBUG")

formatter = UtcIsoFormatter(fmt="%(asctime)s - %(levelname)s - %(message)s")

logHandlerConsole = logging.StreamHandler()
logHandlerConsole.setFormatter(formatter)
logger.addHandler(logHandlerConsole)

logger.debug("Testing")
-1

This works:

os.environ['TZ'] = 'UTC'
time.tzset()

But does change the TZ environment for the whole process and any sub-processes. Not necessarily a bad thing, but something to be aware of before doing this.

Alternately if you set the TZ environment variable from outside (whether just in whatever runs the python, or at a whole system level) before you run python, that also works.

thorfi
  • 109
  • 1
  • 6
-3

I've had problems with both of these answers. So I just changed global timezone for the whole script:

os.environ['TZ'] = 'Europe/London'
time.tzset()
dijxtra
  • 2,681
  • 4
  • 25
  • 37
  • 23
    Be careful as London is not on GMT time in the summer. – Brian Larsen Aug 15 '12 at 21:47
  • I found this was the answer that worked, using Python 2.7 on Linux. Worth checking using the Linux tzselect command that whatever you specify is a valid timezone on your system, and testing outside Python with the 'date' command. Django seems to handle this OK for its setup, but I'm getting the wrong timezone when doing Python logging from non-Django Python scripts. – RichVel Jan 01 '13 at 17:38
  • 3
    This is incorrect! The timezone in London is not guaranteed to be UTC forever. – Federico Jan 19 '16 at 18:15
  • It is an interesting approach, yet this changes the timezone for the entire process, which might have some unwanted side effects, like if you only wanted to change the timezone of the displayed time, but not for other stuff. – Daniel F May 16 '19 at 18:46