UTC Timestamp String to UNIX timestamp - python

I am currently working with a given time in the following format
"2022-03-21T12:14:28.725Z"
I want to compare this time I get from the internet to the local datetime.datetime.utcnow().timestamp() but I can't seem to get the conversion from string to unix timestamp right. Especially with the milliseconds.
I have already tried to use datetime.fromisoformat('2022-03-21T12:14:28.725Z') but no luck there.
To better understand my situation I am doing this to check the time off-set between a Server and my local machine.

Solution:
How do I translate an ISO 8601 datetime string into a Python datetime object?
from dateutil import parser
parser.parse('2022-03-21T12:14:28.725Z')

Related

Python DateTime does not match format when use the function inside celery task

I create a function to get the different between two date time and its working fine, But when i use it in celery it returns the following error:
ValueError: time data '2023-02-16T14:38:33.301574' does not match format '%Y-%m-%d %H:%M:%S.%f'
Any advice please
I recommend not doing this. Python standard library gives you everything you need to deal with ISO 8601 formatted date/time data. I advise you to use datetime.datetime.fromisoformat and datetime.datetime.isoformat instead.

Converting timestamp to unix date python

Here is how the timestamp looks -
2015-07-17 06:01:51.066141+00:00
I'm looking around to convert this to unix date time.
datetime.strptime("2015-07-17 06:01:51.066141+00:00", "%Y-%m-%d %H:%M:%S.%f%z").strftime("%s")
ValueError: 'z' is a bad directive in format '%Y-%m-%d %H:%M:%S.%f%z'
throws error for me, probably because of wrong format being used.
PS: my virtualenv is on python 2.7
ideas please ?
python 2.7 strptime() does not support z directive, either you can use python 3.2+ or some other 3rd party library like dateutil.
For Python 2.7 use arrow:
import arrow
date_str = "2015-07-17 06:01:51.066141+00:00"
unix_time = arrow.get(date_str).timestamp
On PY3 (verified on 3.4), using only standard libs
The date string you show will not be parsed by the standard python datetime library since it has a colon in the timezone (see here). The colon can be easily removed since it's always in the same position (or use rfind to find its index starting from the right). Your simplest solution is:
import datetime
date_str = "2015-07-17 06:01:51.066141+00:00"
date_str_no_colon = date_str[:-3]+date_str[-2:] # remove last colon
dt_obj = datetime.datetime.strptime(date_str_no_colon, "%Y-%m-%d %H:%M:%S.%f%z")
unix_time = dt_obj.timestamp()
Note that arrow should still work with PY3, and is a better solution in general- you don't want to get into datetime parsing wars with python. It will win.
The way to parse the date is not right. You'll either need to parse it by hand, find another library (for example the dateutil.parser.parse method that will parse your string directly without supplying format string) that supports that format or make the timestamp in another format. Even with newer versions of python the %z directive does not accept TZ offsets in the +/-HH:MM format (with colon).
As the source of the timestamp is django.DateTimeField maybe this question can help?
For converting to unix timestamp you seem to have to do some work since there does not seem to be a direct method for that:
(t - datetime.utcfromtimestamp(0)).total_seconds()
where t is the datetime (assuming it's in UTC and there is no tzinfo) you want to convert to POSIX timestamp. If the assumption is not correct you need to put tzinfo in the zero timestamp you subtract as shown below where the assumption does not hold.
If you want to use dateutil.parser the complete solution would be:
(dateutil.parser.parse(timestamp) - datetime.utcfromtimestamp(0).replace(tzinfo=utc()).total_seconds()
strptime() has no support for timezones.
So, you can make the conversion ignoring the timezone in the following way:
datetime.strptime("2015-07-17 06:01:51.066141", "%Y-%m-%d %I:%M:%S.%f").strftime("%s")
'1437102111'
Or in order to avoid using %s, as suggested below in the commments :
from datetime import datetime
(datetime.strptime("2015-07-17 06:01:51.066141", "%Y-%m-%d %I:%M:%S.%f") - datetime(1970, 1, 1)).total_seconds()
1437112911.066141
Notice this is a working version for Python 2, you can also check solutions for other versions here
Otherwise, you will have to use other libraries (django.utils or email.utils) that support timezones, or implement the timezone parsing on your own.
P.S. :
strptime docs appear to have support for timezone, but in fact it has not been implemented. Try :
datetime.strptime("2015-07-17 06:01:51.066141+00:00", "%Y-%m-%d %I:%M:%S.%f%z").strftime("%s")
and you will see that it is not supported. You can also verify it by searching more about strptime()
There are two parts:
to convert "2015-07-17 06:01:51.066141+00:00" into a datetime object that represents UTC time, see Convert timestamps with offset to datetime obj using strptime. Or If you know that the utc offset is always +0000:
from datetime import datetime
utc_time = datetime.strptime(time_string, "%Y-%m-%d %H:%M:%S.%f+00:00")
to convert the UTC time to POSIX timestamp (unix time), see Converting datetime.date to UTC timestamp in Python:
from datetime import datetime
timestamp = (utc_time - datetime(1970, 1, 1)).total_seconds()

Assign timezone to a Python datetime [duplicate]

This question already has answers here:
pytz localize vs datetime replace
(4 answers)
Closed 8 years ago.
Assume that I have a timezone-less datetime object:
import datetime
import pytz
fmt = "%Y-%m-%d %H:%M:%S %Z%z"
dtUnaware = datetime.datetime(1979,2,20,6)
print(dtUnaware.strftime(fmt))
This yields:
1979-02-20 06:00:00
So far, so good. Now, I want to assign a timezone to this object. It seems like I could use either datetime.replace or pytz.localize.
First:
dtAware1 = dtUnaware.replace(tzinfo=pytz.timezone('Asia/Jerusalem'))
print(dtAware1.strftime(fmt))
returns: 1979-02-20 06:00:00 LMT+0221. Secondly:
dtAware2 = pytz.timezone('Asia/Jerusalem').localize(dtUnaware, is_dst=None)
print(dtAware2.strftime(fmt))
returns 1979-02-20 06:00:00 IST+0200.
What's wrong with the first method? It seems to assign a wrong timezone. Am I doing something wrong?
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... Unfortunately these
issues cannot be resolved without modifying the Python datetime
implementation (see PEP-431)
My reading of that is that a pytz timezone is not exactly the same thing as a standard timezone. If you had a genuine timezone, first method should be good, but you have not.
There is a flaw in the datetime API: when you assign a timezone to it, the timezone is not given the opportunity to know the date and time it should be configured for. The historical database that pytz uses goes back a long way, often to periods when the timezone name or offset were different than the ones in use today. Without being given the chance to adjust to a specific date period, the details of the timezone may be wrong.
Using localize is the way around this problem, since both the date and timezone are available within the function at the same time.

How to remove the tzinfo completely from the time after converting to UTC in Python?

I came across this exact issue, and I can't figure out how to achieve the solution in my case.
Guido says
The solution is to remove the tzinfo completely from the time after
converting to UTC.
This is what I have tried:
date_time = parser.parse(i.pubDate.text)
news.publication_date = date_time.replace(tzinfo=None).date()
And I get the same error:
NotImplementedError: DatetimeProperty publication_date_time can only support UTC. Please derive a new Property to support alternative timezones.
So it seems I have to convert the date to UTC first. And here my research has failed me.
I came across this solution:
The solution suggested is this:
def date_time_to_utc(date_time):
tz = pytz.timezone('???')
return tz.normalize(tz.localize(date_time)).astimezone(pytz.utc)
But I don't have the timezone. I am scraping the date from a html source. So the timezone could really be from anywhere in the world. Is there no easy and reliable way to convert a date time to UTC?
I could use both dateutil and pytz to achieve this. Many Thanks.
UPDATE
It has been a really long day. I have misread the stack trace. However the question remains valid.
date_time = (datetime}2015-01-13 18:13:26+00:00
news.publication_date_time = date_time
This caused the crash. And it seems by doing this, I pass the unit test:
news.publication_date_time = date_time.replace(tzinfo=None)
Is this the correct way converting a GMT 0 datetime to UTC datetime? Or in fact any timezone to UTC?
Is this the correct way converting a GMT 0 datetime to UTC datetime? Or in fact any timezone to UTC?
If aware datetime object is already in UTC (+0000) then your formula works:
naive_utc = aware_utc.replace(tzinfo=None)
where aware_utc is a timezone-aware datetime object that represents time in UTC.
But if aware datetime object is not in UTC; it fails. You should take into account a (possibly) non-zero UTC offset in the general case:
assert aware.tzinfo is not None and aware.utcoffset() is not None
# local time = utc time + utc offset (by definition)
# -> utc = local - offset
naive_utc = aware.replace(tzinfo=None) - aware.utcoffset()
where aware is a timezone-aware datetime object in an arbitrary timezone.
But I don't have the timezone. I am scraping the date from a html
source. So the timezone could really be from anywhere in the world. Is
there no easy and reliable way to convert a date time to UTC? I could
use both dateutil and pytz to achieve this. Many Thanks.
No. dateutil, pytz won't help you unless the date string itself contains the timezone (or at least its utc offset).
Remember: It is always noon somewhere on Earth i.e., if you collect date/time strings from different places on Earth then you can't compare them unless you attach the corresponding timezones. You can't convert it to UTC, you can't get a valid POSIX timestamp if you don't know the source timezone for the date.
I'm an idiot and it's late here, this time I read the question.
tstmp= date_time.replace(tzinfo=utc).total_seconds()
naive_date = datetime.utcfromtimestamp(tstmp)
First answer will just give you the current naive time
Try this:
dateTime = dateTime.replace(tzinfo=None)
dtUtcAware = pytz.UTC.localize(dateTime)

Django timezone: feeling a bit confused

So, we have 'Europe/Moscow' TZ in our settings.
Currently this means daylight saving (this is going to change in the future, but at the moment it's UTC+03/04).
I understand that this TZ is used when saving dates to the DB, and when extracting them.
Now, I have to serialize the datetime object to ISO string, including the UTC offset. What is the correct way of doing this?
The dates don't contain the TZ info (i.e. d.strftime('%z') is empty)
I think I could convert them to UTC and serialize with +00:00, but how do I convert them to UTC if I don't know if the specific date is +03 (Moscow winter) or +04 (Moscow summer)
how do I convert them to UTC if I don't know if the specific date is +03 (Moscow winter) or +04 (Moscow summer)
There is no need for UTC conversion, pytz handles such thing for you.
Here's the code to convert from timezone-naive datetime to ISO with timezone offset:
from datetime import datetime
from pytz import timezone
server_timezone = timezone('Europe/Moscow')
server_timezone.localize(datetime(2011, 1, 1)).isoformat()
>>> '2011-01-01T00:00:00+03:00'
server_timezone.localize(datetime(2011, 7, 1)).isoformat()
>>> '2011-07-01T00:00:00+04:00'
First run new_dt = datetime.replace(tzinfo=tz) to create a new timezone-aware datetime. Then run your datetime.strftime() with %z.
Note that you can't then convert the date string back to a timezone-aware datetime directly -- datetime.strptime() doesn't support %z. So you need to instead create a naive datetime and a tzinfo then do datetime.replace(tzinfo=tz) as before.
Some useful external libraries:
http://pytz.sourceforge.net/
http://code.google.com/p/parsedatetime/
http://labix.org/python-dateutil
Also try searching right here on Stack Overflow for more questions on (Python OR django OR appengine) AND (datetime OR timezone OR date OR time OR tzinfo).
ISO-8601 has no notion of "Timezones", only dates and times, and as a convenience, times may be presented with an "offset".
To make matters even more annoying, datetime has only a half-hearted nod in acknowledgement of timezones; the tzinfo attribute on datetime objects is optional, and no implementation of that interface is provided by the main-line python.
The standard answer to this is to just always do everything in UTC; including having the server in UTC, not in local time. This is actually a pretty good idea; it's not the times that are different, only the way individual users prefer to read those times (which is similar to preferring '42' over '0b101010').
You can satisfy your users' (reasonable!) desire to view times in their local timezone by storing the preferred timezone (perhaps just a sitewide preference if everyone is in Moscow) separately from the actual times, and then you can use a robust timezone library (like pytz) to do the formatting to and from local time.

Categories