Gere uma data aleatória entre duas outras datas

137

Como eu geraria uma data aleatória que deve estar entre duas outras datas?

A assinatura da função deve ser algo como isto:

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

e retornaria uma data como: 2/4/2008 7:20 PM

quilby
fonte
Da maneira como a pergunta é apresentada no momento, não está claro se você deseja ou não apenas que a data ou a hora sejam aleatórias. Seu exemplo sugere que você está procurando um tempo. Se houver entre as duas datas, você poderá modificar as respostas fornecidas até o momento para atender às suas necessidades e excluir o horário de término e de início. Por fim, na maioria das respostas, como a aceita, o código gera um datetime exclusivo do endtime devido ao truncamento para int. Para gerar um tempo que pode incluir o fim na resposta alterar o código paraptime = stime + prop * (etime - stime) + 0.5
Tortal

Respostas:

149

Converta ambas as seqüências de caracteres em registros de data e hora (na resolução escolhida, por exemplo, milissegundos, segundos, horas, dias, qualquer que seja), subtraia o anterior do posterior, multiplique seu número aleatório (assumindo que ele esteja distribuído no range [0, 1]) com essa diferença e adicione novamente a o anterior. Converta o carimbo de data e hora de volta à data e você terá um horário aleatório nesse intervalo.

Exemplo de Python (a saída está quase no formato que você especificou, exceto no 0preenchimento - culpe as convenções de formato de hora americano):

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()))
Tom Alsberg
fonte
Esta abordagem não oferece suporte para datas começa antes de 1970.
Cmbone
113
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)

A precisão é segundos. Você pode aumentar a precisão em microssegundos ou diminuir para, por exemplo, meia hora, se desejar. Para isso basta alterar o cálculo da última linha.

exemplo execute:

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

resultado:

2008-12-04 01:50:17
nosklo
fonte
3
O uso da startvariável nesse caso é perfeitamente correto. O único problema que vejo no código é o uso de secondsatributo do resultante delta. Isso não retornaria o número total de segundos em todo o intervalo; em vez disso, é apenas o número de segundos do componente 'time' (algo entre 0 e 60); um timedeltaobjeto tem um total_secondsmétodo que deve ser usado em seu lugar.
21811 Emyller
7
@emyller: Não, estou usando os (delta.days * 24 * 60 * 60) + delta.secondsresultados no total de segundos. O total_seconds()método é novo no python 2.7 e não existia em 2009 quando respondi à pergunta. Se você tem o python 2.7, deve usá-lo, mas o código funciona bem como está.
Nosklo 22/11
Eu não estava ciente da inexistência desse método em 2.7-. Acabei de verificar que um objeto timedelta é basicamente composto por números de dias e segundos, então você está certo. :-)
emyller
@emyller: Apenas para completar, o objeto timedelta é composto por dias, segundos e microssegundos . A precisão do código aleatório de geração de data acima é de segundos, mas pode ser alterada, como mencionei na resposta.
Nosklo
83

Uma versão minúscula.

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

Observe que ambos starte endargumentos devem ser datetimeobjetos. Se você tem seqüências de caracteres, é bastante fácil converter. As outras respostas apontam para algumas maneiras de fazê-lo.

emyller
fonte
54

Resposta atualizada

É ainda mais simples usando o Faker .

Instalação

pip install faker

Uso:

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

Resposta antiga

É muito simples usar radar

Instalação

pip install radar

Uso

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()
Artur Barseghyan
fonte
3
upvote por sugerir módulo faker .. Eu estava usando para gerar perfil, mas não usei o utilitário de data date faker é um módulo muito bom durante o teste.
Gahan #
Estou recebendo a saída neste formato, datetime.date(2039, 3, 16)mas quero uma saída como esta 2039-03-16. Como fazer isso?
Ayush Kumar
Você quer dizer uma corda? Muito fácil (apenas formatá-lo em conformidade): fake.date_between(start_date='today', end_date='+30y').strftime('%Y-%m-%d').
Artur Barseghyan
1
Voto a favor por usar uma biblioteca incrível, mesmo que você precise instalá-lo. Isso reduz a complexidade da implementação para essencialmente 4 linhas.
Blairg23
1
@ KubiK888: Claro, veja minhas respostas de atualizações. Você deve simplesmente fornecer o start_date explicitamente.
Artur Barseghyan
24

Essa é uma abordagem diferente - esse tipo de trabalho ..

from random import randint
import datetime

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

MELHOR ABORDAGEM

startdate=datetime.date(YYYY,MM,DD)
date=startdate+datetime.timedelta(randint(1,365))
amchugh89
fonte
1
A primeira abordagem nunca escolherá uma data que termina nos dias 29, 30 ou 31 e sua segunda abordagem não leva em consideração os anos bissextos, quando o ano é de 366 dias, ou seja, se startdate+ 1 ano passar por 31 de dezembro em um ano bissexto, isso o código nunca escolherá a mesma data exatamente um ano depois. Ambas as abordagens permitem especificar apenas uma data de início e quantos anos no futuro, enquanto a pergunta era sobre a especificação de duas datas e, na minha opinião, essa é uma API mais útil.
Boris
15

Como o Python 3 timedeltasuporta multiplicação com flutuadores, agora você pode:

import random
random_date = start + (end - start) * random.random()

dado que starte endsão do tipo datetime.datetime. Por exemplo, para gerar uma data e hora aleatória no dia seguinte:

import random
from datetime import datetime, timedelta

start = datetime.now()
end = start + timedelta(days=1)
random_date = start + (end - start) * random.random()
Pieter Bos
fonte
6

Para usar uma solução baseada em pandas, eu uso:

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

Eu gosto, por causa do bom pd.Timestamp recursos interessantes que me permitem jogar coisas e formatos diferentes. Considere os seguintes exemplos ...

Sua assinatura.

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

Posição aleatória.

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

Formato diferente.

>>> random_date('2008-01-01 13:30', '2009-01-01 4:50')
Timestamp('2008-11-18 17:20:19', tz=None)

Passando objetos de pandas / data e hora diretamente.

>>> random_date(pd.datetime.now(), pd.datetime.now() + pd.offsets.Hour(3))
Timestamp('2014-03-06 14:51:16.035965', tz=None)
metakermit
fonte
E como você criaria uma série de data e hora aleatória de maneira elegante (ou seja, sem iterar sua função para cada elemento)?
dmvianna 23/10
Bem, talvez seja possível modificar a função para gerar uma matriz de deltavalores e mapeá-los todos de uma vez para registros de data e hora. Pessoalmente, eu preferiria fazer algo assim pd.Series([5] * 10, [random_date('2014-01-01', '2014-01-30') for i in range(10)]).
metakermit
3

Aqui está uma resposta para o significado literal do título e não para o corpo desta pergunta:

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)

Este código é baseado livremente na resposta aceita.

Zach Dwiel
fonte
você pode alterar a segunda última linha para ptime = random.randint(stime, etime)marginalmente mais correta porque randintproduz um intervalo inclusivo.
Boris
3

Você pode usar Mixer,

pip install mixer

e,

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))
Nima Soroush
fonte
1
sintaxe mudou um pouco, não sei como fazer o acima, mas um objeto Django terão uma data aleatória preenchido assim:client = mixer.blend(Client, date=mixer.RANDOM)
tutuDajuju
@tutuDajuju: O que o cliente representa?
Nima Soroush
De acordo com seus documentos , pode ser uma classe de modelo Django, SQLAlchemy ou Mongoengine.
precisa saber é o seguinte
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()
Martin Thoma
fonte
2

Converta suas datas em registros de data e hora e ligue random.randintcom os registros de data e hora e , em seguida, converta o registro de data e hora gerado aleatoriamente em uma data:

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)

Então você pode usá-lo assim

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

Se você se preocupa com fusos horários, deve usar date_time_between_datesa Fakerbiblioteca, de onde roubei esse código , como já sugere uma resposta diferente.

Boris
fonte
1
  1. Converta suas datas de entrada em números (int, float, o que for melhor para seu uso)
  2. Escolha um número entre seus dois números de data.
  3. Converta esse número novamente em uma data.

Muitos algoritmos para converter datas de e para números já estão disponíveis em muitos sistemas operacionais.

mouviciel
fonte
1

Para que você precisa do número aleatório? Normalmente (dependendo do idioma), você pode obter o número de segundos / milissegundos da época a partir de uma data. Portanto, para uma data aleatória entre startDate e endDate, você pode:

  1. calcular o tempo em ms entre startDate e endDate (endDate.toMilliseconds () - startDate.toMilliseconds ())
  2. gere um número entre 0 e o número que você obteve em 1
  3. gerar uma nova data com deslocamento de hora = startDate.toMilliseconds () + número obtido em 2
tehvan
fonte
1

A maneira mais fácil de fazer isso é converter os dois números em registros de data e hora e defina-os como limites mínimo e máximo em um gerador de números aleatórios.

Um exemplo rápido de PHP seria:

// 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);
}

Esta função é usada strtotime()para converter uma descrição de data e hora em um carimbo de data / hora do Unix e date()para tornar uma data válida fora do carimbo de data e hora aleatório que foi gerado.

ConroyP
fonte
Se alguém puder escrever isso em python, isso seria útil.
quilby
1

Apenas para adicionar outro:

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

O manuseio do dia precisa de algumas considerações. Com 28, você está no site seguro.

tobmei05
fonte
1

Aqui está uma solução modificada da abordagem do emyller que retorna uma matriz de datas aleatórias em qualquer resolução

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

Parte do que é legal nessa abordagem é que ela np.datetime64é realmente boa em coagir as coisas até a data, para que você possa especificar suas datas de início / término como strings, datetime, timestamps de pandas ... praticamente tudo funcionará.

David Marx
fonte
0

Conceitualmente, é bastante simples. Dependendo do idioma que você estiver usando, você poderá converter essas datas em um número inteiro de referência de 32 ou 64 bits, geralmente representando segundos desde a época (1 de janeiro de 1970), também conhecida como "hora do Unix" ou milissegundos desde outra data arbitrária. Simplesmente gere um número inteiro aleatório de 32 ou 64 bits entre esses dois valores. Este deve ser um liner em qualquer idioma.

Em algumas plataformas, você pode gerar uma hora como dupla (data é a parte inteira, hora é a parte fracionária e uma implementação). O mesmo princípio se aplica, exceto se você estiver lidando com números de ponto flutuante de precisão simples ou dupla ("floats" ou "doubles" em C, Java e outras linguagens). Subtraia a diferença, multiplique pelo número aleatório (0 <= r <= 1), adicione à hora de início e pronto.

cleto
fonte
0

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

(precisa de dateutilbiblioteca python - pip install python-dateutil)

Artur
fonte
0

Use o ApacheCommonUtils para gerar um longo aleatório dentro de um determinado intervalo e, em seguida, crie Data desse período.

Exemplo:

importar org.apache.commons.math.random.RandomData;

importar org.apache.commons.math.random.RandomDataImpl;

data pública nextDate (data mín., data máx.) {

RandomData randomData = new RandomDataImpl();

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

}

uris
fonte
1
a pergunta está etiquetada como "python"
David Marx
0

Eu fiz isso para outro projeto usando aleatoriamente e tempo. Eu usei um formato geral a partir do momento em que você pode ver a documentação aqui para o primeiro argumento em strftime (). A segunda parte é uma função random.randrange. Retorna um número inteiro entre os argumentos. Altere-o para os intervalos que correspondem às cordas que você deseja. Você deve ter bons argumentos na tupla da segunda versão.

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

Pandas + solução 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 é a diferença entre os carimbos de data e hora em segundos (flutuante). Em seguida, é usado para criar um timedelta do pandas entre 0 e dts, que é adicionado ao carimbo de data / hora de início.

Carlos Santos
fonte
0

Com base na resposta de mouviciel, aqui está uma solução vetorizada usando numpy. Converta as datas de início e término em ints, gere uma matriz de números aleatórios entre elas e converta a matriz inteira novamente em datas.

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
Primavera
fonte
0

É o método modificado de @ (Tom Alsberg). Eu a modifiquei para obter a data em milissegundos.

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)

Exemplo:

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

Resultado: 2028/07/08 12:34:49.977963

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

referir

muthu
fonte
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")))
Clarius
fonte
0

Forma alternativa de criar datas aleatórias entre duas datas usando np.random.randint(), pd.Timestamp().valuee pd.to_datetime()com 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)

Resultado

['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']
Nilesh Ingle
fonte