Reputation: 136141
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?
Upvotes: 150
Views: 240547
Reputation: 1580
The following appears to work for 3.7+, using standard libs:
from datetime import timedelta, 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])
Upvotes: 15
Reputation: 2553
In Python 3.x, local timezone can be figured out like this:
>>> import datetime
>>> datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo
datetime.timezone(datetime.timedelta(seconds=36000), 'AEST')
It's a tricky use of datetime
's code, as described in the docs for astimezone()
:
If called without arguments (or with
tz=None
) the system local time zone is assumed for the target time zone. The.tzinfo
attribute of the converted datetime instance will be set to an instance of timezone with the zone name and offset obtained from the OS.
For python < 3.6, you'll need
>>> import datetime
>>> print(datetime.datetime.now(datetime.timezone(datetime.timedelta(0))).astimezone().tzinfo)
AEST
Upvotes: 219
Reputation: 1138
I was asking the same to myself, and I found the answer here:
The format "%z"
(lowercase, "Z"
returns also the time zone, but not in the 4-digit format, but in the form of timezone abbreviations, more in this wikipedia article) of strftime
returns the form +/- 4DIGIT
that is standard in email headers (see RFC 2822 section 3.3, 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")
Upvotes: 31
Reputation: 16484
This one liner can be used to get the local timezone. It works because astimezone()
has a default argument of None
which implies the local timezone should be used.
datetime.now().astimezone().tzinfo
Upvotes: 0
Reputation: 331
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
Upvotes: 4
Reputation: 19259
To create an ISO formatted string that includes the ISO representation of your local time zone in Israel (+04:00
) :
>>> datetime.now(datetime.now().astimezone().tzinfo).isoformat()
'2021-09-07T01:02.030042+04:00'
This will create a "timezone aware" date object that will compare to any other datetime object in UTC or local time appropriately. But the time zone ISO representation (and the date/time string itself) will change if you ran this on a server in San Francisco at the exact same time, as I did:
>>> datetime.now(datetime.now().astimezone().tzinfo).isoformat()
'2021-09-06T14:01:02.030042-07:00'
The datetime
objects in in both cases would be compatible with each other. So if you subtracted them you'd get a time delta of 0:
>>> (datetime.fromisoformat('2021-09-06T14:01:02.030042-07:00') -
... datetime.fromisoformat('2021-09-07T01:01:02.030042+04:00'))
datetime.timedelta(0)
Upvotes: 8
Reputation: 1454
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.
Upvotes: 2
Reputation: 639
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.
Upvotes: 3
Reputation: 11
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.
Upvotes: 1
Reputation: 1176
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))
Upvotes: 11
Reputation: 8558
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()
Upvotes: 6
Reputation: 1809
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+
Upvotes: 3
Reputation: 2268
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'
Upvotes: 1
Reputation: 2478
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'
>>>
Upvotes: 1
Reputation: 414079
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.Upvotes: 42
Reputation: 740
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>)
Upvotes: 4
Reputation: 31
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)
Upvotes: 3
Reputation: 1130
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)
Upvotes: 4
Reputation: 8751
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())
Upvotes: 1