Reputation: 3387
I'm trying to understand why I'm getting these results when converting time zones to UTC:
In [74]: d1 = datetime(2007, 12, 5, 6, 30,tzinfo=pytz.timezone('US/Pacific'))
In [75]: d1
Out[75]: datetime.datetime(2007, 12, 5, 6, 30, tzinfo=<DstTzInfo 'US/Pacific' LMT-1 day, **16:07:00 STD**>)
In [76]: d1.astimezone(pytz.utc)
Out[76]: datetime.datetime(2007, 12, 5, 14, 23, tzinfo=<UTC>)
Why did 6:30am become 2:23pm?
On the other hand, if I use the following approach, I get the expected result:
In [90]: d2 = datetime(2007, 12, 5, 6, 30)
In [91]: uspac = pytz.timezone('US/Pacific')
In [92]: d2_aware = uspac.localize(d2)
In [94]: d2_aware.astimezone(pytz.utc)
Out[94]: datetime.datetime(2007, 12, 5, 14, 30, tzinfo=<UTC>)
Upvotes: 59
Views: 16119
Reputation: 1086
As of Python 3.9, the recommended way is to create datetime with timezone info by using datetime()
, contrary to what was the case when the currently top-rated answer was posted. However, instead of using the 3rd party library pytz
, you should now instead use zoneinfo
from the standard library.
>>> from zoneinfo import ZoneInfo
>>> from datetime import datetime, timedelta
>>> dt = datetime(2020, 10, 31, 12, tzinfo=ZoneInfo("America/Los_Angeles"))
>>> print(dt)
2020-10-31 12:00:00-07:00
>>> dt.tzname()
'PDT'
Upvotes: 0
Reputation: 9427
Unfortunately, creating timezone aware dates using this method doesn't work.
If you are using Django, they have a utility function, make_aware, that does this correctly.
from django.utils.timezone import make_aware
from pytz import timezone
unaware_datetime = datetime(2007, 12, 5)
local_datetime = make_aware(datetime(2007, 12, 5))
specific_datetime = make_aware(datetime(2007, 12, 5), timezone("Australia/Melbourne"))
If you're not using Django, then the source code for the make_aware function may give you inspiration.
Upvotes: 9
Reputation: 21643
I'm revisiting some questions about date and time to see if some of the newer libraries prove more helpful in situations like this (or not). pendulum is one that stores timezone with date and time, making it particularly valuable in situations such as this.
>>> import pendulum
>>> d1 = pendulum.datetime(2007,12,5,6,30, tzinfo='US/Pacific')
>>> d1
<Pendulum [2007-12-05T06:30:00-08:00]>
>>> d1.timezone
<Timezone [US/Pacific]>
>>> d1.astimezone(tz='UTC')
<Pendulum [2007-12-05T14:30:00+00:00]>
Lots of other sweet features too.
Upvotes: 4
Reputation: 2540
What I got is just a workaround, the simple rule is Never create datetime with timezone info by using datetime().
This sample would give you a hint for this. As you see, you could avoid the unexpected difference, once and only you make "naive" datetime (it is, datetime without timezone info) and then localize it (it is not applied when you create datetime on UTC though) :
import pytz
from datetime import datetime
# make Jan 1 on PDT -> UTC
pdt = pytz.timezone("America/Los_Angeles")
pdtnow1 = datetime(2014,1,1, tzinfo=pdt)
pdtnow2 = pdt.localize(datetime(2014,1,1))
pytz.utc.normalize(pdtnow1)
# > datetime.datetime(2014, 1, 1, 7, 53, tzinfo=<UTC>)
pytz.utc.normalize(pdtnow2)
# > datetime.datetime(2014, 1, 1, 8, 0, tzinfo=<UTC>)
# make Jan 1 on UTC -> PDT
utcnow1 = datetime(2014,1,1, tzinfo=pytz.utc)
utcnow2 = pytz.utc.localize(datetime(2014,1,1))
pdt.normalize(utcnow1)
# > datetime.datetime(2013, 12, 31, 16, 0,
# > tzinfo=<DstTzInfo 'America/Los_Angeles' PST-1 day, 16:00:00 STD>)
pdt.normalize(utcnow2)
# > datetime.datetime(2013, 12, 31, 16, 0,
# > tzinfo=<DstTzInfo 'America/Los_Angeles' PST-1 day, 16:00:00 STD>)
Upvotes: 66
Reputation:
From the partial documentation: http://pytz.sourceforge.net/#localized-times-and-date-arithmetic
Unfortunately using the tzinfo argument of the standard datetime constructors ‘’does not work’’ with pytz for many timezones. [...] It is safe for timezones without daylight saving transitions though, such as UTC. [...] The preferred way of dealing with times is to always work in UTC, converting to localtime only when generating output to be read by humans.
Upvotes: 43
Reputation: 142641
Print d2_aware
before .astimezone
and you see PST-1
(Pacific Standard Time) but in first example you have LMT-1
(Local Mean Time) - and probably it can give 7 minutes difference.
But I don't know why pytz
use different timezones.
Upvotes: 0