Datetime format does not match - python

I have a datetime object with integer number of seconds (ex: 2010-04-16 16:51:23). I am using the following command to extract exact time
dt = datetime.datetime.strptime(time, '%Y-%m-%d %H:%M:%S.%f
(generically, I have decimals (ex: 2010-04-16 16:51:23.1456) but sometimes I don't. So when I run this command, I get an error message
ValueError: time data '2010-04-16 16:51:23' does not match format '%Y-%m-%d %H:%M:%S.%f'
How do I go about resolving this?

It's because you don't have the format you specified. You have the format:
'%Y-%m-%d %H:%M:%S'
There are multiple solutions. First, always generate the data in the same format (adding .00 if you need to).
A second solution is that you try to decode in one format and if you fail, you decode using the other format:
try:
dt = datetime.datetime.strptime(time, '%Y-%m-%d %H:%M:%S.%f')
except ValueError:
dt = datetime.datetime.strptime(time, '%Y-%m-%d %H:%M:%S')

Another way avoiding using the exception handling mechanism is to default the field if not present and just try processing with the one format string:
from datetime import datetime
s = '2010-04-16 16:51:23.123'
dt, secs = s.partition('.')[::2]
print datetime.strptime('{}.{}'.format(dt, secs or '0'), '%Y-%m-%d %H:%M:%S.%f')

if you're using the latest python (3.2+) simple-date will do this kind of thing for you:
>>> from simpledate import *
>>> SimpleDate('2010-04-16 16:51:23.1456')
SimpleDate('2010-04-16 16:51:23.145600', tz='America/Santiago')
>>> SimpleDate('2010-04-16 16:51:23')
SimpleDate('2010-04-16 16:51:23', tz='America/Santiago')
it works by extending the python template format. so you could also write (it's not needed because ISO8601-like formats are handled by default):
>>> SimpleDate('2010-04-16 16:51:23', format='Y-m-d H:M:S(.f)?')
SimpleDate('2010-04-16 16:51:23', tz='America/Santiago')
see how the fractional seconds are (.f)? like a regexp - means it's optional (also, it will add % signs if there are none).
PS and you can access the datetime via an attribute. if you wanted to discard the tzinfo (which is taken from the locale by default - i live in chile, hence America/Santiago above) to get a naive datetime:
>>> SimpleDate('2010-04-16 16:51:23').naive.datetime
datetime.datetime(2010, 4, 16, 16, 51, 23)

Related

Format error when trying to parse datetime string using strptime

Trying to parse a datetime string to unix:
from calendar import timegm
from datetime import datetime
print(timegm(datetime.strptime(('2021-07-21 00:00:07.223977216+00:00'), '%Y-%m-%d %H:%M:%S.%f')))
Results in
ValueError: time data '2021-07-21 00:00:07.223977216+00:00' does not match format '%Y-%m-%d %H:%M:%S.%f+00:00'
Tried a lot, cant get anywhere so far ...
Your date is in ISO format, so you can use datetime.fromisoformat:
>>> from datetime import datetime
>>> datetime.fromisoformat("2021-07-21 00:00:07+00:00")
datetime.datetime(2021, 7, 21, 0, 0, 7, tzinfo=datetime.timezone.utc)
So if you look at the format of the date time you are providing, it does not have the fractional seconds the formatter is looking for:
# '2021-07-21 00:00:07+00:00' <- this date time
# '%Y-%m-%d %H:%M:%S.%f' <- in this format, is parsing like below
# 'YYYY-MM-DD HH:MM:SS.ff' (note the ff part is missing, then there's a +00:00 part leftover so the format is breaking)
If you don't need the microseconds, remove the '.%f' part from your format string. Otherwise, if you're parsing a series of values where some have the fractional part, you're going to need to give both options:
try:
timestamp = datetime.strptime(your_string_here, '%Y-%m-%d %H:%M:%S.%f')
except ValueError:
timestamp = datetime.strptime(your_string_here, '%Y-%m-%d %H:%M:%S')

How to convert string date to dateobject and get the year when string date value is in format 2021-01-22T11:36:52.387000+01:00 with datetime?

I tried this:
timestamp = "2021-01-22T11:36:52.387000+01:00"
timestampObject = datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S')
But gave me error:
ValueError: unconverted data remains: .150000+01:00
What is the rest reprisenting and how do I convert the rest? Also what does the 'T' mean?
Because you also have to supply a format specifier to take care of the trailing microseconds and timezone specifier, like the error is telling you, see Conversion of datetime string with microseconds and ...milliseconds. Probably you need '.fZ'. See the datetime doc.
Also, the 'T' just stands for 'Time'; it separates the date-field from the time-field, for ease in parsing (with sed/perl/grep/regex/etc.). Makes it easy if you wanted to a) locate datetimes within a log or b) throw away/separate the time part from the date part.
The string format you have is actually a datetime in ISO format. Luckily datetime has a function for handling that, you don't have to worry about supplying a format specifier for the trailing time objects...
Do you want only the date?
>>> datetime.datetime.fromisoformat("2021-01-22T11:36:52.387000+01:00").date()
datetime.date(2021, 1, 22)
Or do you want datetime?
>>> datetime.datetime.fromisoformat("2021-01-22T11:36:52.387000+01:00")
datetime.datetime(2021, 1, 22, 11, 36, 52, 387000, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600)))
This worked for me:
timestampObject = datetime.fromisoformat(
"2021-01-22T11:36:52.387000+01:00" ).date()
print('timestampObject.year: ', timestampObject.year)
timestampObject.year: 2021

How to provide default time when using datetime.strptime?

I'm using datetime.strptime to parse and obtain DateTime values from strings, in the form of %Y-%m-%dT%H:%M:%SZ but the data is dirty and sometimes doesn't have the time parameter, is sometimes received in yyyy/mm/dd format instead of yyyy-mm-dd format. I can think of hacky regex and try-catch ways to parse this and get what I need, but is there a clean way to use datetime.strptime and obtain the datetime in '%Y-%m-%dT%H:%M:%SZ' format with 00:00:00 or something as the default time if there is no time information?
Currently doing:
time = datetime.strptime(data['time'], '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=pytz.utc)
which throws an error if the data is in an unexpected format.
Just catch the ValueError and try again with an augmented value.
fmt = '%Y-%m-%dT%H:%M:%SZ'
try:
time = datetime.strptime(data['time'], fmt)
except ValueError:
time = datetime.strptime(data['time'] + "T00:00:00Z", fmt)
Alternatively, try the same string with a date-only format, since the resulting value will already default to 00:00:00.
date_and_time = '%Y-%m-%dT%H:%M:%SZ'
date_only = '%Y-%m-%d'
try:
time = datetime.strptime(data['time'], date_and_time)
except ValueError:
time = datetime.strptime(data['time'], date_only)
The second approach is a bit easier to adapt to multiple possible formats. Make a list, and iterate over them until one succeeds.
formats = ['%Y-%m-%dT%H:%M:%SZ', '%Y-%m-%d', ...]
for fmt in formats:
try:
time = datetime.strptime(data['time'], fmt)
break
except ValueError:
pass
else:
# raise ValueError(f'{data["time"]} does not match any expected format')
time = datetime.now() # Or some other completely artificial value
If you're okay with third-party dependencies, you may also try the dateutil library:
import dateutil.parser
time = parser.isoparse(data['time']).replace(tzinfo=pytz.utc)
Or, if you want to have more control over the default values:
import dateutil.parser
time = parser.parse(data['time'], default=datetime.datetime(2019, 10, 14, 20, 14, 50), yearfirst=True).replace(tzinfo=pytz.utc)
Both of them allow more missing fields in the date string (like YYYY or YYYY-MM, etc.). See https://dateutil.readthedocs.io/en/stable/parser.html for more details.

Format timedelta as time zone offset string

As input I have two timestamp strings, one is a local time, other is the same moment in UTC time. I want to get the difference between them (basically to get local time zone offset) as string in specific format, e.g. +1100 or -0500.
import datetime
local = '2018-01-31 18:34:42.172'
utc = '2018-01-31 23:34:42.172'
local_dt = datetime.datetime.strptime(local, '%Y-%m-%d %H:%M:%S.%f')
utc_dt = datetime.datetime.strptime(utc, '%Y-%m-%d %H:%M:%S.%f')
offset_timedelta = local_dt - utc_dt
offset = offset_timedelta.total_seconds() / 3600
offset
Out[8]: -5.0
Using timedelta I can get offset as float (-5.0 for example above). From there I probably may create a function to turn that float to string in format I want, but I am curious if there's any datetime/timedelta method or formatting which I am missing, or some string format which would do the job with cleaner code and more efficient.
Any help would be appreciated.
edit, since I see my question is not clear:
Is there a way to get "-0500" I need (string in that specific format, not a float), either by datetime library or string formatting?
You've actually done all the work already. But you can use the module dateutil to hide the messy details:
>>> local = '2018-01-31 18:34:42.172'
>>> utc = '2018-01-31 23:34:42.172'
>>> from dateutil import parser, relativedelta
>>> tzh=relativedelta.relativedelta(parser.parse(local), parser.parse(utc))
>>> tzh
relativedelta(hours=-5)
To format it the way you want:
>>> f"{tzh.hours:+03d}{abs(tzh.minutes):02d}"
'-0500'
Or, Python 2.6 to 3.5:
>>> "{hours:+03d}{minutes:02d}".format(hours=tzh.hours, minutes=abs(tzh.minutes))
'-0500'
The module dateutil isn't in the standard library but it is well worth the trouble of downloading. It can do far, far more than this.

datetime validation given time in unix format? [duplicate]

I am getting a response from the rest is an Epoch time format like
start_time = 1234566
end_time = 1234578
I want to convert that epoch seconds in MySQL format time so that I could store the differences in my MySQL database.
I tried:
>>> import time
>>> time.gmtime(123456)
time.struct_time(tm_year=1970, tm_mon=1, tm_mday=2, tm_hour=10, tm_min=17, tm_sec=36, tm_wday=4, tm_yday=2, tm_isdst=0)
The above result is not what I am expecting. I want it be like
2012-09-12 21:00:00
Please suggest how can I achieve this?
Also,
Why I am getting TypeError: a float is required for
>>> getbbb_class.end_time = 1347516459425
>>> mend = time.gmtime(getbbb_class.end_time).tm_hour
Traceback (most recent call last):
...
TypeError: a float is required
To convert your time value (float or int) to a formatted string, use:
import time
time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(1347517370))
For example:
import time
my_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(1347517370))
print(my_time)
You can also use datetime:
>>> import datetime
>>> datetime.datetime.fromtimestamp(1347517370).strftime('%c')
'2012-09-13 02:22:50'
>>> import datetime
>>> datetime.datetime.fromtimestamp(1347517370).strftime('%Y-%m-%d %H:%M:%S')
'2012-09-13 14:22:50' # Local time
To get UTC:
>>> datetime.datetime.utcfromtimestamp(1347517370).strftime('%Y-%m-%d %H:%M:%S')
'2012-09-13 06:22:50'
This is what you need
In [1]: time.time()
Out[1]: 1347517739.44904
In [2]: time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(time.time()))
Out[2]: '2012-09-13 06:31:43'
Please input a float instead of an int and that other TypeError should go away.
mend = time.gmtime(float(getbbb_class.end_time)).tm_hour
Try this:
>>> import time
>>> time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(1347517119))
'2012-09-12 23:18:39'
Also in MySQL, you can FROM_UNIXTIME like:
INSERT INTO tblname VALUES (FROM_UNIXTIME(1347517119))
For your 2nd question, it is probably because getbbb_class.end_time is a string. You can convert it to numeric like: float(getbbb_class.end_time)
If you have epoch in milliseconds a possible solution is convert to seconds:
import time
time.ctime(milliseconds/1000)
For more time functions: https://docs.python.org/3/library/time.html#functions
#This adds 10 seconds from now.
from datetime import datetime
import commands
date_string_command="date +%s"
utc = commands.getoutput(date_string_command)
a_date=datetime.fromtimestamp(float(int(utc))).strftime('%Y-%m-%d %H:%M:%S')
print('a_date:'+a_date)
utc = int(utc)+10
b_date=datetime.fromtimestamp(float(utc)).strftime('%Y-%m-%d %H:%M:%S')
print('b_date:'+b_date)
This is a little more wordy but it comes from date command in unix.
First a bit of info in epoch from man gmtime
The ctime(), gmtime() and localtime() functions all take an argument of data type time_t which represents calendar time. When inter-
preted as an absolute time value, it represents the number of seconds elapsed since 00:00:00 on January 1, 1970, Coordinated Universal
Time (UTC).
to understand how epoch should be.
>>> time.time()
1347517171.6514659
>>> time.gmtime(time.time())
(2012, 9, 13, 6, 19, 34, 3, 257, 0)
just ensure the arg you are passing to time.gmtime() is integer.
Sharing an answer to clearly distinguish UTC and local time conversions. Use import datetime at the top before using the below methods.
Convert to datetime of local machine's timezone
datetime.datetime.fromtimestamp(1347517370)
Convert to datetime of UTC timezone
datetime.datetime.utcfromtimestamp(1347517370)
For both the above methods, if you wish to return a formatted date string, use the following code block
datetime.datetime.fromtimestamp(1347517370).strftime('%Y-%m-%d %H:%M:%S')
datetime.datetime.utcfromtimestamp(1347517370).strftime('%Y-%m-%d %H:%M:%S')

Categories

Resources