[python] Python: Figure out local timezone

I want to compare UTC timestamps from a log file with local timestamps. When creating the local datetime object, I use something like:

>>> local_time=datetime.datetime(2010, 4, 27, 12, 0, 0, 0, 
                                 tzinfo=pytz.timezone('Israel'))

I want to find an automatic tool that would replace thetzinfo=pytz.timezone('Israel') with the current local time zone.

Any ideas?

This question is related to python datetime time timezone utc

The answer is


For simple things, the following tzinfo implementation can be used, which queries the OS for time zone offsets:

import datetime
import time

class LocalTZ(datetime.tzinfo):
    _unixEpochOrdinal = datetime.datetime.utcfromtimestamp(0).toordinal()

    def dst(self, dt):
        return datetime.timedelta(0)

    def utcoffset(self, dt):
        t = (dt.toordinal() - self._unixEpochOrdinal)*86400 + dt.hour*3600 + dt.minute*60 + dt.second + time.timezone
        utc = datetime.datetime(*time.gmtime(t)[:6])
        local = datetime.datetime(*time.localtime(t)[:6])
        return local - utc


print datetime.datetime.now(LocalTZ())
print datetime.datetime(2010, 4, 27, 12, 0, 0, tzinfo=LocalTZ())

# If you're in the EU, the following datetimes are right on the DST change.
print datetime.datetime(2013, 3, 31, 0, 59, 59, tzinfo=LocalTZ())
print datetime.datetime(2013, 3, 31, 1, 0, 0, tzinfo=LocalTZ())
print datetime.datetime(2013, 3, 31, 1, 59, 59, tzinfo=LocalTZ())

# The following datetime is invalid, as the clock moves directly from
# 01:59:59 standard time to 03:00:00 daylight savings time.
print datetime.datetime(2013, 3, 31, 2, 0, 0, tzinfo=LocalTZ())

print datetime.datetime(2013, 10, 27, 0, 59, 59, tzinfo=LocalTZ())
print datetime.datetime(2013, 10, 27, 1, 0, 0, tzinfo=LocalTZ())
print datetime.datetime(2013, 10, 27, 1, 59, 59, tzinfo=LocalTZ())

# The following datetime is ambigous, as 02:00 can be either DST or standard
# time. (It is interpreted as standard time.)
print datetime.datetime(2013, 10, 27, 2, 0, 0, tzinfo=LocalTZ())

You may be happy with pendulum

>>> pendulum.datetime(2015, 2, 5, tz='local').timezone.name
'Israel'

Pendulum has a well designed API for manipulating dates. Everything is TZ-aware.


First get pytz and tzlocal modules

pip install pytz tzlocal

then

from tzlocal import get_localzone
local = get_localzone()

then you can do things like

from datetime import datetime
print(datetime.now(local))

Here's a way to get the local timezone using only the standard library, (only works in a *nix environment):

>>> '/'.join(os.path.realpath('/etc/localtime').split('/')[-2:])
'Australia/Sydney'

You can use this to create a pytz timezone:

>>> import pytz
>>> my_tz_name = '/'.join(os.path.realpath('/etc/localtime').split('/')[-2:])
>>> my_tz = pytz.timezone(my_tz_name)
>>> my_tz
<DstTzInfo 'Australia/Sydney' LMT+10:05:00 STD>

...which you can then apply to a datetime:

>>> import datetime
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2014, 9, 3, 9, 23, 24, 139059)

>>> now.replace(tzinfo=my_tz)
>>> now
datetime.datetime(2014, 9, 3, 9, 23, 24, 139059, tzinfo=<DstTzInfo 'Australia/Sydney' LMT+10:05:00 STD>)

The following appears to work for 3.7+, using standard libs:

from datetime import timedelta
from datetime import timezone
import time

def currenttz():
    if time.daylight:
        return timezone(timedelta(seconds=-time.altzone),time.tzname[1])
    else:
        return timezone(timedelta(seconds=-time.timezone),time.tzname[0])

I have also been looking for a simple way to read the local host configuration and get timezone aware local_time based on it. As of python 3.6+ the simplest approach is use dateutil.tz which will read /etc/localtime and assist in getting timezone aware datetime object.

Here is more info on it: https://dateutil.readthedocs.io/en/stable/tz.html

The implementation to accomplish what you're looking for is as follows:

from datetime import datetime
from dateutil import tz
local_time = datetime.now(tz.gettz())

This will provide you the following local_time:

2019-10-18 13:41:06.624536-05:00

Additional Resources I used in researching this topic: Paul Ganssle Presentation about time zones: https://www.youtube.com/watch?v=l4UCKCo9FWY

pytz: The Fastest Footgun in the West https://blog.ganssle.io/articles/2018/03/pytz-fastest-footgun.html


Based on J. F. Sebastian's answer, you can do this with the standard library:

import time, datetime
local_timezone = datetime.timezone(datetime.timedelta(seconds=-time.timezone))

Tested in 3.4, should work on 3.4+


I was asking the same to myself, and I found the answer in 1:

Take a look at section 8.1.7: the format "%z" (lowercase, the Z uppercase returns also the time zone, but not in the 4-digit format, but in the form of timezone abbreviations, like in [3]) of strftime returns the form "+/- 4DIGIT" that is standard in email headers (see section 3.3 of RFC 2822, see [2], which obsoletes the other ways of specifying the timezone for email headers).

So, if you want your timezone in this format, use:

time.strftime("%z")

[1] http://docs.python.org/2/library/datetime.html

[2] http://tools.ietf.org/html/rfc2822#section-3.3

[3] Timezone abbreviations: http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations , only for reference.


In Python 3.x, local timezone can be figured out like this:

import datetime
LOCAL_TIMEZONE = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo

It's a tricky use of datetime's code .

For python >= 3.6, you'll need

import datetime
LOCAL_TIMEZONE = datetime.datetime.now(datetime.timezone(datetime.timedelta(0))).astimezone().tzinfo

now_dt = datetime.datetime.now()
utc_now = datetime.datetime.utcnow()
now_ts, utc_ts = map(time.mktime, map(datetime.datetime.timetuple, (now_dt, utc_now)))
offset = int((now_ts - utc_ts) / 3600)

hope this will help you.


to compare UTC timestamps from a log file with local timestamps.

It is hard to find out Olson TZ name for a local timezone in a portable manner. Fortunately, you don't need it to perform the comparison.

tzlocal module returns a pytz timezone corresponding to the local timezone:

from datetime import datetime

import pytz # $ pip install pytz
from tzlocal import get_localzone # $ pip install tzlocal

tz = get_localzone()
local_dt = tz.localize(datetime(2010, 4, 27, 12, 0, 0, 0), is_dst=None)
utc_dt = local_dt.astimezone(pytz.utc) #NOTE: utc.normalize() is unnecessary here

Unlike other solutions presented so far the above code avoids the following issues:

  • local time can be ambiguous i.e., a precise comparison might be impossible for some local times
  • utc offset can be different for the same local timezone name for dates in the past. Some libraries that support timezone-aware datetime objects (e.g., dateutil) fail to take that into account

Note: to get timezone-aware datetime object from a naive datetime object, you should use*:

local_dt = tz.localize(datetime(2010, 4, 27, 12, 0, 0, 0), is_dst=None)

instead of:

#XXX fails for some timezones
local_dt = datetime(2010, 4, 27, 12, 0, 0, 0, tzinfo=tz)

*is_dst=None forces an exception if given local time is ambiguous or non-existent.

If you are certain that all local timestamps use the same (current) utc offset for the local timezone then you could perform the comparison using only stdlib:

# convert a naive datetime object that represents time in local timezone to epoch time
timestamp1 = (datetime(2010, 4, 27, 12, 0, 0, 0) - datetime.fromtimestamp(0)).total_seconds()

# convert a naive datetime object that represents time in UTC to epoch time
timestamp2 = (datetime(2010, 4, 27, 9, 0) - datetime.utcfromtimestamp(0)).total_seconds()

timestamp1 and timestamp2 can be compared directly.

Note:

  • timestamp1 formula works only if the UTC offset at epoch (datetime.fromtimestamp(0)) is the same as now
  • fromtimestamp() creates a naive datetime object in the current local timezone
  • utcfromtimestamp() creates a naive datetime object in UTC.

I want to compare UTC timestamps from a log file with local timestamps

If this is your intent, then I wouldn't worry about specifying specific tzinfo parameters or any additional external libraries. Since Python 3.5, the built in datetime module is all you need to create a UTC and a local timestamp automatically.

import datetime
f = "%a %b %d %H:%M:%S %Z %Y"         # Full format with timezone

# tzinfo=None
cdatetime = datetime.datetime(2010, 4, 27, 12, 0, 0, 0)  # 1. Your example from log
cdatetime = datetime.datetime.now()   # 2. Basic date creation (default: local time)
print(cdatetime.strftime(f))          # no timezone printed
# Tue Apr 27 12:00:00  2010

utctimestamp = cdatetime.astimezone(tz=datetime.timezone.utc)  # 1. convert to UTC
utctimestamp = datetime.datetime.now(tz=datetime.timezone.utc) # 2. create in UTC
print(utctimestamp.strftime(f))
# Tue Apr 27 17:00:00 UTC 2010

localtimestamp = cdatetime.astimezone()               # 1. convert to local [default]
localtimestamp = datetime.datetime.now().astimezone()  # 2. create with local timezone
print(localtimestamp.strftime(f))
# Tue Apr 27 12:00:00 CDT 2010

The '%Z' parameter of datetime.strftime() prints the timezone acronym into the timestamp for humans to read.


tzlocal from dateutil.

Code example follows. Last string suitable for use in filenames.

>>> from datetime import datetime
>>> from dateutil.tz import tzlocal
>>> str(datetime.now(tzlocal()))
'2015-04-01 11:19:47.980883-07:00'
>>> str(datetime.now(tzlocal())).replace(' ','-').replace(':','').replace('.','-')
'2015-04-01-111947-981879-0700'
>>> 

Here's a slightly more concise version of @vbem's solution:

from datetime import datetime as dt

dt.utcnow().astimezone().tzinfo

The only substantive difference is that I replaced datetime.datetime.now(datetime.timezone.utc) with datetime.datetime.utcnow(). For brevity, I also aliased datetime.datetime as dt.

For my purposes, I want the UTC offset in seconds. Here's what that looks like:

dt.utcnow().astimezone().utcoffset().total_seconds()

Avoiding non-standard module (seems to be a missing method of datetime module):

from datetime import datetime
utcOffset_min = int(round((datetime.now() - datetime.utcnow()).total_seconds())) / 60   # round for taking time twice
utcOffset_h = utcOffset_min / 60
assert(utcOffset_min == utcOffset_h * 60)   # we do not handle 1/2 h timezone offsets

print 'Local time offset is %i h to UTC.' % (utcOffset_h)

First, note that the question presents an incorrect initialization of an aware datetime object:

>>> local_time=datetime.datetime(2010, 4, 27, 12, 0, 0, 0,
...                                  tzinfo=pytz.timezone('Israel'))

creates an invalid instance. One can see the problem by computing the UTC offset of the resulting object:

>>> print(local_time.utcoffset())
2:21:00

(Note the result which is an odd fraction of an hour.)

To initialize an aware datetime properly using pytz one should use the localize() method as follows:

>>> local_time=pytz.timezone('Israel').localize(datetime.datetime(2010, 4, 27, 12))
>>> print(local_time.utcoffset())
3:00:00

Now, if you require a local pytz timezone as the new tzinfo, you should use the tzlocal package as others have explained, but if all you need is an instance with a correct local time zone offset and abbreviation then tarting with Python 3.3, you can call the astimezone() method with no arguments to convert an aware datetime instance to your local timezone:

>>> local_time.astimezone().strftime('%Y-%m-%d %H:%M %Z %z')
'2010-04-27 05:00 EDT -0400'

Based on Thoku's answer above, here's an answer that resolves the time zone to the nearest half hour (which is relevant for some timezones eg South Australia's) :

from datetime import datetime
round((round((datetime.now()-datetime.utcnow()).total_seconds())/1800)/2)

Examples related to python

programming a servo thru a barometer Is there a way to view two blocks of code from the same file simultaneously in Sublime Text? python variable NameError Why my regexp for hyphenated words doesn't work? Comparing a variable with a string python not working when redirecting from bash script is it possible to add colors to python output? Get Public URL for File - Google Cloud Storage - App Engine (Python) Real time face detection OpenCV, Python xlrd.biffh.XLRDError: Excel xlsx file; not supported Could not load dynamic library 'cudart64_101.dll' on tensorflow CPU-only installation

Examples related to datetime

Comparing two joda DateTime instances How to format DateTime in Flutter , How to get current time in flutter? How do I convert 2018-04-10T04:00:00.000Z string to DateTime? How to get current local date and time in Kotlin Converting unix time into date-time via excel Convert python datetime to timestamp in milliseconds SQL Server date format yyyymmdd Laravel Carbon subtract days from current date Check if date is a valid one Why is ZoneOffset.UTC != ZoneId.of("UTC")?

Examples related to time

Date to milliseconds and back to date in Swift How to manage Angular2 "expression has changed after it was checked" exception when a component property depends on current datetime how to sort pandas dataframe from one column Convert time.Time to string How to get current time in python and break up into year, month, day, hour, minute? Xcode swift am/pm time to 24 hour format How to add/subtract time (hours, minutes, etc.) from a Pandas DataFrame.Index whos objects are of type datetime.time? What does this format means T00:00:00.000Z? How can I parse / create a date time stamp formatted with fractional seconds UTC timezone (ISO 8601, RFC 3339) in Swift? Extract time from moment js object

Examples related to timezone

How to set the timezone in Django? How to convert Moment.js date to users local timezone? What does this format means T00:00:00.000Z? How do I get the current timezone name in Postgres 9.3? MySQL JDBC Driver 5.1.33 - Time Zone Issue Python get current time in right timezone Symfony2 and date_default_timezone_get() - It is not safe to rely on the system's timezone settings PHP date() with timezone? How to store a datetime in MySQL with timezone info Java SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") gives timezone as IST

Examples related to utc

Convert LocalDateTime to LocalDateTime in UTC How to set the timezone in Django? Java Convert GMT/UTC to Local time doesn't work as expected Should MySQL have its timezone set to UTC? How to Convert UTC Date To Local time Zone in MySql Select Query How to convert UTC timestamp to device local time in android Convert python datetime to epoch with strftime Convert Java Date to UTC String How do I get a UTC Timestamp in JavaScript? Converting datetime.date to UTC timestamp in Python