Python3.5 Time Zone conversion - python

I have tried a number of posts/suggestions on here on converting time zone objects and have failed. I hope someone can point me to an easy way to do this.
I have a string/datetime of 2017-05-11T16:24:56-04:00
I can parse it a number of ways, dateutil, etc, into a datetime object.
when printed i get
datetime.datetime(2017, 5, 11, 16, 24, 56, tzinfo=tzoffset(None, -14400))
so it gets a tzoffset.
Trying any conversion doesn't seem to update the actual time portion, just the zone information.
How do I convert this string to my local time zone (EST, or offset -5hrs).
edit: trying astimezone() gets me this:
dt.astimezone()
Out[18]: datetime.datetime(2017, 5, 11, 16, 24, 56,
tzinfo=datetime.timezone(datetime.timedelta(-1, 72000), 'EDT'))
Thanks!

When you convert it using tzinfo you only change the suffix of the output string (e.g. with tzutc()): 2017-05-11 16:24:56+00:00
If you want to print it in your time zone, first create the datetime object using the actual timezone it represents:
dt = datetime(2017, 5, 11, 16, 24, 56,
tzinfo=tzoffset(None, -18000))
# 2017-05-11 16:24:56-05:00
And then convert it to the desired timezone using:
mydt = dt.astimezone(tzutc())
# 2017-05-11 21:24:56+00:00

Related

Difference between datetime.strptime and parse from dateutil?

I am getting two different results in seconds when I parse the following time string:
Method 1:
from datetime import datetime
int(datetime.strptime('2015-03-25T19:46:23.286966Z', '%Y-%m-%dT%H:%M:%S.%fZ').timestamp())
yields 1427309183
Method 2:
from dateutil.parser import parse
int(parse('2015-03-25T19:46:23.286966Z').timestamp())
yields 1427312783
It seems that method 1 ignores the TZ vs method do (I run it from a UTC+1 tz).
Question: Why do these two methods yield different second timestamps? Can someone please explain what's going on under the hood and how to best handle such situations.
My goal is to convert the string to seconds in unix epoch time (i.e. utc).
If you take a look at the repr of your intermediate result (the datetime objects), you notice a difference:
from datetime import datetime
from dateutil.parser import parse
print(repr(datetime.strptime('2015-03-25T19:46:23.286966Z', '%Y-%m-%dT%H:%M:%S.%fZ')))
# datetime.datetime(2015, 3, 25, 19, 46, 23, 286966)
print(repr(parse('2015-03-25T19:46:23.286966Z')))
# datetime.datetime(2015, 3, 25, 19, 46, 23, 286966, tzinfo=tzutc())
The first one is naive, no tzinfo set since you use a literal Z in the parsing directive. The second one is aware; tzinfo is set to UTC since dateutil's parser recognizes the Z to signal UTC. That makes for the difference in the timestamp, since Python treats naive datetime as local time - thus the difference of 1 hour, which is your local time's UTC offset.
You can correctly parse like
print(repr(datetime.fromisoformat('2015-03-25T19:46:23.286966Z'.replace('Z', '+00:00'))))
# datetime.datetime(2015, 3, 25, 19, 46, 23, 286966, tzinfo=datetime.timezone.utc)
see also here.
Or less convenient (imho), with strptime:
print(repr(datetime.strptime('2015-03-25T19:46:23.286966Z', '%Y-%m-%dT%H:%M:%S.%f%z')))
# datetime.datetime(2015, 3, 25, 19, 46, 23, 286966, tzinfo=datetime.timezone.utc)

Generalize timestamp format in python

I get two type of timestamp (one with millisecond and another one without it)
'endtime': '2020-09-09T05:46:41.620Z'
'starttime': '2020-09-08T18:20:57Z'
I have to specify the format to convert it into datetime
timestampstart = pd.to_datetime(starttime, format="%Y-%m-%dT%H:%M:%S%fZ")
is there a way to generalize "format" in this line, because if my time has millisecond, the code will crash.
how can rewrite this to always ignore millisecond without getting my code crashed?
Both formats are ISO8601 compliant. You can parse the timestamps conveniently using datetime.fromisoformat after you replace the 'Z' character (which denotes UTC) with '+00:00' (also UTC). You can find this method also here.
from datetime import datetime
endtime = '2020-09-09T05:46:41.620Z'
starttime = '2020-09-08T18:20:57Z'
for t in (endtime, starttime):
print(repr(datetime.fromisoformat(t.replace('Z', '+00:00'))))
# datetime.datetime(2020, 9, 9, 5, 46, 41, 620000, tzinfo=datetime.timezone.utc)
# datetime.datetime(2020, 9, 8, 18, 20, 57, tzinfo=datetime.timezone.utc)
To set all microseconds to zero you can write
# setting microseconds to zero:
for t in (endtime, starttime):
print(repr(datetime.fromisoformat(t.replace('Z', '+00:00')).replace(microsecond=0)))
# datetime.datetime(2020, 9, 9, 5, 46, 41, tzinfo=datetime.timezone.utc)
# datetime.datetime(2020, 9, 8, 18, 20, 57, tzinfo=datetime.timezone.utc)

Changing string to UTC to dateTime object

I have time = '2020-06-24T13:30:00-04:00'. How can I change it to a dateTime object in UTC time. I would prefer not to use pd.Timestamp(time).tz_convert("UTC").to_pydatetime() because it returns a weird output that would look like this datetime.datetime(2020, 6, 24, 17, 30, tzinfo=<UTC>). As a result, when I check for equality with datetime.datetime(2020, 6, 24, 17, 30), it return False.
Edit:
import datetime
import pytz
time = '2020-06-24T13:30:00-04:00
dt = datetime.datetime(2020, 6, 24, 17, 30)
print("dt: ",dt)
so = datetime.datetime.strptime(time, '%Y-%m-%dT%H:%M:%S%z').astimezone(pytz.utc)
print("so:",so)
print(dt == so)
outputs
dt: 2020-06-24 17:30:00
so: 2020-06-24 17:30:00+00:00
False
How can I get it to properly evaluate to True?
#1 Since your string is ISO 8601 compatible, use fromisoformat() on Python 3.7+:
from datetime import datetime, timezone
s = '2020-06-24T13:30:00-04:00'
dtobj = datetime.fromisoformat(s)
# dtobj
# datetime.datetime(2020, 6, 24, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=72000)))
Note that this will give you a timezone-aware datetime object; the tzinfo property is a UTC offset. You can easily convert that to UTC using astimezone():
dtobj_utc = dtobj.astimezone(timezone.utc)
# dtobj_utc
# datetime.datetime(2020, 6, 24, 17, 30, tzinfo=datetime.timezone.utc)
#2 You can achieve the same with strptime (also Python3.7+ according to this):
dtobj = datetime.strptime(s, '%Y-%m-%dT%H:%M:%S%z')
dtobj_utc = dtobj.astimezone(timezone.utc)
# dtobj_utc
# datetime.datetime(2020, 6, 24, 17, 30, tzinfo=datetime.timezone.utc)
#3 If you want to turn the result into a naive datetime object, i.e. remove the tzinfo property, replace with None:
dtobj_utc_naive = dtobj_utc.replace(tzinfo=None)
# dtobj_utc_naive
# datetime.datetime(2020, 6, 24, 17, 30)
#4 For older Python versions, you should be able to use dateutil's parser:
from dateutil import parser
dtobj = parser.parse(s)
dtobj_utc = dtobj.astimezone(timezone.utc)
dtobj_utc_naive = dtobj_utc.replace(tzinfo=None)
# dtobj_utc_naive
# datetime.datetime(2020, 6, 24, 17, 30)
Alright so my previous answer was sort of wack because I did not understand your issue entirely so I am rewriting it. You problem is that you are constructing a datetime object from a string and it is timezone aware(UTC). However, whenever you make a datetime object in python, dt = datetime.datetime(2020, 6, 24, 17, 30), it is creating it but with no timezone information (which you can check using .tzinfo on it). All you would need to do is make dt timezone aware when you first create it. See below my code snippit.
import datetime
time = '2020-06-24T13:30:00-04:00'
dt = datetime.datetime(2020, 6, 24, 17, 30, tzinfo=datetime.timezone.utc)
print("dt: ",dt.tzinfo)
so = datetime.datetime.strptime(time, '%Y-%m-%dT%H:%M:%S%z')
print("so:",so.tzinfo)
print(dt == so)

How to convert a timestamp string with 7 digits on the microseconds part using strptime?

Having a timestamp as string like 2016-09-22T13:57:31.2311892-04:00, how can one get the datetime object?
I've tried using strptime for this, but I got two issues:
I need to remove : from the timezone part, at the end, for %z to work properly.
The microseconds part has 7 digits, but strptime handles only up to 6 digits.
Is there a way to parse timestamps in this format without modifying* the string itself before passing to strptime?
* - by modifying, I think of removing the last microsecond digit, and removing the last :.
Note: This is for inserting a record in MySQL. If that helps.
How about convert like this:
dt = datetime.strptime(s[:-len('2-04:00')], '%Y-%m-%dT%H:%M:%S.%f')
# datetime.datetime(2016, 9, 22, 13, 57, 31, 231189)
https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior
Suddenly found a useful method at django:
from django.utils.dateparse import parse_datetime
dt = parse_datetime('2016-09-22T13:57:31.2311892-04:00')
# datetime.datetime(2016, 9, 22, 13, 57, 31, 231189, tzinfo=<django.utils.timezone.FixedOffset object at 0x7f20184f8390>)
https://docs.djangoproject.com/en/2.0/ref/utils/#module-django.utils.dateparse
Another pythonic format (use maya https://github.com/kennethreitz/maya):
# pip install maya
import maya
maya.parse('2016-09-22T13:57:31.2311892-04:00').datetime()
# datetime.datetime(2016, 9, 22, 17, 57, 31, 231189, tzinfo=<UTC>)

Converting datetime object to timestamp and back gives me a different time

I have encountered this problem today and I don't have an explanation for it.
I have a Python datetime object:
dt = datetime.datetime(2012, 3, 31, 18, 30, 48, tzinfo=<FixedOffset '-04:00'>)
which, to my understanding is 18:30 in a time zone offset from UTC by 4 hours.
I then tried to convert it to timestamp like so:
epo = time.mktime(dt.timetuple()) and get back 1333247448.0.
However, when I try to convert it back to make sure it's correct using date
time.datetime.fromtimestring(epo),
I get back
datetime.datetime(2012, 3, 31, 19, 30, 48)
Notice that time is 19 not 18.
Can anybody tell me why it's doing that?
Try using
time.localtime(epo)
instead of
time.datetime.fromtimestring(epo)

Categories

Resources