Trouble converting to datetime object - python

I am trying to convert using strptime and for the life of me cannot figure this out
'07-17-2019 23:39 PM GMT-4' does not match format '%m-%d-%y %H:%M %p %z'
Thank you for any help

So far I've found that %y should be %Y. The best way to approach this is to test it a bit at a time. Like starting with datetime.strptime('07-17-2019', '%m-%d-%Y'). There's also something wrong with the GMT-4. %z will match -0400 fine, and %Z will match UTC, EST, and others, which might be better than an offset if you want to include daylight savings time, but it looks like that's all you get with strptime.
dateutil.parser.parse might provide you with more options and flexibility.

I found a way to do this, which is not super flexible, but should have a bit of give.
Firstly, a few points:
%y should be %Y, to match a 4-digit year.
Using a 24-hour time with AM/PM is confusing, so let's just ignore the AM/PM.
GMT-4 is not a standard timezone name, so we need to handle it manually.
#!/usr/bin/env python3
import datetime
s = '07-17-2019 23:39 PM GMT-4'
fmt = '%m-%d-%Y %H:%M' # Excludes AM/PM and timezone on purpose
words = s.split()
# Get just date and time as a string.
s_dt = ' '.join(words[:2])
# Convert date and time to datetime, tz-unaware.
unaware = datetime.datetime.strptime(s_dt, fmt)
# Get GMT offset as int - assumes whole hour.
gmt_offset = int(words[3].replace('GMT', ''))
# Convert GMT offset to timezone.
tz = datetime.timezone(datetime.timedelta(hours=gmt_offset))
# Add timezone to datetime
aware = unaware.replace(tzinfo=tz)
print(aware) # -> 2019-07-17 23:39:00-04:00
P.s. I used these to reverse-engineer a bit of it
tz = datetime.timezone(datetime.timedelta(hours=-4))
dt = datetime.datetime(2019, 7, 17, 23, 39, tzinfo=tz)

Related

Generating a Python datetime from String

I have a date formated like this: "Thu Jan 05 17:42:26 MST 2023" and need to change it to be formated like this: "2023-01-06T04:58:00Z".
I thought this would be really easy. Parse the date with datetime.datetime.strptime(), adjust the timezone with datetime.datetime.astimezone(pytz.utc) and output it with datetime.datetime.strftime().
On my machine running Python 3.10 it is that simple. Even though strptime discards timezone, astimezone(pytz.utc) still works for some reason and outputs the correct time format.
On the server, running Python 2.7 it throws "ValueError: astimezone() requires an aware datetime". So I slice the timezone out of the initial string and localize the datetime. Works great except pytz.timezone() cannot parse daylight savings timezones like MDT. I know there is a parameter for DST but then I have to manually parse the timezone string to figure out DST.
The only way I have gotten this work work properly is by making a dictionary of every timezone and their offsets, parsing the intial string into a epoch timestamp, applying the offset, then formatting back into my desired string.
What am I doing wrong? Why is this so insanely difficult?
# Works fine on Python 3.10 but returns error on Python 2.7
def _formatTimestamp1(timestamp):
local_dt = datetime.strptime(str(timestamp), '%a %b %d %H:%M:%S %Z %Y')
utc_dt = local_dt.astimezone(pytz.utc)
fmt_dt = utc_dt.strftime("%Y-%m-%dT%H:%M:%SZ")
return str(fmt_dt)
# Works good but pytz.timezone() cannot handle paring DST times like 'MDT'
def _formatTimestamp2(timestamp):
local_dt = datetime.strptime(str(timestamp), '%a %b %d %H:%M:%S %Z %Y')
timezone = pytz.timezone(timestamp[20:-5])
aware = timezone.localize(local_dt)
utc_dt = aware.astimezone(pytz.utc)
fmt_dt = utc_dt.strftime("%Y-%m-%dT%H:%M:%SZ")
return str(fmt_dt)
# So far this is the best method, but requires building a timezone database
def _formatTimestamp3(timestamp):
tz_dict = {"MST":-7,"MDT":-6}
local_dt = datetime.strptime(str(timestamp), '%a %b %d %H:%M:%S %Z %Y')
utc_dt = datetime.fromtimestamp(local_dt.timestamp() - tz_dict[timestamp[20:-5]] * 60 * 60)
fmt_dt = utc_dt.strftime("%Y-%m-%dT%H:%M:%SZ")
return str(fmt_dt)

How can I convert text to DateTime?

I scraped a website and got the following Output:
2018-06-07T12:22:00+0200
2018-06-07T12:53:00+0200
2018-06-07T13:22:00+0200
Is there a way I can take the first one and convert it into a DateTime value?
Just parse the string into year, month, day, hour and minute integers and then create a new date time object with those variables.
Check out the datetime docs
You can convert string format of datetime to datetime object like this using strptime, here %z is the time zone :
import datetime
dt = "2018-06-07T12:22:00+0200"
ndt = datetime.datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S%z")
# output
2018-06-07 12:22:00+02:00
The following function (not mine) should help you with what you want:
df['date_column'] = pd.to_datetime(df['date_column'], format = '%d/%m/%Y %H:%M').dt.strftime('%Y%V')
You can mess around with the keys next to the % symbols to achieve what you want. You may, however, need to do some light cleaning of your values before you can use them with this function, i.e. replacing 2018-06-07T12:22:00+0200 with 2018-06-07 12:22.
You can use datetime lib.
from datetime import datetime
datetime_object = datetime.strptime('Jun 1 2005 1:33PM', '%b %d %Y %I:%M%p')
datetime.strptime documentation
Solution here

Python strptime ValueError: time data does not match format

I have added timezones to my datetime column in my postgreSQL DB.
Now I have the error above everytime I want to compare dates.
On some points I have JSON requests, datetime objects are passed as strings, so I need to parse them, with the additonal timezone info I get:
ValueError: time data '2018-05-02 11:52:26.108540+02:00'
does not match format '%Y-%m-%d %H:%M:%S.%f+%Z'
Earlier I had:
2018-05-02 11:52:26.108540
which worked perfectly with:
%Y-%m-%d %H:%M:%S.%f
The new information which has been added is: +02:00
In the strptime docu it is telling me to use %z or %Z but it does not work.
EDIT:
I am using Python 3
The issue is the offset +02:00 you need to remove the colon ':' then it will work:
In[48]:
dt.datetime.strptime('2018-05-02 11:52:26.108540+0200', '%Y-%m-%d %H:%M:%S.%f%z')
Out[48]: datetime.datetime(2018, 5, 2, 11, 52, 26, 108540, tzinfo=datetime.timezone(datetime.timedelta(0, 7200)))
So you would need to go through all your datetime strings and remove this in order for strptime to parse it correctly
You need to remove the colon and use the small %z for this to work.
>>> s = '2018-05-02 11:52:26.108540+02:00'
>>> fmt = %Y-%m-%d %H:%M:%S.%f%z'
>>> time.strptime(s, fmt)
time.struct_time(tm_year=2018, tm_mon=5, tm_mday=2, tm_hour=11, tm_min=52, tm_sec=26, tm_wday=2, tm_yday=122, tm_isdst=-1)

How to replace missing parts of datetime strftime with zeroes?

I receive date objects and need to turn them into string according to format:
"%a %b %d %H:%M:%S %z %Y"
To achieve this I use Python's datetime.strftime method. The problem is that sometimes these date objects doesn't have all this data, for example, I can have both:
a = datetime.date(1999, 1, 2)
b = datetime.datetime(2015, 10, 1, 9, 38, 50, 920000, tzinfo=datetime.timezone.utc)
Tried with string format method:
"{:%a %b %d %H:%M:%S %z %Y}".format(a)
But if timezone is not set then it is dropped, so:
"{:%a %b %d %H:%M:%S %z %Y}".format(b)
'Thu Oct 01 09:38:50 +0000 2015'
but
"{:%a %b %d %H:%M:%S %z %Y}".format(a)
'Sat Jan 02 00:00:00 1999'
While for a it is expected to be:
'Sat Jan 02 00:00:00 +0000 1999'
Is it possible somehow to fill timezone with zeros?
As you've probably noticed from the strftime documentation, %z and %Z will yield an empty string if the datetime object is naive, i.e. if it doesn't have a timezone set.
If you always want it to emit +0000 even if you don't know the timezone, what you want is to treat it as UTC.
So set a default. If timezone isn't passed to you, use the timezone info as you did, i.e. tzinfo = datetime.timezone.utc. You'll always get a +0000 in that case.
Update, in response to comment:
Realize, that by the time you're at the lines beginning format, you're already committed. Your datetime at that point is already naive or aware, and it's well defined how strftime will behave in either situation. When setting the default, you probably shouldn't do it at the format point, but at the point of constructing the datetime.
I can't give further specific help without seeing more of your code, but you obviously have something that differentiates the data you have for a and b, so you must know if you have the tzinfo available. I'm going to make up an example, so I can show you where to put your default:
for it in magic_iterator:
(year, month, day, hour, minute, second, microsecond, timezone) = it.get_data()
# note, some of these can be None. Set defaults:
hour = hour or 0
minute = minute or 0
second = second or 0
timezone = timezone or datetime.tzinfo.utc
foo = datetime(year, month, day, hour, minute, second, microsecond, timezone)
# do something with foo
This construct with the or will see if those values are falsey (i.e. False, 0, or an empty string), and if so, set them appropriately. Note that in the case of hour, minute and second, if the actual value is 0, the or part of the clause will execute, since 0 is falsey. This is normally a logic error (solved by doing something like hour = hour if hour is not None else 0) but in this case, you'd be setting something to 0 that's already 0, so it's ok.
Come to think of it, you can do it as a one liner attached to the format, but it's ugly:
"{:%a %b %d %H:%M:%S %z %Y}".format(a if a.tzinfo else datetime(a.year, a.month, a.day, a.hour, a.minute, a.second, a.microsecond, datetime.tzinfo.utc))
I would much prefer to put the default in the construction of the datetime than in the formatting line.

How can I convert a date/time string in local time into UTC in Python?

I am trying to write a function that will convert a string date/time from local time to UTC in Python.
According to this question, you can use time.tzname to get some forms of the local timezone, but I have not found a way to use this in any of the datetime conversion methods. For example, this article shows there are a couple of things you can do with pytz and datetime to convert times, but all of them have timezones that are hardcoded in and are of different formats than what time.tznamereturns.
Currently I have the following code to translate a string-formatted time into milliseconds (Unix epoch):
local_time = time.strptime(datetime_str, "%m/%d/%Y %H:%M:%S") # expects UTC, but I want this to be local
dt = datetime.datetime(*local_time[:6])
ms = int((dt - datetime.datetime.utcfromtimestamp(0)).total_seconds() * 1000)
However, this is expecting the time to be input as UTC. Is there a way to convert the string formatted time as if it were in the local timezone? Thanks.
Essentially, I want to be able to do what this answer does, but instead of hard-coding in "America/Los_Angeles", I want to be able to dynamically specify the local timezone.
If I understand your question correctly you want this :
from time import strftime,gmtime,mktime,strptime
# you can pass any time you want
strftime("%Y-%m-%d %H:%M:%S", gmtime(mktime(strptime("Thu, 30 Jun 2016 03:12:40", "%a, %d %b %Y %H:%M:%S"))))
# and here for real time
strftime("%Y-%m-%d %H:%M:%S", gmtime(mktime(strptime(strftime("%a, %d %b %Y %H:%M:%S"), "%a, %d %b %Y %H:%M:%S"))))
make a time structure from a timetuple then use the structure to create a utc time
from datetime import datetime
def local_to_utc(local_st):
time_struct = time.mktime(local_st)
utc_st = datetime.utcfromtimestamp(time_struct)
return utc_st
d=datetime(2016,6,30,3,12,40,0)
timeTuple = d.timetuple()
print(local_to_utc(timeTuple))
output:
2016-06-30 09:12:40

Categories