I want to compare UTC timestamps from a log file with local timestamps. When creating the local datetime
object, I use something like:
>>&
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:
dateutil
) fail to take that into accountNote: 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 nowfromtimestamp()
creates a naive datetime object in the current local timezoneutcfromtimestamp()
creates a naive datetime object in UTC.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'
>>>
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)
Try dateutil, which has a tzlocal type that does what you need.
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)
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())