pytz - Converting UTC and timezone to local time
I think I got it:
pytz.utc.localize(utc_time, is_dst=None).astimezone(tz)
This line first converts the naive (time zone unaware) utc_time
datetime
object to a datetime
object that contains a timezone (UTC). Then it uses the astimezone
function to adjust the time according to the requested time zone.
Converting datetime from one time zone to another using pytz
You can convert from New York time to Frankfurt time by using localize()
to create your naive datetime objects in New York time and astimezone()
to then convert them to Frankfurt (Berlin) time. Using the timezone name (rather than a specific timezone abbreviation that only applies during part of the year) will handle the daylight savings difference for you.
For example:
from datetime import datetime
from pytz import timezone
newyork_tz = timezone('America/New_York')
berlin_tz = timezone('Europe/Berlin')
newyork = newyork_tz.localize(datetime(2018, 5, 1, 8, 0, 0))
berlin = newyork.astimezone(berlin_tz)
print(newyork)
print(berlin)
# OUTPUT
# 2018-05-01 08:00:00-04:00
# 2018-05-01 14:00:00+02:00
Datetime Timezone conversion using pytz
I assume you have these questions:
- why does the first function work for UTC timezone?
- why does it fail for
'US/Eastern'
timezone (DstTzInfo
instance)? - why does the second function work for all provided examples?
The first function is incorrect because it uses d.replace(tzinfo=dsttzinfo_instance)
instead of dsttzinfo_instance.localize(d)
.
The second function is correct most of the time except during ambiguous or non-existing times e.g., during DST transitions -- you can change the behaviour by passing is_dst
parameter to .localize()
: False
(default)/True
/None
(raise an exception).
The first function works for UTC timezone because it has a fixed utc offset (zero) for any date. Other timezones such as America/New_York
may have different utc offsets at different times (Daylight saving time, war time, any time that some local politician might think is a good idea -- it can be anything -- the tz database works in most cases). To implement tzinfo.utcoffset(dt)
, tzinfo.tzname(dt)
, tzinfo.dst(dt)
methods pytz
uses a collection of DstTzInfo
instances each with a different set of (_tzname, _utcoffset, _dst)
attributes. Given dt
(date/time) and is_dst
, .localize()
method chooses an appropriate (in most cases but not always) DstTzInfo
instance from the collection. pytz.timezone('America/New_York')
returns a DstTzInfo
instance with (_tzname, _utcoffset, _dst)
attributes that correspond to some undocumented moment in time (different pytz
versions may return different values -- the current version may return tzinfo
instance that corresponds to the earliest date for which zoneinfo is available -- you don't want this value most of the time: I think the motivation behind the choice of the default value is to highlight the error (passing pytz.timezone
to datetime
constructor or .replace()
method).
To summarize: .localize()
selects appropriate utcoffset, tzname, dst values, .replace()
uses the default (inappropriate) value. UTC has only one set of utcoffset, tzname, dst therefore the default value may be used and .replace()
method works with UTC timezone. You need to pass a datetime object and is_dst
parameter to select appropriate values for other timezones such as 'America/New_York'
.
In principle, pytz
could have called localize()
method to implement utcoffset()
, tzname()
, dst()
methods even if dt.tzinfo == self
: it would make these methods O(log n) in time where n
is number of intervals with different (utcoffset, tzname, dst) values but datetime
constructor and .replace()
would work as is i.e., the explicit localize()
call would be necessary only to pass is_dst
.
Python (datetime) timezone conversion off by 4 minutes
From pytz documentation:
This library differs from the documented Python API for tzinfo implementations; if you want to create local wallclock times you need to use the
localize()
method documented in this document. In addition, if you perform date arithmetic on local times that cross DST boundaries, the result may be in an incorrect timezone (ie. subtract 1 minute from 2002-10-27 1:00 EST and you get 2002-10-27 0:59 EST instead of the correct 2002-10-27 1:59 EDT).
So, you are using pytz incorrectly.
Following is both correct, and erroneous code Following code shows results of your use of pytz (datetime.replace(tzinfo=pytz.timezone)
), and the recommended way of using pytz with datetime (pytz.timezone.localize(datetime)
).
from datetime import datetime, date, time, timezone
from dateutil import tz
import pytz
d = date(2019, 1, 27)
t = time(19, 32, 00)
t1 = datetime.combine(d, t)
t1_epoch = t1.timestamp()
print("t1_epoch " + str(t1_epoch))
print("t1 " + str(t1))
# your approach/code
nytz = pytz.timezone('America/New_York')
t3 = t1.replace(tzinfo=nytz)
t3_epoch = t3.timestamp()
print("t3_epoch " + str(t3_epoch))
print("t3 " + str(t3))
# recommended approach/code using localize
nytz = pytz.timezone('America/New_York')
t6 = nytz.localize(t1)
t6_epoch = t6.timestamp()
print("t6_epoch " + str(t6_epoch))
print("t6 " + str(t6))
Output of above code:
t1_epoch 1548617520.0
t1 2019-01-27 19:32:00
t3_epoch 1548635280.0
t3 2019-01-27 19:32:00-04:56
t6_epoch 1548635520.0
t6 2019-01-27 19:32:00-05:00
t3
is what you are doing, and it is giving incorrect offset (-4:56). Note that POSIX time is also incorrect in this case. POSIX time, by definition, does not change with timezone.
t6
has been created using pytz.timezone.localize()
method, and gives correct UTC offset (-5:00).
Update: Updated language of the answer as one user found the answer confusing.
datetime and timezone conversion with pytz - mind blowing behaviour
The documentation http://pytz.sourceforge.net/ states "Unfortunately using the tzinfo argument of the standard datetime constructors 'does not work' with pytz for many timezones." The code:
t = datetime(
2013, 5, 11, hour=11, minute=0,
tzinfo=pytz.timezone('Europe/Warsaw')
)
doesn't work according to this, instead you should use the localize method:
t = pytz.timezone('Europe/Warsaw').localize(
datetime(2013, 5, 11, hour=11, minute=0))
How to convert a UTC datetime to a local datetime using only standard library?
I think I figured it out: computes number of seconds since epoch, then converts to a local timzeone using time.localtime, and then converts the time struct back into a datetime...
EPOCH_DATETIME = datetime.datetime(1970,1,1)
SECONDS_PER_DAY = 24*60*60
def utc_to_local_datetime( utc_datetime ):
delta = utc_datetime - EPOCH_DATETIME
utc_epoch = SECONDS_PER_DAY * delta.days + delta.seconds
time_struct = time.localtime( utc_epoch )
dt_args = time_struct[:6] + (delta.microseconds,)
return datetime.datetime( *dt_args )
It applies the summer/winter DST correctly:
>>> utc_to_local_datetime( datetime.datetime(2010, 6, 6, 17, 29, 7, 730000) )
datetime.datetime(2010, 6, 6, 19, 29, 7, 730000)
>>> utc_to_local_datetime( datetime.datetime(2010, 12, 6, 17, 29, 7, 730000) )
datetime.datetime(2010, 12, 6, 18, 29, 7, 730000)
Python pytz timezone conversion returns values that differ from timezone offset for different dates
Assuming you are on Linux or a BSD, if you run 'zdump -v US/Eastern' you will see the complete list of transitions. It wasn't until 1918 that the US switched to whole hour offsets, probably because of the needs of railroads or telegraph.
US/Eastern Sun Nov 18 16:59:59 1883 UT = Sun Nov 18 12:03:57 1883 LMT isdst=0 gmtoff=-17762
US/Eastern Sun Nov 18 17:00:00 1883 UT = Sun Nov 18 12:00:00 1883 EST isdst=0 gmtoff=-18000
US/Eastern Sun Mar 31 06:59:59 1918 UT = Sun Mar 31 01:59:59 1918 EST isdst=0 gmtoff=-18000
US/Eastern Sun Mar 31 07:00:00 1918 UT = Sun Mar 31 03:00:00 1918 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Oct 27 05:59:59 1918 UT = Sun Oct 27 01:59:59 1918 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Oct 27 06:00:00 1918 UT = Sun Oct 27 01:00:00 1918 EST isdst=0 gmtoff=-18000
US/Eastern Sun Mar 30 06:59:59 1919 UT = Sun Mar 30 01:59:59 1919 EST isdst=0 gmtoff=-18000
US/Eastern Sun Mar 30 07:00:00 1919 UT = Sun Mar 30 03:00:00 1919 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Oct 26 05:59:59 1919 UT = Sun Oct 26 01:59:59 1919 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Oct 26 06:00:00 1919 UT = Sun Oct 26 01:00:00 1919 EST isdst=0 gmtoff=-18000
US/Eastern Sun Mar 28 06:59:59 1920 UT = Sun Mar 28 01:59:59 1920 EST isdst=0 gmtoff=-18000
US/Eastern Sun Mar 28 07:00:00 1920 UT = Sun Mar 28 03:00:00 1920 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Oct 31 05:59:59 1920 UT = Sun Oct 31 01:59:59 1920 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Oct 31 06:00:00 1920 UT = Sun Oct 31 01:00:00 1920 EST isdst=0 gmtoff=-18000
[...]
US/Eastern Sun Mar 8 06:59:59 2015 UT = Sun Mar 8 01:59:59 2015 EST isdst=0 gmtoff=-18000
US/Eastern Sun Mar 8 07:00:00 2015 UT = Sun Mar 8 03:00:00 2015 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Nov 1 05:59:59 2015 UT = Sun Nov 1 01:59:59 2015 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Nov 1 06:00:00 2015 UT = Sun Nov 1 01:00:00 2015 EST isdst=0 gmtoff=-18000
US/Eastern Sun Mar 13 06:59:59 2016 UT = Sun Mar 13 01:59:59 2016 EST isdst=0 gmtoff=-18000
US/Eastern Sun Mar 13 07:00:00 2016 UT = Sun Mar 13 03:00:00 2016 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Nov 6 05:59:59 2016 UT = Sun Nov 6 01:59:59 2016 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Nov 6 06:00:00 2016 UT = Sun Nov 6 01:00:00 2016 EST isdst=0 gmtoff=-18000
US/Eastern Sun Mar 12 06:59:59 2017 UT = Sun Mar 12 01:59:59 2017 EST isdst=0 gmtoff=-18000
US/Eastern Sun Mar 12 07:00:00 2017 UT = Sun Mar 12 03:00:00 2017 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Nov 5 05:59:59 2017 UT = Sun Nov 5 01:59:59 2017 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Nov 5 06:00:00 2017 UT = Sun Nov 5 01:00:00 2017 EST isdst=0 gmtoff=-18000
US/Eastern Sun Mar 11 06:59:59 2018 UT = Sun Mar 11 01:59:59 2018 EST isdst=0 gmtoff=-18000
US/Eastern Sun Mar 11 07:00:00 2018 UT = Sun Mar 11 03:00:00 2018 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Nov 4 05:59:59 2018 UT = Sun Nov 4 01:59:59 2018 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Nov 4 06:00:00 2018 UT = Sun Nov 4 01:00:00 2018 EST isdst=0 gmtoff=-18000
[...]
US/Eastern Sun Mar 9 06:59:59 2498 UT = Sun Mar 9 01:59:59 2498 EST isdst=0 gmtoff=-18000
US/Eastern Sun Mar 9 07:00:00 2498 UT = Sun Mar 9 03:00:00 2498 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Nov 2 05:59:59 2498 UT = Sun Nov 2 01:59:59 2498 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Nov 2 06:00:00 2498 UT = Sun Nov 2 01:00:00 2498 EST isdst=0 gmtoff=-18000
US/Eastern Sun Mar 8 06:59:59 2499 UT = Sun Mar 8 01:59:59 2499 EST isdst=0 gmtoff=-18000
US/Eastern Sun Mar 8 07:00:00 2499 UT = Sun Mar 8 03:00:00 2499 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Nov 1 05:59:59 2499 UT = Sun Nov 1 01:59:59 2499 EDT isdst=1 gmtoff=-14400
US/Eastern Sun Nov 1 06:00:00 2499 UT = Sun Nov 1 01:00:00 2499 EST isdst=0 gmtoff=-18000
Related Topics
Opencv Python Rotate Image by X Degrees Around Specific Point
How to Escape Curly-Brackets in F-Strings
Matplotlib Bar Chart with Dates
Python: Open File in Zip Without Temporarily Extracting It
Using Cprofile Results with Kcachegrind
How to Compare Two JSON Objects with the Same Elements in a Different Order Equal
Return and Yield in the Same Function
Enable Python to Connect to MySQL via Ssh Tunnelling
Prevent Plot from Showing in Jupyter Notebook
Checking File Permissions in Linux with Python
What's the Difference Between "Update" and "Update_Idletasks"
Print Current Call Stack from a Method in Code
Generate a List of Datetimes Between an Interval