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

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'

Related

How to get last three months in year-mon format in python?

I want to get last three months from todays date in year-mon format. For example if todays date is 2021-08-04 then I want list of last three months as -
["2021-05", "2021-06", "2021-07"]
I have no idea how to start with this. Any help will be appreciated.
use dateutil's relativedelta to get consistent results, as not all months have equal number of days. E.g.
from datetime import datetime
from dateutil.relativedelta import relativedelta
NOW = datetime.now() # reference date
delta = relativedelta(months=-1) # delta in time
n = 3 # how many steps
fmt = lambda dt: dt.strftime("%Y-%m") # formatter; datetime object to string
l = sorted((fmt(NOW+delta*i) for i in range(1, n+1)))
# l
# ['2021-05', '2021-06', '2021-07']

How to add a certain time to a datetime?

I want to add hours to a datetime and use:
date = date_object + datetime.timedelta(hours=6)
Now I want to add a time:
time='-7:00' (string) plus 4 hours.
I tried hours=time+4 but this doesn't work. I think I have to int the string like int(time) but this doesn't work either.
Better you parse your time like below and access datetime attributes for getting time components from the parsed datetime object
input_time = datetime.strptime(yourtimestring,'yourtimeformat')
input_seconds = input_time.second # for seconds
input_minutes = input_time.minute # for minutes
input_hours = input_time.hour # for hours
# Usage: input_time = datetime.strptime("07:00","%M:%S")
Rest you have datetime.timedelta method to compose the duration.
new_time = initial_datetime + datetime.timedelta(hours=input_hours,minutes=input_minutes,seconds=input_seconds)
See docs strptime
and datetime format
You need to convert to a datetime object in order to add timedelta to your current time, then return it back to just the time portion.
Using date.today() just uses the arbitrary current date and sets the time to the time you supply. This allows you to add over days and reset the clock to 00:00.
dt.time() prints out the result you were looking for.
from datetime import date, datetime, time, timedelta
dt = datetime.combine(date.today(), time(7, 00)) + timedelta(hours=4)
print dt.time()
Edit:
To get from a string time='7:00' to what you could split on the colon and then reference each.
this_time = this_time.split(':') # make it a list split at :
this_hour = this_time[0]
this_min = this_time[1]
Edit 2:
To put it all back together then:
from datetime import date, datetime, time, timedelta
this_time = '7:00'
this_time = this_time.split(':') # make it a list split at :
this_hour = int(this_time[0])
this_min = int(this_time[1])
dt = datetime.combine(date.today(), time(this_hour, this_min)) + timedelta(hours=4)
print dt.time()
If you already have a full date to use, as mentioned in the comments, you should convert it to a datetime using strptime. I think another answer walks through how to use it so I'm not going to put an example.

string convert to datetime timezone

I want to linear interpolation some points between two time string.
So I try to convert string to datetime then insert some point then convert datetime to string. but it seems the timezone not correct.
In below example. I wish to insert one point between 9-28 11:07:57.435" and "9-28 12:00:00.773".
#!/usr/bin/env python
import numpy as np
from time import mktime
from datetime import datetime
#-----------------------------------------#
def main():
dtstr = [
"9-28 11:07:57.435",
"9-28 12:00:00.773"
]
print "input",dtstr
dtlst = str2dt(dtstr)
floatlst = dt2float(dtlst)
bins = 3
x1 = list(np.arange(floatlst[0],floatlst[-1],(floatlst[-1]-floatlst[0])/bins))
dtlst = float2dt(x1)
dtstr = dt2str(dtlst)
print "output",dtstr
return
def str2dt(strlst):
dtlst = [datetime.strptime("2014-"+i, "%Y-%m-%d %H:%M:%S.%f") for i in strlst]
return dtlst
def dt2float(dtlst):
floatlst = [mktime(dt.timetuple()) for dt in dtlst]
return floatlst
def dt2str(dtlst):
dtstr = [dt.strftime("%Y-%m-%d %H:%M:%S %Z%z") for dt in dtlst]
return dtstr
def float2dt(floatlst):
dtlst = [datetime.utcfromtimestamp(seconds) for seconds in floatlst]
return dtlst
#-----------------------------------------#
if __name__ == "__main__":
main()
The output looks like:
input ['9-28 11:07:57.435', '9-28 12:00:00.773']
output ['2014-09-28 16:07:57 ', '2014-09-28 16:25:18 ', '2014-09-28 16:42:39 ']
Two questions here:
The input and output has 4 hours differ (9-28 16:07:57 to 9-28 11:07:57). I guess it caused by timezone but not sure how to fix it.
I wish the first and last point the same as input, but now it seems the last point is less than the input last point (16:42:39 vs 12:00:00).
Q1. You're right about the timezones, you're using time.mktime which converts struct_time to seconds assuming the input is local time, but then using datetime.utcfromtimestamp which (naturally) converts to utc. Use datetime.fromtimestamp instead to keep everything in local time.
Q2. As with the native Python range/xrange, when you do numpy.arange(x, y, z), the result starts with x and goes upto, but not including y (except in weird floating point roundoff cases. Don't rely on this behaviour). if you want consistent behaviour on the end points w/ floating values, use numpy.linspace
On the other hand, why convert datetime to seconds, then go back again? datetime objects support addition and subtraction. Below would be my suggestion.
from time import mktime, localtime
from datetime import datetime
from copy import copy
def main():
input_timestrings = ["9-28 11:07:57.435", "9-28 12:00:00.773"]
input_datetimes = timestrings_to_datestimes(input_timestrings)
start_datetime = input_datetimes[0]
end_datetime = input_datetimes[1]
# subtraction between datetime objects returns a timedelta object
period_length = end_datetime - start_datetime
bins = 3
# operation w/ timedelta objects and datetime objects work pretty much as you'd expect it to
delta = period_length / bins
datetimes = list(custom_range(start_datetime, end_datetime + delta, delta))
output_timestrings = datetimes_to_timestrings(datetimes)
print output_timestrings
return
def timestrings_to_datetimes(timestrings):
datetimes = [datetime.strptime("2014-"+timestring, "%Y-%m-%d %H:%M:%S.%f") for timestring in timestrings]
return datetimes
def datetimes_to_timestrings(datetimes):
timestrings = [datetime_.strftime("%Y-%m-%d %H:%M:%S %Z%z") for datetime_ in datetimes]
return timestrings
def custom_range(start, end, jump):
x = start
while x < end:
yield x
x = x + jump
if __name__ == "__main__":
main()

Working with time values greater than 24 hours

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

How to calculate the time interval between two time strings

I have two times, a start and a stop time, in the format of 10:33:26 (HH:MM:SS). I need the difference between the two times. I've been looking through documentation for Python and searching online and I would imagine it would have something to do with the datetime and/or time modules. I can't get it to work properly and keep finding only how to do this when a date is involved.
Ultimately, I need to calculate the averages of multiple time durations. I got the time differences to work and I'm storing them in a list. I now need to calculate the average. I'm using regular expressions to parse out the original times and then doing the differences.
For the averaging, should I convert to seconds and then average?
Yes, definitely datetime is what you need here. Specifically, the datetime.strptime() method, which parses a string into a datetime object.
from datetime import datetime
s1 = '10:33:26'
s2 = '11:15:49' # for example
FMT = '%H:%M:%S'
tdelta = datetime.strptime(s2, FMT) - datetime.strptime(s1, FMT)
That gets you a timedelta object that contains the difference between the two times. You can do whatever you want with that, e.g. converting it to seconds or adding it to another datetime.
This will return a negative result if the end time is earlier than the start time, for example s1 = 12:00:00 and s2 = 05:00:00. If you want the code to assume the interval crosses midnight in this case (i.e. it should assume the end time is never earlier than the start time), you can add the following lines to the above code:
if tdelta.days < 0:
tdelta = timedelta(
days=0,
seconds=tdelta.seconds,
microseconds=tdelta.microseconds
)
(of course you need to include from datetime import timedelta somewhere). Thanks to J.F. Sebastian for pointing out this use case.
Try this -- it's efficient for timing short-term events. If something takes more than an hour, then the final display probably will want some friendly formatting.
import time
start = time.time()
time.sleep(10) # or do something more productive
done = time.time()
elapsed = done - start
print(elapsed)
The time difference is returned as the number of elapsed seconds.
Here's a solution that supports finding the difference even if the end time is less than the start time (over midnight interval) such as 23:55:00-00:25:00 (a half an hour duration):
#!/usr/bin/env python
from datetime import datetime, time as datetime_time, timedelta
def time_diff(start, end):
if isinstance(start, datetime_time): # convert to datetime
assert isinstance(end, datetime_time)
start, end = [datetime.combine(datetime.min, t) for t in [start, end]]
if start <= end: # e.g., 10:33:26-11:15:49
return end - start
else: # end < start e.g., 23:55:00-00:25:00
end += timedelta(1) # +day
assert end > start
return end - start
for time_range in ['10:33:26-11:15:49', '23:55:00-00:25:00']:
s, e = [datetime.strptime(t, '%H:%M:%S') for t in time_range.split('-')]
print(time_diff(s, e))
assert time_diff(s, e) == time_diff(s.time(), e.time())
Output
0:42:23
0:30:00
time_diff() returns a timedelta object that you can pass (as a part of the sequence) to a mean() function directly e.g.:
#!/usr/bin/env python
from datetime import timedelta
def mean(data, start=timedelta(0)):
"""Find arithmetic average."""
return sum(data, start) / len(data)
data = [timedelta(minutes=42, seconds=23), # 0:42:23
timedelta(minutes=30)] # 0:30:00
print(repr(mean(data)))
# -> datetime.timedelta(0, 2171, 500000) # days, seconds, microseconds
The mean() result is also timedelta() object that you can convert to seconds (td.total_seconds() method (since Python 2.7)), hours (td / timedelta(hours=1) (Python 3)), etc.
This site says to try:
import datetime as dt
start="09:35:23"
end="10:23:00"
start_dt = dt.datetime.strptime(start, '%H:%M:%S')
end_dt = dt.datetime.strptime(end, '%H:%M:%S')
diff = (end_dt - start_dt)
diff.seconds/60
This forum uses time.mktime()
Structure that represent time difference in Python is called timedelta. If you have start_time and end_time as datetime types you can calculate the difference using - operator like:
diff = end_time - start_time
you should do this before converting to particualr string format (eg. before start_time.strftime(...)). In case you have already string representation you need to convert it back to time/datetime by using strptime method.
I like how this guy does it — https://amalgjose.com/2015/02/19/python-code-for-calculating-the-difference-between-two-time-stamps.
Not sure if it has some cons.
But looks neat for me :)
from datetime import datetime
from dateutil.relativedelta import relativedelta
t_a = datetime.now()
t_b = datetime.now()
def diff(t_a, t_b):
t_diff = relativedelta(t_b, t_a) # later/end time comes first!
return '{h}h {m}m {s}s'.format(h=t_diff.hours, m=t_diff.minutes, s=t_diff.seconds)
Regarding to the question you still need to use datetime.strptime() as others said earlier.
Try this
import datetime
import time
start_time = datetime.datetime.now().time().strftime('%H:%M:%S')
time.sleep(5)
end_time = datetime.datetime.now().time().strftime('%H:%M:%S')
total_time=(datetime.datetime.strptime(end_time,'%H:%M:%S') - datetime.datetime.strptime(start_time,'%H:%M:%S'))
print total_time
OUTPUT :
0:00:05
import datetime as dt
from dateutil.relativedelta import relativedelta
start = "09:35:23"
end = "10:23:00"
start_dt = dt.datetime.strptime(start, "%H:%M:%S")
end_dt = dt.datetime.strptime(end, "%H:%M:%S")
timedelta_obj = relativedelta(start_dt, end_dt)
print(
timedelta_obj.years,
timedelta_obj.months,
timedelta_obj.days,
timedelta_obj.hours,
timedelta_obj.minutes,
timedelta_obj.seconds,
)
result:
0 0 0 0 -47 -37
Both time and datetime have a date component.
Normally if you are just dealing with the time part you'd supply a default date. If you are just interested in the difference and know that both times are on the same day then construct a datetime for each with the day set to today and subtract the start from the stop time to get the interval (timedelta).
Take a look at the datetime module and the timedelta objects. You should end up constructing a datetime object for the start and stop times, and when you subtract them, you get a timedelta.
you can use pendulum:
import pendulum
t1 = pendulum.parse("10:33:26")
t2 = pendulum.parse("10:43:36")
period = t2 - t1
print(period.seconds)
would output:
610
import datetime
day = int(input("day[1,2,3,..31]: "))
month = int(input("Month[1,2,3,...12]: "))
year = int(input("year[0~2020]: "))
start_date = datetime.date(year, month, day)
day = int(input("day[1,2,3,..31]: "))
month = int(input("Month[1,2,3,...12]: "))
year = int(input("year[0~2020]: "))
end_date = datetime.date(year, month, day)
time_difference = end_date - start_date
age = time_difference.days
print("Total days: " + str(age))
Concise if you are just interested in the time elapsed that is under 24 hours. You can format the output as needed in the return statement :
import datetime
def elapsed_interval(start,end):
elapsed = end - start
min,secs=divmod(elapsed.days * 86400 + elapsed.seconds, 60)
hour, minutes = divmod(min, 60)
return '%.2d:%.2d:%.2d' % (hour,minutes,secs)
if __name__ == '__main__':
time_start=datetime.datetime.now()
""" do your process """
time_end=datetime.datetime.now()
total_time=elapsed_interval(time_start,time_end)
Usually, you have more than one case to deal with and perhaps have it in a pd.DataFrame(data) format. Then:
import pandas as pd
df['duration'] = pd.to_datetime(df['stop time']) - pd.to_datetime(df['start time'])
gives you the time difference without any manual conversion.
Taken from Convert DataFrame column type from string to datetime.
If you are lazy and do not mind the overhead of pandas, then you could do this even for just one entry.
Here is the code if the string contains days also [-1 day 32:43:02]:
print(
(int(time.replace('-', '').split(' ')[0]) * 24) * 60
+ (int(time.split(' ')[-1].split(':')[0]) * 60)
+ int(time.split(' ')[-1].split(':')[1])
)

Categories