Compare times with python - python

I have data in a file with dates marked, for example, '2015.05.05-11:46', and want to read these lines and then see if they fulfill certain conditions. For example, as input to the function, I may have
get_times('hour', -3.0, -1.2)
which has function defintion:
get_times(unit, start_time, end_time):
which means I want to return all strings that are from -3.0 hours in the past to -1.2 hours in the past. I can get the current time with now = datetime.datetime.now(). Assuming I read in time1 = '2015.05.05-11:46', how do I compare that to now and find out if it is within start_time and end_time units from now?

You can use < and > operators normally.
But for that to work, you have to make all data be datetime type.
For instance:
time_str = "2015.05.05-11:46"
reference_time = datetime.datetime.strptime(time_str, "%Y.%m.%d-%H:%M")
start_time = reference_time - datetime.timedelta(hours=3)
end_time = reference_time - datetime.timedelta(hours=1.2)
now = datetime.datetime.now()
if end_time <= now <= start_time:
print 'It is in between'
You can also pass arguments to timedelta function using a dictionary:
>>> a = datetime.timedelta(hours=3, minutes=10)
>>> args = {'hours': 3, 'minutes': 10}
>>> b = datetime.timedelta(**args)
>>> a == b
True

Use datetime.strptime to convert your string '2015.05.05-11:46'
then = datetime.datetime.strptime('2015.05.05-11:46', "%Y.%m.%d-%H:%M")
now = datetime.datetime.now()
Then use datetime.timedelta to compare times.
tdelta = now - then
if datetime.timedelta(hours=1.2) < tdelta < datetime.timedelta(hours=3.0):
print "In range"
For writing your function, you'll probably want to stick to the units that are in datetime.timedelta, unless you have a good reason not to.
class datetime.timedelta([days[, seconds[, microseconds[, milliseconds[, minutes[, hours[, weeks]]]]]]])
So, 'days', 'seconds', 'microseconds', 'milliseconds', 'minutes', 'hours', 'weeks'

A couple things need to be done in your situation. First, you need to convert your datetime strings to datetime objects for easy comparison. We do this via strptime:
input_datetime = datetime.datetime.strptime(i, '%Y.%m.%d-%H:%M')
We also need the function to return start and end times based on your input. If you can make a slight modification and utilize hours instead of hour, we can do this without setting up a large if/elif block.
def get_times(unit, start_time, end_time):
now = datetime.datetime.now()
start_kwarg = {unit: start_time}
end_kwarg = {unit: end_time}
time_start = now + datetime.timedelta(**start_kwarg)
time_end = now + datetime.timedelta(**end_kwarg)
return time_start, time_end
This takes your unit and creates a dictionary that is passed as a keyword argument to timedelta. Since hours is one of the arguments it accepts, we can utilize the keyword instead of mapping hour to hours. Then we return start and end time.
Finally, we just need to compare that the input time is between start and end:
start < input_datetime < end
A final script could look like this:
import datetime
def get_times(unit, start_time, end_time):
now = datetime.datetime.now()
start_kwarg = {unit: start_time}
end_kwarg = {unit: end_time}
time_start = now + datetime.timedelta(**start_kwarg)
time_end = now + datetime.timedelta(**end_kwarg)
return time_start, time_end
start, end = get_times('hours', -3.0, -1.2)
input_times = [
'2015.05.12-11:46',
'2014.05.12-11:46',
'2016.05.12-11:46',
'2015.04.12-11:46',
'2015.05.05-11:46'
]
for i in input_times:
input_datetime = datetime.datetime.strptime(i, '%Y.%m.%d-%H:%M')
print "{} => {}".format(input_datetime, start < input_datetime < end)
Output would look like this (if run at 12:46pm on 2015-05-12):
2015-05-12 11:46:00 => True
2014-05-12 11:46:00 => False
2016-05-12 11:46:00 => False
2015-04-12 11:46:00 => False
2015-05-05 11:46:00 => False

hope this is what you are looking for:
import datetime
import time
def get_times(unit, start_time, end_time):
now = datetime.datetime.now().timetuple()
matched_dates = []
for date in your_file:
converted_date = time.strptime(date,"%Y.%m.%d-%H:%M")
if converted_date.tm_hour > (now.tm_hour + start_time) and converted_date.tm_hour < (now.tm_hour + end_time):
matched_dates.append(date)
return matched_dates

To compare time from the file, you should convert it to UTC time (POSIX timestamp) or an aware datetime object (local time + utc offset).
start_time, end_time = get_times('hour', -3, -1.2)
if start_time <= utc_time < end_time:
# utc_time is in between
You should not use start_time <= naive_local_time < end_time. Convert input time to UTC or create an aware datetime objects instead.
If local times in your input file are consecutive then you could use that fact to disambiguate the timestamps if necessary, see Parsing of Ordered Timestamps in Local Time (to UTC) While Observing Daylight Saving Time.
More explanation and solutions that use time.mktime(), pytz, aware datetime objects are in: Find if 24 hrs have passed between datetimes - Python.
Why you should not use datetime.now()
datetime.now() returns local time as a naive datetime object may be ambiguous e.g., during a DST transition:
>>> from datetime import datetime
>>> import pytz
>>> tz = pytz.timezone('America/New_York')
>>> tz.localize(datetime(2015,11,1,1,30), is_dst=None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/dist-packages/pytz/tzinfo.py", line 349, in localize
raise AmbiguousTimeError(dt)
pytz.exceptions.AmbiguousTimeError: 2015-11-01 01:30:00
>>> tz.localize(datetime(2015,11,1,1,30), is_dst=True).astimezone(pytz.utc)
datetime.datetime(2015, 11, 1, 5, 30, tzinfo=<UTC>)
>>> tz.localize(datetime(2015,11,1,1,30), is_dst=False).astimezone(pytz.utc)
datetime.datetime(2015, 11, 1, 6, 30, tzinfo=<UTC>)
Note: if you remove UTC offset then the same local time may correspond to different UTC time. datetime.utcnow() is unambiguous (except perhaps during a leap second such as 2015-06-30T23:59:60Z).
How to implement get_times('hour', -3.0, -1.2)
Use UTC time or aware datetime objects:
#!/usr/bin/env python
from datetime import datetime, timedelta
def get_times(unit, relative_start, relative_end):
relative_start, relative_end = [timedelta(**{unit+'s': v})
for v in [relative_start, relative_end]]
now = datetime.utcnow() # or datetime.now(timezone.utc).astimezone()
return now + relative_start, now + relative_end

Related

Python comparing to different time values to get time delta in minutes

I am trying to get get the time delta i minutes from two different time values.
time1 = 2020-11-28T10:31:12Z
time2 = 2020-11-28T09:10:23.203+0000
Then i will make i condition: if time difference is bigger then x minutes, run code...
Anyone have a solution for that.
I have tried using datetime.datetime.strptime() but cant get them on same format.
Thanks
Using date parser to let it figure out the date format
Code
from dateutil.parser import parse
def time_difference(time1, time2):
# Parse strings into datetime objects
dt1 = parse(time1)
dt2 = parse(time2)
# Get timedelta object
c = dt1 - dt2
# Difference in minutes
return (c.total_seconds()/60)
Test
time1 = "2020-11-28T10:31:12Z"
time2 = "2020-11-28T09:10:23.203+0000"
print(time_difference(time1, time2))
# Output: 80.81328333333333
well assuming you don't need split seconds you could do something like that:
time1 = '2020-11-28T10:31:12Z'
time2 = '2020-11-28T09:10:23.203+0000'
import time
import datetime
def get_timestamp(time_str):
time_splited = time_str.split('T')
time_str_formatted = ' '.join([time_splited[0],time_splited[1][:8]])
return time.mktime(datetime.datetime.strptime(time_str_formatted,"%Y-%m-%d %H:%M:%S").timetuple())
print(get_timestamp(time1))
print(get_timestamp(time2))
reformatting both times to the same time format.
then your condition would look like:
if abs(get_timestamp(time1) -get_timestamp(time2) ) > x*60:
do_something(....)
The times are not uniform so you will have to make them the same to use strptime. For accuracy I prefer to convert to seconds then you can also at a later stage compare seconds, minutes or hours if you needed to.
import datetime
time1 = '2020-11-28T10:31:12Z'
time2 = '2020-11-28T09:10:23.203+0000'
def minutes_diff():
#Make the times uniform so you can then use strptime
date_time1 = datetime.datetime.strptime(time1[:-1], "%Y-%m-%dT%H:%M:%S")
date_time2 = datetime.datetime.strptime(time2[:-9], "%Y-%m-%dT%H:%M:%S")
#Convert to seconds for accuracy
a_timedelta = date_time1 - datetime.datetime(1900, 1, 1)
b_timedelta = date_time2 - datetime.datetime(1900, 1, 1)
seconds_time_a = a_timedelta.total_seconds()
seconds_time_b = b_timedelta.total_seconds()
#Take one from each other for minutes
time_in_minutes = (seconds_time_a - seconds_time_b) / 60
#Then decide what to do with it
if time_in_minutes < 60: # 1 hour
print('Less than an hours do something')
else:
print('More than an hour do nothing')
minutes_diff()
DARRYL, JOHNNY and MARCIN, thanks for your solutions, problem solved!!
Andy

Check if XX seconds have elapsed since time in 'timestamp with time zone' format

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())

Converting datetime to timedelta so they can be added

When subtracting two datetime objects, I understand the result is timedelta object:
import datetime
AcDepart = 1900-01-01 18:00:00
AcArrival = 1900-01-01 07:00:00
ActualHours = AcDepart - AcArrival
I want to then subtract the sum of two other date time objects from ActualHours
These are the two other objects:
HrsEarly = 1900-01-01 02:00:00
HrsLate = 1900-01-01 00:30:00
This is the equation that fails to complete:
UnCalcTime = ActualHours - (HrsEarly + HrsLate)
This is the error:
UnCalcTime = ActualHours - (HrsEarly + HrsLate)
TypeError: unsupported operand type(s) for +: 'datetime.datetime' and 'datetime.datetime'
So, I obviously can't add datetime.datetime. Does anyone know how I could get around this? Can timedelta be added together? If so, how can I convert datetime to timedelta?
Any help would be greatly appreciated as I have been trying to solve this unsuccessfully for a long time.
The best solution is to create your variables as timedelta in the first place.
HrsEarly = datetime.timedelta(hours=2)
HrsLate = datetime.timedelta(minutes=30)
If you can't do that, you can simply subtract your "zero date" from the datetime objects.
>>> HrsEarly
datetime.datetime(1900, 1, 1, 2, 0)
>>> HrsEarly = HrsEarly - datetime.datetime(1900, 1, 1)
>>> HrsEarly
datetime.timedelta(0, 7200)
Convert the string to timedelta
from datetime import datetime
AcDepart = '1900-01-01 18:00:00'
AcDepart_ = datetime.strptime(AcDepart, '%Y-%m-%d %H:%M:%S')
AcArrival = '1900-01-01 07:00:00'
AcArrival_ = datetime.strptime(AcArrival, '%Y-%m-%d %H:%M:%S')
ActualHours = (AcDepart_ - AcArrival_).total_seconds()/3600
print ActualHours
It makes no sense to add two datetime objects: It might seem, in your example, that "2AM on the 1st of January 1900" plus "half past midnight on the 1st of January 1900" should be "half past two on the 1st of January 1900", but in another context the desired result could as easily be "half past two on the 2nd of February 3800", or even (if the UNIX epoch is used as an origin) "half past two on the first of January 1830".
Looking at a different example might make this more obvious: what should be the result of Tuesday + Saturday?
Your HrsEarly and HrsLate variables are presumably meant to store a time difference, and there's an appropriate type for that: datetime.timedelta. Adding two of those together does what you want:
>>> from datetime import timedelta
>>> HrsEarly = timedelta(hours=2)
>>> HrsLate = timedelta(minutes=30)
>>> HrsTotal = (HrsEarly + HrsLate)
>>> str(HrsTotal)
'2:30:00'
How about this method using built-in timestamp function?
import datetime
a = "2017-01-01 14:30:00"
b = datetime.datetime.strptime(a, '%Y-%m-%d %H:%M:%S')
c = b.timestamp()
d = datetime.timedelta(seconds=c)
Runtime environment
  OS: Ubuntu 16.04
  Python 3.6
Create a modules.py and paste the following two functions. Import them wherever you want and use as is.
import datetime
def JsTimestampToPyDatetime(js_date):
"""
converts javascript timestamp to python datetime taking care of
milliseconds and seconds
Args:
js_date(Timestamp, required)
Returns:
Datetime
"""
try:
# handles seconds
date = datetime.datetime.fromtimestamp(int(js_date))
except (ValueError):
# handles miliseconds
date = datetime.datetime.fromtimestamp(int(js_date) / 1000)
return date
# consuming javascript generated timestamps
a = JsTimestampToPyDatetime(1627303810000) # with miliseconds
b = JsTimestampToPyDatetime(1627476610) # with seconds only
def GetDaysInDateTime(min_stamp, max_stamp):
"""
Calculates time difference between two timestamps in days
Args:
min_stamp(Datetime, required): Minimum/start datetime
max_stamp(Datetime, required): Maximum/end datetime
Returns:
Int: Days
"""
days = (max_stamp-min_stamp).days
return int(days)
print(GetDaysInDateTime(a, b))

How do I check the difference, in seconds, between two dates?

There has to be an easier way to do this. I have objects that want to be refreshed every so often, so I want to record when they were created, check against the current timestamp, and refresh as necessary.
datetime.datetime has proven to be difficult, and I don't want to dive into the ctime library. Is there anything easier for this sort of thing?
if you want to compute differences between two known dates, use total_seconds like this:
import datetime as dt
a = dt.datetime(2013,12,30,23,59,59)
b = dt.datetime(2013,12,31,23,59,59)
(b-a).total_seconds()
86400.0
#note that seconds doesn't give you what you want:
(b-a).seconds
0
import time
current = time.time()
...job...
end = time.time()
diff = end - current
would that work for you?
>>> from datetime import datetime
>>> a = datetime.now()
# wait a bit
>>> b = datetime.now()
>>> d = b - a # yields a timedelta object
>>> d.seconds
7
(7 will be whatever amount of time you waited a bit above)
I find datetime.datetime to be fairly useful, so if there's a complicated or awkward scenario that you've encountered, please let us know.
EDIT: Thanks to #WoLpH for pointing out that one is not always necessarily looking to refresh so frequently that the datetimes will be close together. By accounting for the days in the delta, you can handle longer timestamp discrepancies:
>>> a = datetime(2010, 12, 5)
>>> b = datetime(2010, 12, 7)
>>> d = b - a
>>> d.seconds
0
>>> d.days
2
>>> d.seconds + d.days * 86400
172800
We have function total_seconds() with Python 2.7
Please see below code for python 2.6
import datetime
import time
def diffdates(d1, d2):
#Date format: %Y-%m-%d %H:%M:%S
return (time.mktime(time.strptime(d2,"%Y-%m-%d %H:%M:%S")) -
time.mktime(time.strptime(d1, "%Y-%m-%d %H:%M:%S")))
d1 = datetime.now()
d2 = datetime.now() + timedelta(days=1)
diff = diffdates(d1, d2)
Here's the one that is working for me.
from datetime import datetime
date_format = "%H:%M:%S"
# You could also pass datetime.time object in this part and convert it to string.
time_start = str('09:00:00')
time_end = str('18:00:00')
# Then get the difference here.
diff = datetime.strptime(time_end, date_format) - datetime.strptime(time_start, date_format)
# Get the time in hours i.e. 9.60, 8.5
result = diff.seconds / 3600;
Hope this helps!
Another approach is to use timestamp values:
end_time.timestamp() - start_time.timestamp()
By reading the source code, I came to a conclusion: the time difference cannot be obtained by .seconds:
#property
def seconds(self):
"""seconds"""
return self._seconds
# in the `__new__`, you can find the `seconds` is modulo by the total number of seconds in a day
def __new__(cls, days=0, seconds=0, microseconds=0,
milliseconds=0, minutes=0, hours=0, weeks=0):
seconds += minutes*60 + hours*3600
# ...
if isinstance(microseconds, float):
microseconds = round(microseconds + usdouble)
seconds, microseconds = divmod(microseconds, 1000000)
# ! 👇
days, seconds = divmod(seconds, 24*3600)
d += days
s += seconds
else:
microseconds = int(microseconds)
seconds, microseconds = divmod(microseconds, 1000000)
# ! 👇
days, seconds = divmod(seconds, 24*3600)
d += days
s += seconds
microseconds = round(microseconds + usdouble)
# ...
total_seconds can get an accurate difference between the two times
def total_seconds(self):
"""Total seconds in the duration."""
return ((self.days * 86400 + self.seconds) * 10**6 +
self.microseconds) / 10**6
in conclusion:
from datetime import datetime
dt1 = datetime.now()
dt2 = datetime.now()
print((dt2 - dt1).total_seconds())

Generate a random date between two other dates

How would I generate a random date that has to be between two other given dates?
The function's signature should be something like this:
random_date("1/1/2008 1:30 PM", "1/1/2009 4:50 AM", 0.34)
^ ^ ^
date generated has date generated has a random number
to be after this to be before this
and would return a date such as: 2/4/2008 7:20 PM
Convert both strings to timestamps (in your chosen resolution, e.g. milliseconds, seconds, hours, days, whatever), subtract the earlier from the later, multiply your random number (assuming it is distributed in the range [0, 1]) with that difference, and add again to the earlier one. Convert the timestamp back to date string and you have a random time in that range.
Python example (output is almost in the format you specified, other than 0 padding - blame the American time format conventions):
import random
import time
def str_time_prop(start, end, time_format, prop):
"""Get a time at a proportion of a range of two formatted times.
start and end should be strings specifying times formatted in the
given format (strftime-style), giving an interval [start, end].
prop specifies how a proportion of the interval to be taken after
start. The returned time will be in the specified format.
"""
stime = time.mktime(time.strptime(start, time_format))
etime = time.mktime(time.strptime(end, time_format))
ptime = stime + prop * (etime - stime)
return time.strftime(time_format, time.localtime(ptime))
def random_date(start, end, prop):
return str_time_prop(start, end, '%m/%d/%Y %I:%M %p', prop)
print(random_date("1/1/2008 1:30 PM", "1/1/2009 4:50 AM", random.random()))
from random import randrange
from datetime import timedelta
def random_date(start, end):
"""
This function will return a random datetime between two datetime
objects.
"""
delta = end - start
int_delta = (delta.days * 24 * 60 * 60) + delta.seconds
random_second = randrange(int_delta)
return start + timedelta(seconds=random_second)
The precision is seconds. You can increase precision up to microseconds, or decrease to, say, half-hours, if you want. For that just change the last line's calculation.
example run:
from datetime import datetime
d1 = datetime.strptime('1/1/2008 1:30 PM', '%m/%d/%Y %I:%M %p')
d2 = datetime.strptime('1/1/2009 4:50 AM', '%m/%d/%Y %I:%M %p')
print(random_date(d1, d2))
output:
2008-12-04 01:50:17
Updated answer
It's even more simple using Faker.
Installation
pip install faker
Usage:
from faker import Faker
fake = Faker()
fake.date_between(start_date='today', end_date='+30y')
# datetime.date(2025, 3, 12)
fake.date_time_between(start_date='-30y', end_date='now')
# datetime.datetime(2007, 2, 28, 11, 28, 16)
# Or if you need a more specific date boundaries, provide the start
# and end dates explicitly.
import datetime
start_date = datetime.date(year=2015, month=1, day=1)
fake.date_between(start_date=start_date, end_date='+30y')
Old answer
It's very simple using radar
Installation
pip install radar
Usage
import datetime
import radar
# Generate random datetime (parsing dates from str values)
radar.random_datetime(start='2000-05-24', stop='2013-05-24T23:59:59')
# Generate random datetime from datetime.datetime values
radar.random_datetime(
start = datetime.datetime(year=2000, month=5, day=24),
stop = datetime.datetime(year=2013, month=5, day=24)
)
# Just render some random datetime. If no range is given, start defaults to
# 1970-01-01 and stop defaults to datetime.datetime.now()
radar.random_datetime()
A tiny version.
import datetime
import random
def random_date(start, end):
"""Generate a random datetime between `start` and `end`"""
return start + datetime.timedelta(
# Get a random amount of seconds between `start` and `end`
seconds=random.randint(0, int((end - start).total_seconds())),
)
Note that both start and end arguments should be datetime objects. If
you've got strings instead, it's fairly easy to convert. The other answers point
to some ways to do so.
This is a different approach - that sort of works..
from random import randint
import datetime
date=datetime.date(randint(2005,2025), randint(1,12),randint(1,28))
BETTER APPROACH
startdate=datetime.date(YYYY,MM,DD)
date=startdate+datetime.timedelta(randint(1,365))
Since Python 3 timedelta supports multiplication with floats, so now you can do:
import random
random_date = start + (end - start) * random.random()
given that start and end are of the type datetime.datetime. For example, to generate a random datetime within the next day:
import random
from datetime import datetime, timedelta
start = datetime.now()
end = start + timedelta(days=1)
random_date = start + (end - start) * random.random()
To chip in a pandas-based solution I use:
import pandas as pd
import numpy as np
def random_date(start, end, position=None):
start, end = pd.Timestamp(start), pd.Timestamp(end)
delta = (end - start).total_seconds()
if position is None:
offset = np.random.uniform(0., delta)
else:
offset = position * delta
offset = pd.offsets.Second(offset)
t = start + offset
return t
I like it, because of the nice pd.Timestamp features that allow me to throw different stuff and formats at it. Consider the following few examples...
Your signature.
>>> random_date(start="1/1/2008 1:30 PM", end="1/1/2009 4:50 AM", position=0.34)
Timestamp('2008-05-04 21:06:48', tz=None)
Random position.
>>> random_date(start="1/1/2008 1:30 PM", end="1/1/2009 4:50 AM")
Timestamp('2008-10-21 05:30:10', tz=None)
Different format.
>>> random_date('2008-01-01 13:30', '2009-01-01 4:50')
Timestamp('2008-11-18 17:20:19', tz=None)
Passing pandas/datetime objects directly.
>>> random_date(pd.datetime.now(), pd.datetime.now() + pd.offsets.Hour(3))
Timestamp('2014-03-06 14:51:16.035965', tz=None)
Convert your dates into timestamps and call random.randint with the timestamps, then convert the randomly generated timestamp back into a date:
from datetime import datetime
import random
def random_date(first_date, second_date):
first_timestamp = int(first_date.timestamp())
second_timestamp = int(second_date.timestamp())
random_timestamp = random.randint(first_timestamp, second_timestamp)
return datetime.fromtimestamp(random_timestamp)
Then you can use it like this
from datetime import datetime
d1 = datetime.strptime("1/1/2018 1:30 PM", "%m/%d/%Y %I:%M %p")
d2 = datetime.strptime("1/1/2019 4:50 AM", "%m/%d/%Y %I:%M %p")
random_date(d1, d2)
random_date(d2, d1) # ValueError because the first date comes after the second date
If you care about timezones you should just use date_time_between_dates from the Faker library, where I stole this code from, as a different answer already suggests.
Here is an answer to the literal meaning of the title rather than the body of this question:
import time
import datetime
import random
def date_to_timestamp(d) :
return int(time.mktime(d.timetuple()))
def randomDate(start, end):
"""Get a random date between two dates"""
stime = date_to_timestamp(start)
etime = date_to_timestamp(end)
ptime = stime + random.random() * (etime - stime)
return datetime.date.fromtimestamp(ptime)
This code is based loosely on the accepted answer.
You can Use Mixer,
pip install mixer
and,
from mixer import generators as gen
print gen.get_datetime(min_datetime=(1900, 1, 1, 0, 0, 0), max_datetime=(2020, 12, 31, 23, 59, 59))
Just to add another one:
datestring = datetime.datetime.strftime(datetime.datetime( \
random.randint(2000, 2015), \
random.randint(1, 12), \
random.randint(1, 28), \
random.randrange(23), \
random.randrange(59), \
random.randrange(59), \
random.randrange(1000000)), '%Y-%m-%d %H:%M:%S')
The day handling needs some considerations. With 28 you are on the secure site.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Create random datetime object."""
from datetime import datetime
import random
def create_random_datetime(from_date, to_date, rand_type='uniform'):
"""
Create random date within timeframe.
Parameters
----------
from_date : datetime object
to_date : datetime object
rand_type : {'uniform'}
Examples
--------
>>> random.seed(28041990)
>>> create_random_datetime(datetime(1990, 4, 28), datetime(2000, 12, 31))
datetime.datetime(1998, 12, 13, 23, 38, 0, 121628)
>>> create_random_datetime(datetime(1990, 4, 28), datetime(2000, 12, 31))
datetime.datetime(2000, 3, 19, 19, 24, 31, 193940)
"""
delta = to_date - from_date
if rand_type == 'uniform':
rand = random.random()
else:
raise NotImplementedError('Unknown random mode \'{}\''
.format(rand_type))
return from_date + rand * delta
if __name__ == '__main__':
import doctest
doctest.testmod()
# needed to create data for 1000 fictitious employees for testing code
# code relating to randomly assigning forenames, surnames, and genders
# has been removed as not germaine to the question asked above but FYI
# genders were randomly assigned, forenames/surnames were web scrapped,
# there is no accounting for leap years, and the data stored in mySQL
import random
from datetime import datetime
from datetime import timedelta
for employee in range(1000):
# assign a random date of birth (employees are aged between sixteen and sixty five)
dlt = random.randint(365*16, 365*65)
dob = datetime.today() - timedelta(days=dlt)
# assign a random date of hire sometime between sixteenth birthday and today
doh = datetime.today() - timedelta(days=random.randint(0, dlt-365*16))
print("born {} hired {}".format(dob.strftime("%d-%m-%y"), doh.strftime("%d-%m-%y")))
Convert your input dates to numbers
(int, float, whatever is best for
your usage)
Choose a number between your two date numbers.
Convert this number back to a date.
Many algorithms for converting date to and from numbers are already available in many operating systems.
What do you need the random number for? Usually (depending on the language) you can get the number of seconds/milliseconds from the Epoch from a date. So for a randomd date between startDate and endDate you could do:
compute the time in ms between
startDate and endDate
(endDate.toMilliseconds() -
startDate.toMilliseconds())
generate a number between 0 and the number you obtained in 1
generate a new Date with time offset = startDate.toMilliseconds() + number obtained in 2
The easiest way of doing this is to convert both numbers to timestamps, then set these as the minimum and maximum bounds on a random number generator.
A quick PHP example would be:
// Find a randomDate between $start_date and $end_date
function randomDate($start_date, $end_date)
{
// Convert to timetamps
$min = strtotime($start_date);
$max = strtotime($end_date);
// Generate random number using above bounds
$val = rand($min, $max);
// Convert back to desired date format
return date('Y-m-d H:i:s', $val);
}
This function makes use of strtotime() to convert a datetime description into a Unix timestamp, and date() to make a valid date out of the random timestamp which has been generated.
It's modified method of #(Tom Alsberg). I modified it to get date with milliseconds.
import random
import time
import datetime
def random_date(start_time_string, end_time_string, format_string, random_number):
"""
Get a time at a proportion of a range of two formatted times.
start and end should be strings specifying times formated in the
given format (strftime-style), giving an interval [start, end].
prop specifies how a proportion of the interval to be taken after
start. The returned time will be in the specified format.
"""
dt_start = datetime.datetime.strptime(start_time_string, format_string)
dt_end = datetime.datetime.strptime(end_time_string, format_string)
start_time = time.mktime(dt_start.timetuple()) + dt_start.microsecond / 1000000.0
end_time = time.mktime(dt_end.timetuple()) + dt_end.microsecond / 1000000.0
random_time = start_time + random_number * (end_time - start_time)
return datetime.datetime.fromtimestamp(random_time).strftime(format_string)
Example:
print TestData.TestData.random_date("2000/01/01 00:00:00.000000", "2049/12/31 23:59:59.999999", '%Y/%m/%d %H:%M:%S.%f', random.random())
Output: 2028/07/08 12:34:49.977963
Here's a solution modified from emyller's approach which returns an array of random dates at any resolution
import numpy as np
def random_dates(start, end, size=1, resolution='s'):
"""
Returns an array of random dates in the interval [start, end]. Valid
resolution arguments are numpy date/time units, as documented at:
https://docs.scipy.org/doc/numpy-dev/reference/arrays.datetime.html
"""
start, end = np.datetime64(start), np.datetime64(end)
delta = (end-start).astype('timedelta64[{}]'.format(resolution))
delta_mat = np.random.randint(0, delta.astype('int'), size)
return start + delta_mat.astype('timedelta64[{}]'.format(resolution))
Part of what's nice about this approach is that np.datetime64 is really good at coercing things to dates, so you can specify your start/end dates as strings, datetimes, pandas timestamps... pretty much anything will work.
Alternative way to create random dates between two dates using np.random.randint(), pd.Timestamp().value and pd.to_datetime() with for loop:
# Import libraries
import pandas as pd
# Initialize
start = '2020-01-01' # Specify start date
end = '2020-03-10' # Specify end date
n = 10 # Specify number of dates needed
# Get random dates
x = np.random.randint(pd.Timestamp(start).value, pd.Timestamp(end).value,n)
random_dates = [pd.to_datetime((i/10**9)/(60*60)/24, unit='D').strftime('%Y-%m-%d') for i in x]
print(random_dates)
Output
['2020-01-06',
'2020-03-08',
'2020-01-23',
'2020-02-03',
'2020-01-30',
'2020-01-05',
'2020-02-16',
'2020-03-08',
'2020-02-09',
'2020-01-04']
Get random date between start_date and end_date.
If any of them is None, then get random date between
today and past 100 years.
class GetRandomDateMixin:
def get_random_date(self, start_date=None, end_date=None):
"""
get random date between start_date and end_date.
If any of them is None, then get random date between
today and past 100 years.
:param start_date: datetime obj.
eg: datetime.datetime(1940, 1, 1).date()
:param end_date: datetime obj
:return: random date
"""
if start_date is None or end_date is None:
end_date = datetime.datetime.today().date()
start_date = end_date - datetime.timedelta(
days=(100 * 365)
)
delta = end_date - start_date
random_days = random.randint(1, delta.days)
new_date = start_date + datetime.timedelta(
days=random_days
)
return new_date
Building off of #Pieter Bos 's answer:
import random
import datetime
start = datetime.date(1980, 1, 1)
end = datetime.date(2000, 1, 1)
random_date = start + (end - start) * random.random()
random_date = datetime.datetime.combine(random_date, datetime.datetime.min.time())
Use my randomtimestamp module. It has 3 functions, randomtimestamp, random_time, and random_date.
Below is the signature of randomtimestamp function. It can generate a random timestamp between two years, or two datetime objects (if you like precision).
There's option to get the timestamp as a datetime object or string. Custom patterns are also supported (like strftime)
randomtimestamp(
start_year: int = 1950,
end_year: int = None,
text: bool = False,
start: datetime.datetime = None,
end: datetime.datetime = None,
pattern: str = "%d-%m-%Y %H:%M:%S"
) -> Union[datetime, str]:
Example:
>>> randomtimestamp(start_year=2020, end_year=2021)
datetime.datetime(2021, 1, 10, 5, 6, 19)
>>> start = datetime.datetime(2020, 1, 1, 0, 0, 0)
>>> end = datetime.datetime(2021, 12, 31, 0, 0, 0)
>>> randomtimestamp(start=start, end=end)
datetime.datetime(2020, 7, 14, 14, 12, 32)
Why not faker?
Because randomtimestamp is lightweight and fast. As long as random timestamps are the only thing you need, faker is an overkill and also heavy (being feature rich).
Conceptually it's quite simple. Depending on which language you're using you will be able to convert those dates into some reference 32 or 64 bit integer, typically representing seconds since epoch (1 January 1970) otherwise known as "Unix time" or milliseconds since some other arbitrary date. Simply generate a random 32 or 64 bit integer between those two values. This should be a one liner in any language.
On some platforms you can generate a time as a double (date is the integer part, time is the fractional part is one implementation). The same principle applies except you're dealing with single or double precision floating point numbers ("floats" or "doubles" in C, Java and other languages). Subtract the difference, multiply by random number (0 <= r <= 1), add to start time and done.
In python:
>>> from dateutil.rrule import rrule, DAILY
>>> import datetime, random
>>> random.choice(
list(
rrule(DAILY,
dtstart=datetime.date(2009,8,21),
until=datetime.date(2010,10,12))
)
)
datetime.datetime(2010, 2, 1, 0, 0)
(need python dateutil library – pip install python-dateutil)
I made this for another project using random and time. I used a general format from time you can view the documentation here for the first argument in strftime(). The second part is a random.randrange function. It returns an integer between the arguments. Change it to the ranges that match the strings you would like. You must have nice arguments in the tuple of the second arugment.
import time
import random
def get_random_date():
return strftime("%Y-%m-%d %H:%M:%S",(random.randrange(2000,2016),random.randrange(1,12),
random.randrange(1,28),random.randrange(1,24),random.randrange(1,60),random.randrange(1,60),random.randrange(1,7),random.randrange(0,366),1))
Pandas + numpy solution
import pandas as pd
import numpy as np
def RandomTimestamp(start, end):
dts = (end - start).total_seconds()
return start + pd.Timedelta(np.random.uniform(0, dts), 's')
dts is the difference between timestamps in seconds (float). It is then used to create a pandas timedelta between 0 and dts, that is added to the start timestamp.
Based on the answer by mouviciel, here is a vectorized solution using numpy. Convert the start and end dates to ints, generate an array of random numbers between them, and convert the whole array back to dates.
import time
import datetime
import numpy as np
n_rows = 10
start_time = "01/12/2011"
end_time = "05/08/2017"
date2int = lambda s: time.mktime(datetime.datetime.strptime(s,"%d/%m/%Y").timetuple())
int2date = lambda s: datetime.datetime.fromtimestamp(s).strftime('%Y-%m-%d %H:%M:%S')
start_time = date2int(start_time)
end_time = date2int(end_time)
random_ints = np.random.randint(low=start_time, high=end_time, size=(n_rows,1))
random_dates = np.apply_along_axis(int2date, 1, random_ints).reshape(n_rows,1)
print random_dates
start_timestamp = time.mktime(time.strptime('Jun 1 2010 01:33:00', '%b %d %Y %I:%M:%S'))
end_timestamp = time.mktime(time.strptime('Jun 1 2017 12:33:00', '%b %d %Y %I:%M:%S'))
time.strftime('%b %d %Y %I:%M:%S',time.localtime(randrange(start_timestamp,end_timestamp)))
refer
What about
import datetime
import random
def random_date(begin: datetime.datetime, end: datetime.datetime):
epoch = datetime.datetime(1970, 1, 1)
begin_seconds = int((begin - epoch).total_seconds())
end_seconds = int((end - epoch).total_seconds())
dt_seconds = random.randint(begin_seconds, end_seconds)
return datetime.datetime.fromtimestamp(dt_seconds)
Haven't tried it with "epoch" years different than 1970 but it does the job
Generates random dates between last 50 yrs to last 30 years. And generates date only.
import random
from datetime import date, timedelta
from dateutil.relativedelta import relativedelta
start_date = date.today() - relativedelta(years=50)
end_date = date.today() - relativedelta(years=20)
delta = end_date - start_date
print(delta.days)
random_number = random.randint(1, delta.days)
new_date = start_date + timedelta(days=random_number)
print (new_date)

Categories

Resources