2 votes

Comment savoir si aujourd'hui est un jour dû à un changement d'heure locale, par exemple l'heure d'été, dans les horodatages standards de python et de pandas ?

Selon les règles de l'heure d'été britannique / heure d'été ( https://www.gov.uk/when-do-the-clocks-change ) les horloges :

  • avancer d'une heure à 1 heure du matin le dernier dimanche de mars,
  • reculer d'une heure à 2 heures du matin le dernier dimanche d'octobre.

En 2019, ce changement d'heure locale civile a lieu le 31 mars et le 27 octobre. les jours changent légèrement chaque année . Existe-t-il un moyen propre de connaître ces dates pour chaque année d'entrée ?

J'ai besoin de vérifier ces dates de "changement d'heure" de manière automatique. Existe-t-il un moyen d'éviter une boucle for pour vérifier les détails de chaque date afin de voir s'il s'agit d'une date de "changement d'heure" ?

En ce moment, j'explore ces dates pour 2019 afin d'essayer de trouver une procédure reproductible/automatique et j'ai trouvé ceci :

# using datetime from the standard library
march_utc_30 = datetime.datetime(2019, 3, 30, 0, 0, 0, 0, tzinfo=datetime.timezone.utc)
march_utc_31 = datetime.datetime(2019, 3, 31, 0, 0, 0, 0, tzinfo=datetime.timezone.utc)
april_utc_1 = datetime.datetime(2019, 4, 1, 0, 0, 0, 0, tzinfo=datetime.timezone.utc)
# using pandas timestamps
pd_march_utc_30 = pd.Timestamp(march_utc_30) #, tz='UTC')
pd_march_utc_31 = pd.Timestamp(march_utc_31) #, tz='UTC')
pd_april_utc_1 = pd.Timestamp(april_utc_1) #, tz='UTC')
# using pandas wrappers
pd_local_march_utc_30 = pd_march_utc_30.tz_convert('Europe/London')
pd_local_march_utc_31 = pd_march_utc_31.tz_convert('Europe/London')
pd_local_april_utc_1 = pd_april_utc_1.tz_convert('Europe/London')
# then printing all these dates
print("march_utc_30 {} pd_march_utc_30 {} pd_local_march_utc_30 {}".format(march_utc_30, pd_march_utc_30, pd_local_march_utc_30))
print("march_utc_31 {} pd_march_utc_31 {} pd_local_march_utc_31 {}".format(march_utc_31, pd_march_utc_31, pd_local_march_utc_31))
print("april_utc_1  {} pd_april_utc_1  {} pd_local_april_utc_1  {}".format(april_utc_1, pd_april_utc_1, pd_local_april_utc_1))

Les résultats de ces print est :

march_utc_30 2019-03-30 00:00:00+00:00 pd_march_utc_30 2019-03-30 00:00:00+00:00 pd_local_march_utc_30 2019-03-30 00:00:00+00:00
march_utc_31 2019-03-31 00:00:00+00:00 pd_march_utc_31 2019-03-31 00:00:00+00:00 pd_local_march_utc_31 2019-03-31 00:00:00+00:00
april_utc_1  2019-04-01 00:00:00+00:00 pd_april_utc_1  2019-04-01 00:00:00+00:00 pd_local_april_utc_1  2019-04-01 01:00:00+01:00

J'aurais besoin d'un for boucle à déterminer si la date actuelle est le dernier dimanche du mois ou comparer le "delta horaire" entre la date du jour et la date du lendemain pour voir s'il y a un +1, mais je me demande s'il n'y a pas une façon plus propre de faire cela ?

Y a-t-il un lien avec l'année, par exemple si l'on sait que l'année d'entrée est 2019 Nous savons donc avec certitude que la "date de changement" du mois de mars sera le 31 mars ?

1voto

Arount Points 4988

Utilisation dateutil.rrule peut aider (installer avec pip install python-dateutil ).

Comme nous pouvons récupérer les dates par semaine, nous n'avons pas besoin de boucles,

from dateutil.rrule import rrule, WEEKLY
from dateutil.rrule import SU as Sunday
from datetime import date
import datetime

def get_last_sunday(year, month):
    date = datetime.datetime(year=year, month=month, day=1)
    # we can find max 5 sundays in a months
    days = rrule(freq=WEEKLY, dtstart=date, byweekday=Sunday, count=5)
    # Check if last date is same month,
    # If not this couple year/month only have 4 Sundays
    if days[-1].month == month:
        return days[-1]
    else:
        return days[-2]

def get_march_switch(year):
    # Get 5 next Sundays from first March
    day = get_last_sunday(year, 3)
    return day.replace(hour=1, minute=0, second=0, microsecond=0)

def get_october_switch(year):
    day = get_last_sunday(year, 10)
    return day.replace(hour=2, minute=0, second=0, microsecond=0)

print('2019:')
print('  {}'.format(get_march_switch(2019)))
print('  {}'.format(get_october_switch(2019)))

print('2021:')
print('  {}'.format(get_march_switch(2021)))
print('  {}'.format(get_october_switch(2021)))

get_sundays() renvoie les 5 prochains dimanches à partir du premier jour de l'année donnée month car un mois ne peut avoir plus de 5 dimanches.

Ensuite, je vérifie simplement (dans get_(march|october)_switch() ) si le dernier dimanche donné est du mois attendu, sinon ce mois n'a que 4 dimanches, j'ai pris celui-ci.

Enfin, je fixe les heures, les secondes et les microsecondes.

Sortie :

2019:
  2019-03-31 01:00:00
  2019-10-27 02:00:00
2021:
  2021-03-28 01:00:00
  2021-10-24 02:00:00

1voto

Matteo Cabassi Points 11

Je sais que le sujet est déjà ancien. Cependant, j'ai eu la même question aujourd'hui, et à la fin j'ai trouvé une solution qui me semble assez simple, en utilisant seulement le datetime standard :

Je veux vérifier si ma date refdate est le jour de l'heure avancée d'octobre - j'ai procédé de la manière suivante :

refdate est mon objet datetime standard. Si vous avez un timestamp panda, vous pouvez le convertir en datetime native en utilisant .to_pydatetime()

if refdate.month == 10 and refdate.weekday() == 6 and (refdate + dt.timedelta(weeks = 1)).month == 11:
    oct_dst = 1

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