2

This should be very simple, but I can't quite figure it out in Python. I want to have a function which takes two arguments, a UTC time in seconds and a zoneinfo name like 'Europe/Vienna' and returns the offset in seconds from local time and UTC for that point in time.

In C it would be:

/* ... code to to set local time to the time zone I want to compare against,
   not shown here. Then call function below to get difference vs localtime.
   Hardly an ideal solution,
   but just to demonstrate what I want in a "lingua franca" (C): */


int get_diff_vs_localtime(const time_t original_utc_time)
{
    struct tm* ts;

    ts = localtime(&original_utc_time);

    return mktime(ts) - original_utc_time;
}

I guess my question really boils down to: "given an Olson timezone (example 'Europe/Stockholm') and a UTC time, what is the local time?

Zero Piraeus
  • 56,143
  • 27
  • 150
  • 160
Prof. Falken
  • 24,226
  • 19
  • 100
  • 173
  • 1
    http://stackoverflow.com/questions/6801429/python-from-dst-adjusted-local-time-to-utc http://stackoverflow.com/questions/79797/how-do-i-convert-local-time-to-utc-in-python http://stackoverflow.com/questions/4115310/converting-utc-datetime-to-users-local-date-and-time http://stackoverflow.com/questions/6377179/converting-from-local-to-utc-timezone http://stackoverflow.com/questions/10524165/comparing-a-time-in-utc-with-a-time-in-eastern-time-using-python http://stackoverflow.com/questions/4770297/python-convert-utc-datetime-string-to-local-datetime Maybe related – Prof. Falken Oct 02 '12 at 13:40
  • 1
    http://niemeyer.net/python-dateutil – Prof. Falken Oct 02 '12 at 13:45
  • 2
    I summon the powers of @JonSkeet! – Prof. Falken Oct 02 '12 at 14:12
  • I've looked through the links you provided (to other SO questions). Beware all of them don't handle DST-related issues correctly. – jfs Oct 03 '12 at 10:47
  • @J.F.Sebastian, very ambitious of you. Did you mean that none of them do or only some? – Prof. Falken Oct 03 '12 at 13:16
  • none. You can read my comments there. The [pytz docs](http://pytz.sourceforge.net/) explain the issues. – jfs Oct 03 '12 at 14:21

4 Answers4

4

Assuming "UTC time in seconds" means POSIX timestamp. To convert it to Stockholm time:

from datetime import datetime
import pytz

tz = pytz.timezone('Europe/Stockholm')

utc_dt = datetime.utcfromtimestamp(posix_timestamp).replace(tzinfo=pytz.utc)
dt = tz.normalize(utc_dt.astimezone(tz))
print(dt.strftime('%Y-%m-%d %H:%M:%S %Z%z'))

tz.normalize() is unnecessary if the source timezone is UTC (like in this case).

A simpler alternative is to use fromtimestamp()'s tz parameter, to convert "seconds since the epoch" to local time:

from datetime import datetime
import pytz

tz = pytz.timezone('Europe/Stockholm')

dt = datetime.fromtimestamp(posix_timestamp, tz)
print(dt.strftime('%Y-%m-%d %H:%M:%S %Z%z'))

Both examples produce the same result.

If local machine uses "right" timezones then to convert POSIX timestamp received from an external source to UTC, an explicit formula could be used:

from datetime import datetime, timedelta
import pytz

utc_dt = datetime(1970, 1, 1, tzinfo=pytz.utc) + timedelta(seconds=posix_timestamp)

The latest formula may also support a larger date range (less likely issues with dates before 1970, after 2038 or 3000 years).

If the timestamp comes from the local "right" source then the first two examples should be used instead (they call "right" time.gmtime()).

jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • I like this, since it looked most closely to what my cobbled together solution with http://labix.org/python-dateutil looked like. What do you think about Kermit666s answer? – Prof. Falken Oct 02 '12 at 16:04
  • AmigableClarkKant: if you need offset: `st_dt.utcoffset()` might work. Can't comment on @Kermit666's answer: arithmetic with localized times is too complicated and buggy. *At first glance* it might not work *around* and *during* DST transitions. – jfs Oct 02 '12 at 17:30
  • Any particular reason why you prefer pytz instead of python-dateutil? For some reason (docs?) I found python-dateutil easier to understand. (Or more likely, _believe, albeit_ _incorrectly_, I understand.) – Prof. Falken Oct 05 '12 at 07:06
  • 1
    @AmigableClarkKant: [I can't get it to work for times during DST](https://gist.github.com/3838828). It doesn't mean that `dateutil` doesn't work, maybe I just don't know how to use it correctly. – jfs Oct 05 '12 at 08:58
  • 1
    That's a good reason to stick with pytz in my book, you are the one on SO distinguishing as time after time pointing out python datetime pitfalls. Thanks. – Prof. Falken Oct 05 '12 at 09:10
3

You could use pytz and datetime to do something in the manner of:

from datetime import datetime
from pytz import timezone

def get_diff(now, tzname):
    tz = timezone(tzname)
    utc = timezone('UTC')
    utc.localize(datetime.now())
    delta =  utc.localize(now) - tz.localize(now)
    return delta

Which for the following example...

now = datetime.utcnow()
print(now)
tzname = 'Europe/Stockholm'
delta = get_diff(now, tzname)
print(delta)
now_in_stockholm = now + delta
print(now_in_stockholm)

... outputs:

2012-10-02 14:38:56.547475
2:00:00
2012-10-02 16:38:56.547475
metakermit
  • 21,267
  • 15
  • 86
  • 95
3

This is pretty old, but I couldn't find a great answer, so here's what I came up with:

from datetime import datetime
local = datetime.now()
utc = datetime.utcnow()
int((local - utc).days * 86400 + round((local - utc).seconds, -1))

Returns:

-21600

because I am (currently) 21600 seconds (6 hours) behind UTC.

Note: the second date calculated (in this case UTC) needs to be rounded since there is a super small difference in time at each calculation.

Luke Olson
  • 345
  • 3
  • 6
1

I guess my question really boils down to: "given an Olson timezone (example 'Europe/Stockholm') and a UTC time, what is the local time?

If I understand your problem correctly:

from pytz import timezone
import datetime, time

tz = timezone('Asia/Kuwait')
utc_dt = datetime.datetime.utcfromtimestamp(time.time())
utc_dt + tz.utcoffset(utc_dt)

>>> tz.utcoffset(utc_dt).seconds
10800
>>> tz
<DstTzInfo 'Asia/Kuwait' LMT+3:12:00 STD>
>>> utc_dt + tz.utcoffset(utc_dt)
datetime.datetime(2012, 10, 2, 17, 13, 53, 504322)
>>> utc_dt
datetime.datetime(2012, 10, 2, 14, 13, 53, 504322)
Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284
  • 1
    `tz.utcoffset()` interprets `utc_dt` as a naive datetime object in `tz` timezone that is not true (`utc_dt` is in UTC). Also it might produce AmbiguousTimeError without `is_dst` parameter. – jfs Oct 02 '12 at 15:28