Genera una data casuale tra altre due date


138

Come potrei generare una data casuale che deve essere compresa tra altre due date?

La firma della funzione dovrebbe essere simile a questa:

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 restituirebbe una data come: 2/4/2008 7:20 PM


Il modo in cui la domanda viene presentata al momento non è chiaro se si desidera che la data o l'ora siano casuali. Il tuo esempio suggerisce che stai cercando un momento. Se deve essere compreso tra le due date, potresti voler modificare le risposte fornite finora per soddisfare le tue esigenze ed escludere la fine e l'ora di inizio. Infine, nella maggior parte delle risposte, come quella accettata, il codice genera un datetime esclusivo dell'endtime dovuto al troncamento di int. Per generare un tempo che può includere la fine nella risposta, modifica il codice inptime = stime + prop * (etime - stime) + 0.5
tortal

Risposte:


149

Converti entrambe le stringhe in timestamp (nella risoluzione scelta, ad esempio millisecondi, secondi, ore, giorni, qualunque cosa), sottrai il precedente dal successivo, moltiplica il tuo numero casuale (supponendo che sia distribuito nel range [0, 1]) con quella differenza, e aggiungi nuovamente a il precedente. Converti il ​​timestamp in stringa data e hai un intervallo casuale in quell'intervallo.

Esempio di Python (l'output è quasi nel formato specificato, oltre al 0riempimento - incolpare le convenzioni sul formato dell'ora 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()))

Questo approccio non supporta le date che iniziano prima del 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)

La precisione è secondi. Puoi aumentare la precisione fino a microsecondi o ridurre, ad esempio, a mezz'ora, se lo desideri. Per questo basta cambiare il calcolo dell'ultima riga.

esempio di esecuzione:

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

produzione:

2008-12-04 01:50:17

3
L'uso della startvariabile in quel caso è perfettamente giusto. L'unico problema che vedo nel codice è l'uso secondsdell'attributo dal risultante delta. Ciò non restituirebbe il numero totale di secondi nell'intero intervallo; invece, è solo il numero di secondi dal componente 'time' (qualcosa tra 0 e 60); un timedeltaoggetto ha un total_secondsmetodo, che dovrebbe essere usato invece.
emyller,

7
@emyller: No, sto usando (delta.days * 24 * 60 * 60) + delta.secondsquali risultati nei secondi totali. Il total_seconds()metodo è nuovo in Python 2.7 e non esisteva nel 2009 quando ho risposto alla domanda. Se hai Python 2.7, dovresti invece usarlo, ma il codice funziona bene così com'è.
nosklo,

Non ero a conoscenza dell'inesistenza di questo metodo nel 2.7-. Ho appena verificato che un oggetto timedelta è sostanzialmente composto da numeri di giorni e secondi, quindi hai ragione. :-)
emyller,

@emyller: solo per completezza, l'oggetto timedelta è composto da giorni, secondi e microsecondi . La precisione del codice di generazione casuale della data sopra è fino a pochi secondi, ma potrebbe essere cambiata, come ho già detto nella risposta.
nosklo,

83

Una versione minuscola.

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

Si noti che entrambi starte endgli argomenti devono essere datetimeoggetti. Se invece hai le stringhe, è abbastanza facile da convertire. Le altre risposte indicano alcuni modi per farlo.


54

Risposta aggiornata

È ancora più semplice usando Faker .

Installazione

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

Vecchia risposta

È molto semplice usare il radar

Installazione

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

3
voto per suggerire il modulo faker. Stavo usando per generare il profilo ma non ho usato l'utilità data faker è un modulo molto buono durante i test.
Gahan,

Sto ottenendo l'output in questo formato datetime.date(2039, 3, 16)Ma voglio un output in questo modo 2039-03-16. Come farlo?
Ayush Kumar

Vuoi dire che vuoi una stringa? Molto facile (basta formattarlo di conseguenza): fake.date_between(start_date='today', end_date='+30y').strftime('%Y-%m-%d').
Artur Barseghyan

1
È utile utilizzare una libreria incredibile, anche se è necessario installarla. Ciò riduce la complessità dell'implementazione essenzialmente a 4 righe.
Blairg23,

1
@ KubiK888: Certo, vedi la risposta dei miei aggiornamenti. Dovresti semplicemente fornire esplicitamente start_date.
Artur Barseghyan,

24

Questo è un approccio diverso - quel tipo di opere ..

from random import randint
import datetime

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

MIGLIOR APPROCCIO

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

1
Il primo approccio non sceglierà mai una data che termina il 29, 30 o 31 e il secondo approccio non tiene conto degli anni bisestili, quando l'anno è di 366 giorni, ovvero se startdate+ 1 anno passa al 31 dicembre in un anno bisestile, questo il codice non sceglierà mai la stessa data esattamente un anno dopo. Entrambi gli approcci consentono solo di specificare una data di inizio e quanti anni in futuro, mentre la domanda era di specificare due date e, a mio avviso, è un'API più utile.
Boris,

15

Poiché Python 3 timedeltasupporta la moltiplicazione con float, ora puoi fare:

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

dato che starte endsono del tipo datetime.datetime. Ad esempio, per generare un datetime casuale entro il giorno successivo:

import random
from datetime import datetime, timedelta

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

6

Per aggiungere un chip in una soluzione basata su Panda 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

Mi piace, grazie al bello pd.Timestamp funzionalità che mi permettono di lanciarci cose e formati diversi. Considera i seguenti esempi ...

La tua firma.

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

Posizione casuale.

>>> 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 diverso.

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

Passando direttamente oggetti panda / datetime.

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

E come creeresti elegantemente una serie casuale di datetime (ovvero, senza iterare la tua funzione per ciascun elemento)?
dmvianna,

Bene, forse è possibile modificare la funzione per generare una matrice di deltavalori e mapparli tutti contemporaneamente su timestamp. Personalmente, preferirei fare qualcosa del genere pd.Series([5] * 10, [random_date('2014-01-01', '2014-01-30') for i in range(10)]).
metakermit,

3

Ecco una risposta al significato letterale del titolo piuttosto che al corpo di questa domanda:

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)

Questo codice si basa vagamente sulla risposta accettata.


potresti cambiare la seconda ultima riga in modo ptime = random.randint(stime, etime)che sia leggermente più corretta perché randintproduce un intervallo inclusivo.
Boris,

3

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

1
la sintassi è cambiata un po ', non so come fare quanto sopra, ma un oggetto django avrà una data casuale riempita in questo modo:client = mixer.blend(Client, date=mixer.RANDOM)
tutuDajuju

@tutuDajuju: Cosa rappresenta il cliente?
Nima Soroush,

Secondo i loro documenti , può essere una classe di modello Django, SQLAlchemy o 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

Converti le tue date in timestamp e chiama random.randintcon i timestamp, quindi converti nuovamente il timestamp generato casualmente in una 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)

Quindi puoi usarlo in questo modo

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 ti interessano i fusi orari dovresti semplicemente utilizzare date_time_between_datesdalla Fakerlibreria, da cui ho rubato questo codice , come suggerisce già una risposta diversa.


1
  1. Converti le date di input in numeri (int, float, qualunque sia la cosa migliore per il tuo utilizzo)
  2. Scegli un numero tra i due numeri di data.
  3. Converti questo numero in una data.

Molti algoritmi per convertire la data in e da numeri sono già disponibili in molti sistemi operativi.


1

A cosa serve il numero casuale? Di solito (a seconda della lingua) è possibile ottenere il numero di secondi / millisecondi dall'epoca a partire da una data. Quindi per una data casuale tra startDate e endDate potresti fare:

  1. calcola il tempo in ms tra startDate ed endDate (endDate.toMilliseconds () - startDate.toMilliseconds ())
  2. genera un numero compreso tra 0 e il numero ottenuto in 1
  3. genera una nuova data con time offset = startDate.toMilliseconds () + numero ottenuto in 2

1

Il modo più semplice per farlo è convertire entrambi i numeri in timestamp, quindi impostarli come limiti minimi e massimi su un generatore di numeri casuali.

Un rapido esempio di PHP sarebbe:

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

Questa funzione consente di strtotime()convertire una descrizione data / ora in un timestamp Unix e date()di creare una data valida dal timestamp casuale che è stato generato.


Se qualcuno potesse scriverlo in Python sarebbe utile.
Quilby,

1

Solo per aggiungerne un altro:

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

La gestione del giorno richiede alcune considerazioni. Con 28 sei sul sito sicuro.


1

Ecco una soluzione modificata dall'approccio di emyller che restituisce una serie di date casuali a qualsiasi risoluzione

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 di ciò che è bello di questo approccio è che np.datetime64è davvero bravo a forzare le cose alle date, quindi puoi specificare le tue date di inizio / fine come stringhe, data, timestamp dei panda ... praticamente tutto funzionerà.


0

Concettualmente è abbastanza semplice. A seconda della lingua che stai usando, sarai in grado di convertire quelle date in un numero intero di riferimento a 32 o 64 bit, che in genere rappresenta i secondi dall'epoca (1 gennaio 1970), altrimenti noto come "tempo Unix" o millisecondi da qualche altra data arbitraria. Generare semplicemente un numero intero a 32 o 64 bit tra questi due valori. Questo dovrebbe essere un liner in qualsiasi lingua.

Su alcune piattaforme puoi generare un tempo come doppio (la data è la parte intera, il tempo è la parte frazionaria è un'implementazione). Lo stesso principio si applica tranne per il fatto che hai a che fare con numeri in virgola mobile a precisione singola o doppia ("float" o "double" in C, Java e altre lingue). Sottrarre la differenza, moltiplicare per numero casuale (0 <= r <= 1), aggiungere l'ora di inizio e il gioco è fatto.


0

In pitone:

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

(serve dateutillibreria Python - pip install python-dateutil)


0

Utilizzare ApacheCommonUtils per generare un long casuale all'interno di un determinato intervallo, quindi creare Date fuori da quel long.

Esempio:

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

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

public Date nextDate (Date min, Date max) {

RandomData randomData = new RandomDataImpl();

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

}


1
la domanda è taggata "pitone"
David Marx

0

L'ho realizzato per un altro progetto usando random e time. Ho usato un formato generale da quando è possibile visualizzare la documentazione qui per il primo argomento in strftime (). La seconda parte è una funzione random.randrange. Restituisce un numero intero tra gli argomenti. Modificalo negli intervalli che corrispondono alle stringhe che desideri. Devi avere simpatici argomenti nella tupla del secondo 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))

0

Panda + soluzione intorpidita

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 è la differenza tra i timestamp in secondi (float). Viene quindi utilizzato per creare un panda timedelta tra 0 e dts, che viene aggiunto al timestamp iniziale.


0

Sulla base della risposta di mouviciel, ecco una soluzione vettoriale utilizzando numpy. Converti le date di inizio e fine in ints, genera una matrice di numeri casuali tra loro e converti l'intera matrice in date.

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

È il metodo modificato di @ (Tom Alsberg). L'ho modificato per ottenere la data con millisecondi.

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)

Esempio:

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

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

fare riferimento


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

Modo alternativo per creare date casuali tra due date utilizzando np.random.randint(), pd.Timestamp().valuee pd.to_datetime()con 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)

Produzione

['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']
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.