Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python (datetime) timezone conversion off by 4 minutes

when I run this code:

#!/usr/bin/env python3
from datetime import datetime, timedelta
from dateutil import tz
from pytz import timezone

time = "2020-01-15 10:14:00"
time = datetime.strptime(time, "%Y-%m-%d %H:%M:%S")

print("time1 = " + str(time))

time = time.replace(tzinfo=timezone('America/New_York'))
print("time2 = " + str(time))

time = time.astimezone(tz.gettz('UTC')) # explicity convert to UTC time
print("time3 = " + str(time))

time = datetime.strftime(time, "%Y-%m-%d %H:%M:%S")  # output format
print("done time4 = " + str(time))

I get this output:

time1 = 2020-01-15 10:14:00
time2 = 2020-01-15 10:14:00-04:56
time3 = 2020-01-15 15:10:00+00:00
done time4 = 2020-01-15 15:10:00

I would have expected the final time to be "2020-01-15 15:14:00" anyone have any ideas why it's off by 4 mintutes? I don't understand why the offset in time2 would by "-04:56" instead of "-05:00"

like image 708
Daniel E Avatar asked Apr 02 '20 16:04

Daniel E


1 Answers

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.

like image 181
narendra-choudhary Avatar answered Nov 17 '22 06:11

narendra-choudhary