How to convert a timedelta to a string and back again - python

Dateutil's timedelta object appears to have a custom __str__ method:
In [1]: from datetime import timedelta
In [2]: td = timedelta(hours=2)
In [3]: str(td)
Out[3]: '2:00:00'
What I'd like to do is re-create a timedelta object from its string representation. As far as I can tell, however, the datetime.parser.parse method will always return a datetime.datetime object (cf. https://dateutil.readthedocs.io/en/stable/parser.html):
In [4]: import dateutil.parser
In [5]: dateutil.parser.parse(str(td))
Out[5]: datetime.datetime(2016, 11, 25, 2, 0)
The only way I see now to do this is to, in the parlance of Convert a timedelta to days, hours and minutes, 'bust out some nauseatingly simple (but verbose) mathematics' to obtain the seconds, minutes, hours, etc., and pass these back to the __init__ of a new timedelta. Or is there perhaps a simpler way?

Use datetime.strptime to convert a string to timedelta.
import datetime
td = datetime.timedelta(hours=2)
# timedelta to string
s = str(td) # 2:00:00
# string to timedelta
t = datetime.datetime.strptime(s,"%H:%M:%S")
td2 = datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second)

The module pytimeparse, which was inspired by How to construct a timedelta object from a simple string, seems to do the heavy lifting by returning the number of seconds. I just put a wrapper around it which returns a timedelta object with the same number of seconds:
#!/usr/bin/env python3.5
import datetime
import pytimeparse
import unittest
def reconstruct_timedelta(td_string):
seconds = pytimeparse.parse(td_string)
return datetime.timedelta(seconds=seconds)
class TestReconstruction(unittest.TestCase):
def test_reconstruct_timedelta_is_inverse_of_str(self):
td = datetime.timedelta(weeks=300, days=20, hours=3, minutes=4, milliseconds=254, microseconds=984)
td_reconstructed = reconstruct_timedelta(str(td))
self.assertTrue(td == td_reconstructed)
if __name__ == "__main__":
unittest.main()
As you can see from the test, the reconstructed timedelta object is the same as the original one, even when it is initialized with an arbitrary number if milliseconds and microseconds.

How about use pickle? You may refer to https://docs.python.org/2/library/pickle.html
Serialize the time delta object, and get back the object later.
import pickle
tdi = pickle.dumps(td)
tdo = pickle.loads(tdi) # will have the time delta object
str(tdo)

Related

How to use milliseconds instead of microsenconds in datetime python

A client has specified that they use DateTime to store their dates using the format 2021-06-22T11:17:09.465Z, and so far I've been able only to obtain it in string dates, because If I want to maintain the milliseconds it saves them like 2021-06-22T11:17:09.465000.
Is there any possible way to force DateTime to use milliseconds instead of microseconds? I'm aware of the %f for microseconds in the format, but I've tried everything I can think of to reduce those 3 decimals while keeping it DateTime with no results however.
I suggest to use the timespec parameter, as described in python docs https://docs.python.org/3/library/datetime.html#datetime.datetime.isoformat:
>>> from datetime import datetime
>>> datetime.now().isoformat(timespec='minutes')
'2002-12-25T00:00'
>>> dt = datetime(2015, 1, 1, 12, 30, 59, 0)
>>> datetime.now().isoformat(timespec='milliseconds')
'2021-12-02T14:03:57.937'
Something like this works:
from datetime import datetime
dt = datetime.now()
print(f"{dt:%Y/%m/%dT%H:%M:%S}.{f'{dt:%f}'[:3]}")
Hope I help.
I assume you're looking for this? See also my general comment at question.
The variable 3 in [:3] can be adjusted to your liking for amount of zeros in ms to ns range. Use the type() to show you its a DateTime object.
import time
from datetime import datetime
tm = time.time()
print(tm)
dt = str(tm).split('.')
print(dt)
timestamp = float(dt[0] + '.' + dt[1][:3])
dt_object = datetime.fromtimestamp(timestamp)
print(dt_object)
This prints for example:
tm : 1638463260.919723
dt : ['1638463260', '919723']
and
dd_object : 2021-12-02 17:41:00.919000
You can divide nanoseconds by 1000000000 to get seconds and by 1000000 to get milliseconds.
Here is some code that will get nanoseconds:
tim = time.time_ns()
You can then combine the output of this with the rest of the format. Probably not the cleanest solution but it should work.

Calling class method inside string format

Consider this:
from datetime import datetime
now = datetime.now()
now.strftime("%p") # returns 'PM'
'{0.day}'.format(now) # returns 22
'{0.strftime("%p")}'.format(now)
# gives
# AttributeError: 'datetime.datetime' object has no attribute 'strftime("%p")'
This seems to imply that I can't call a class method inside the format (I guess that's what strftime is).
What's a workaround for this (assuming I need to call the method inside the string, and keep using a format) ?
You could do this.
>>> from datetime import datetime
>>> now = datetime.now()
>>> '{0:%p}'.format(now)
'PM'
This will also work with f-strings.
>>> f"{now:%p}"
'PM'
You can use the f-string:
from datetime import datetime
now = datetime.now()
now.strftime("%p") # returns 'PM'
'{0.day}'.format(now) # returns 22
print(f'{now.strftime("%p")}')
Else:
from datetime import datetime
now = datetime.now()
now.strftime("%p") # returns 'PM'
'{0.day}'.format(now) # returns 22
print('{0:%p}'.format(now))
Documentation
strftime() and strptime() Behavior
You could use f-strings like this:
from datetime import datetime
now = datetime.now()
now.strftime("%p")
print(f'{now.day}')
print(f'{now.strftime("%p")}')

Extract time from datetime object and compare with string time

In python, I have a datetime object in python with that format.
datetime_object = datetime.strptime(date_time_str, '%Y-%m-%d %H:%M:%S')
In other classes, I'm using this object. When i reach this object,i want to extract time from it and compare string time.
Like below;
if "01:15:13" == time_from_datetime_object
How can I do this?
You need to use the strftime method:
from datetime import datetime
date_time_str = '2021-01-15 01:15:13'
datetime_object = datetime.strptime(date_time_str, '%Y-%m-%d %H:%M:%S')
if "01:15:13" == datetime_object.strftime('%H:%M:%S'):
print("match")
If you want to compare it as string:
if "01:15:13" == datetime_object.strftime('%H:%M:%S'):
Use its time method to return a time object, which you can compare to another time object.
from datetime import time
if datetime_object.time() == time(1, 15, 13):
...
You may have to be careful with microseconds though, so at some point you might want to do datetime_object = datetime_object.replace(microsecond=0), should your datetime objects contain non-zero microseconds.

Get current date from datetime.datetime

I'm trying to get current date so I can pass it to the DATE field in SQL. I'm using datetime.datetime, below is my code:
from datetime import datetime
dt = datetime.strptime(datetime.today().date(), "%m/%d/%Y").date()
However, i'm getting this error:
TypeError: strptime() argument 1 must be str, not datetime.datetime
How can I fix the issue above? I'm still confused about datetime and datetime.datetime, and i want to keep using from datetime import datetime not import datetime.
How can I fix the issue above? thank you
If you see closely, the result of following statement,
>>> datetime.today().date()
datetime.date(2019, 9, 30)
>>> str(datetime.today().date())
'2019-09-30'
You'll notice that the datetime returned is - seperated and you'll have to convert it explicitly to a string value. Hence, for the above statement to work, change it to :
dt = datetime.strptime(str(datetime.today().date()), "%Y-%M-%d").date()
Then change it to whatever format you desire for using strftime (in your case >>> "%d/%m/%Y")
>>> dt.strftime("%d/%m/%Y")
'30/01/2019'
Just use datetime.strftime:
from datetime import datetime
dt = datetime.today().strftime("%m/%d/%Y")
print(dt)
Prints:
'09/30/2019'
strptime takes a string and makes a datetime object. Whereas strftime does exactly the opposite, taking a datetime object and returning a string.

Turn number representing total minutes into a datetime object in python

If I have a number representing a period I am interested in, for example the number 360 representing 360 minutes or 6 hours, how do I turn this into a datetime object such that I can perform the standard datetime object functions on it?
Similarly, if I have a datetime object in the format 00:30:00, representing 30 minutes, how do I turn that into a normal integer variable?
import datetime
t = datetime.timedelta(minutes=360)
This will create an object, t, that you can use with other datetime objects.
To answer the 2nd question you just edited in, you can use t.total_seconds() to return whatever your timedelta holds back into an integer in seconds. You'll have to do the conversion to minutes or hours manually though.
You may want to look at time deltas:
delta = datetime.timedelta(minutes=360)
If your time data is in '00:30:00' format then you should use strptime
>>> from datetime import datetime
>>> time = '00:30:00'
>>> datetime.strptime(time, '%H:%M:%S).time()
datetime.time(0, 30)
If your data is in 30 (integer) format
>>> from datetime import datetime, timedelta
>>> from time import strftime, gmtime
>>> minutes = timedelta(minutes=360)
>>> time = strftime('%H:%M:%S', gmtime(minutes.total_seconds()))
>>> datetime.strptime(time, '%H:%M:%S').time()
datetime.time(6, 0)

Categories