Get Random Time Between Midnight to Current Time - python

I'm trying to get the get the random time between midnight and the current time in seconds.
Example
12:01 AM -> 10:15 AM of today which is 04/02/2016
def random_date(start, end):
delta = end - start
int_delta = (delta.days * 24 * 60 * 60) + delta.seconds
random_second = randrange(int_delta)
return start + timedelta(seconds=random_second)
start = datetime.datetime.strptime('2016-04-02 12:00:00', '%Y-%m-%d %H:%M:%S')
end = datetime.datetime.strptime(strftime('%Y-%m-%d %H:%M:%S', gmtime()), '%Y-%m-%d %H:%M:%S')
print random_date(start, end)
Result
python new_visitor.py
2016-04-02 04:49:54
──[/Applications/MAMP/htdocs/code/python]
└── python new_visitor.py
2016-04-02 09:06:15
──[/Applications/MAMP/htdocs/code/python]
└── python new_visitor.py
2016-04-02 08:59:22
──[/Applications/MAMP/htdocs/code/python]
└── python new_visitor.py
2016-04-02 **12:36:38**
──[/Applications/MAMP/htdocs/code/python]
└── python new_visitor.py
2016-04-02 02:38:54
Current time is 10:22 AM; I went passed the current time.

Take the current time, subtract the current date at midnight to get a timedelta giving you the number of seconds, use random.randrange() to get a new offset and translate that back with the help of timedelta again:
from datetime import datetime, time, timedelta
import random
now = datetime.now()
midnight = datetime.combine(now.date(), time.min)
delta = int((now - midnight).total_seconds())
random_dt = midnight + timedelta(seconds=random.randrange(delta))
Demo:
>>> from datetime import datetime, time, timedelta
>>> import random
>>> now = datetime.now()
>>> midnight = datetime.combine(now.date(), time.min)
>>> delta = int((now - midnight).total_seconds())
>>> midnight + timedelta(seconds=random.randrange(delta))
datetime.datetime(2016, 4, 2, 2, 11, 11)
>>> midnight + timedelta(seconds=random.randrange(delta))
datetime.datetime(2016, 4, 2, 0, 45, 35)
>>> midnight + timedelta(seconds=random.randrange(delta))
datetime.datetime(2016, 4, 2, 5, 56, 58)
>>> midnight + timedelta(seconds=random.randrange(delta))
datetime.datetime(2016, 4, 2, 4, 35, 47)
>>> midnight + timedelta(seconds=random.randrange(delta))
datetime.datetime(2016, 4, 2, 2, 10, 1)

Here's a modification of #Martijn Pieters' answer, to avoid producing bias or non-existing times around DST transitions:
#!/usr/bin/env python
from datetime import datetime, timedelta
from random import randrange
from tzlocal import get_localzone # $ pip install tzlocal
local_timezone = get_localzone()
now = datetime.now(local_timezone)
today = datetime(now.year, now.month, now.day)
midnight = local_timezone.normalize(local_timezone.localize(today, is_dst=False))
max_seconds = int((now - midnight).total_seconds())
random_time = midnight + timedelta(seconds=randrange(max_seconds))
is_dst=False is used to avoid ambiguity if there is a DST transition at midnight.

Related

How to round down a datetime to the nearest 5 Minutes?

I need a Python3 function that rounds down a datetime.datetime object to the nearest 5 minutes. Yes, this has been discussed in previous SO posts here and here and even here, but I'm having no luck implementing their solutions.
NOTE: I can not use pandas
I want a function, given the below DateTime (%Y%m%d%H%M) objects, returns the following:
INPUT OUTPUT
202301131600 202301131600
202301131602 202301131600
202301131604 202301131600
202301131605 202301131605
202301131609 202301131605
202301131610 202301131610
Here's my code, using timedelta as a mechanism:
from datetime import datetime
from datetime import timedelta
def roundDownDateTime(dt):
# Arguments:
# dt DateTime object
delta = timedelta(minutes=5)
return dt - (datetime.min - dt) % delta
tmpDate = datetime.now()
# Print the current time and then rounded-down time:
print("\t"+tmpDate.strftime('%Y%m%d%H%M')+" --> "+(roundDownDateTime(tmpDate)).strftime('%Y%m%d%H%M') )
Here's some output when I test the code multiple times:
202301131652 --> 202301131650
202301131700 --> 202301131655
202301131701 --> 202301131657
Ugh, no good! I adapted my function to this:
def roundDownDateTime(dt):
# Arguments:
# dt DateTime object
n = dt - timedelta(minutes=5)
return datetime(year=n.year, month=n.month, day=n.day, hour=n.hour)
But that was even worse:
202301131703 --> 202301131600
202301131707 --> 202301131700
202301131710 --> 202301131700
I am all thumbs when figuring out this basic datetime arithmetic stuff; can anyone see my error?
Since you can only affect the minutes by rounding down to the nearest 5 minutes, just figure out how many minutes you need to subtract. Set everything else from the original datetime object, and seconds and microseconds to zero:
def roundDownDateTime(dt):
delta_min = dt.minute % 5
return datetime.datetime(dt.year, dt.month, dt.day,
dt.hour, dt.minute - delta_min)
To test:
import datetime
expio = [['202301131600', '202301131600'],
['202301131602', '202301131600'],
['202301131604', '202301131600'],
['202301131605', '202301131605'],
['202301131609', '202301131605'],
['202301131610', '202301131610']]
for i, eo in expio:
o = roundDownDateTime(datetime.datetime.strptime(i, "%Y%m%d%H%M")).strftime("%Y%m%d%H%M")
assert eo == o
asserts all True
You have (datetime.min - dt) backwards - this results in a negative value which doesn't behave the way you expect with %. If you swap to (dt - datetime.min) you get your expected results:
In []:
def roundDownDateTime(dt, delta=timedelta(minutes=5)):
return dt - (dt - datetime.min) % delta
tmpDate = datetime.now()
tmpDate
Out[]:
datetime.datetime(2023, 1, 13, 11, 36, 7, 821196)
In []:
roundDownDateTime(tmpDate)
Out[]:
datetime.datetime(2023, 1, 13, 11, 35)
In []:
roundDownDateTime(tmpDate, timedelta(minutes=10)
Out[]:
datetime.datetime(2023, 1, 13, 11, 30)
I think I would be inclined to obtain the timestamp and round it then convert back to datetime:
def round_datetime(dt, secs):
return datetime.datetime.fromtimestamp(secs * (dt.timestamp() // secs))
You might test with:
import datetime
import time
def round_datetime(dt, secs):
return datetime.datetime.fromtimestamp(secs * (dt.timestamp() // secs))
while True:
now = datetime.datetime.now()
print(now, round_datetime(now, 5 * 60))
time.sleep(1)

python - iteration by date and time - half hour

I think about how to iterate by data and time in following way:
2016-06-10,00:00
2016-06-10,01:30
2016-06-10,02:00
2016-06-10,02:30
....
Can somebody help me ?
Use timedelta to generate a range of datetime objects:
from datetime import timedelta, datetime
start_date = datetime(2016, 6, 9, 5, 0, 0)
for td in (start_date + timedelta(minutes=30*it) for it in xrange(10)):
print td.strftime("%Y-%m-%d,%H:%M")
Output:
2016-06-09,05:00
2016-06-09,05:30
2016-06-09,06:00
2016-06-09,06:30
2016-06-09,07:00
2016-06-09,07:30
2016-06-09,08:00
2016-06-09,08:30
2016-06-09,09:00
2016-06-09,09:30
import datetime
from datetime import timedelta
format = "%Y-%m-%d,%H:%M"
start = datetime.datetime(2016, 6, 10, 0, 0)
minutes = 0
for i in range(6):
print (start + timedelta(minutes=minutes)).strftime(format)
minutes += 30
Output:
$ python timespan.py
2016-06-10,00:00
2016-06-10,00:30
2016-06-10,01:00
2016-06-10,01:30
2016-06-10,02:00
2016-06-10,02:30

print dates between two dates: TypeError: Required argument 'month' (pos 2) not found

I am trying to print list of dates between two dates but I keep getting error. Below is my code can you please help me figure this out.
#!/usr/bin/python
import sys
from datetime import date, timedelta as td
d1 = date(2016-02-04)
d2 = date(2016-02-06)
delta = d2 - d1
for i in range(delta.days + 1):
print d1 + td(days=i)
See Print all day-dates between two dates
Also, date() takes three arguments, the day, month and year.
Code:
from datetime import date, timedelta as td
d1 = date(2008, 8, 15)
d2 = date(2008, 9, 15)
delta = d2 - d1
for i in range(delta.days + 1):
print d1 + td(days=i)
Addressing the error first, you are defining dates like this:
date(2016-02-04)
However the proper syntax is:
#date(Year, Month, Day)
date(2016, 2, 6)
Now for the days in range question:
from datetime import date, timedelta
d1 = date(2016, 2, 4)
d2 = date(2016, 2, 6)
delta = (d2 - d1).days
days = [d1 + timedelta(days=days_to_add) for days_to_add in range(0, delta+1)]
print days
The above outputs:
[datetime.date(2016, 2, 4), datetime.date(2016, 2, 5), datetime.date(2016, 2, 6)]
Note that the solution provided assumes you want to include both the start and end date. If you intended differrently alter the range function.
Also if you would like to print it out in the format you provided you could use the strftime method
for day in days:
print day.strftime("%Y-%m-%d")
Outputs:
2016-02-04
2016-02-05
2016-02-06
Here is the solution
#!/usr/bin/python
import sys
from datetime import timedelta, date, datetime
def daterange(start_date, end_date):
for n in range((end_date - start_date).days):
yield start_date + timedelta(n)
d1= str(sys.argv[1]) #start date in YYYY-MM-DD
d2= str(sys.argv[2]) #end date in YYYY-MM-DD
start_date = datetime.strptime(d1, "%Y-%m-%d")
end_date = datetime.strptime(d2, "%Y-%m-%d")
for single_date in daterange(start_date, end_date):
input1 = single_date.strftime("%Y-%m-%d")
print input1
As MattCorr said, the only change you need to make is that date() takes three arguments, and you need to format days/months properly ('2' instead of '02' for the example you provided).
EDIT:
The edits I suggest are added here.
from datetime import date, timedelta as td
d1 = date(2016, 2, 4)
d2 = date(2016, 2, 6)
delta = d2 - d1
for i in range(delta.days + 1):
print(d1 + td(days=i))
Output:
2016-02-04
2016-02-05
2016-02-06

How do I set a python datetime to something that is (somewhat) relative to now?

I can do some basic time calcs in python such as these:
when = 'Mon Sep 08 00:00:00 +0000 2014'
frmt = "%a %b %d %H:%M:%S +0000 %Y"
then = datetime.datetime.strptime(when,frmt)
now = datetime.datetime.now()
delta = now-then
print delta
That will calculate how much time has elapsed since when.
What I want to do is to set when to a very specific time. And that time will depend on what today is. I want when to be midnight (zero hours) of the immediately previous Monday from today. How can I do that?
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2014, 9, 10, 12, 40, 25, 525000)
>>> when = now.replace(hour=0, minute=0, second=0, microsecond=0)
>>> when
datetime.datetime(2014, 9, 10, 0, 0)
>>> when.weekday()
2
>>> when = when - datetime.timedelta(when.weekday())
>>> when
datetime.datetime(2014, 9, 8, 0, 0)
This should give you what you want.
from datetime import datetime, timedelta
today = datetime.now()
days_from_monday = today.weekday()
if days_from_monday == 0:
days_from_monday = 7
monday = today + timedelta(days=-days_from_monday)
midnight_monday = monday.replace(hour=0, minute=0, second=0)
datetime.replace can be used to easily change parts of a datetime, but note that datetimes are immutable and that .replace returns a new one.
datetime.weekday will give you the day of the week. Monday=0 to Saturday=6

How to round the minute of a datetime object

I have a datetime object produced using strptime().
>>> tm
datetime.datetime(2010, 6, 10, 3, 56, 23)
What I need to do is round the minute to the closest 10th minute. What I have been doing up to this point was taking the minute value and using round() on it.
min = round(tm.minute, -1)
However, as with the above example, it gives an invalid time when the minute value is greater than 56. i.e.: 3:60
What is a better way to do this? Does datetime support this?
This will get the 'floor' of a datetime object stored in tm rounded to the 10 minute mark before tm.
tm = tm - datetime.timedelta(minutes=tm.minute % 10,
seconds=tm.second,
microseconds=tm.microsecond)
If you want classic rounding to the nearest 10 minute mark, do this:
discard = datetime.timedelta(minutes=tm.minute % 10,
seconds=tm.second,
microseconds=tm.microsecond)
tm -= discard
if discard >= datetime.timedelta(minutes=5):
tm += datetime.timedelta(minutes=10)
or this:
tm += datetime.timedelta(minutes=5)
tm -= datetime.timedelta(minutes=tm.minute % 10,
seconds=tm.second,
microseconds=tm.microsecond)
General function to round a datetime at any time lapse in seconds:
def roundTime(dt=None, roundTo=60):
"""Round a datetime object to any time lapse in seconds
dt : datetime.datetime object, default now.
roundTo : Closest number of seconds to round to, default 1 minute.
Author: Thierry Husson 2012 - Use it as you want but don't blame me.
"""
if dt == None : dt = datetime.datetime.now()
seconds = (dt.replace(tzinfo=None) - dt.min).seconds
rounding = (seconds+roundTo/2) // roundTo * roundTo
return dt + datetime.timedelta(0,rounding-seconds,-dt.microsecond)
Samples with 1 hour rounding & 30 minutes rounding:
print roundTime(datetime.datetime(2012,12,31,23,44,59,1234),roundTo=60*60)
2013-01-01 00:00:00
print roundTime(datetime.datetime(2012,12,31,23,44,59,1234),roundTo=30*60)
2012-12-31 23:30:00
I used Stijn Nevens code (thank you Stijn) and have a little add-on to share. Rounding up, down and rounding to nearest.
update 2019-03-09 = comment Spinxz incorporated; thank you.
update 2019-12-27 = comment Bart incorporated; thank you.
Tested for date_delta of "X hours" or "X minutes" or "X seconds".
import datetime
def round_time(dt=None, date_delta=datetime.timedelta(minutes=1), to='average'):
"""
Round a datetime object to a multiple of a timedelta
dt : datetime.datetime object, default now.
dateDelta : timedelta object, we round to a multiple of this, default 1 minute.
from: http://stackoverflow.com/questions/3463930/how-to-round-the-minute-of-a-datetime-object-python
"""
round_to = date_delta.total_seconds()
if dt is None:
dt = datetime.now()
seconds = (dt - dt.min).seconds
if seconds % round_to == 0 and dt.microsecond == 0:
rounding = (seconds + round_to / 2) // round_to * round_to
else:
if to == 'up':
# // is a floor division, not a comment on following line (like in javascript):
rounding = (seconds + dt.microsecond/1000000 + round_to) // round_to * round_to
elif to == 'down':
rounding = seconds // round_to * round_to
else:
rounding = (seconds + round_to / 2) // round_to * round_to
return dt + datetime.timedelta(0, rounding - seconds, - dt.microsecond)
# test data
print(round_time(datetime.datetime(2019,11,1,14,39,00), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2019,11,2,14,39,00,1), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2019,11,3,14,39,00,776980), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2019,11,4,14,39,29,776980), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2018,11,5,14,39,00,776980), date_delta=datetime.timedelta(seconds=30), to='down'))
print(round_time(datetime.datetime(2018,11,6,14,38,59,776980), date_delta=datetime.timedelta(seconds=30), to='down'))
print(round_time(datetime.datetime(2017,11,7,14,39,15), date_delta=datetime.timedelta(seconds=30), to='average'))
print(round_time(datetime.datetime(2017,11,8,14,39,14,999999), date_delta=datetime.timedelta(seconds=30), to='average'))
print(round_time(datetime.datetime(2019,11,9,14,39,14,999999), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2012,12,10,23,44,59,7769),to='average'))
print(round_time(datetime.datetime(2012,12,11,23,44,59,7769),to='up'))
print(round_time(datetime.datetime(2010,12,12,23,44,59,7769),to='down',date_delta=datetime.timedelta(seconds=1)))
print(round_time(datetime.datetime(2011,12,13,23,44,59,7769),to='up',date_delta=datetime.timedelta(seconds=1)))
print(round_time(datetime.datetime(2012,12,14,23,44,59),date_delta=datetime.timedelta(hours=1),to='down'))
print(round_time(datetime.datetime(2012,12,15,23,44,59),date_delta=datetime.timedelta(hours=1),to='up'))
print(round_time(datetime.datetime(2012,12,16,23,44,59),date_delta=datetime.timedelta(hours=1)))
print(round_time(datetime.datetime(2012,12,17,23,00,00),date_delta=datetime.timedelta(hours=1),to='down'))
print(round_time(datetime.datetime(2012,12,18,23,00,00),date_delta=datetime.timedelta(hours=1),to='up'))
print(round_time(datetime.datetime(2012,12,19,23,00,00),date_delta=datetime.timedelta(hours=1)))
From the best answer I modified to an adapted version using only datetime objects, this avoids having to do the conversion to seconds and makes the calling code more readable:
def roundTime(dt=None, dateDelta=datetime.timedelta(minutes=1)):
"""Round a datetime object to a multiple of a timedelta
dt : datetime.datetime object, default now.
dateDelta : timedelta object, we round to a multiple of this, default 1 minute.
Author: Thierry Husson 2012 - Use it as you want but don't blame me.
Stijn Nevens 2014 - Changed to use only datetime objects as variables
"""
roundTo = dateDelta.total_seconds()
if dt == None : dt = datetime.datetime.now()
seconds = (dt - dt.min).seconds
# // is a floor division, not a comment on following line:
rounding = (seconds+roundTo/2) // roundTo * roundTo
return dt + datetime.timedelta(0,rounding-seconds,-dt.microsecond)
Samples with 1 hour rounding & 15 minutes rounding:
print roundTime(datetime.datetime(2012,12,31,23,44,59),datetime.timedelta(hour=1))
2013-01-01 00:00:00
print roundTime(datetime.datetime(2012,12,31,23,44,49),datetime.timedelta(minutes=15))
2012-12-31 23:30:00
Pandas has a datetime round feature, but as with most things in Pandas it needs to be in Series format.
>>> ts = pd.Series(pd.date_range(Dt(2019,1,1,1,1),Dt(2019,1,1,1,4),periods=8))
>>> print(ts)
0 2019-01-01 01:01:00.000000000
1 2019-01-01 01:01:25.714285714
2 2019-01-01 01:01:51.428571428
3 2019-01-01 01:02:17.142857142
4 2019-01-01 01:02:42.857142857
5 2019-01-01 01:03:08.571428571
6 2019-01-01 01:03:34.285714285
7 2019-01-01 01:04:00.000000000
dtype: datetime64[ns]
>>> ts.dt.round('1min')
0 2019-01-01 01:01:00
1 2019-01-01 01:01:00
2 2019-01-01 01:02:00
3 2019-01-01 01:02:00
4 2019-01-01 01:03:00
5 2019-01-01 01:03:00
6 2019-01-01 01:04:00
7 2019-01-01 01:04:00
dtype: datetime64[ns]
Docs - Change the frequency string as needed.
Here is a simpler generalized solution without floating point precision issues and external library dependencies:
import datetime
def time_mod(time, delta, epoch=None):
if epoch is None:
epoch = datetime.datetime(1970, 1, 1, tzinfo=time.tzinfo)
return (time - epoch) % delta
def time_round(time, delta, epoch=None):
mod = time_mod(time, delta, epoch)
if mod < delta / 2:
return time - mod
return time + (delta - mod)
def time_floor(time, delta, epoch=None):
mod = time_mod(time, delta, epoch)
return time - mod
def time_ceil(time, delta, epoch=None):
mod = time_mod(time, delta, epoch)
if mod:
return time + (delta - mod)
return time
In your case:
>>> tm = datetime.datetime(2010, 6, 10, 3, 56, 23)
>>> time_round(tm, datetime.timedelta(minutes=10))
datetime.datetime(2010, 6, 10, 4, 0)
>>> time_floor(tm, datetime.timedelta(minutes=10))
datetime.datetime(2010, 6, 10, 3, 50)
>>> time_ceil(tm, datetime.timedelta(minutes=10))
datetime.datetime(2010, 6, 10, 4, 0)
if you don't want to use condition, you can use modulo operator:
minutes = int(round(tm.minute, -1)) % 60
UPDATE
did you want something like this?
def timeround10(dt):
a, b = divmod(round(dt.minute, -1), 60)
return '%i:%02i' % ((dt.hour + a) % 24, b)
timeround10(datetime.datetime(2010, 1, 1, 0, 56, 0)) # 0:56
# -> 1:00
timeround10(datetime.datetime(2010, 1, 1, 23, 56, 0)) # 23:56
# -> 0:00
.. if you want result as string. for obtaining datetime result, it's better to use timedelta - see other responses ;)
i'm using this. it has the advantage of working with tz aware datetimes.
def round_minutes(some_datetime: datetime, step: int):
""" round up to nearest step-minutes """
if step > 60:
raise AttrbuteError("step must be less than 60")
change = timedelta(
minutes= some_datetime.minute % step,
seconds=some_datetime.second,
microseconds=some_datetime.microsecond
)
if change > timedelta():
change -= timedelta(minutes=step)
return some_datetime - change
it has the disadvantage of only working for timeslices less than an hour.
A straightforward approach:
def round_time(dt, round_to_seconds=60):
"""Round a datetime object to any number of seconds
dt: datetime.datetime object
round_to_seconds: closest number of seconds for rounding, Default 1 minute.
"""
rounded_epoch = round(dt.timestamp() / round_to_seconds) * round_to_seconds
rounded_dt = datetime.datetime.fromtimestamp(rounded_epoch).astimezone(dt.tzinfo)
return rounded_dt
This will do it, I think it uses a very useful application of round.
from typing import Literal
import math
def round_datetime(dt: datetime.datetime, step: datetime.timedelta, d: Literal['no', 'up', 'down'] = 'no'):
step = step.seconds
round_f = {'no': round, 'up': math.ceil, 'down': math.floor}
return datetime.datetime.fromtimestamp(step * round_f[d](dt.timestamp() / step))
date = datetime.datetime(year=2022, month=11, day=16, hour=10, minute=2, second=30, microsecond=424242)#
print('Original:', date)
print('Standard:', round_datetime(date, datetime.timedelta(minutes=5)))
print('Down: ', round_datetime(date, datetime.timedelta(minutes=5), d='down'))
print('Up: ', round_datetime(date, datetime.timedelta(minutes=5), d='up'))
The result:
Original: 2022-11-16 10:02:30.424242
Standard: 2022-11-16 10:05:00
Down: 2022-11-16 10:00:00
Up: 2022-11-16 10:05:00
yes, if your data belongs to a DateTime column in a pandas series, you can round it up using the built-in pandas.Series.dt.round function.
See documentation here on pandas.Series.dt.round.
In your case of rounding to 10min it will be Series.dt.round('10min') or Series.dt.round('600s') like so:
pandas.Series(tm).dt.round('10min')
Edit to add Example code:
import datetime
import pandas
tm = datetime.datetime(2010, 6, 10, 3, 56, 23)
tm_rounded = pandas.Series(tm).dt.round('10min')
print(tm_rounded)
>>> 0 2010-06-10 04:00:00
dtype: datetime64[ns]
I came up with this very simple function, working with any timedelta as long as it's either a multiple or divider of 60 seconds. It's also compatible with timezone-aware datetimes.
#!/usr/env python3
from datetime import datetime, timedelta
def round_dt_to_delta(dt, delta=timedelta(minutes=30)):
ref = datetime.min.replace(tzinfo=dt.tzinfo)
return ref + round((dt - ref) / delta) * delta
Output:
In [1]: round_dt_to_delta(datetime(2012,12,31,23,44,49), timedelta(seconds=15))
Out[1]: datetime.datetime(2012, 12, 31, 23, 44, 45)
In [2]: round_dt_to_delta(datetime(2012,12,31,23,44,49), timedelta(minutes=15))
Out[2]: datetime.datetime(2012, 12, 31, 23, 45)
General Function to round down times of minutes:
from datetime import datetime
def round_minute(date: datetime = None, round_to: int = 1):
"""
round datetime object to minutes
"""
if not date:
date = datetime.now()
date = date.replace(second=0, microsecond=0)
delta = date.minute % round_to
return date.replace(minute=date.minute - delta)
Those seem overly complex
def round_down_to():
num = int(datetime.utcnow().replace(second=0, microsecond=0).minute)
return num - (num%10)
def get_rounded_datetime(self, dt, freq, nearest_type='inf'):
if freq.lower() == '1h':
round_to = 3600
elif freq.lower() == '3h':
round_to = 3 * 3600
elif freq.lower() == '6h':
round_to = 6 * 3600
else:
raise NotImplementedError("Freq %s is not handled yet" % freq)
# // is a floor division, not a comment on following line:
seconds_from_midnight = dt.hour * 3600 + dt.minute * 60 + dt.second
if nearest_type == 'inf':
rounded_sec = int(seconds_from_midnight / round_to) * round_to
elif nearest_type == 'sup':
rounded_sec = (int(seconds_from_midnight / round_to) + 1) * round_to
else:
raise IllegalArgumentException("nearest_type should be 'inf' or 'sup'")
dt_midnight = datetime.datetime(dt.year, dt.month, dt.day)
return dt_midnight + datetime.timedelta(0, rounded_sec)
Based on Stijn Nevens and modified for Django use to round current time to the nearest 15 minute.
from datetime import date, timedelta, datetime, time
def roundTime(dt=None, dateDelta=timedelta(minutes=1)):
roundTo = dateDelta.total_seconds()
if dt == None : dt = datetime.now()
seconds = (dt - dt.min).seconds
# // is a floor division, not a comment on following line:
rounding = (seconds+roundTo/2) // roundTo * roundTo
return dt + timedelta(0,rounding-seconds,-dt.microsecond)
dt = roundTime(datetime.now(),timedelta(minutes=15)).strftime('%H:%M:%S')
dt = 11:45:00
if you need full date and time just remove the .strftime('%H:%M:%S')
Not the best for speed when the exception is caught, however this would work.
def _minute10(dt=datetime.utcnow()):
try:
return dt.replace(minute=round(dt.minute, -1))
except ValueError:
return dt.replace(minute=0) + timedelta(hours=1)
Timings
%timeit _minute10(datetime(2016, 12, 31, 23, 55))
100000 loops, best of 3: 5.12 µs per loop
%timeit _minute10(datetime(2016, 12, 31, 23, 31))
100000 loops, best of 3: 2.21 µs per loop
A two line intuitive solution to round to a given time unit, here seconds, for a datetime object t:
format_str = '%Y-%m-%d %H:%M:%S'
t_rounded = datetime.strptime(datetime.strftime(t, format_str), format_str)
If you wish to round to a different unit simply alter format_str.
This approach does not round to arbitrary time amounts as above methods, but is a nicely Pythonic way to round to a given hour, minute or second.
Other solution:
def round_time(timestamp=None, lapse=0):
"""
Round a timestamp to a lapse according to specified minutes
Usage:
>>> import datetime, math
>>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), 0)
datetime.datetime(2010, 6, 10, 3, 56)
>>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), 1)
datetime.datetime(2010, 6, 10, 3, 57)
>>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), -1)
datetime.datetime(2010, 6, 10, 3, 55)
>>> round_time(datetime.datetime(2019, 3, 11, 9, 22, 11), 3)
datetime.datetime(2019, 3, 11, 9, 24)
>>> round_time(datetime.datetime(2019, 3, 11, 9, 22, 11), 3*60)
datetime.datetime(2019, 3, 11, 12, 0)
>>> round_time(datetime.datetime(2019, 3, 11, 10, 0, 0), 3)
datetime.datetime(2019, 3, 11, 10, 0)
:param timestamp: Timestamp to round (default: now)
:param lapse: Lapse to round in minutes (default: 0)
"""
t = timestamp or datetime.datetime.now() # type: Union[datetime, Any]
surplus = datetime.timedelta(seconds=t.second, microseconds=t.microsecond)
t -= surplus
try:
mod = t.minute % lapse
except ZeroDivisionError:
return t
if mod: # minutes % lapse != 0
t += datetime.timedelta(minutes=math.ceil(t.minute / lapse) * lapse - t.minute)
elif surplus != datetime.timedelta() or lapse < 0:
t += datetime.timedelta(minutes=(t.minute / lapse + 1) * lapse - t.minute)
return t
Hope this helps!
The shortest way I know
min = tm.minute // 10 * 10
Most of the answers seem to be too complicated for such a simple question.
Assuming your_time is the datetime object your have, the following rounds (actually floors) it at a desired resolution defined in minutes.
from math import floor
your_time = datetime.datetime.now()
g = 10 # granularity in minutes
print(
datetime.datetime.fromtimestamp(
floor(your_time.timestamp() / (60*g)) * (60*g)
))
The function below with minimum of import will do the job. You can round to anything you want by setting te parameters unit, rnd, and frm. Play with the function and you will see how easy it will be.
def toNearestTime(ts, unit='sec', rnd=1, frm=None):
''' round to nearest Time format
param ts = time string to round in '%H:%M:%S' or '%H:%M' format :
param unit = specify unit wich must be rounded 'sec' or 'min' or 'hour', default is seconds :
param rnd = to which number you will round, the default is 1 :
param frm = the output (return) format of the time string, as default the function take the unit format'''
from time import strftime, gmtime
ts = ts + ':00' if len(ts) == 5 else ts
if 'se' in unit.lower():
frm = '%H:%M:%S' if frm is None else frm
elif 'm' in unit.lower():
frm = '%H:%M' if frm is None else frm
rnd = rnd * 60
elif 'h' in unit.lower():
frm = '%H' if frm is None else frm
rnd = rnd * 3600
secs = sum(int(x) * 60 ** i for i, x in enumerate(reversed(ts.split(':'))))
rtm = int(round(secs / rnd, 0) * rnd)
nt = strftime(frm, gmtime(rtm))
return nt
Call function as follow:
Round to nearest 5 minutes with default ouput format = hh:mm as follow
ts = '02:27:29'
nt = toNearestTime(ts, unit='min', rnd=5)
print(nt)
output: '02:25'
Or round to nearest hour with ouput format hh:mm:ss as follow
ts = '10:30:01'
nt = toNearestTime(ts, unit='hour', rnd=1, frm='%H:%M:%S')
print(nt)
output: '11:00:00'
last updated version

Categories