Создание случайной даты между двумя другими датами
Как бы я создать произвольную дату, которая должна быть между двумя заданными датами?
Сигнатура функции должна быть примерно такой -
randomDate("1/1/2008 1:30 PM", "1/1/2009 4:50 AM", 0.34)
^ ^ ^
date generated has date generated has random number
to be after this to be before this
и вернуть дату, например-
"2/4/2008 7: 20 PM"
22 ответов:
преобразуйте обе строки в метки времени (в выбранном вами разрешении, например, миллисекунды, секунды, часы, дни, что угодно), вычитайте более раннее из более позднего, умножьте свое случайное число (предполагая, что оно распределено в диапазоне [0, 1]) с этой разницей и снова добавьте к более раннему. Преобразуйте метку времени обратно в строку даты, и у вас есть случайное время в этом диапазоне.
пример Python (вывод почти в указанном вами формате, кроме 0 padding-виноват Американский формат времени конвенций):
import random import time def strTimeProp(start, end, format, prop): """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. """ stime = time.mktime(time.strptime(start, format)) etime = time.mktime(time.strptime(end, format)) ptime = stime + prop * (etime - stime) return time.strftime(format, time.localtime(ptime)) def randomDate(start, end, prop): return strTimeProp(start, end, '%m/%d/%Y %I:%M %p', prop) print randomDate("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)точность секунд. Вы можете увеличить точность до микросекунд или уменьшить, скажем, до получаса, если хотите. Для этого просто измените последние строки расчета.
пример запуска:
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)выход:
2008-12-04 01:50:17
крошечная версия.
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())), )обратите внимание, что оба
startиendаргументы должны бытьdatetimeобъекты. Если у вас есть строки вместо этого, это довольно легко конвертировать. Другие ответы указывают к некоторым способам сделать это.
обновил ответ
это еще более просто с помощью Faker.
установка
pip install fakerиспользование:
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)ответ
это очень просто с помощью радара
установка
pip install radarиспользование
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()
это другой подход - такого рода работ..
from random import randint import datetime date=datetime.date(randint(2005,2025), randint(1,12),randint(1,28))WAIITT-ЛУЧШИЙ ПОДХОД
startdate=datetime.date(YYYY,MM,DD) date=startdate+datetime.timedelta(randint(1,365))
Начиная С Python 3
timedeltaподдерживает умножение с поплавками, так что теперь вы можете сделать:import random random_date = start + (end - start) * random.random()учитывая, что
startиendтипаdatetime.datetime. Например, чтобы сгенерировать случайную дату и время в течение следующего дня:import random from datetime import datetime, timedelta start = datetime.now() end = start + timedelta(days=1) random_date = start + (end - start) * random.random()
для чипирования решения на основе панд я использую:
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мне это нравится, потому что приятно
pd.Timestampфункции, которые позволяют мне бросать разные вещи и форматы на него. Рассмотрим несколько следующих примеров...ваша подпись.
>>> 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_date(start="1/1/2008 1:30 PM", end="1/1/2009 4:50 AM") Timestamp('2008-10-21 05:30:10', tz=None)другой формат.
>>> random_date('2008-01-01 13:30', '2009-01-01 4:50') Timestamp('2008-11-18 17:20:19', tz=None)передача объектов pandas / datetime напрямую.
>>> random_date(pd.datetime.now(), pd.datetime.now() + pd.offsets.Hour(3)) Timestamp('2014-03-06 14:51:16.035965', tz=None)
самый простой способ сделать это-преобразовать оба числа в метки времени, а затем установить их как минимальную и максимальную границы для генератора случайных чисел.
быстрый пример PHP будет:
// 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); }эта функция использует
strtotime()преобразовать дату в метку времени Unix, иdate()чтобы сделать допустимую дату из случайной метки времени, которая была сгенерирована.
можно использовать
Mixer,pip install mixerи
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))
вот ответ на буквальный смысл названия, а не тело этот вопрос:
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)этот код основан свободно на принятом ответе.
просто добавить еще один:
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')обработка дня требует некоторых соображений. С 28 вы находитесь на защищенном сайте.
- преобразование даты ввода чисел (int, float, все, что лучше всего подходит использования)
- выбрать число между двумя числами.
- преобразовать это число обратно в дату.
многие алгоритмы для преобразования даты и цифры уже доступны во многих операционных системах.
для чего вам нужно случайное число? Обычно (в зависимости от языка) вы можете получить количество секунд/миллисекунд от эпохи от дата. Так что для случайной даты между startDate и endDate вы могли бы сделать:
- вычислить время в мс между StartDate и enddate (конец света.томиллисекунды() - дата начала.toMilliseconds ())
- сгенерируйте число между 0 и числом, полученным в 1
- создать новую дату со смещением = дата начала.toMilliseconds () + число, полученное в 2
вот решение, модифицированное из подхода эмиллера, который возвращает массив случайных дат при любом разрешении
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))часть того, что хорошо об этом подходе является то, что
np.datetime64действительно хорош в приведении вещей к датам, поэтому вы можете указать даты начала/окончания в виде строк, дат, временных меток панд... почти все будет работать.
#!/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()
концептуально это довольно просто. В зависимости от того, какой язык вы используете, вы сможете конвертировать эти даты в некоторое эталонное 32 или 64-разрядное целое число, обычно представляющее секунды с эпохи (1 января 1970 года), иначе известной как "время Unix" или миллисекунды с некоторой другой произвольной даты. Просто генерировать случайный 32-или 64-разрядное целое число между этими двумя значениями. Это должен быть один лайнер на любом языке.
на некоторых платформах вы можете создать время как двойной (дата-это целая часть, время-дробная часть-это одна реализация). Тот же принцип применяется, за исключением того, что вы имеете дело с числами с плавающей запятой одиночной или двойной точности ("плавает" или "удваивается" на C, Java и других языках). Вычтите разницу, умножьте на случайное число (0
используйте ApacheCommonUtils для генерации случайной длины в заданном диапазоне, а затем создать дату из этого длинного.
пример:
импорт орг.апаш.палата общин.математика.случайность.RandomData;
импорт орг.апаш.палата общин.математика.случайность.RandomDataImpl;
публичная дата nextDate (дата min, дата max) {
RandomData randomData = new RandomDataImpl(); return new Date(randomData.nextLong(min.getTime(), max.getTime()));}
Я сделал это для другого проекта, используя случайные и времени. Я использовал обычный формат времени вы можете просмотреть документацию здесь для первого аргумента в функцию strftime(). Вторая часть-случайная.функция randrange. Он возвращает целое число между аргументами. Измените его на диапазоны, соответствующие строкам, которые вы хотите. У вас должны быть хорошие аргументы в кортеже второго 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))
панды + numpy решение
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-это разница между метками времени в секундах (float). Затем он используется для создания панды timedelta между 0 и dts, который добавляется в метку времени начала.
основываясь на ответе mouviciel, вот векторизованное решение с использованием numpy. Преобразуйте даты начала и окончания в ints, сгенерируйте массив случайных чисел между ними и преобразуйте весь массив обратно в даты.
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
это модифицированный метод @(Tom Alsberg). Я изменил его, чтобы получить дату с миллисекундами.
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)пример:
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())выход:
2028/07/08 12:34:49.977963
в 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)(нужен python
dateutilбиблиотекаpip install python-dateutil)
Comments