I have a time representation as string in the format:
9:00 am
8:45 pm
e.g., 12-hour, no leading hour 0, am/pm suffix
I need to get the time difference in minutes between then and now.
The time is always in the future, so if it's 09:00 right now, 9:10 am is in 10 mins time and 8:50 am is in 23h, 50m.
I've been playing with strptime but I can't seem to work out how to get my parsed time and now() in a compatible format to do arithmetic on.
something like this, indeed with strptime:
from datetime import datetime
timeString1 = "9:00 am"
timeString2 = "8:45 pm"
format = '%I:%M %p'
datetime1 = datetime.strptime(timeString1, format)
datetime2 = datetime.strptime(timeString2, format)
minutes_diff = (datetime2 - datetime1).total_seconds() / 60.0
print(f"the time difference in minutes is: {minutes_diff}")
this is a variant using datetime.
the format string FMT = "%I:%M %p" is selected according to strptime#time.strftime. and as only datetime objects support differences, i use those only (using datetime.combine).
from datetime import datetime, timedelta
FMT = "%I:%M %p"
TODAY_DATE = datetime.today().date()
def to_datetime(t_str):
return datetime.combine(TODAY_DATE, datetime.strptime(t_str, FMT).time())
NOW = to_datetime("9:00 am")
for t_str in ("9:10 am", "8:45 pm"):
t = to_datetime(t_str)
if t < NOW:
t += timedelta(days=1)
print(f"{t_str}, {(t - NOW)}, {(t - NOW).total_seconds() / 60:.0f} min")
it outputs:
9:10 am, 0:10:00, 10 min
8:45 pm, 11:45:00, 705 min
There are most likely better suited modules for that. But quick and dirty you could do:
def to_minutes(time_str)
time, suffix = time_str.split(" ")
hours, min = time.split(":")
if suffix == "pm":
hours+=12
min = hours*60+min
return min
time1 = to_minuntes("9:00 am")
time2 = to_minutes("8:45 pm")
diff = time2-time1
if diff < 0:
diff+= 24*60
# and if necessary you can do a
hours = diff //60
minutes = diff % 60
if hours > 0:
final_diff = f"{hours}h {minutes}min"
else:
final_diff = f"{minutes}min"
Related
I want to calculate the difference in minutes between two datetimes.
My current code results in a timedelta of '1 day, 23:33:00'.
My question is how can I convert this to minutes (or generate the timedelta in minutes)?
import datetime
import time
kodate = '2019-01-13'
kotime = '14:15'
currdatetime = datetime.datetime.now()
currdate = currdatetime.strftime("%Y-%m-%d")
currtime = currdatetime.strftime("%H:%M")
datetimeFormat = '%Y-%m-%d %H:%M'
time1 = currdate + ' ' + currtime
time2 = kodate + ' ' + kotime
timedelta = datetime.datetime.strptime(time2, datetimeFormat) - datetime.datetime.strptime(time1, datetimeFormat)
print ('Timedelta: ' + str(timedelta))
So the current timedelta is 1 day 23 hours and 33 minutes, when I actually want 2853 (i.e. the actual number of minutes).
There's no direct method to return it in minutes, so just divide the number of seconds:
minutes = timedelta.total_seconds() / 60
I'm trying to generate random list of 24hr timestamps. I can generate one sample of date and time between the set range using the code below. I'm hoping to generate multiple samples (e.g. 10 samples)
Also, the date component isn't a priority for me. If i could drop that and just generate random 24hr timestamps that would be good.
Most threads I've found only consider generate random dates. I can find anything that concerns time.
import random
import time
from datetime import datetime
def randomDate(start, end):
frmt = '%d-%m-%Y %H:%M:%S'
stime = time.mktime(time.strptime(start, frmt))
etime = time.mktime(time.strptime(end, frmt))
ptime = stime + random.random() * (etime - stime)
dt = datetime.fromtimestamp(time.mktime(time.localtime(ptime)))
return dt
random_datetime = randomDate("20-01-2018 13:30:00", "23-01-2018 04:50:34")
print(random_datetime)
Output:
2018-01-21 03:33:55
The whole point of the datetime library: datetime, timedelta, etc. objects act as much like numbers as possible, so you can just do arithmetic on them.
So, to generate a uniform distribution over a day, just take a uniform distribution from 0.0 to 1.0, and multiply it by a day:1
td = random.random() * datetime.timedelta(days=1)
To generate a uniform random time on some particular day, just add that to midnight on that day:
dt = datetime.datetime(2018, 5, 1) + random.random() * datetime.timedelta(days=1)
To generate a random timestamp between two timestamps:
dt = random.random() * (end - start) + start
And if you want 10 of those:
[random.random() * (end - start) + start for _ in range(10)]
That's all there is to it. Stay away from all those other time formats from the time module; they're only needed if you need compatibility with stuff like C libraries and filesystem data. Just use datetime in the first place:
def randomtimes(stime, etime, n):
frmt = '%d-%m-%Y %H:%M:%S'
stime = datetime.datetime.strptime(start, frmt)
etime = datetime.datetime.strptime(end, frmt)
td = etime - stime
return [random.random() * td + stime for _ in range(n)]
1. However, keep in mind that if you're dealing with local rather than UTC times, some days are actually 23 or 25 hours long, because of Daylight Saving Time. A timedelta doesn't understand that.
Depending on your needs, it might be well worth the trouble to learn the Python datetime and time modules. If your code will do lots of different manipulations, then go with #abarnert's answer. If all you need is a time string (rather than a Python timestamp), this function will crank it out for you:
import random
def randomTime():
# generate random number scaled to number of seconds in a day
# (24*60*60) = 86,400
rtime = int(random.random()*86400)
hours = int(rtime/3600)
minutes = int((rtime - hours*3600)/60)
seconds = rtime - hours*3600 - minutes*60
time_string = '%02d:%02d:%02d' % (hours, minutes, seconds)
return time_string
for i in range(10):
print(randomTime())
this outputs:
19:07:31
16:32:00
02:01:30
20:31:21
20:20:26
09:49:12
19:38:42
10:49:32
13:13:36
15:02:54
But if you don't want 24 hour time, then you can intercept the 'hours' variable before you stuff it in into the string:
import random
def randomTime():
# generate random number scaled to number of seconds in a day
# (24*60*60) = 86,400
rtime = int(random.random()*86400)
hours = int(rtime/3600)
minutes = int((rtime - hours*3600)/60)
seconds = rtime - hours*3600 - minutes*60
# figure out AM or PM
if hours >= 12:
suffix = 'PM'
if hours > 12:
hours = hours - 12
else:
suffix = 'AM'
time_string = '%02d:%02d:%02d' % (hours, minutes, seconds)
time_string += ' ' + suffix
return time_string
for i in range(10):
print(randomTime())
which gives :
05:11:45 PM
02:28:44 PM
08:09:19 PM
02:52:30 PM
07:40:02 PM
03:55:16 PM
03:48:44 AM
12:35:43 PM
01:32:51 PM
07:54:26 PM
In case you need continuous times:
from datetime import datetime,timedelta
time_starter = datetime.strptime("12:00:00","%H:%M:%S")
for i in range(1,10):
time = time_starter + timedelta(hours=i)
time = time.strftime("%H:%M:%S")
print(time)
if you need random or continuous minutes use:
time = time_starter + timedelta(minutes=i) #continuous
time = time_starter + timedelta(minutes=randint(0,60)) #random
import random
import time
from datetime import datetime
dates = []
def randomDate(start, end):
frmt = '%d-%m-%Y %H:%M:%S'
stime = time.mktime(time.strptime(start, frmt))
etime = time.mktime(time.strptime(end, frmt))
ptime = stime + random.random() * (etime - stime)
dt = datetime.fromtimestamp(time.mktime(time.localtime(ptime)))
return dt
for i in range(0 , 10)
dates.append(randomDate("20-01-2018 13:30:00", "23-01-2018 04:50:34"))
Your dates will have a list of 10 sample date :)
Good Luck
I have a db record created with Django with a ‘created_at' field in the format 'timestamp with time zone': 2017-01-13 14:12:18.307877+00:00.
I need to check if 30 seconds have elapsed between that time and now.
Should I first convert it to epoch time ? If yes how, without being hit by timezone issues ?
With the string
2017-01-13 14:12:18.307877+00:00
we can use the datetime.datetime.strptime function to produce a datetime object that we can then do time arithmetic with.
First, we remove the last :, because the format for timezones that datetime uses is +0000 not +00:00. Then we hand that string to strptime along with a format string.
from datetime import datetime, timedelta
s = '2017-01-13 14:12:18.307877+00:00'
s = s[:-3]+s[-2:]
pat = '%Y-%m-%d %H:%M:%S.%f%z'
then = datetime.strptime(s, pat)
if datetime.now(then.tzinfo) - then < timedelta(0, 30):
print("It has been less than 30 seconds")
If this is a datetime object, then you can subtract another datetime object and get a timedelta, where you can ask elapsed time.
d1 = datetime(2017, 1, 1) # create datetime at 2017-01-01T00:00
d0 = datetime.now()
diff = (d0 - d1).seconds
if diff > 30:
pass
The datetime method takes an optional tzinfo, which you can use the set the timezone. This is just a subclass of datetime.tzinfo
Example with GMT +1
class GMT1(tzinfo):
def utcoffset(self, dt):
return timedelta(hours=1) + self.dst(dt)
def dst(self, dt):
# DST starts last Sunday in March
d = datetime(dt.year, 4, 1) # ends last Sunday in October
self.dston = d - timedelta(days=d.weekday() + 1)
d = datetime(dt.year, 11, 1)
self.dstoff = d - timedelta(days=d.weekday() + 1)
if self.dston <= dt.replace(tzinfo=None) < self.dstoff:
return timedelta(hours=1)
else:
return timedelta(0)
def tzname(self,dt):
return "GMT +1"
Then you can do
d0 = datetime(2017, 1, 1, tzinfo=GMT1())
I want to know how many years, months, days, hours, minutes and seconds in between '2014-05-06 12:00:56' and '2012-03-06 16:08:22'. The result shall looked like: “the difference is xxx year xxx month xxx days xxx hours xxx minutes”
For example:
import datetime
a = '2014-05-06 12:00:56'
b = '2013-03-06 16:08:22'
start = datetime.datetime.strptime(a, '%Y-%m-%d %H:%M:%S')
ends = datetime.datetime.strptime(b, '%Y-%m-%d %H:%M:%S')
diff = start – ends
if I do:
diff.days
It gives the difference in days.
What else I can do? And how can I achieve the wanted result?
Use a relativedelta from the dateutil package. This will take into account leap years and other quirks.
import datetime
from dateutil.relativedelta import relativedelta
a = '2014-05-06 12:00:56'
b = '2013-03-06 16:08:22'
start = datetime.datetime.strptime(a, '%Y-%m-%d %H:%M:%S')
ends = datetime.datetime.strptime(b, '%Y-%m-%d %H:%M:%S')
diff = relativedelta(start, ends)
>>> print "The difference is %d year %d month %d days %d hours %d minutes" % (diff.years, diff.months, diff.days, diff.hours, diff.minutes)
The difference is 1 year 1 month 29 days 19 hours 52 minutes
You might want to add some logic to print for e.g. "2 years" instead of "2 year".
diff is a timedelta instance.
for python2, see:
https://docs.python.org/2/library/datetime.html#timedelta-objects
for python 3, see:
https://docs.python.org/3/library/datetime.html#timedelta-objects
from docs:
timdelta instance attributes (read-only):
days
seconds
microseconds
timdelta instance methods:
total_seconds()
timdelta class attributes are:
min
max
resolution
You can use the days and seconds instance attributes to calculate what you need.
for example:
import datetime
a = '2014-05-06 12:00:56'
b = '2013-03-06 16:08:22'
start = datetime.datetime.strptime(a, '%Y-%m-%d %H:%M:%S')
ends = datetime.datetime.strptime(b, '%Y-%m-%d %H:%M:%S')
diff = start - ends
hours = int(diff.seconds // (60 * 60))
mins = int((diff.seconds // 60) % 60)
I'm trying to get my head around the datetime module. I know the time now as an epoch and the time an event last happened (as an epoch time). What I need to do is figure out whether that event happened between midnight and midnight of yesterday.
t = time.time() # is now
t2 = 1234567890 # some arbitrary time from my log
24 hours ago is t - 86400, but how can I round that up and down to midnight. I'm having real trouble finding a way to get timestamps in and out of datetime or then manipulating a datetime to set the time.
In the Middle of the Night
Generating the last midnight is easy:
from datetime import datetime, time
midnight = datetime.combine(datetime.today(), time.min)
That combines today's date (you can use date() or a datetime() instance, your pick), together with time.min to form a datetime object at midnight.
Yesterday
With a timedelta() you can calculate the previous midnight:
from datetime import timedelta
yesterday_midnight = midnight - timedelta(days=1)
That Was Yesterday
Now test if your timestamp is in between these two points:
timestamp = datetime.fromtimestamp(some_timestamp_from_your_log)
if yesterday_midnight <= timestamp < midnight:
# this happened between 00:00:00 and 23:59:59 yesterday
All Together Now
Combined into one function:
from datetime import datetime, time, timedelta
def is_yesterday(timestamp):
midnight = datetime.combine(datetime.today(), time.min)
yesterday_midnight = midnight - timedelta(days=1)
return yesterday_midnight <= timestamp < midnight:
if is_yesterday(datetime.fromtimestamp(some_timestamp_from_your_log)):
# ...
Midnight at the start of today is:
midnight = (int(time.time() // 86400)) * 86400
so yesterday's midnight is:
midnight = (int(time.time() // 86400)) * 86400 - 86400
Given such a timestamp, you can use divmod to compute the number of days since the epoch (which you don't care about), and how many seconds are leftover (which you do):
days_since, remaining_seconds = divmod(t, 24*3600) # Divide by number of seconds in one day
Then, you subtract the leftover seconds from your original timestamp, which produces midnight
of the current day.
t -= remaining_seconds
Rounding up is as simple as shifting your target timestamp forward exactly one day before rounding down.
tomorrow_t = t + 24 * 3600
days_since, remaining_seconds = divmod(tomorrow_t, 24*3600)
t = tomorrow_t - remaining_seconds
To get the specific timezone's midnight timestamp:
from datetime import datetime
import pytz
TZ = "Asia/Shanghai"
datetime.now(pytz.timezone(TZ)).replace(hour=0, minute=0, second=0, microsecond=0).timestamp()
In my estimation, many date and time manipulations are easier to do, and to understand, using the arrow library. This is one of them.
Create an arbitrary date and time.
>>> import arrow
>>> arbitrary = arrow.get(2017,8,16,11,5)
Calculate midnight_yesterday: first, midnight of arbitrary as its 'day' floor; then shift this back by one day. Display the result.
>>> midnight_yesterday = arbitrary.floor('day').shift(days=-1)
>>> midnight_yesterday
<Arrow [2017-08-15T00:00:00+00:00]>
Use timestamp for the desired overall result, for Python 3.3+.
>>> midnight_yesterday.datetime.timestamp()
1502755200.0
Or use this expression for Python 2.7. (Credit: https://stackoverflow.com/a/11743262/131187 for the latter two expressions.)
>>> (midnight_yesterday-arrow.get(1970,1,1)).total_seconds()
1502755200.0
You can use this code:
import time
seconds_of_day = 24 * 60 * 60 # 86400
last_midnight = (round(time.time()) // seconds_of_day) * seconds_of_day
yesterday_last_midnight = last_midnight - seconds_of_day
import time
start_str = time.strftime( "%m/%d/%Y" ) + " 00:00:00"
end_str = time.strftime( "%m/%d/%Y ") + " 23:59:59"
start_ts = int( time.mktime( time.strptime( start_str, "%m/%d/%Y %H:%M:%S" ) ) )
end_ts = int( time.mktime( time.strptime( end_str, "%m/%d/%Y %H:%M:%S" ) ) )
print (start_ts) # timestamp today at 00:00:00
print (end_ts) # timestamp today at 23:59:59
# 1552435200
# 1552521599
Source Python get unix epoch for today’s midnight and today’s 23:59:59 (start of day, end of day)