web-dev-qa-db-fra.com

Générer une date aléatoire entre deux autres dates

Comment pourrais-je générer une date aléatoire qui doit se situer entre deux autres dates données?

La signature de la fonction devrait ressembler à ceci:

randomDate("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

et retournerait une date telle que: 2/4/2008 7:20 PM

102
quilby

Convertissez les deux chaînes en horodatages (dans la résolution de votre choix, par exemple millisecondes, secondes, heures, jours, etc.), soustrayez le plus tôt possible, multipliez votre nombre aléatoire (en supposant qu'il soit distribué dans le range [0, 1]) avec cette différence, puis ajoutez à la précédente. Convertissez l'horodatage en chaîne de date et vous avez une heure aléatoire dans cette plage.

Exemple Python (la sortie est presque au format que vous avez spécifié, à l'exception de 0 padding - reprocher aux conventions de format d'heure américaines):

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())
112
Tom Alsberg
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 précision est en secondes. Vous pouvez augmenter la précision jusqu’à quelques microsecondes ou la réduire à une demi-heure, si vous le souhaitez. Pour cela, il suffit de changer le calcul des dernières lignes.

exemple exécuté:

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)

sortie:

2008-12-04 01:50:17
89
nosklo

Une version minuscule.

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

Notez que les deux arguments start et end doivent être des objets datetime. Si Vous avez plutôt des chaînes, il est assez facile de convertir. Les autres réponses indiquent des moyens de le faire.

72
emyller

Réponse mise à jour

C'est encore plus simple avec 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')

Ancienne réponse

C'est très simple en utilisant le 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()
35
Artur Barseghyan

C'est une approche différente - ce genre de travail ..

from random import randint
import datetime

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

MEILLEURE APPROCHE

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

Puisque Python 3 timedelta prend en charge la multiplication avec des flottants, vous pouvez maintenant faire:

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

étant donné que start et end sont du type datetime.datetime. Par exemple, pour générer une date/heure aléatoire le lendemain, procédez comme suit:

import random
from datetime import datetime, timedelta

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

Pour intégrer une solution à base de pandas, j'utilise:

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

Je l’aime bien, à cause des fonctionnalités de Nice pd.Timestamp qui me permettent d’utiliser différents supports et formats. Considérez les quelques exemples suivants ...

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

Position aléatoire.

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

Format différent.

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

Passer des objets pandas/datetime directement.

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

Vous pouvez utiliser Mixer,

pip install mixer

et,

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))
3
Nima Soroush

Juste pour en ajouter un autre:

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 gestion de jour nécessite quelques considérations. Avec 28, vous êtes sur le site sécurisé.

2
tobmei05

Le moyen le plus simple consiste à convertir les deux nombres en horodatages, puis à les définir comme limites minimales et maximales sur un générateur de nombres aléatoires.

Un exemple PHP rapide serait:

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

Cette fonction utilise strtotime() pour convertir une description datetime en un horodatage Unix et date() pour définir une date valide à partir de l'horodatage aléatoire généré.

2
ConroyP
#!/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 __== '__main__':
    import doctest
    doctest.testmod()
2
Martin Thoma

Voici une réponse à la signification littérale du titre plutôt que le corps de cette 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)

Ce code est basé vaguement sur la réponse acceptée.

2
Zach Dwiel

Voici une solution modifiée de l'approche d'Emyller qui renvoie un tableau de dates aléatoires à n'importe quelle résolution.

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

Une partie de ce qui est bien avec cette approche est que np.datetime64 est vraiment doué pour contraindre les choses à des dates, vous pouvez donc spécifier vos dates de début/fin sous forme de chaînes, de dates/heures, d'horodatages de pandas ... pratiquement tout fonctionnera.

1
David Marx
  1. Convertissez vos dates d'entrée en nombres (Int, float, tout ce qui convient le mieux à Votre utilisation)
  2. Choisissez un nombre entre vos deux numéros de date.
  3. Convertissez ce numéro en date.

De nombreux algorithmes de conversion de date en nombre sont déjà disponibles dans de nombreux systèmes d'exploitation.

1
mouviciel

Pourquoi avez-vous besoin du nombre aléatoire? Généralement (en fonction de la langue), vous pouvez obtenir le nombre de secondes/millisecondes à partir d'une époque. Donc, pour une date aléatoire entre startDate et endDate, vous pouvez faire:

  1. calcule le temps en ms entre startDate et endDate (endDate.toMilliseconds () - startDate.toMilliseconds ())
  2. générer un nombre compris entre 0 et le nombre obtenu en 1
  3. générer une nouvelle date avec décalage horaire = startDate.toMilliseconds () + nombre obtenu en 2
1
tehvan

Sur la base de la réponse de mouviciel, voici une solution vectorisée utilisant numpy. Convertissez les dates de début et de fin en entiers, générez un tableau de nombres aléatoires entre elles et reconvertissez tout le tableau en 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
0
spring

Solution Pandas + 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 est la différence entre les horodatages en secondes (float). Il est ensuite utilisé pour créer un pandas temporisé entre 0 et dts, qui est ajouté à l'horodatage de départ.

0
Carlos Santos

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

(besoin de la bibliothèque dateutil de python - pip install python-dateutil)

0
Artur

Conceptuellement, c'est assez simple. En fonction de la langue utilisée, vous pourrez convertir ces dates en un entier de référence de 32 ou 64 bits, représentant généralement les secondes depuis Epoch (1er janvier 1970), également appelé "heure Unix" ou millisecondes depuis une autre date arbitraire. Générez simplement un entier aléatoire de 32 ou 64 bits entre ces deux valeurs. Cela devrait être un one-line dans n'importe quelle langue.

Sur certaines plates-formes, vous pouvez générer une heure sous forme de double (la date est la partie entière, le temps la fraction est une implémentation). Le même principe s'applique sauf que vous avez affaire à des nombres à virgule flottante simple ou double précision («flottants» ou «doubles» en C, Java et autres langages). Soustrayez la différence, multipliez par un nombre aléatoire (0 <= r <= 1), ajoutez à l'heure de début et c'est fait.

0
cletus

Je l'ai fait pour un autre projet en utilisant aléatoire et le temps. J'ai utilisé un format général de temps, vous pouvez voir la documentation ici pour le premier argument de strftime (). La deuxième partie est une fonction random.randrange. Il retourne un entier entre les arguments. Changez-le pour les plages qui correspondent aux chaînes que vous souhaitez. Vous devez avoir de jolis arguments dans le tuple du deuxième article.

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
user2723240

Utilisez ApacheCommonUtils pour générer une longueur aléatoire dans une plage donnée, .__, puis créez une Date à partir de cette longueur. 

Exemple:

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

}

0
uris

C'est une méthode modifiée de @ (Tom Alsberg). Je l'ai modifié pour obtenir une date avec millisecondes.

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)

Exemple:

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

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

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

référer

0
muthu

Convertissez vos dates en horodatages et appelez random.randint avec les horodatages, puis reconvertissez l'horodatage généré aléatoirement en une 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(
        min(first_timestamp, second_timestamp), max(first_timestamp, second_timestamp)
    )
    return datetime.fromtimestamp(random_timestamp)

Ensuite, vous pouvez l'utiliser comme ça

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)  # works the same

Si vous vous souciez des fuseaux horaires, vous devriez simplement utiliser la bibliothèque faker, où j'ai volé ce code , comme le suggère déjà une réponse différente.

0
Boris