Inconsistent datetime parse timezone in Python - python

When I run the following in Python 3.X
import datetime
DATE_TS_FORMAT = '%Y-%m-%d %H:%M:%S.%f %Z'
date_ts = datetime.datetime(2019, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)
date_ts = date_ts.strftime(DATE_TS_FORMAT)
print(date_ts)
date_ts = datetime.datetime.strptime(date_ts, DATE_TS_FORMAT)
date_ts = date_ts.strftime(DATE_TS_FORMAT)
print(date_ts)
I get
2019-01-02 03:04:05.000000 UTC
2019-01-02 03:04:05.000000
Why did the timezone information disappear and how can I fix this issue?

Inconsistent indeed... The point is that %Z makes strptime accept certain strings (GMT, UTC and any value in time.tzname - docs), but doesn't actually make anything out of it. Ex:
from datetime import datetime
s = "2019-01-02 03:04:05.000000 UTC"
dt = datetime.strptime(s, '%Y-%m-%d %H:%M:%S.%f %Z')
print(repr(dt))
# datetime.datetime(2019, 1, 2, 3, 4, 5)
The resulting datetime object is naive; no sign of UTC anymore.
To account for this behavior, you could post-process the datetime object, something like
if "UTC" in s:
dt = dt.replace(tzinfo=timezone.utc)
(which I think is a bit painful...) or replace "UTC" with something that %z parses to UTC1,
dt = datetime.strptime(s.replace("UTC", "+00:00"), '%Y-%m-%d %H:%M:%S.%f %z')
print(repr(dt))
# datetime.datetime(2019, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)
(which I think is a bit ugly...) or use a suitable parser, e.g.
from dateutil.parser import parse
dt = parse(s)
print(repr(dt))
# datetime.datetime(2019, 1, 2, 3, 4, 5, tzinfo=tzutc())
print(dt.strftime('%Y-%m-%d %H:%M:%S.%f %Z'))
# 2019-01-02 03:04:05.000000 UTC
(which will be a bit slower if performance is an issue...).
1 IMO, this is inconsistent as well; "+00:00" could also be the UTC offset of some time zone that happens to have a UTC offset of 0 hours at that time...

Related

Python time zone conversion from UTC to EST

I have the below list in python.
[['File_1','2021-09-09 07:05:10'],['File_2','2021-09-08 08:05:11']]
The above timestamp is a string in UTC timezone. I would like to convert this to EST timezone.
I tried using pytz package using
datetime.strptime(timestamp,'%Y-%m-%d %H:%M:%S').astimezone(pytz.timezone('US/Eastern'))
but it gives me result like
['File_1',datetime.datetime(2021,09,03,4,20,5)].
The format of date time is not as expected.
you need to set UTC first, then convert to the desired tz:
from datetime import datetime, timezone
from zoneinfo import ZoneInfo # Python 3.9+ standard lib
l = [['File_1','2021-09-09 07:05:10'],['File_2','2021-09-08 08:05:11']]
out = [[i[0], datetime.fromisoformat(i[1]) # Python 3.7+
.replace(tzinfo=timezone.utc)
.astimezone(ZoneInfo("America/New_York"))] for i in l]
print(out)
# [['File_1', datetime.datetime(2021, 9, 9, 3, 5, 10, tzinfo=zoneinfo.ZoneInfo(key='America/New_York'))], ['File_2', datetime.datetime(2021, 9, 8, 4, 5, 11, tzinfo=zoneinfo.ZoneInfo(key='America/New_York'))]]
# with pytz:
import pytz
outp = [[i[0], datetime.fromisoformat(i[1]) # Python 3.7+
.replace(tzinfo=timezone.utc)
.astimezone(pytz.timezone("America/New_York"))] for i in l]
print(outp)
# [['File_1', datetime.datetime(2021, 9, 9, 3, 5, 10, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)], ['File_2', datetime.datetime(2021, 9, 8, 4, 5, 11, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)]]
If you want a string instead of datetime object, use strftime or even simpler: .isoformat().
You can use the below snippet to get your output in the same format as your input
from datetime import datetime
import pytz
from pytz import timezone
timestamp = '2021-09-09 07:05:10'
datetime.strptime(timestamp,'%Y-%m-%d %H:%M:%S').astimezone(pytz.timezone('US/Eastern')).strftime("%Y-%m-%d %H:%M:%S")
# Output
'2021-09-09 03:05:10'
If you wish to display the timezone in the format, you can use
datetime.strptime(timestamp,'%Y-%m-%d %H:%M:%S').astimezone(pytz.timezone('US/Eastern')).strftime("%Y-%m-%d %H:%M:%S %Z%z")
# Output
'2021-09-09 03:05:10 EDT-0400'
Here's one way to convert it to EST
1st. Declare the list, and identify the date you want to convert as string
list = [['File_1','2021-09-09 07:05:10'],['File_2','2021-09-08 08:05:11']]
date_to_convert = list[1][1]
2nd. Import the needed libraries
import pytz
from datetime import datetime,timezone
3rd. Convert the string to date time
d = datetime.fromisoformat(date_to_convert)
4th. Declare datetime timezone as utc.
d = date_to_string.replace(tzinfo=timezone.utc)
print(d.isoformat())
# the output for the above: '2021-09-08T08:05:11+00:00'
5th. Set the format and convert to EST
fmt = '%Y-%m-%d %H:%M:%S'
est_date = d.astimezone(pytz.timezone('US/Eastern')).strftime(fmt)
print(est_date)
# the output for the above: '2021-09-08 04:05:11'
USE THIS WAY REMBER UPERCASE AND LOWERCASE ALSO MATTER
import time
timer = time.strftime("%Y-%m-%d -- %H:%M:%S %p")
print(timer)

convert given time from a given timezone to UTC

I have two inputs time 00:00 and timezone 'Asia/Kolkata'
I want to convert this to UTC time like '18.30'
I don't want to add or subtract offsets because it may affect the day light saving
what i did is
local = pytz.timezone ("UTC")
nativetime = datetime.strptime (setTime,frmt)
local_dt = local.localize(nativetime, is_dst=None)
utc_dt = local_dt.astimezone(pytz.utc)
but this doesn't change anything, the time is not converted to UTC
Please help
Something like this, assuming you're on py3:
>>> import datetime
>>> import pytz
>>> tz = pytz.timezone('Asia/Kolkata')
>>> dt = datetime.datetime(2020, 8, 4, 0, 0, tzinfo=tz)
>>> dt.astimezone(pytz.utc)
datetime.datetime(2020, 8, 3, 18, 7, tzinfo=<UTC>)
>>>
Since you say you're new to Python, it might be good to skip pytz since it's going to be deprecated with Python 3.9. You can use dateutil instead, which can be replaced more easily with zoneinfo in Python 3.9.
from datetime import datetime, timezone
from dateutil.tz import gettz
# assuming you have something like
dt_naive = datetime.strptime('2020-08-05', '%Y-%m-%d')
# dt_naive has no time zone info, so set it:
dt_aware = dt_naive.replace(tzinfo=gettz('Asia/Kolkata'))
# now you can convert to another timezone using .astimezone:
dt_aware_utc = dt_aware.astimezone(timezone.utc)
# datetime.datetime(2020, 8, 4, 18, 30, tzinfo=datetime.timezone.utc)
# -> 5:30 hours behind, which matches dt_aware.utcoffset()
#thebjorn gave me the answer
here is what i did
def utc_to_local(utc_dt,local_tz):
local_dt = utc_dt.replace(tzinfo=pytz.utc).astimezone(local_tz)
return local_tz.normalize(local_dt)
setTime='00:00:00'
setZone='Asia/Kolkata'
datePart = str(datetime.utcnow()).split(' ')[0]
dateTimeUtcStr = datePart+' '+str(setTime)
tz = pytz.timezone('Asia/Kolkata')
tz_utc = pytz.timezone('UTC')
dateTimeRef = datetime.strptime(dateTimeUtcStr, '%Y-%m-%d %H:%M:%S')
#local to utc
tzUtc = pytz.timezone('UTC')
local_dt = tz.localize(dateTimeRef, is_dst=None)
utc_dt = local_dt.astimezone(pytz.utc)
print(utc_dt)
#utc to local
altTime = utc_to_local(utc_dt,tz)
print(altTime)

How to render timestamp according to the timezone in Python

I have two datetime objects, they represent the same datetime value in different timezones. I would like to convert them to POSIX timestamp. However appearently calling datetime.timestamp() returns a value regardless of the timezone.
from datetime import datetime
import pytz
dt = datetime(2020, 7, 26, 6, 0)
utc_dt = pytz.utc.localize(dt) # datetime.datetime(2020, 7, 26, 6, 0, tzinfo=<UTC>)
bp = pytz.timezone("Europe/Budapest")
bp_dt = utc_dt.astimezone(bp) # datetime.datetime(2020, 7, 26, 8, 0, tzinfo=<DstTzInfo 'Europe/Budapest' CEST+2:00:00 DST>)
utc_dt.timestamp() # 1595743200.0
bp_dt.timestamp() # 1595743200.0
The documentation of datetime.timestamp() says the following:
For aware datetime instances, the return value is computed as:
(dt - datetime(1970, 1, 1, tzinfo=timezone.utc)).total_seconds()
Running utc_dt - bp_dt returns datetime.timedelta(0). So it seems it calculates with the UTC value of the datetime objects.
I use Python in a web stack. I want the backend to deal with the timezone handling and the client to recieve the precalculated datetime values in the user's timezone in the API responses.
What is the Pythonic way to get timezone aware timestamps?
In short, I would not recommend doing this because you can create a total mess, see my comment.
Technically, you could do it by simply replacing the tzinfo property of the datetime object with UTC. Note that I'm using dateutil.tz here so I can set the initial timezone directly (no localize()).
from datetime import datetime, timezone
from dateutil import tz
dt = datetime(2020, 7, 26, 6, 0, tzinfo=tz.gettz("Europe/Budapest"))
# dt.utcoffset()
# >>> datetime.timedelta(seconds=7200)
# POSIX timestamp that references to 1970-01-01 UTC:
ts_posix = dt.timestamp()
# timestamp that includes the UTC offset:
ts = dt.replace(tzinfo=timezone.utc).timestamp()
# ts-ts_posix
# >>> 7200.0

Why does Convertingt EST datetime object to UTC unix timestamp and back to EST add 5 hours?

Why does calling thee below 2 functions on dt result in adding 5 hours? I figured it would remain the same.
from datetime import datetime, time, timedelta
from pytz import timezone
def est_datetime_to_utc_timestamp(dt):
dt_utc = dt.astimezone(timezone('UTC'))
ts = int(dt_utc.strftime("%s"))
return ts
def utc_timestamp_to_est_datetime(ts):
dt = datetime.fromtimestamp(ts, timezone('UTC'))
dt = dt.astimezone(timezone('America/New_York'))
return dt
dt = timezone('America/New_York').localize(datetime(2017, 11, 27, 0, 0))
utc_timestamp_to_est_datetime(est_datetime_to_utc_timestamp(dt))
> datetime.datetime(2017, 11, 27, 5, 0, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)
strftime("%s") is not defined in every implementation.
Replacing it with .timestamp() works for Python 3.3+, and gives the correct result.
Alternatively, you can use (dt - datetime(1970, 1, 1, tzinfo=timezone.utc)).total_seconds() if not on Python 3.3+.

What datetime format string is 2017-01-05T14:23:33.986-0500 in Python

I have a string:
t = "2017-01-05T14:23:33.986-0500"
I need to convert it to a Python date.
I used:
t_obj = datetime.strptime(t, '%Y-%m-%dT%H:%M:%S.%f')
I think it is in YYYY-MM-DD with time as HH:MM:SS.sss , but am not able to figure out what -0500 could be...could it be subtracting -5 hrs for UTC?
Any help would be greatly appreciated
%z is what you need it's the timezone offset from UTC, see the docs
%z - UTC offset in the form +HHMM or -HHMM (empty string if the the object
is naive). (empty), +0000, -0400, +1030
In [89]:
t= "2017-01-05T14:23:33.986-0500"
dt.datetime.strptime(t, '%Y-%m-%dT%H:%M:%S.%f%z')
Out[89]:
datetime.datetime(2017, 1, 5, 14, 23, 33, 986000, tzinfo=datetime.timezone(datetime.timedelta(-1, 68400)))
EdChum's answer is definitely correct. However, there is an easier way to go about parsing dates - python-dateutil:
>>> from dateutil.parser import parse
>>> parse("2017-01-05T14:23:33.986-0500")
datetime.datetime(2017, 1, 5, 14, 23, 33, 986000, tzinfo=tzoffset(None, -18000))
The parse() function is very robust and able to handle a wide variety of date formats:
>>> parse("Friday January 6, 2017 11:12 AM")
datetime.datetime(2017, 1, 6, 11, 12)
This is on 3.6.0 with dateutil 2.6.0.

Categories

Resources