I have given date strings like these:
Mon Jun 28 10:51:07 2010
Fri Jun 18 10:18:43 2010
Wed Dec 15 09:18:43 2010
What is a handy python way to calculate the difference in days? Assuming the time zone is the same.
The strings were returned by linux commands.
Edit: Thank you, so many good answers
Use strptime.
Sample usage:
from datetime import datetime
my_date = datetime.strptime('Mon Jun 28 10:51:07 2010', '%a %b %d %H:%M:%S %Y')
print my_date
EDIT:
You could also print the time difference in a human readable form, like so:
from time import strptime
from datetime import datetime
def date_diff(older, newer):
"""
Returns a humanized string representing time difference
The output rounds up to days, hours, minutes, or seconds.
4 days 5 hours returns '4 days'
0 days 4 hours 3 minutes returns '4 hours', etc...
"""
timeDiff = newer - older
days = timeDiff.days
hours = timeDiff.seconds/3600
minutes = timeDiff.seconds%3600/60
seconds = timeDiff.seconds%3600%60
str = ""
tStr = ""
if days > 0:
if days == 1: tStr = "day"
else: tStr = "days"
str = str + "%s %s" %(days, tStr)
return str
elif hours > 0:
if hours == 1: tStr = "hour"
else: tStr = "hours"
str = str + "%s %s" %(hours, tStr)
return str
elif minutes > 0:
if minutes == 1:tStr = "min"
else: tStr = "mins"
str = str + "%s %s" %(minutes, tStr)
return str
elif seconds > 0:
if seconds == 1:tStr = "sec"
else: tStr = "secs"
str = str + "%s %s" %(seconds, tStr)
return str
else:
return None
older = datetime.strptime('Mon Jun 28 10:51:07 2010', '%a %b %d %H:%M:%S %Y')
newer = datetime.strptime('Tue Jun 28 10:52:07 2010', '%a %b %d %H:%M:%S %Y')
print date_diff(older, newer)
Original source for the time snippet.
#!/usr/bin/env python
import datetime
def hrdd(d1, d2):
"""
Human-readable date difference.
"""
_d1 = datetime.datetime.strptime(d1, "%a %b %d %H:%M:%S %Y")
_d2 = datetime.datetime.strptime(d2, "%a %b %d %H:%M:%S %Y")
diff = _d2 - _d1
return diff.days # <-- alternatively: diff.seconds
if __name__ == '__main__':
d1 = "Mon Jun 28 10:51:07 2010"
d2 = "Fri Jun 18 10:18:43 2010"
d3 = "Wed Dec 15 09:18:43 2010"
print hrdd(d1, d2)
# ==> -11
print hrdd(d2, d1)
# ==> 10
print hrdd(d1, d3)
# ==> 169
# ...
>>> import datetime
>>> a = datetime.datetime.strptime("Mon Jun 28 10:51:07 2010", "%a %b %d %H:%M:%S %Y")
>>> b = datetime.datetime.strptime("Fri Jun 18 10:18:43 2010", "%a %b %d %H:%M:%S %Y")
>>> c = a-b
>>> c.days
10
This isn't along the same lines as the other answers, but it might be helpful to someone wanting to display something more human readable (and less precise). I did this quickly, so suggestions welcome.
(Note that it assumes until_seconds is the later timestamp.)
def readable_delta(from_seconds, until_seconds=None):
'''Returns a nice readable delta.
readable_delta(1, 2) # 1 second ago
readable_delta(1000, 2000) # 16 minutes ago
readable_delta(1000, 9000) # 2 hours, 133 minutes ago
readable_delta(1000, 987650) # 11 days ago
readable_delta(1000) # 15049 days ago (relative to now)
'''
if not until_seconds:
until_seconds = time.time()
seconds = until_seconds - from_seconds
delta = datetime.timedelta(seconds=seconds)
# deltas store time as seconds and days, we have to get hours and minutes ourselves
delta_minutes = delta.seconds // 60
delta_hours = delta_minutes // 60
## show a fuzzy but useful approximation of the time delta
if delta.days:
return '%d day%s ago' % (delta.days, plur(delta.days))
elif delta_hours:
return '%d hour%s, %d minute%s ago' % (delta_hours, plur(delta_hours), delta_minutes, plur(delta_minutes))
elif delta_minutes:
return '%d minute%s ago' % (delta_minutes, plur(delta_minutes))
else:
return '%d second%s ago' % (delta.seconds, plur(delta.seconds))
def plur(it):
'''Quick way to know when you should pluralize something.'''
try:
size = len(it)
except TypeError:
size = int(it)
return '' if size==1 else 's'
Here is an improved version of date_diff() routine by #the_void. It will print difference in the following fashion depending on how much the difference is:
1d
12 sec
30 min 12 sec
3h 30m
5d 3h 30m
Here is the routine:
def date_diff(newer, older):
if newer < older:
return '-1'
timeDiff = newer - older
days = int(timeDiff.days)
hours = int(timeDiff.seconds/3600)
minutes = int(timeDiff.seconds%3600/60)
seconds = int(timeDiff.seconds%3600%60)
str = ""
tStr = ""
if days > 0:
tStr = "d"
str = str + "%s%s " %(days, tStr)
if hours > 0:
tStr = "h"
str = str + "%s%s " %(hours, tStr)
if minutes > 0:
if days == 0 and hours == 0:
tStr = 'min'
str = str + "%s %s " %(minutes, tStr)
else:
tStr = "m"
str = str + "%s%s " %(minutes, tStr)
if days == 0 and hours == 0:
if seconds >= 0:
if days == 0 and hours == 0:
tStr = "sec"
str = str + "%s %s" %(seconds, tStr)
else:
tStr = 's'
str = str + "%s%s" %(seconds, tStr)
return str
Try this:
>>> (datetime.datetime.strptime("Mon Jun 28 10:51:07 2010", "%a %b %d %H:%M:%S %Y") - datetime.datetime.strptime("Fri Jun 18 10:18:43 2010", "%a %b %d %H:%M:%S %Y")).days
10
from datetime import datetime
resp = raw_input("What is the first date ?")
date1 = datetime.strptime(resp,"%a %b %d %H:%M:%S %Y")
resp2 = raw_input("What is the second date ?")
date2 = datetime.strptime(resp2,"%a %b %d %H:%M:%S %Y")
res = date2-date1
print str(res)
For details on how to print a timedelta object better, you can see this previous post.
Related
initial=2022-04-14 14:00:00
final=2022-04-14 15:30:00
case1:
t1=2022-04-14 13:30:00
t2=2022-04-14 14:30:00
case 2:
t1=2022-04-14 15:00:00
t2=2022-04-14 16:30:00
Want the python odoo search query to check whether initial & final time falls in between t1 &t2
Simple Python example:
from datetime import datetime
dt_1 = datetime.strptime('15 Mar 2022, 19:55 PM', '%d %b %Y, %I:%M %p')
dt_2 = datetime.strptime('30 Apr 2023, 13:45 PM', '%d %b %Y, %I:%M %p')
dt_now = datetime.now()
if dt_1 > dt_2:
print('dt_1 > dt_2')
if dt_1 > dt_now:
print('dt_1 > dt_now')
Example in Odoo: in the "event" module:
from odoo import _, api, fields, models
class EventEvent(models.Model):
_name = 'event.event'
date_end = fields.Datetime(string='End Date')
def _is_event_registrable(self):
return self.date_end > fields.Datetime.now()
def get_date_range_str(self):
today = fields.Datetime.now()
event_date = self.event_begin_date
diff = (event_date.date() - today.date())
if diff.days <= 0:
return _('today')
elif diff.days == 1:
return _('tomorrow')
elif (diff.days < 7):
return _('in %d days') % (diff.days, )
In python, I am trying to make an alarm system where it converts "x Hours y Minutes and z Seconds" to the x:y:z format
For example:
5 hours 20 minutes 6 seconds
05:20:06
1 hour 25 seconds
01:00:25
This is my code, but it seems scuffed:
time_string = '1 hour and 25 seconds'
correction = time_string.replace('and ', '')
duration = correction.replace(' hour', ':').replace(' minute', ':').replace(' second', ':').replace(' ','').replace('s', '')
if 'minute' not in correction and 'second' not in correction:
duration = duration + '00:00'
elif 'minute' not in correction and 'second' in correction:
duration = duration.replace(':',':00:')
elif 'second' not in correction:
duration = duration + '00'
secs = sum(int(x) * 60 ** i for i, x in enumerate(reversed(duration.split(':'))))
How do I improve it?
This returns total number of seconds, which seems to be what you wanted:
def parsex(s):
hh = mm = ss = 0
for word in s.split():
word = word.lower()
if word.isdigit():
save = word
elif word.startswith('hour'):
hh = int(save)
elif word.startswith('minute'):
mm = int(save)
elif word.startswith('second'):
ss = int(save)
return (hh*60+mm)*60+ss
print(parsex('1 hour and 30 seconds'))
print(parsex('2 hours 15 minutes 45 seconds'))
You can use datetime library to convert this type of string to proper formatted string.
from datetime import datetime
def format_time(string):
format_string = ''
if 'hour' in string:
if 'hours' in string:
format_string += '%H hours '
else:
format_string += '%H hour '
if 'minute' in string:
if 'minutes' in string:
format_string += '%M minutes '
else:
format_string += '%M minute '
if 'second' in string:
if 'seconds' in string:
format_string += '%S seconds'
else:
format_string += '%S second'
value = datetime.strptime(string, format_string)
return value.strftime('%H:%M:%S')
string = '5 hours 20 minutes 6 seconds'
print(format_time(string))
string = '1 hour 25 seconds'
print(format_time(string))
string = '1 minute 25 seconds'
print(format_time(string))
Output
05:20:06
01:00:25
00:01:25
from collections import defaultdict
dataexp = [
("5 hours 20 minutes 6 seconds","05:20:06"),
("1 hour 25 seconds","01:00:25")
]
def convert(input_):
words = input_.replace('and','').split()
di = defaultdict(lambda:0)
while words:
num = int(words.pop(0))
unit = words.pop(0)[0]
di[unit] = num
return f"{di['h']:02}:{di['m']:02}:{di['s']:02}"
for inp, exp in dataexp:
got = convert(inp)
msg = "\nfor %-100.100s \nexp :%s:\ngot :%s:\n" % (inp, exp, got)
if exp == got:
print("✅! %s" % msg)
else:
print("❌! %s" % msg)
which outputs:
✅!
for 5 hours 20 minutes 6 seconds
exp :05:20:06:
got :05:20:06:
✅!
for 1 hour 25 seconds
exp :01:00:25:
got :01:00:25:
I have pairs of timestamps from the unix date:
alvas#ubi:~$ date
Wed May 20 01:04:43 CEST 2015
How can I calculate the time difference between the pairs of timestamp?
Note: I don't have the full datetime stamp from $date but only the time in hr:min:sec left in my logfile.
For example, timediff(start, end):
timediff('11:12:10', '19:58:50')
timediff('15:17:09', '03:11:10')
[out]:
31600
42841
[out2]:
8 hrs 46 mins 40 secs (31600 secs)
11 hrs 54 mins 1 secs (42841 secs)
In the case that end < start, treat it as the next day.
I've tried the script below but is there an easier way to do that?
def timediff(start, end):
start_hr, start_min, start_sec = map(float, start.split(':'))
end_hr, end_min, end_sec = map(float, end.split(':'))
if end_hr < start_hr:
end_hr = end_hr + 24
if end_min < start_min:
end_min = end_min + 60
end_hr -= 1
if end_sec < start_sec:
end_sec = end_sec + 60
end_min -= 1
num_hrs = end_hr - start_hr
num_mins = end_min - start_min
num_secs = end_sec - start_sec
total_seconds = 60*60*num_hrs + 60*num_mins+num_secs
total_time = " ".join([str(num_hrs), 'hrs', str(num_mins), 'mins', str(num_secs), 'secs'])
return total_seconds, total_time
print timediff('11:12:10', '19:58:50')
print timediff('15:17:09', '03:11:10')
[out]:
(31600.0, '8.0 hrs 46.0 mins 40.0 secs')
(42841.0, '11.0 hrs 54.0 mins 1.0 secs')
When I tried dateutil.parser.parse:
>>> from dateutil.parser import parse as dtparse
>>> dtparse('19:58:50') - dtparse('11:12:10')
datetime.timedelta(0, 31600)
>>> dtparse('03:11:10') - dtparse('15:17:09')
datetime.timedelta(-1, 42841)
dateutil.parser(pip install python-dateutil) can parse just about anything ... and its timezone aware
from dateutil.parser import parse as dtparse
print dtparse("Wed May 20 01:04:43 CEST 2015") - dtparse("Wed May 20 00:02:43 CEST 2015")
>>> print dtparse("Fri May 22 01:04:43 CEST 2015") - dtparse("Wed May 20 00:02:43
CEST 2015")
2 days, 1:02:00
>>> print dtparse("15:22:36") - dtparse("12:00:45")
3:21:51 # 3 hours, 21 minutes, 51 seconds
here ... this will work if you dont know which timestamp is later ...
def tdiff(t1,t2):
if t1 > t2:t1,t2 = t2,t1
return t2-t1
print tdiff(dtparse('11:12:10'), dtparse('19:58:50'))
if you want to subtract a day in the event the order is wrong try this
def tdiff(t1,t2):
if t1 > t2:t1 - datetime.timedelta(days=1)
return t2-t1
Probably easier to use datetime:
import datetime
def timediff(t1, t2):
d1=datetime.datetime.strptime(t1, "%H:%M:%S")
d2=datetime.datetime.strptime(t2, "%H:%M:%S")
if d2<d1:
d1-=datetime.timedelta(days=1)
return ((d2-d1).total_seconds(), str(d2-d1))
>>> timediff('11:12:10', '19:58:50')
(31600.0, '8:46:40')
>>> timediff('15:17:09', '03:11:10')
(42841.0, '11:54:01')
Given:
from datetime import datetime
date = datetime.strptime('Wed 12 Nov', '%a %d %b')
It returns datetime.datetime(1900, 11, 12, 0, 0). What might be the best way to get the greatest past year?, in this case should 2014 instead of 1900.
Any help will be appreciate.
You can get the year from datetime.now() and subtract 1:
from datetime import datetime
date = datetime.strptime('Wed 12 Nov {}'.format(datetime.now().year-1), '%a %d %b %Y')
This will not work for feb 29.
Actually a bug in the first implementation, it was starting on a monday because 12 November 1900 was a Monday:
dte = 'Wed 12 Nov'
start = datetime.strptime('Wed 12 Nov', "%a %d %b")
greatest = None
while start <= datetime.now():
start += timedelta(days=1)
if start.strftime("%a %d %b") == dte:
greatest = start
print(greatest)
2014-11-12 00:00:00
There is also a monthdelta package that you can use to increment by month:
from datetime import datetime
from monthdelta import monthdelta
dte = 'Wed 12 Nov'
start = datetime.strptime('Wed 12 Nov', "%a %d %b")
greatest = None
while start <= datetime.now():
start += monthdelta(1)
if start.strftime("%a %d %b") == dte:
greatest = start
print(greatest)
You can see incrementing by months is much more efficient:
In [1]: from datetime import datetime, timedelta
In [2]: %%timeit
...: dte = 'Wed 12 Nov'
...: start = datetime.strptime('Wed 12 Nov', "%a %d %b")
...: greatest = None
...: while start <= datetime.now():
...: start += timedelta(days=1)
...: if start.strftime("%a %d %b") == dte:
...: greatest = start
...:
1 loops, best of 3: 382 ms per loop
In [3]: from datetime import datetime
In [4]: from monthdelta import monthdelta
In [5]: %%timeit
...: dte = 'Wed 12 Nov'
...: start = datetime.strptime('Wed 12 Nov', "%a %d %b")
...: greatest = None
...: while start <= datetime.now():
...: start += monthdelta(1)
...: if start.strftime("%a %d %b") == dte:
...: greatest = start
...:
100 loops, best of 3: 18.7 ms per loop
Both return pretty quick but if you had many calls to the method then the monthly increase is a better option.
We could also add 30 days and then set the day to 12, there may be bugs as I have not overly tested it:
def match_date(abb_wk_dy, day_date, abb_mon):
dte = "{} {} {}".format(abb_wk_dy.capitalize(), day_date, abb_mon.capitalize())
start = datetime.strptime(dte, "%a %d %b")
greatest = None
while start <= datetime.now():
start += timedelta(days=30)
start = start.strptime("{} {} {}".format(start.year, start.month, day_date), "%Y %m %d")
if start.strftime("%a %d %b") == dte:
greatest = start
return greatest
The last code runs pretty efficiently:
In [12]: timeit match_date("wed","12","nov")
10 loops, best of 3: 34.7 ms per loop
If you only want the year then return greatest.year.
On testing the above code fails for leap years so we need to catch that, we can also just increase the year by 1 each time:
def match_date(abb_wk_dy, day_date, abb_mon):
wkd, dd, ab = abb_wk_dy.capitalize(), day_date, abb_mon.capitalize()
match = "{} {} {}".format(wkd, dd, ab)
try:
dte = "{} {} {} {}".format(1900, wkd, dd, ab)
start = datetime.strptime(dte, "%Y %a %d %b")
except ValueError:
# first leap year since 1900
dte = "{} {} {} {}".format(1904, wkd, dd, ab)
start = datetime.strptime(dte, "%Y %a %d %b")
day, mon = start.day, start.month
greatest = None
while start <= datetime.now():
try:
start = start.strptime("{} {} {}".format(start.year + 1, mon, day), "%Y %m %d")
except ValueError:
start = start.strptime("{} {} {}".format(start.year + 1, 01, 01), "%Y %m %d")
continue
if start.strftime("%a %d %b") == match:
greatest = start
return greatest.year if greatest else "No match"
Which runs in:
In [27]: timeit match_date("Wed","12","Nov")
100 loops, best of 3: 2.63 ms per loop
You would also need to validate that no day > 31 is ever entered and other months and days match up which could be achieved using a dict or calender.monthrange or a dict mapping max day in month to month name.
day = "13/Oct/2013"
print("Parsing :",day)
day, mon, yr= day.split("/")
sday = yr+" "+day+" "+mon
myday = time.strptime(sday, '%Y %d %b')
Sstart = yr+" "+time.strftime("%U",myday )+" 0"
Send = yr+" "+time.strftime("%U",myday )+" 6"
startweek = time.strptime(Sstart, '%Y %U %w')
endweek = time.strptime(Send, '%Y %U %w')
print("Start of week:",time.strftime("%a, %d %b %Y",startweek))
print("End of week:",time.strftime("%a, %d %b %Y",endweek))
print("Data entered:",time.strftime("%a, %d %b %Y",myday))
out:
Parsing : 13/Oct/2013
Start of week: Sun, 13 Oct 2013
End of week: Sat, 19 Oct 2013
Sun, 13 Oct 2013
Learned python in the past 2 days and was wondering if there is a cleaner way to do this.This method works...it just looks ugly and It seems silly to have to create a new time variable for each date, and that there should be a way to offset the given date to the start and end of the week through a simple call but i have been unable to find anything on the internet or documentation that looks like it would work.
Use the datetime module.
This will yield start and end of week (from Monday to Sunday):
from datetime import datetime, timedelta
day = '12/Oct/2013'
dt = datetime.strptime(day, '%d/%b/%Y')
start = dt - timedelta(days=dt.weekday())
end = start + timedelta(days=6)
print(start)
print(end)
EDIT:
print(start.strftime('%d/%b/%Y'))
print(end.strftime('%d/%b/%Y'))
Slight variation if you want to keep the standard time formatting and refer to the current day:
from datetime import date, timedelta
today = date.today()
start = today - timedelta(days=today.weekday())
end = start + timedelta(days=6)
print("Today: " + str(today))
print("Start: " + str(start))
print("End: " + str(end))
Use the pendulum module:
today = pendulum.now()
start = today.start_of('week')
end = today.end_of('week')
you can also use Arrow:
import arrow
now = arrow.now()
start_of_week = now.floor('week')
end_of_week = now.ceil('week')
pip install pendulum
import pendulum
today = pendulum.now()
start = today.start_of('week')
print(start.to_datetime_string())
end = today.end_of('week')
print(end.to_datetime_string())
found from here