What's a good way of converting timezone of a timestamp? - python-3.x

I have a string in this format: 09/20/2020 10:30 AM
That timestamp is in Eastern Timezone.
I need to obtain the UTC equivalent, but in the following ISO format: 2020-09-20T14:30:00.0000Z
I've tried a few things but there doesn't seem to be a clean/short way of converting it.
So far I've tried:
dtSept = "09/20/2020 10:00 PM"
dtSeptTZ = pytz.timezone('US/Eastern').localize(datetime.datetime.strptime(dtSept, "%m/%d/%Y %I:%M %p")).isoformat(timespec='milliseconds')
dtSeptTZ at this point is a string object.
If I have to convert its TimeZone and format it, I have to execute the following which each take a datetime object but return a string.
dtSeptTZ.astimezone(pytz.timezone('Etc/UTC'))
dtSeptTZ.strftime("%Y-%m-%dT%I:%M.%fZ")
Is there a clean/short way of getting the proper output without coverting it back and forth between string and datetime?
Many thanks.

due to the immanent deprecation of pytz, I'd suggest to use dateutil. The usage of dateutil also transforms nicely to Python 3.9's zoneinfo.
from datetime import datetime, timezone
from dateutil.tz import gettz
dtSept = "09/20/2020 10:00 PM"
# string to datetime object
dt = datetime.strptime(dtSept, "%m/%d/%Y %I:%M %p")
# set tzinfo to appropriate time zone; (!) use "localize" instead with pytz timezone class
dt = dt.replace(tzinfo=gettz('US/Eastern'))
# to UTC (could use any other tz here)
dt_utc = dt.astimezone(timezone.utc)
# to ISO format string:
print(dt_utc.isoformat())
>>> 2020-09-21T02:00:00+00:00

Related

Using timezone with openpyxl

I need to add a date in an excel file.
I use timezones on these dates. It works very well with django rest framework. (My GET requests return the date with this format: 2022-07-23T13:19:59+02:00) Same in Django admin, the Europe/Paris timezone is well taken into account (+02:00).
However, when I use openpyxl, the indicated time is 2h late (it takes the UTC timezone).
sheet.append([date_recorded.strftime("%d/%m/%Y %H:%M:%S")])
Same thing if I print this date in console. (2022-07-11 15:19:50+00:00)
How to correct this?
You can simply convert it to your desired zone like this:
from dateutil import tz
utctime = "YOUR CURRENT VALUE OF DATETIME"
from_zone = tz.gettz("UTC")
to_zone = tz.gettz("yourzone")
utctime = utctime.replace(tzinfo=from_zone)
new_time = utctime.astimezone(to_zone)
Since you are using django, you can use built-in get_current_timezone to convert datetime objects to the local timezone:
from django.utils import get_current_timezone
timezone = get_current_timezone()
date_recorded = date_recorded.astimezone(timezone)
sheet.append([date_recorded.strftime("%d/%m/%Y %H:%M:%S")])

Why does this python datetime format not convert the string of the same format into a datetime object successfully?

import datetime as dt
time_str = '2022-02-25 18:37:46.594385+00:00'
Then I try to convert this into a datetime object as follows:
dt.datetime.strptime(time_str,'%Y-%m-%d %H:%M:%S.%f%z')
However it results in the following error:
ValueError: time data '2022-02-25 18:37:46.594385+00:00' does not match format '%Y-%m-%d %H:%M:%S.%f%z'
The error appears to be coming from the %z section of the format, but overall I do not understand why this is not working, since it seems the specified format does match the string format. If you could help identify any issues and suggest a solution to convert the example time_str into a datetime object successfully. Thanks!

Python strptime parse timezone format "GMT+-H"

I'm using python 3.7 and trying to figure out the correct format to get this code to work
dt = datetime.strptime("4 January 2022, 22:03 GMT-5", "%-d %b %Y, %H:%M %Zz")
The above line always fails. Is there something I can do to get it to parse? I am assuming its failing on the "GMT-5 part"
Edit:
Adding context, the input string is scraped from a website so I need to find a way to turn it into a python datetime object so by code can understand when the event took place. Im not really sure how I could "In Code" change the input to match the required format of strptime
%z parsing directive won't parse an hour-only UTC offset (docs: requires ±HHMM[SS[.ffffff]] form). But you can derive a timezone object from a timedelta and set it like
from datetime import datetime, timedelta, timezone
s = "4 January 2022, 22:03 GMT-5"
parts = s.split('GMT')
dt = (datetime.strptime(parts[0].strip(), "%d %B %Y, %H:%M") # parse to datetime w/o offset
.replace(tzinfo=timezone(timedelta(hours=int(parts[1]))))) # add UTC offset
print(dt)
# 2022-01-04 22:03:00-05:00
You're using the wrong format for the month and invalid text for the UTC offset (it has to be four digits, as described in the documentation):
>>> datetime.datetime.strptime("4 January 2022, 22:03 GMT-0500", "%d %B %Y, %H:%M %Z%z")
datetime.datetime(2022, 1, 4, 22, 3, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=68400), 'GMT'))

Convert string to datetime in local timezone Python

I have datetime in string needing to be converted in datetime format. Below is my code but it returns error. what I am missing here.
from datetime import datetime
LocalStartTime='2020-09-17T10:55:06.4000000+1000'
datetime_object = datetime.strptime(LocalStartTime, '%Y-%m-%dT%H:%M:%S.%f%z')
Required output shd be date converted in current timezone to format like: '2020-09-17 20:55:06' whatever will be the actual value.
returns below error:
ValueError: time data '2020-09-17T10:55:06.4000000+1000' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
from datetime documentation:
When used with the strptime() method, the %f directive accepts from one to six digits and zero pads on the right. %f is an extension to the set of format characters in the C standard (but implemented separately in datetime objects, and therefore always available).
you have one too many zeros in the float part after the seconds part.
the limitation is 6 digits.
from datetime import datetime
LocalStartTime='2020-09-17T10:55:06.400000+1000'
datetime_object = datetime.strptime(LocalStartTime, '%Y-%m-%dT%H:%M:%S.%f%z')
should work
Edit:
after the OP edited and asked about converting to a different timestamp:
seems like what you're looking for is timestamp() and fromtimestamp()
you can get the timestamp which is a posix timestamp represented as float, and convert it back to datetime object with fromtimestamp() if you want to remove the float part after the seconds you can convert the time stamp to int.
datetime.fromtimestamp(int(datetime_object.timestamp()))

convertion of datetime to numpy datetime without timezone info

Suppose I have a datetime variable:
dt = datetime.datetime(2001,1,1,0,0)
and I convert it to numpy as follows numpy.datetime64(dt) I get
numpy.datetime64('2000-12-31T19:00:00.000000-0500')
with dtype('<M8[us]')
But this automatically takes into account my time-zone (i.e. EST in this case) and gives me back a date of 2001-12-31 and a time of 19:00 hours.
How can I convert it to datetime64[D] in numpy that ignores the timezone information and simply gives me
numpy.datetime64('2001-01-01')
with dtype('<M8[D]')
The numpy datetime64 doc page gives no information on how to ignore the time-zone or give the default time-zone as UTC
I was just playing around with this the other day. I think there are 2 issues - how the datetime.datetime object is converted to np.datetime64, and how the later is displayed.
The numpy doc talks about creating a datatime64 object from a date string. It appears that when given a datetime.datetime object, it first produces a string.
np.datetime64(dt) == np.datetime64(dt.isoformat())
I found that I could add timezone info to that string
np.datetime64(dt.isoformat()+'Z') # default assumption
np.datetime64(dt.isoformat()+'-0500')
Numpy 1.7.0 reads ISO 8601 strings w/o TZ as local (ISO specifies this)
Datetimes are always stored based on POSIX time with an epoch of 1970-01-01T00:00Z
As for display, the test_datetime.py file offers some clues as to the undocumented behavior.
https://github.com/numpy/numpy/blob/280f6050d2291e50aeb0716a66d1258ab3276553/numpy/core/tests/test_datetime.py
e.g.:
def test_datetime_array_str(self):
a = np.array(['2011-03-16', '1920-01-01', '2013-05-19'], dtype='M')
assert_equal(str(a), "['2011-03-16' '1920-01-01' '2013-05-19']")
a = np.array(['2011-03-16T13:55Z', '1920-01-01T03:12Z'], dtype='M')
assert_equal(np.array2string(a, separator=', ',
formatter={'datetime': lambda x :
"'%s'" % np.datetime_as_string(x, timezone='UTC')}),
"['2011-03-16T13:55Z', '1920-01-01T03:12Z']")
So you can customize the print behavior of an array with np.array2string, and np.datetime_as_string. np.set_printoptions also takes a formatter parameter.
The pytz module is used to add further timezone handling:
#dec.skipif(not _has_pytz, "The pytz module is not available.")
def test_datetime_as_string_timezone(self):
# timezone='local' vs 'UTC'
a = np.datetime64('2010-03-15T06:30Z', 'm')
assert_equal(np.datetime_as_string(a, timezone='UTC'),
'2010-03-15T06:30Z')
assert_(np.datetime_as_string(a, timezone='local') !=
'2010-03-15T06:30Z')
....
Examples:
In [48]: np.datetime_as_string(np.datetime64(dt),timezone='local')
Out[48]: '2000-12-31T16:00:00.000000-0800'
In [49]: np.datetime64(dt)
Out[49]: numpy.datetime64('2000-12-31T16:00:00.000000-0800')
In [50]: np.datetime_as_string(np.datetime64(dt))
Out[50]: '2001-01-01T00:00:00.000000Z'
In [51]: np.datetime_as_string(np.datetime64(dt),timezone='UTC')
Out[51]: '2001-01-01T00:00:00.000000Z'
In [52]: np.datetime_as_string(np.datetime64(dt),timezone='local')
Out[52]: '2000-12-31T16:00:00.000000-0800'
In [81]: np.datetime_as_string(np.datetime64(dt),timezone=pytz.timezone('US/Eastern'))
Out[81]: '2000-12-31T19:00:00.000000-0500'

Resources