452 votes

Itération dans une plage de dates en Python

J'ai le code suivant pour le faire, mais comment puis-je l'améliorer ? Pour l'instant, je pense que c'est mieux que des boucles imbriquées, mais ça commence à devenir Perl-one-linerish quand on a un générateur dans une compréhension de liste.

day_count = (end_date - start_date).days + 1
for single_date in [d for d in (start_date + timedelta(n) for n in range(day_count)) if d <= end_date]:
    print strftime("%Y-%m-%d", single_date.timetuple())

Notes

  • Je ne l'utilise pas vraiment pour imprimer. C'est juste pour la démonstration.
  • El start_date y end_date Les variables sont datetime.date car je n'ai pas besoin de l'horodatage. (Ils vont être utilisés pour générer un rapport).

Exemple de sortie

Pour une date de début de 2009-05-30 et une date de fin de validité de 2009-06-09 :

2009-05-30
2009-05-31
2009-06-01
2009-06-02
2009-06-03
2009-06-04
2009-06-05
2009-06-06
2009-06-07
2009-06-08
2009-06-09

3 votes

Juste pour préciser : Je ne pense pas qu'il y ait de différence entre 'time.strftime("%Y-%m-%d", single_date.timetuple())' et le plus court 'single_date.strftime("%Y-%m-%d")'. La plupart des réponses semblent copier le style le plus long.

11 votes

Wow, ces réponses sont beaucoup trop compliquées. Essaie ça : stackoverflow.com/questions/7274267/

0 votes

@GringoSuave : qu'est-ce qui est compliqué dans La réponse de Sean Cavanagh ?

2voto

leftjoin Points 6979

Utilisation de pendule.period :

import pendulum

start = pendulum.from_format('2020-05-01', 'YYYY-MM-DD', formatter='alternative')
end = pendulum.from_format('2020-05-02', 'YYYY-MM-DD', formatter='alternative')

period = pendulum.period(start, end)

for dt in period:
    print(dt.to_date_string())

2voto

Nazar Points 121

Pour ceux qui sont intéressés par la voie fonctionnelle pythonique :

from datetime import date, timedelta
from itertools import count, takewhile

for d in takewhile(lambda x: x<=date(2009,6,9), map(lambda x:date(2009,5,30)+timedelta(days=x), count())):
    print(d)

1voto

teambob Points 954

Que pensez-vous de ce qui suit pour faire une plage incrémentée par des jours :

for d in map( lambda x: startDate+datetime.timedelta(days=x), xrange( (stopDate-startDate).days ) ):
  # Do stuff here
  • startDate et stopDate sont des objets datetime.date

Pour une version générique :

for d in map( lambda x: startTime+x*stepTime, xrange( (stopTime-startTime).total_seconds() / stepTime.total_seconds() ) ):
  # Do stuff here
  • startTime et stopTime sont des objets datetime.date ou datetime.datetime (les deux doivent être du même type)
  • stepTime est un objet timedelta

Notez que .total_seconds() n'est supporté qu'à partir de python 2.7. Si vous êtes coincé avec une version antérieure, vous pouvez écrire votre propre fonction :

def total_seconds( td ):
  return float(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6

1voto

DMfll Points 104

Cette fonction présente quelques caractéristiques supplémentaires :

  • peut passer une chaîne de caractères correspondant au DATE_FORMAT pour le début ou la fin et elle est convertie en un objet date.
  • peut passer un objet date pour le début ou la fin
  • vérification des erreurs dans le cas où la fin est plus ancienne que le début

    import datetime
    from datetime import timedelta
    
    DATE_FORMAT = '%Y/%m/%d'
    
    def daterange(start, end):
          def convert(date):
                try:
                      date = datetime.datetime.strptime(date, DATE_FORMAT)
                      return date.date()
                except TypeError:
                      return date
    
          def get_date(n):
                return datetime.datetime.strftime(convert(start) + timedelta(days=n), DATE_FORMAT)
    
          days = (convert(end) - convert(start)).days
          if days <= 0:
                raise ValueError('The start date must be before the end date.')
          for n in range(0, days):
                yield get_date(n)
    
    start = '2014/12/1'
    end = '2014/12/31'
    print list(daterange(start, end))
    
    start_ = datetime.date.today()
    end = '2015/12/1'
    print list(daterange(start, end))

1voto

Turtles Are Cute Points 1068

Voici un code pour une fonction générale de plage de dates, similaire à la réponse de Ber, mais plus flexible :

def count_timedelta(delta, step, seconds_in_interval):
    """Helper function for iterate.  Finds the number of intervals in the timedelta."""
    return int(delta.total_seconds() / (seconds_in_interval * step))

def range_dt(start, end, step=1, interval='day'):
    """Iterate over datetimes or dates, similar to builtin range."""
    intervals = functools.partial(count_timedelta, (end - start), step)

    if interval == 'week':
        for i in range(intervals(3600 * 24 * 7)):
            yield start + datetime.timedelta(weeks=i) * step

    elif interval == 'day':
        for i in range(intervals(3600 * 24)):
            yield start + datetime.timedelta(days=i) * step

    elif interval == 'hour':
        for i in range(intervals(3600)):
            yield start + datetime.timedelta(hours=i) * step

    elif interval == 'minute':
        for i in range(intervals(60)):
            yield start + datetime.timedelta(minutes=i) * step

    elif interval == 'second':
        for i in range(intervals(1)):
            yield start + datetime.timedelta(seconds=i) * step

    elif interval == 'millisecond':
        for i in range(intervals(1 / 1000)):
            yield start + datetime.timedelta(milliseconds=i) * step

    elif interval == 'microsecond':
        for i in range(intervals(1e-6)):
            yield start + datetime.timedelta(microseconds=i) * step

    else:
        raise AttributeError("Interval must be 'week', 'day', 'hour' 'second', \
            'microsecond' or 'millisecond'.")

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X