106

How can I get UTC offset from time zone name in python?

For example: I have Asia/Jerusalem and I want to get +0200

FObersteiner
  • 22,500
  • 8
  • 42
  • 72
alexarsh
  • 5,123
  • 12
  • 42
  • 51
  • 16
    with Python 3.9 you would use `datetime.datetime.now(zoneinfo.ZoneInfo('Asia/Jerusalem')).utcoffset()`, not needing any third party libraries. – FObersteiner May 27 '21 at 18:51

5 Answers5

146

Because of DST (Daylight Saving Time), the result depends on the time of the year:

import datetime, pytz

datetime.datetime.now(pytz.timezone('Asia/Jerusalem')).strftime('%z')

# returns '+0300' (because 'now' they have DST)


pytz.timezone('Asia/Jerusalem').localize(datetime.datetime(2011,1,1)).strftime('%z')

# returns '+0200' (because in January they didn't have DST)
eumiro
  • 207,213
  • 34
  • 299
  • 261
  • `pytz.timezone("Etc/GMT-5").localize(datetime.datetime(2011, 1, 1)).strftime("%z")` returns "+0500", not "-0500" – 404usernamenotfound Aug 03 '23 at 13:22
  • @404usernamenotfound I think that in programmatical contexts GMT-5 actually means +0500 and translated to human language it means "GMT+5". Confusing? Yes. – Janne Paalijarvi Aug 17 '23 at 11:44
  • @JannePaalijarvi No, the positive ones are named `Etc/GMT+n` in my list. There are also negative `Etc/GMT-n` zones. I got it working, but not using pytz. – 404usernamenotfound Aug 17 '23 at 13:28
  • Etc/GMT-5 => +0500 is valid : root@am335x-evm:~# timedatectl Local time: Fri 2023-08-18 10:46:24 +05 Universal time: Fri 2023-08-18 05:46:24 UTC RTC time: Fri 2023-08-18 05:46:25 Time zone: Etc/GMT-5 (+05, +0500) System clock synchronized: yes NTP service: active RTC in local TZ: no – Janne Paalijarvi Aug 18 '23 at 05:47
84

Have you tried using the pytz project and the utcoffset method?

e.g.

>>> import datetime
>>> import pytz
>>> pacific_now = datetime.datetime.now(pytz.timezone('US/Pacific'))
>>> pacific_now.utcoffset().total_seconds()/60/60
-7.0
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 2
    BTW, the Ubuntu package for pytz is python-tz. – Randall Cook Apr 23 '12 at 18:06
  • 2
    I don't dare downvote him, but utcoffset is a method on datetime objects, as best I can tell, so it doesn't provide this from a timezone name. – Tom Apr 26 '13 at 21:04
  • 1
    @Tom: It's *also* available on `tzinfo` objects though. See http://pytz.sourceforge.net/#tzinfo-api – Jon Skeet Apr 27 '13 at 07:19
  • 1
    @jon-skeet Thanks, I missed that. Are we officially beefing now? – Tom Apr 28 '13 at 14:32
  • 4
    Beware that if the server is using a timezone other than the one given than this produces incorrect results during the daylight savings time switch over. The datetime passed to `timezone.utcoffset()` is assumed to be local to that time zone and will fail if passed either the hour that daylight savings begins or ends. `datetime.datetime.utcnow().replace(tzinfo=pytz.utc).astimezone(pytz.timezone('US/Pacific')).utcoffset().total_seconds() / 60 / 60` is a better approach. – Nathan Villaescusa Nov 06 '16 at 22:20
  • @NathanVillaescusa: Would just changing `today = datetime.datetime.now()` into `today = datetime.datetime.utcnow()` not work? Doesn't that value "know" that it's in UTC? – Jon Skeet Nov 07 '16 at 06:29
  • @jon-skeet You end up with the same result if you use `.utcnow()` instead of `.now()` because `pytz.timezone.utcoffset()` interprets whatever is passed to it as being in that time zone. Furthermore I'd bet most servers use UTC as their time zone so `.now()` and `.utcnow()` will be the exact same thing. I did try `today = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)` but this fails with `ValueError: Not naive datetime (tzinfo is already set)`. – Nathan Villaescusa Nov 07 '16 at 07:37
  • @NathanVillaescusa: Urgh. That's unfortunate. So should your earlier suggestion actually just use `datetime.datetime.utcnow().astimezone(pytz.timezone('US‌​/Pacific')).utcoffse‌​t()`? (I know from experience that it's hard to design a date/time API, but I do wish the existing ones would be better documented...) – Jon Skeet Nov 07 '16 at 07:40
  • @JonSkeet Heh, that fails because you end up with a datetime that is unbound to a time zone and pytz raises: `ValueError: astimezone() cannot be applied to a naive datetime`. A quicker way that does work is `datetime.datetime.now(pytz.timezone('US/Pacific')).utcoffset()` – Nathan Villaescusa Nov 07 '16 at 19:53
  • @NathanVillaescusa: Ah joy. That's what you get when you use a single type for multiple things :( Have edited my answer based on your comments. – Jon Skeet Nov 07 '16 at 20:48
2

I faced a similar issue while converting to UTC timestamp from python datetime object. My datetime was timezone agnostic (very naive) and as such astimezone would not work.

To mitigate the issue, I made my datetime object timezone aware and then used the above magic.

import pytz
system_tz = pytz.timezone(constants.TIME_ZONE)
localized_time = system_tz.localize(time_of_meeting)
fmt = "%Y%m%dT%H%M%S" + 'Z'
return localized_time.astimezone(pytz.utc).strftime(fmt)

Here, constants.TIME_ZONE is where I had the default timezone of my persisted objects.

Hope this helps someone attempting to convert python datetime objects to UTC. Once converted, format any way you please.

Rohan Bagchi
  • 649
  • 10
  • 17
1

Another perspectife from @Jon Skeet answer, assuming you already have datetime.datetime object, for example day = datetime.datetime(2021, 4, 24):

import pytz
tz = pytz.timezone("Asia/Kolkata")

import datetime
day = datetime.datetime(2021, 4, 24)

offset = tz.utcoffset(day)/3600
Muhammad Yasirroni
  • 1,512
  • 12
  • 22
0

Another way to get UTC Offset as an integer:

import datetime
import pytz
from tzwhere import tzwhere

tzwhere = tzwhere.tzwhere()
timezone = pytz.timezone('Asia/Jerusalem')
offSet_str = str(timezone.utcoffset(datetime.datetime.now()))
if offSet_str[0] != '-':
    offSet = int(offSet_str[0])
else:
    offSet = int(offSet_str[8] + offSet_str[9]) - 24

print(offSet)

Jon Skeet has a faster method