Convert python timezone aware datetime string to utc time - python

I have a Python datetime string that is timezone aware and need to convert it to UTC timestamp.
'2016-07-15T10:00:00-06:00'
Most of the SO links talks about getting the current datetime in UTC but not on converting the given datetime to UTC.

Hi this was a bit tricky, but here is my, probably far from perfect, answer:
[IN]
import datetime
import pytz
date_str = '2016-07-15T10:00:00-06:00'
# Have to get rid of that bothersome final colon for %z to work
datetime_object = datetime.datetime.strptime(date_str[:-3] + date_str[-2:],
'%Y-%m-%dT%H:%M:%S%z')
datetime_object.astimezone(pytz.utc)
[OUT]
datetime.datetime(2016, 7, 15, 16, 0, tzinfo=<UTC>)

Related

How to convert datetime like `2021-06-25 15:00:08+00:00` to local timezone datetime.datetime python?

I have many datetime.datetime object like 2021-06-25 15:00:08+00:00 where the timezone is different for different data.Eg.another data is 2021-06-24 06:33:06-07:00 .I want to save all of them by converting into a local tmezone.How can I do that?
The datetime.datetime.astimezone() method will return a datetime object with the same UTC time but in the local timezone. For your example times:
>>> dt_1 = datettime.fromisoformat(2021-06-25 15:00:08+00:00)
>>> dt_1.astimezone()
datetime.datetime(2021, 6, 25, 11, 0, 8, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=72000), 'EDT'))
>>> dt_2 = datetime.fromisoformat(2021-06-24 06:33:06-07:00)
>>> dt_2.astimezone()
datetime.datetime(2021, 6, 24, 9, 33, 6, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=72000), 'EDT'))
Since datetime.datetime objects with tzinfo are timezone-aware, the information will be stored in the objects regardless. This is just a handy way to get the local time.
UPDATE, based on a follow-up question below:
astimezone() doesn't depend on the way the datetime object is created. For differently formatted date/time strings, datetime.strptime can be used to create a timezone-aware datetime objects. From the example given in that follow-up question:
>>> dt_3 = datetime.strptime('Sat, 26 Jun 2021 15:00:09 +0000 (UTC)',
'%a, %d %b %Y %H:%M:%S %z (%Z)')
>>> dt_3.astimezone()
datetime.datetime(2021, 6, 26, 11, 0, 9, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=72000), 'EDT'))
You could use pytz library
from datetime import datetime
import pytz
dt_input = datetime.fromisoformat('2021-06-24 06:33:06-07:00')
print(dt_input) # prints datetime in input timezone
local_tz = pytz.timezone('Asia/Kolkata') #provide your timezone here
dt_local = dt_input.astimezone(local_tz)
print(dt_local) #prints in your local timezone as provided above
You can refer to this SO question similar to your question:
How to convert a UTC datetime to a local datetime using only standard library?
EDIT:
Convert any string to datetime object:
You can use strptime('datestring', 'dateformat')
example from your comment:
#This will convert the string to datetime object
datetime.strptime('Sat, 26 Jun 2021 15:00:09 +0000 (UTC)','%a, %d %b %Y %H:%M:%S %z (%Z)')
Once it is converted to datetime object you can convert it to your local timezone as mentioned above

Python convert timestamp to unix

I know these questions have been asked before but I'm struggling to convert a timestamp string to a unix time and figuring out whether the datetime objects are naive or aware
For example, to convert the time "2021-05-19 12:51:47" to unix:
>>> from datetime import datetime as dt
>>> dt_obj = dt.strptime("2021-05-19 12:51:47", "%Y-%m-%d %H:%M:%S")
>>> dt_obj
datetime.datetime(2021, 5, 19, 12, 51, 47)
is dt_obj naive or aware and how would you determine this? The methods on dt_obj such as timetz, tzinfo, and tzname don't seem to indicate anything - does that mean that dt_obj is naive?
Then to get unix:
>>> dt_obj.timestamp()
1621421507.0
However when I check 1621421507.0 on say https://www.unixtimestamp.com then it tells me that gmt for the above is Wed May 19 2021 10:51:47 GMT+0000, ie 2 hours behind the original timestamp?
since Python's datetime treats naive datetime as local time by default, you need to set the time zone (tzinfo attribute):
from datetime import datetime, timezone
# assuming "2021-05-19 12:51:47" represents UTC:
dt_obj = datetime.fromisoformat("2021-05-19 12:51:47").replace(tzinfo=timezone.utc)
Or, as #Wolf suggested, instead of setting the tzinfo attribute explicitly, you can also modify the input string by adding "+00:00" which is parsed to UTC;
dt_obj = datetime.fromisoformat("2021-05-19 12:51:47" + "+00:00")
In any case, the result
dt_obj.timestamp()
# 1621428707.0
now converts as expected on https://www.unixtimestamp.com/:
As long as you don't specify the timezone when calling strptime, you will produce naive datetime objects. You may pass time zone information via %z format specifier and +00:00 added to the textual date-time representation to get a timezone aware datetime object:
from datetime import datetime
dt_str = "2021-05-19 12:51:47"
print(dt_str)
dt_obj = datetime.strptime(dt_str+"+00:00", "%Y-%m-%d %H:%M:%S%z")
print(dt_obj)
print(dt_obj.timestamp())
The of above script is this:
2021-05-19 12:51:47
2021-05-19 12:51:47+00:00
1621428707.0
datetime.timestamp()
Naive datetime instances are assumed to represent local time and this method relies on the platform C mktime() function to perform the conversion.
So using this does automatically apply yours machine current timezone, following recipe is given to calculate timestamp from naive datetime without influence of timezone:
timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)

Converting string (with timezone) to datetime in python

I aim to convert
stringtime = '2020-02-30 10:27:00+01:00'
so that I can compare it to
nowtime = datetime.datetime.utcnow()
using
if nowtime > stringtime:
print(1)
I tried strptime:
datetime.datetime.strptime(stringtime, '%Y-%m-%d %H:%M:%S')
But cannot find a format specification for the timezone in the strptime documentation.
I also tried
pandas.Timestamp(stringtime)
but I get ValueError: could not convert string to Timestamp.
How can this be done?
datetime.datetime.strptime(stringtime, '%Y-%m-%d %H:%M:%S%z')
Will give you the expected result %z is the format (Python3 only), however your original date is invalid as February doesnt have 30 days :)
First of all: Your stringtime is wrong, there exists no February 30th. ;)
You can achieve what you want with dateutil:
import dateutil.parser
stringtime = '2020-03-30 10:27:00+01:00'
dateutil.parser.isoparse(stringtime)
# datetime.datetime(2020, 3, 30, 10, 27, tzinfo=tzoffset(None, 3600))

convert str date to datetime for timezone

I have an API that return this date string
strdate = '2019-10-07T06:09:28.984Z'
How do I convert it to a datetime object?
dt = datetime.datetime.strptime(strdate, '%Y-%m-%d')
If I use strptime like above i get "ValueError: unconverted data remains: T06:09:54.346Z"
What do I do if there is "T" and "Z" included in the string date? I want the data in local time. But is the string really timezone aware so I can convert it properly? In this case I know the timezone, but what if I did not know?
The error is because you're not including the time part in the format string. Do that:
datetime.strptime('2019-10-07T06:09:28.984Z', '%Y-%m-%dT%H:%M:%S.%f%z')
This results in:
datetime.datetime(2019, 10, 7, 6, 9, 28, 984000, tzinfo=datetime.timezone.utc)
If you want to convert this to a local timezone, do that:
from pytz import timezone
dt = datetime.strptime(strdate, '%Y-%m-%dT%H:%M:%S.%f%z')
local_dt = dt.astimezone(timezone('Asia/Tokyo'))
Demo: https://repl.it/repls/RotatingSqueakyCertifications
import datetime
strdate = '2019-10-07T06:09:28.984Z'
dt=datetime.datetime.strptime(strdate, "%Y-%m-%dT%H:%M:%S.%fZ")
print(dt)
# output - 2019-10-07 06:09:28.984000

Python UTC datetime object's ISO format doesn't include Z (Zulu or Zero offset)

Why python 2.7 doesn't include Z character (Zulu or zero offset) at the end of UTC datetime object's isoformat string unlike JavaScript?
>>> datetime.datetime.utcnow().isoformat()
'2013-10-29T09:14:03.895210'
Whereas in javascript
>>> console.log(new Date().toISOString());
2013-10-29T09:38:41.341Z
Option: isoformat()
Python's datetime does not support the military timezone suffixes like 'Z' suffix for UTC. The following simple string replacement does the trick:
In [1]: import datetime
In [2]: d = datetime.datetime(2014, 12, 10, 12, 0, 0)
In [3]: str(d).replace('+00:00', 'Z')
Out[3]: '2014-12-10 12:00:00Z'
str(d) is essentially the same as d.isoformat(sep=' ')
See: Datetime, Python Standard Library
Option: strftime()
Or you could use strftime to achieve the same effect:
In [4]: d.strftime('%Y-%m-%dT%H:%M:%SZ')
Out[4]: '2014-12-10T12:00:00Z'
Note: This option works only when you know the date specified is in UTC.
See: datetime.strftime()
Additional: Human Readable Timezone
Going further, you may be interested in displaying human readable timezone information, pytz with strftime %Z timezone flag:
In [5]: import pytz
In [6]: d = datetime.datetime(2014, 12, 10, 12, 0, 0, tzinfo=pytz.utc)
In [7]: d
Out[7]: datetime.datetime(2014, 12, 10, 12, 0, tzinfo=<UTC>)
In [8]: d.strftime('%Y-%m-%d %H:%M:%S %Z')
Out[8]: '2014-12-10 12:00:00 UTC'
Python datetime objects don't have time zone info by default, and without it, Python actually violates the ISO 8601 specification (if no time zone info is given, assumed to be local time). You can use the pytz package to get some default time zones, or directly subclass tzinfo yourself:
from datetime import datetime, tzinfo, timedelta
class simple_utc(tzinfo):
def tzname(self,**kwargs):
return "UTC"
def utcoffset(self, dt):
return timedelta(0)
Then you can manually add the time zone info to utcnow():
>>> datetime.utcnow().replace(tzinfo=simple_utc()).isoformat()
'2014-05-16T22:51:53.015001+00:00'
Note that this DOES conform to the ISO 8601 format, which allows for either Z or +00:00 as the suffix for UTC. Note that the latter actually conforms to the standard better, with how time zones are represented in general (UTC is a special case.)
Short answer
datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
Long answer
The reason that the "Z" is not included is because datetime.now() and even datetime.utcnow() return timezone naive datetimes, that is to say datetimes with no timezone information associated. To get a timezone aware datetime, you need to pass a timezone as an argument to datetime.now. For example:
from datetime import datetime, timezone
datetime.utcnow()
#> datetime.datetime(2020, 9, 3, 20, 58, 49, 22253)
# This is timezone naive
datetime.now(timezone.utc)
#> datetime.datetime(2020, 9, 3, 20, 58, 49, 22253, tzinfo=datetime.timezone.utc)
# This is timezone aware
Once you have a timezone aware timestamp, isoformat will include a timezone designation. Thus, you can then get an ISO 8601 timestamp via:
datetime.now(timezone.utc).isoformat()
#> '2020-09-03T20:53:07.337670+00:00'
"+00:00" is a valid ISO 8601 timezone designation for UTC. If you want to have "Z" instead of "+00:00", you have to do the replacement yourself:
datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
#> '2020-09-03T20:53:07.337670Z'
The following javascript and python scripts give identical outputs. I think it's what you are looking for.
JavaScript
new Date().toISOString()
Python
from datetime import datetime
datetime.utcnow().isoformat()[:-3]+'Z'
The output they give is the UTC (zulu) time formatted as an ISO string with a 3 millisecond significant digit and appended with a Z.
2019-01-19T23:20:25.459Z
Your goal shouldn't be to add a Z character, it should be to generate a UTC "aware" datetime string in ISO 8601 format. The solution is to pass a UTC timezone object to datetime.now() instead of using datetime.utcnow():
from datetime import datetime, timezone
datetime.now(timezone.utc)
>>> datetime.datetime(2020, 1, 8, 6, 6, 24, 260810, tzinfo=datetime.timezone.utc)
datetime.now(timezone.utc).isoformat()
>>> '2020-01-08T06:07:04.492045+00:00'
That looks good, so let's see what Django and dateutil think:
from django.utils.timezone import is_aware
is_aware(datetime.now(timezone.utc))
>>> True
from dateutil.parser import isoparse
is_aware(isoparse(datetime.now(timezone.utc).isoformat()))
>>> True
Note that you need to use isoparse() from dateutil.parser because the Python documentation for datetime.fromisoformat() says it "does not support parsing arbitrary ISO 8601 strings".
Okay, the Python datetime object and the ISO 8601 string are both UTC "aware". Now let's look at what JavaScript thinks of the datetime string. Borrowing from this answer we get:
let date = '2020-01-08T06:07:04.492045+00:00';
const dateParsed = new Date(Date.parse(date))
document.write(dateParsed);
document.write("\n");
// Tue Jan 07 2020 22:07:04 GMT-0800 (Pacific Standard Time)
document.write(dateParsed.toISOString());
document.write("\n");
// 2020-01-08T06:07:04.492Z
document.write(dateParsed.toUTCString());
document.write("\n");
// Wed, 08 Jan 2020 06:07:04 GMT
Notes:
I approached this problem with a few goals:
generate a UTC "aware" datetime string in ISO 8601 format
use only Python Standard Library functions for datetime object and string creation
validate the datetime object and string with the Django timezone utility function, the dateutil parser and JavaScript functions
Note that this approach does not include a Z suffix and does not use utcnow(). But it's based on the recommendation in the Python documentation and it passes muster with both Django and JavaScript.
See also:
Stop using utcnow and utcfromtimestamp
What is the “right” JSON date format?
In Python >= 3.2 you can simply use this:
>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).isoformat()
'2019-03-14T07:55:36.979511+00:00'
Python datetimes are a little clunky. Use arrow.
> str(arrow.utcnow())
'2014-05-17T01:18:47.944126+00:00'
Arrow has essentially the same api as datetime, but with timezones and some extra niceties that should be in the main library.
A format compatible with Javascript can be achieved by:
arrow.utcnow().isoformat().replace("+00:00", "Z")
'2018-11-30T02:46:40.714281Z'
Javascript Date.parse will quietly drop microseconds from the timestamp.
I use pendulum:
import pendulum
d = pendulum.now("UTC").to_iso8601_string()
print(d)
>>> 2019-10-30T00:11:21.818265Z
There are a lot of good answers on the post, but I wanted the format to come out exactly as it does with JavaScript. This is what I'm using and it works well.
In [1]: import datetime
In [1]: now = datetime.datetime.utcnow()
In [1]: now.strftime('%Y-%m-%dT%H:%M:%S') + now.strftime('.%f')[:4] + 'Z'
Out[3]: '2018-10-16T13:18:34.856Z'
Using only standard libraries, making no assumption that the timezone is already UTC, and returning the exact format requested in the question:
dt.astimezone(timezone.utc).replace(tzinfo=None).isoformat(timespec='milliseconds') + 'Z'
This does require Python 3.6 or later though.
>>> import arrow
>>> now = arrow.utcnow().format('YYYY-MM-DDTHH:mm:ss.SSS')
>>> now
'2018-11-28T21:34:59.235'
>>> zulu = "{}Z".format(now)
>>> zulu
'2018-11-28T21:34:59.235Z'
Or, to get it in one fell swoop:
>>> zulu = "{}Z".format(arrow.utcnow().format('YYYY-MM-DDTHH:mm:ss.SSS'))
>>> zulu
'2018-11-28T21:54:49.639Z'
By combining all answers above I came with following function :
from datetime import datetime, tzinfo, timedelta
class simple_utc(tzinfo):
def tzname(self,**kwargs):
return "UTC"
def utcoffset(self, dt):
return timedelta(0)
def getdata(yy, mm, dd, h, m, s) :
d = datetime(yy, mm, dd, h, m, s)
d = d.replace(tzinfo=simple_utc()).isoformat()
d = str(d).replace('+00:00', 'Z')
return d
print getdata(2018, 02, 03, 15, 0, 14)
pip install python-dateutil
>>> a = "2019-06-27T02:14:49.443814497Z"
>>> dateutil.parser.parse(a)
datetime.datetime(2019, 6, 27, 2, 14, 49, 443814, tzinfo=tzutc())

Categories