Given a variable containing the datetime of 2000-01-01 00:01 in Paris timezone (UTC+2 in winter afaik):
datetime.datetime(2000, 1, 1, 0, 1, tzinfo=pytz.timezone('Europe/Paris'))
I expected the conversion to UTC to result in a datetime of 1999-12-31 22:01, but got instead:
datetime.datetime(2000, 1, 1, 0, 1, tzinfo=pytz.timezone('Europe/Paris')).astimezone(pytz.utc)
datetime.datetime(1999, 12, 31, 23, 52, tzinfo=<UTC>)
What am I missing ?
Thanks
Unfortunately using the tzinfo argument of the standard datetime
constructors ‘’does not work’’ with pytz for many timezones.
>>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=amsterdam).strftime(fmt)
'2002-10-27 12:00:00 LMT+0020'
It is safe for timezones without daylight saving transitions though, such as UTC:
>>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=pytz.utc).strftime(fmt)
'2002-10-27 12:00:00 UTC+0000'
As you'll notice:
>>> datetime.datetime(2000, 1, 1, 0, 1, tzinfo=pytz.timezone('Europe/Paris'))
datetime.datetime(2000, 1, 1, 0, 1, tzinfo=<DstTzInfo 'Europe/Paris' LMT+0:09:00 STD>)
"LMT+0:09:00 STD"…?! That's a historical offset, not a current standard.
The timezone bundles (containing all historical offsets since forever) returned by pytz aren't handled correctly by datetime, and it chooses some random (well, the first probably) offset instead of the offset pertinent to the actual time. Arguably, since it needs to interpret the time correctly first it cannot choose the right offset by time from the timezone bundle.
This library only supports two ways of building a localized time. The
first is to use the localize() method provided by the pytz library.
This is used to localize a naive datetime (datetime with no timezone
information):
>>> loc_dt = eastern.localize(datetime(2002, 10, 27, 6, 0, 0))
>>> print(loc_dt.strftime(fmt))
2002-10-27 06:00:00 EST-0500
The second way of building a localized time is by converting an existing
localized time using the standard astimezone() method:
>>> ams_dt = loc_dt.astimezone(amsterdam)
>>> ams_dt.strftime(fmt)
'2002-10-27 12:00:00 CET+0100'
http://pytz.sourceforge.net
Related
I am using python 3.6
I converted midnight of "US/Pacific" timezone to unix timestamp.
When I convert the timestamp back to "US/Pacific" local time, I see its 7 minutes before the midnight.
Can anyone shade light on what is happening?
>>> (
datetime(2021, 5, 5, 0, 0)
.replace(tzinfo=pytz.timezone("US/Pacific"))
.timestamp()
)
>>> 1620201180.0
>>> datetime.utcfromtimestamp(1620201180.0)
>>> datetime.datetime(2021, 5, 5, 7, 53)
>>> datetime.fromtimestamp(1620201180.0, tz=pytz.timezone("US/Pacific"))
>>> datetime.datetime(2021, 5, 5, 0, 53, tzinfo=<DstTzInfo 'US/Pacific' PDT-1 day, 17:00:00 DST>)
FYI I am located at "Asia/Kathmandu" timezone.
I've been reading the pytz and datetime module documentation but I can't figure out why one date is under DST and the other is not.
import pytz
import datetime
mytz = pytz.timezone('America/New_York')
od = datetime.datetime(2021, 7, 1, 4, 0)
mytz.localize(od)
# Out: datetime.datetime(2021, 7, 1, 4, 0, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)
mytz.localize(od).dst()
# Out: datetime.timedelta(0, 3600)
dt = datetime.datetime(2089, 7, 1, 4, 0)
mytz.localize(dt)
# Out: datetime.datetime(2089, 7, 1, 4, 0, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)
mytz.localize(dt).dst()
# Out: datetime.timedelta(0)
If you look at the source of the time zone rules, you find that they can have a keyword "max" specified that "is used to extend a rule’s application into the indefinite future" ref. For the US, you can find that here. Unless otherwise specified, DST just continues to be applied during the specified period of the year. But keep in mind that this does not mean that it will actually be the case in the future, since time zones are subject to political decisions.
As an addition to #balmy 's comment suggesting this is a deficiency of pytz, Python 3.9's zoneinfo gives the result to be expected from the above:
import datetime
from zoneinfo import ZoneInfo
od = datetime.datetime(2021, 7, 1, 4, 0, tzinfo=ZoneInfo('America/New_York'))
print(od.dst())
# 1:00:00
dt = datetime.datetime(2089, 7, 1, 4, 0, tzinfo=ZoneInfo('America/New_York'))
print(dt.dst())
# 1:00:00
when I create a timezone aware datetime object for 'US/Eastern' and print it out, It shows as if my time zone is -4:56 instead of -4:00
>>> obj = datetime.datetime(2020, 7, 1, 9, 30, tzinfo=pytz.timezone('US/Eastern'))
>>> print(obj)
2020-07-01 09:30:00-04:56
instead of the expected:
2020-07-01 09:30:00-04:00
Am i doing something wrong?
Have a look at dateutil - you can safely construct the tz-aware datetime object using your originally intended method:
import datetime
import dateutil
obj = datetime.datetime(2020, 7, 1, 9, 30, tzinfo=dateutil.tz.gettz('US/Eastern'))
print(obj)
# 2020-07-01 09:30:00-04:00
In Python 3.9, there will be zoneinfo as part of the standard lib for that task.
It is mentioned in the docs that constructing datetime objects doesn't work this way.
You are supposed to do this:
from datetime import datetime
from pytz import timezone
eastern = timezone('US/Eastern')
obj = eastern.localize(datetime(2020, 7, 1, 9, 30))
>>> obj
datetime.datetime(2020, 7, 1, 9, 30, tzinfo=<DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST>)
>>> print(obj)
2020-07-01 09:30:00-04:00
I would like to calculate how many hours there are in a date interval: for example "2014.03.29-30" should give 47, because of the daylight savings.
My method is making two datetime objects, in the example the following:
datetime.datetime(2014, 3, 29, 0, 0, tzinfo=<DstTzInfo 'Europe/Budapest' LMT+1:16:00 STD>)
datetime.datetime(2014, 3, 30, 23, 59, tzinfo=<DstTzInfo 'Europe/Budapest' LMT+1:16:00 STD>)
return (date2-date1) + timedelta(minutes=1)
However, it gives "2 days, 0:00:00", which is not correct. How could I make a timedelta object which takes timezones and dst into account? Also, if there's a simpler solution for the whole problem, I'm open to it.
Thank you!
Before 1901-12-13 20:45:52 UTC, the 'Europe/Budapest' timezone was LMT+1:16:00 STD.
Currently, as of 2016-05-05, the 'Europe/Budapest' timezone is CET+2:00:00 DST.
If you use pytz's localize method, then pytz will choose the timezone (utcoffset and dstoffset) for 'Europe/Budapest' which is appropriate for the given naive datetime:
import datetime as DT
import pytz
tzone = pytz.timezone('Europe/Budapest')
date1 = tzone.localize(DT.datetime(2014, 3, 29, 0, 0), is_dst=None)
# datetime.datetime(2014, 3, 29, 0, 0, tzinfo=<DstTzInfo 'Europe/Budapest' CET+1:00:00 STD>)
In contrast, if you supply tzinfo=tzone directly to datetime.datetime, as in:
wrong_date1 = datetime.datetime(2014, 3, 29, 0, 0, tzinfo=tzone)
# datetime.datetime(2014, 3, 29, 0, 0, tzinfo=<DstTzInfo 'Europe/Budapest' LMT+1:16:00 STD>)
then the datetime.datetime incorrectly chooses the very first timezone associated with 'Europe/Budapest' regardless of whether or not that was the timezone in effect on 2014-3-29.
Therefore, when using pytz, always use tzone.localize to make naive datetimes timezone-aware:
import datetime as DT
import pytz
tzone = pytz.timezone('Europe/Budapest')
date1 = tzone.localize(DT.datetime(2014, 3, 29, 0, 0), is_dst=None)
date2 = tzone.localize(DT.datetime(2014, 3, 30, 23, 59), is_dst=None)
print(((date2-date1) + DT.timedelta(minutes=1)).total_seconds()/3600.)
# 47.0
Do not use tzinfo=tzone unless tzone is pytz.utc (or a timezone which is alway the same throughout its history.)
Where did the date 1901-12-13 20:45:52 UTC come from?
You can peek at a pytz timezone's utc transition times (and associated transition info) using its tzone._utc_transition_times and tzone._transition_info private attributes:
In [43]: [(utcdate, utcoffset, dstoffset, tzabbrev) for utcdate, (utcoffset, dstoffset, tzabbrev) in zip(tzone._utc_transition_times, tzone._transition_info)][:2]
Out[43]:
[(datetime.datetime(1, 1, 1, 0, 0),
datetime.timedelta(0, 4560),
datetime.timedelta(0),
'LMT'),
(datetime.datetime(1901, 12, 13, 20, 45, 52),
datetime.timedelta(0, 3600),
datetime.timedelta(0),
'CET')]
This shows that from the date 1-1-1 UTC to 1901-12-13 20:45:52 UTC the timezone abbreviation was LMT and the utcoffset was 4560 seconds, which equals 1 hour and 16 minutes:
In [47]: print(DT.timedelta(0, 4560))
1:16:00
Hence the first timezone associated with 'Europe/Budapest' is LMT+1:16:00 STD.
I'm having trouble understanding the conversion between the "Etc/GMT-5" timezone and UTC in pytz.
>>> dt = datetime(2009, 9, 9, 10, 0) # September 9 2009, 10:00
>>> gmt_5 = pytz.timezone("Etc/GMT-5")
>>> gmt_5.localize(dt)
datetime.datetime(2009, 9, 9, 10, 0, tzinfo=<StaticTzInfo 'Etc/GMT-5'>)
Everything is fine so far, but then I try to convert that to UTC:
>>> gmt_5.localize(dt).astimezone(pytz.utc)
datetime.datetime(2009, 9, 9, 5, 0, tzinfo=<UTC>)
So to me it seems that when converting from 10:00 in GMT-5 to UTC I get 05:00? I would expect pytz to give me 15:00 instead.
What am I missing?
EDIT: I have confirmed that timezone conversion for the US/Eastern timezone works just as I'd expect:
>>> eastern = pytz.timezone("US/Eastern")
>>> eastern.localize(dt)
datetime.datetime(2009, 9, 9, 10, 0, tzinfo=...) # Too long
>>> pytz.utc.normalize(eastern.localize(dt).astimezone(pytz.utc))
datetime.datetime(2009, 9, 9, 14, 0, tzinfo=<UTC>)
EDIT 2: I have confirmed that when I use Etc/GMT+5 I get 15:00, which is what I'd expect to get from Etc/GMT-5. Is this a pytz bug?
This is apparently a POSIX thing. From Wikipedia:
In order to conform with the POSIX style, those zones beginning with "Etc/GMT" have their sign reversed from what most people expect. In this style, zones west of GMT have a positive sign and those east have a negative sign.
This bug report explains this behavior. Apparently they know that it is all inverted, but that's because anything else would break compatibility.