Створіть випадкову дату між двома іншими датами


138

Як я можу генерувати випадкову дату, яка повинна бути між двома іншими датами?

Підпис функції повинен бути приблизно таким:

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

і поверне дату, таку як: 2/4/2008 7:20 PM


З того, як поставлено питання на даний момент, не зрозуміло, хочете ви, щоб дата чи час були випадковими чи ні. Ваш приклад говорить про те, що ви шукаєте час. Якщо це повинно бути між двома датами, ви можете змінити відповіді, наведені до цього часу, щоб відповідати вашим потребам та виключити час закінчення та час початку. Нарешті, у більшості відповідей, таких як прийнятий, код виводить дату, що не враховує кінцевий час, завдяки скороченню до int. Щоб створити час, який може включати кінець у відповідь, змініть код наptime = stime + prop * (etime - stime) + 0.5
tortal

Відповіді:


149

Перетворіть обидва рядки у часові позначки (у вибраній роздільній здатності, наприклад, мілісекунди, секунди, години, дні, що завгодно), відніміть більш раннє від пізнішого, помножте випадкове число (припускаючи, що воно розподілене в range [0, 1]) з цією різницею та додайте ще раз до більш ранній. Перетворіть часову позначку назад у рядок дати, і у вас буде випадковий час у цьому діапазоні.

Приклад Python (вихід майже у визначеному вами форматі, крім 0прокладки - звинувачуйте американські конвенції про формат часу):

import random
import time

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

Цей підхід не підтримує дати, що починаються до 1970 року.
Cmbone

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

Точність - секунди. Ви можете збільшити точність до мікросекунд або зменшити до, скажімо, півгодини, якщо хочете. Для цього просто змініть обчислення останнього рядка.

Приклад запуску:

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

вихід:

2008-12-04 01:50:17

3
Використання startзмінної в цьому випадку цілком правильно. Єдина проблема, яку я бачу в коді, - це використання secondsатрибута від результуючого delta. Це не поверне загальну кількість секунд за весь інтервал; натомість це лише кількість секунд від компонента 'time' (щось середнє від 0 до 60); timedeltaоб'єкт має total_secondsметод, який слід використовувати замість цього.
emyller

7
@emyller: Ні, я використовую (delta.days * 24 * 60 * 60) + delta.secondsрезультати, за загальні секунди. total_seconds()Метод є новим в Python 2.7 і не існувало в 2009 році , коли я відповів на питання. Якщо у вас є python 2.7, ви повинні використовувати це замість цього, але код працює нормально.
nosklo

Я ще не знав про відсутність цього методу ще в 2.7-. Я щойно перевірив, що об'єкт timedelta в основному складається з числа днів і секунд, тож ти маєш рацію. :-)
emyller

@emyller: Просто для повноти об'єкт timedelta складається з днів, секунд та мікросекунд . Точність генерування коду випадкової дати вище - до секунд, але це може бути змінено, як я вже згадував у відповіді.
nosklo

83

Крихітна версія.

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об'єктами. Якщо натомість у вас є рядки, конвертувати це досить просто. Інші відповіді вказують на деякі способи зробити це.


54

Оновлена ​​відповідь

Це ще простіше за допомогою 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)

# 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')

Стара відповідь

Це дуже просто, використовуючи радари

Установка

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

3
Оновлення пропозицій про модуль фейкера .. Я використовував для створення профілю, але не використовував дату утиліти, це дуже хороший модуль під час тестування.
Гахан

Я отримую вихід у такому форматі, datetime.date(2039, 3, 16)але я хочу такий вихід 2039-03-16. Як це зробити?
Аюш Кумар

Ти маєш на увазі, ти хочеш струну? Дуже легко (просто відформатувати його відповідним чином ): fake.date_between(start_date='today', end_date='+30y').strftime('%Y-%m-%d').
Артур Барсегян

1
Оновлення за використання неймовірної бібліотеки, навіть якщо вам доведеться її встановити. Це зменшує складність реалізації до 4 рядків.
Blairg23

1
@ KubiK888: Звичайно, дивіться моєї відповіді на оновлення. Ви повинні просто надати початковий_файл явно.
Артур Барсегян

24

Це інший підхід - такий вид робіт ..

from random import randint
import datetime

date=datetime.date(randint(2005,2025), randint(1,12),randint(1,28))

КРАЩИЙ ПІДХІД

startdate=datetime.date(YYYY,MM,DD)
date=startdate+datetime.timedelta(randint(1,365))

1
Перший підхід ніколи не вибере дату, що закінчується 29-го, 30-го чи 31-го, і ваш другий підхід не враховує високосні роки, коли рік становить 366 днів, тобто якщо startdate+ 1 рік проходить до 31 грудня у високосний рік, це Код ніколи не вибере ту саму дату рівно через рік. Обидва підходи дозволяють лише вказати дату початку та скільки років у майбутньому, тоді як питання про те, щоб вказати дві дати, і на мою думку, це більш корисний API.
Борис

15

Оскільки 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()

6

Для чіпінгу в рішенні на основі панди я використовую:

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)

Безперервне передавання об'єктів панди / дати.

>>> random_date(pd.datetime.now(), pd.datetime.now() + pd.offsets.Hour(3))
Timestamp('2014-03-06 14:51:16.035965', tz=None)

І як би ви елегантно створили випадкову серію дат (наприклад, не повторюючи свою функцію для кожного елемента)?
dmvianna

Ну, можливо, можливо змінити функцію, щоб генерувати масив deltaзначень і відображати їх усі відразу на часові позначки. Хоча я особисто хотів би зробити щось подібне pd.Series([5] * 10, [random_date('2014-01-01', '2014-01-30') for i in range(10)]).
metakermit

3

Ось відповідь на буквальне значення заголовка, а не на тему цього питання:

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)

Цей код вільно базується на прийнятій відповіді.


ви можете змінити другий останній рядок на ptime = random.randint(stime, etime)гранично правильніший, оскільки randintстворює інклюзивний діапазон.
Борис

3

Ви можете використовувати 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))

1
синтаксис трохи змінився, не знаю, як це зробити вище, але об'єкт django буде заповнено випадкову дату так:client = mixer.blend(Client, date=mixer.RANDOM)
tutuDajuju

@tutuDajuju: За що стоїть Клієнт?
Німа Соруш

Відповідно до їхніх документів , це може бути клас моделей Django, SQLAlchemy або Mongoengine.
tutuDajuju

2
#!/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()

2

Перетворіть ваші дати у часові позначки та зателефонуйте random.randintза допомогою часових позначок, а потім перетворіть випадково генеровану часову марку назад у дату:

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)

Тоді ви можете використовувати його так

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

Якщо ви дбаєте про часові пояси, вам слід просто скористатися date_time_between_datesз Fakerбібліотеки, звідки я вкрав цей код , як вже підказує інша відповідь.


1
  1. Перетворіть ваші дати введення в цифри (int, float, що найкраще для вашого використання)
  2. Виберіть номер між двома номерами дати.
  3. Перетворити цей номер назад на дату.

Багато алгоритмів перетворення дати в номери і з них вже доступні в багатьох операційних системах.


1

Для чого вам потрібно випадкове число? Зазвичай (залежно від мови) ви можете отримати кількість секунд / мілісекунд з епохи від дати. Отже, для випадкової дати між startDate та endDate ви можете зробити:

  1. обчислити час у мс між startDate та endDate (endDate.toMilliseconds () - startDate.toMilliseconds ())
  2. генерувати число від 0 до числа, яке ви отримали в 1
  3. створити нову дату із зміщенням часу = startDate.toMilliseconds () + число, отримане за 2

1

Найпростіший спосіб зробити це перетворити обидва числа у часові позначки, а потім встановити їх як мінімальні та максимальні межі на генераторі випадкових чисел.

Швидкий приклад 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()для отримання дійсної дати з генерованої випадкової мітки часу.


Якщо хтось може написати це в python, це було б корисно.
quilby

1

Просто додайте ще один:

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 ти на захищеному сайті.


1

Ось рішення, модифіковане підходом еміллера, яке повертає масив випадкових дат при будь-якій роздільній здатності

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він дійсно хороший у примусовому доведенні до дат, тому ви можете вказати свої дати початку та закінчення як рядки, дати, часові позначки панди ... майже все буде працювати.


0

Концептуально це досить просто. Залежно від того, якою мовою ви користуєтесь, ви зможете перетворити ці дати в деяке посилальне 32 або 64-бітове ціле число, як правило, секунди з епохи (1 січня 1970 року), інакше відомої як "час Unix", або мілісекунд з часу іншої довільної дати. Просто генеруйте випадкове 32 або 64 бітове ціле число між цими двома значеннями. Це має бути один вкладиш на будь-якій мові.

На деяких платформах ви можете генерувати час як подвійний (дата - ціла частина, час - дробова частина - одна реалізація). Цей же принцип застосовується за винятком того, що ви маєте справу з числами з плаваючою точкою з одною або подвійною точністю ("плаває" або "подвоюється" на C, Java та інших мовах). Відніміть різницю, помножте на випадкове число (0 <= r <= 1), додайте до початку часу і зробіть.


0

У пітоні:

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

(потрібна dateutilбібліотека python - pip install python-dateutil)


0

Використовуйте ApacheCommonUtils для генерації випадкових довгих у заданому діапазоні, а потім створіть дату поза цим довгим.

Приклад:

імпорт org.apache.commons.math.random.RandomData;

імпорт org.apache.commons.math.random.RandomDataImpl;

дата публіки nextDate (дата хв., дата макс.) {

RandomData randomData = new RandomDataImpl();

return new Date(randomData.nextLong(min.getTime(), max.getTime()));

}


1
питання позначено тегом "python"
Девід Маркс

0

Я зробив це для іншого проекту, використовуючи випадковий час і час. Я використовував загальний формат, коли ви можете переглянути тут документацію для першого аргументу у strroll (). Друга частина - це функція random.randrange. Він повертає ціле число між аргументами. Змініть його на діапазони, які відповідають потрібним рядкам. Ви повинні мати приємні аргументи в кортежі другого фрагменту.

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

0

Панди + нумеровані рішення

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 - різниця між часовими позначками в секундах (поплавком). Потім він використовується для створення тимчасової панди між 0 і dts, яка додається до часової мітки початку.


0

Виходячи з відповіді мувівієля, ось векторизоване рішення з використанням нуме. Перетворіть дати початку та кінця в 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

0

Це модифікований метод @ (Том Альсберг). Я змінив його, щоб отримати дату з мілісекундами.

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


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

посилатися


0
    # 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 yesterday
        doh = datetime.today() - timedelta(days=random.randint(1, dlt-365*16))
        print("born {} hired {}".format(dob.strftime("%d-%m-%y"), doh.strftime("%d-%m-%y")))

0

Альтернативний спосіб створення випадкових дат між двома датами , використовуючи np.random.randint(), pd.Timestamp().valueі pd.to_datetime()з 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)

Вихідні дані

['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']
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.