Working with time values greater than 24 hours - python

How does one work with time periods greater than 24 hours in python? I looked at the datetime.time object but this seems to be for handling the time of a day, not time in general.
datetime.time has the requirement of 0 <= hour < 24 which makes it useless if you want to record a time of more than 24 hours unless I am missing something?
Say for example I wanted to calculate the total time worked by someone. I know the time they've taken to complete tasks individually. What class should I be using to safely calculate that total time.
My input data would look something like this:
# The times in HH:MM:SS
times = ["16:35:21", "8:23:14"]
total_time = ? # 24:58:35

Unfortunately there is not a builtin way to construct timedeltas from strings (like strptime() for datetime objects) so we have to build a parser:
>>> from datetime import timedelta
>>> import re
>>> def interval(s):
"Converts a string to a timedelta"
d = re.match(r'((?P<days>\d+) days, )?(?P<hours>\d+):'
r'(?P<minutes>\d+):(?P<seconds>\d+)', str(s)).groupdict(0)
return timedelta(**dict(((key, int(value)) for key, value in d.items())))
>>> times = ["16:35:21", "8:23:14"]
>>> print sum([interval(time) for time in times])
1 day, 0:58:35
EDIT: Old wrong answer (where I misread the question):
If you substract datetimes you get a timedelta object:
>>> import datetime as dt
>>> times = ["16:35:21", "8:23:14"]
>>> fmt = '%H:%M:%S'
>>> start = dt.datetime.strptime(times[1], fmt )
>>> end = dt.datetime.strptime(times[0], fmt)
>>> diff = (end - start)
>>> diff.total_seconds()
29527.0
>>> (diff.days, diff.seconds, diff.microseconds)
(0, 29527, 0)
>>> print diff
8:12:07

As I understand, you want a sum of all times and not difference. So you can convert your time to timedelta and then sum it:
>>> from datetime import timedelta
# get hours, minutes and seconds
>>> tm1 = [map(int, x.split(':')) for x in times]
# convert to timedelta
>>> tm2 = [timedelta(hours=x[0], minutes=x[1], seconds=x[2]) for x in tm1]
# sum
>>> print sum(tm2, timedelta())
1 day, 0:58:35

Related

How to subtract 2 hours from time formatted as string [duplicate]

This question already has answers here:
Subtract hours and minutes from time
(3 answers)
Closed last year.
My initial string looks like following:
a1 = "06:00:00"
a2 = "01:00:00"
I want to set the time back by two hours.
How to get the following output (in string format)?
a1_new = "04:00:00"
a2_new = "23:00:00"
Here you go!
from datetime import datetime, timedelta
a1 = "06:00:00"
x = datetime.strptime(a1, "%H:%M:%S") - timedelta(hours=2, minutes=0)
y = x.strftime("%H:%M:%S")
print(y)
Steps:
Convert HMS into a DateTime Object
Minus 2 hours from this
Convert the result into a String that only contains Hour Minute & Second
from datetime import datetime
from datetime import timedelta
time_fmt = "%H:%M:%S"
a1_new = datetime.strptime(a1, time_fmt) - timedelta(hours = 2)
a1_new = a1_new.strftime("%H:%M:%S")
print(a1_new)
'08:00:00'
I am assuming here that you only need a simple 24-hour clock.
s = "01:00:00"
h, m, s = s.split(":")
new_hours = (int(h) - 2) % 24
result = ':'.join((str(new_hours).zfill(2), m, s))
convert to datetime:
import datetime
a1 = "06:00:00"
obj = datetime.datetime.strptime(a1,"%H:%M:%S")
obj.replace(hour=obj.hour-2) #hours = hours - 2
tostr = obj.hour+":"+obj.min+":"+obj.second
print(tostr)
If your strings are always going to follow that exact format and you don't want to use datetime, here's a different way to do it: You could split the strings by their colons to isolate the hours, then work on them that way before joining back to a string.
a1 = "06:00:00"
parts = a1.split(":") # split by colons
hour = (int(parts[0]) - 2) % 24 # isolate hour, convert to int, and subtract hours, and clamp to our 0-23 bounds
parts[0] = f"{hour:02}" # :02 in an f-string specifies that you want to zero-pad that string up to a maximum of 2 characters
a1_new = ":".join(parts) # rejoin string to get new time
If there's any uncertainty in the format of the string however, this completely falls apart.
Convert to datetime, subtract timedelta, convert to string.
from datetime import datetime, timedelta
olds = ["06:00:00", "01:00:00"]
objs = [datetime.strptime(t, "%H:%M:%S") - timedelta(hours=2) for t in olds]
news = [t.strftime("%H:%M:%S") for t in objs]
You can use datetime and benefit from the parameters of datetime.timedelta:
from datetime import datetime, timedelta
def subtime(t, **kwargs):
return (datetime.strptime(t, "%H:%M:%S") # convert to datetime
- timedelta(**kwargs) # subtract parameters passed to function
).strftime("%H:%M:%S") # format as text again
subtime('01:00:00', hours=2)
# '23:00:00'
subtime('01:00:00', hours=2, minutes=62)
# '21:58:00'

python check datetime is older then n days?

I am given a date as string,for example '2019-10-29T10:31:58.000Z'.
I want to check if this date and time is older then 5 days from the current date and time.
What is the best way to check this?
All other related threads I found had a different datetime format.
The format is ISO8601 (with a Z for a zero timezone), so...
>>> import datetime
>>> s = '2019-10-29T10:31:58.000Z'
>>> dt = datetime.datetime.fromisoformat(s.rstrip('Z'))
>>> days_since = (datetime.datetime.now() - dt).total_seconds() / 86400.0
>>> print(days_since)
2.1420510361689815 # (at the time of writing)

How to convert a string date in mongodb to ISODate(), or DATE() and delete if it is less than 30 days using python?

Using python I saved dates into MongoDB in below format,
completed_time : "2017:08:20 02:30:02"
Now I want to delete all entries which are older than 30 days.
How can I implement that logic?
You can do it more simply. This code is considerably longer than needed, in order to be explanatory.
I first create a collection of MongoDB records with dates that start from about a month and a half ago, and end about two two weeks ago.
>>> from pymongo import MongoClient
>>> client = MongoClient()
>>> db = client.test_database
>>> from datetime import datetime, timedelta
>>> some_dates = [datetime(2017, 7, d).strftime('%Y:%m:%d %H:%M:%S') for d in range(15,31)]+[datetime(2017, 8, d).strftime('%Y:%m:%d %H:%M:%S') for d in range(1,16)]
>>> posts = db.create_collection
>>> for some_date in some_dates:
... post = {'completed_time': some_date, 'stuff': 'more stuff'}
... post_id = posts.insert_one(post).inserted_id
...
This calculates the time and date that is (or was) 30 days earlier than 'now' when I calculated it, and puts it in the format in you MongoDB database.
>>> boundary = (datetime.now()-timedelta(30)).strftime('%Y:%m:%d %H:%M:%S')
This counts the number of records in the database whose dates and times precede the value in boundary just calculated, for later reference.
>>> count = 0
>>> for post in posts.find({'completed_time': {'$lt': boundary}}):
... count+=1
...
>>> count
19
This is the one line that, with the calculation of boundary, does what you want.
>>> r = posts.delete_many({'completed_time': {'$lt': boundary}})
Now we can check that the correct number of records has been deleted.
>>> count = 0
>>> for post in posts.find({'completed_time': {'$lt': boundary}}):
... count+=1
...
>>> count
0
You can use the datetime module to convert your date/time string into a datetime object, and then convert it to an ordinal day (just a single number), and compare it to the day that was thirty days ago.
Hopefully this will do what you want:
import datetime
completed_time = "2017:07:20 02:30:02"
timeFormat = '%Y:%m:%d %H:%M:%S'
thisDate = datetime.datetime.strptime(completed_time, timeFormat).toordinal()
today = datetime.date.today()
thirtyDaysAgo = today.toordinal() - 30
if thisDate < thirtyDaysAgo:
print("That needs deleting!")

How to subtract datetimes / timestamps in python

Seems like this should be so simple but for the life of me, I can't find the answer. I pull two datetimes/timestamps from the database:
2015-08-10 19:33:27.653
2015-08-10 19:31:28.209
How do I subtract the first from the second, preferably the result being in milliseconds? And yes, I have the date in there, too, because I need it to work at around midnight, as well.
Parse your strings as datetime.datetime objects and subtract them:
from datetime import datetime
d1 = datetime.strptime("2015-08-10 19:33:27.653", "%Y-%m-%d %H:%M:%S.%f")
d2 = datetime.strptime("2015-08-10 19:31:28.209", "%Y-%m-%d %H:%M:%S.%f")
print(d1 - d2)
Gives me:
0:01:59.444000
Also check out timedelta documentation for all possible operations.
you can do subtraction on 2 datetime objects to get the difference
>>> import time
>>> import datetime
>>>
>>> earlier = datetime.datetime.now()
>>> time.sleep(10)
>>> now = datetime.datetime.now()
>>>
>>> diff = now - earlier
>>> diff.seconds
10
convert your strings to datetime objects with time.strptime
datetime.strptime("2015-08-10 19:33:27.653", "%Y-%m-%d %H:%M:%S.%f")
timedelta.seconds does not represent the total number of seconds in the timedelta, but the total number of seconds modulus 60.
Call the function timedelta.total_seconds() instead of accessing the timedelta.seconds property.
For python 3.4, first you'd need to convert the strings representing times into datetime objects, then the datetime module has helpful tools work with dates and times.
from datetime import datetime
def to_datetime_object(date_string, date_format):
s = datetime.strptime(date_string, date_format)
return s
time_1 = '2015-08-10 19:33:27'
time_2 = '2015-08-10 19:31:28'
date_format = "%Y-%m-%d %H:%M:%S"
time_1_datetime_object = to_datetime_object(time_1, date_format)
time_2_datetime_object = to_datetime_object(time_2, date_format)
diff_time = time_1_datetime_object - time_2_datetime_object

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