Getting Computer's Utc Offset in Python

Getting computer's UTC offset in Python

gmtime() will return the UTC time and localtime() will return the local time so subtracting the two should give you the utc offset.

From https://pubs.opengroup.org/onlinepubs/009695399/functions/gmtime.html

The gmtime() function shall convert the time in seconds since the Epoch pointed to by timer into a broken-down time, expressed as Coordinated Universal Time (UTC).

So, despite the name gmttime, the function returns UTC.

Getting the correct timezone offset in Python using local timezone

According to Wikipedia, the transition to and from Summer Time occurs at 01:00 UTC.

  • At 00:12 UTC you are still in Central European Summer Time (i.e. UTC+02:00), so the local time is 02:12.

  • At 01:12 UTC you are back in the standard Central European Time (i.e. UTC+01:00), so the local time is again 02:12.

When changing from Summer Time back to standard time, the local time goes from 02:59 back to 02:00 and the hour repeats itself. So when asking for the UTC offset of 02:12 (local time), the answer could truthfully be either +01:00 or +02:00 - it depends which version of 02:12 you are talking about.

On further investigation of the pytz library, I think your problem may be that you shouldn't be using the pytz.reference implementation, which may not deal with these ambiguities very well. Quoting from the comments in the source code:

Reference tzinfo implementations from the Python docs.
Used for testing against as they are only correct for the years
1987 to 2006. Do not use these for real code.

Working with ambiguous times in pytz

What you should be doing is constructing a timezone object for the appropriate timezone:

import pytz
cet = pytz.timezone('CET')

Then you can use the utcoffset method to calculate the UTC offset of a date/time in that timezone.

dt = datetime.datetime(2010, 10, 31, 2, 12, 30)
offset = cet.utcoffset(dt)

Note, that the above example will throw an AmbiguousTimeError exception, because it can't tell which of the two versions of 02:12:30 you meant. Fortunately pytz will let you specify whether you want the dst version or the standard version by setting the is_dst parameter. For example:

offset = cet.utcoffset(dt, is_dst = True)

Note that it doesn't harm to set this parameter on all calls to utcoffset, even if the time wouldn't be ambiguous. According to the documentation, it is only used during DST transition ambiguous periods to resolve that ambiguity.

How to deal with timestamps

As for dealing with timestamps, it's best you store them as UTC values for as long as possible, otherwise you potentially end up throwing away valuable information. So first convert to a UTC datetime with the datetime.utcfromtimestamp method.

dt = datetime.datetime.utcfromtimestamp(1288483950)

Then use pytz to localize the time as UTC, so the timezone is attached to the datetime object.

dt = pytz.utc.localize(dt)

Finally you can convert that UTC datetime into your local timezone, and obtain the timezone offset like this:

offset = dt.astimezone(cet).utcoffset()

Note that this set of calculations will produce the correct offsets for both 1288483950 and 1288487550, even though both timestamps are represented by 02:12:30 in the CET timezone.

Determining the local timezone

If you need to use the local timezone of your computer rather than a fixed timezone, you can't do that from pytz directly. You also can't just construct a pytz.timezone object using the timezone name from time.tzname, because the names won't always be recognised by pytz.

The solution is to use the tzlocal module - its sole purpose is to provide this missing functionality in pytz. You use it like this:

import tzlocal
local_tz = tzlocal.get_localzone()

The get_localzone() function returns a pytz.timezone object, so you should be able to use that value in all the places I've used the cet variable in the examples above.

How do I automatically get the timezone offset for my local time zone?

You can use the dateutil module for this. To get the local timezone right now:

>>> import dateutil.tz
>>> import datetime
>>> localtz = dateutil.tz.tzlocal()
>>> localtz.tzname(datetime.datetime.now(localtz))
'EDT'

I am currently in Eastern Daylight Time. You can see it change back to EST in the future, after daylight savings switches back:

>>> localtz.tzname(datetime.datetime.now(localtz) +
datetime.timedelta(weeks=20))
'EST'

If you want the offset from UTC, you can use the utcoffset function. It returns a timedelta:

>>> localtz.utcoffset(datetime.datetime.now(localtz))
datetime.timedelta(-1, 72000)

In this case, since I'm UTC-4, it returns -1 days + 20 hours. You can convert it to hours if that's what you need:

>>> localoffset = localtz.utcoffset(datetime.datetime.now(localtz))
>>> localoffset.total_seconds() / 3600
-4.0

How to get current offset of any timezone in Python

I assume the previous code is not aware of the political decisions of each country regarding DST and probably gets you the offset according to fixed DST dates or something like that.

Your assumption is incorrect. Political changes of time zones are recorded and distributed via the TZ Database. Those changes are then implemented in hundreds of different libraries, platforms, and operating systems - such as the pytz library you mention.

The change to America/Santiago that you describe was reflected in TZDB 2016c, which is implemented in pytz 2016.3. If you are using pytz 2016.3 or greater, then your code is aware of this change.

Pytz is fine, but you may want to consider using dateutil instead. Version 2.5.2 or higher has this data.

Python - get UTC offset by seconds

>>> import datetime, pytz
>>> melbourne = pytz.timezone("Australia/Melbourne")
>>> melbourne.utcoffset(datetime.datetime.now())
datetime.timedelta(0, 36000)

>>> pacific = pytz.timezone("US/Pacific")
>>> pacific.utcoffset(datetime.datetime.now())
datetime.timedelta(-1, 61200)
>>> -1*86400+61200
-25200
>>> pacific.utcoffset(datetime.datetime.now()).total_seconds()
-25200.0

Python: strftime() UTC Offset Not working as Expected in Windows

For a proper solution, see abarnert’s answer below.


You can use time.altzone which returns a negative offset in seconds. For example, I’m on CEST at the moment (UTC+2), so I get this:

>>> time.altzone
-7200

And to put it in your desired format:

>>> '{}{:0>2}{:0>2}'.format('-' if time.altzone > 0 else '+', abs(time.altzone) // 3600, abs(time.altzone // 60) % 60)
'+0200'

As abarnert mentioned in the comments, time.altzone gives the offset when DST is active while time.timezone does for when DST is not active. To figure out which to use, you can do what J.F. Sebastian suggested in his answer to a different question. So you can get the correct offset like this:

time.altzone if time.daylight and time.localtime().tm_isdst > 0 else time.timezone

As also suggested by him, you can use the following in Python 3 to get the desired format using datetime.timezone:

>>> datetime.now(timezone.utc).astimezone().strftime('%z')
'+0200'

Python: Figure out local timezone

Try dateutil, which has a tzlocal type that does what you need.

Get time zone information of the system in Python?

Check out the Python Time Module.

from time import gmtime, strftime
print(strftime("%z", gmtime()))

Pacific Standard Time

How to get system timezone setting and pass it to pytz.timezone?

A very simple method to solve this question:

import time

def localTzname():
offsetHour = time.timezone / 3600
return 'Etc/GMT%+d' % offsetHour

Update: @MartijnPieters said 'This won't work with DST / summertime.' So how about this version?

import time

def localTzname():
if time.daylight:
offsetHour = time.altzone / 3600
else:
offsetHour = time.timezone / 3600
return 'Etc/GMT%+d' % offsetHour


Related Topics



Leave a reply



Submit