Как я узнаю, что сегодня выходной день из-за изменения местного времени, например летнего времени в стандартных точках времени Python и Pandas? - PullRequest
0 голосов
/ 05 февраля 2019

Согласно правилам британского летнего времени / перехода на летнее время (https://www.gov.uk/when-do-the-clocks-change) часы:

  • вперед на 1 час в 1:00 в последнее воскресенье марта,
  • вернуться на 1 час в 2 часа ночи в последнее воскресенье октября.

В 2019 году это гражданское изменение местного времени происходит 31 марта и 27 октября, но дни слегка меняются каждый год. Есть ли чистый способ узнать эти даты для каждого входного года?

Мне нужно проверить эти даты «меняющегося времени» автоматически, есть ли способ избежать цикла for для проверкидетали каждой даты, чтобы увидеть, является ли она датой «меняющегося времени»?

В настоящий момент я изучаю эти даты на 2019 год, просто чтобы попытаться выяснить воспроизводимую / автоматическую процедуру, и я нашел это:

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

Вывод этих операторов print:

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

Я мог бы использовать цикл for, чтобы выяснить, является ли текущая дата последним воскресеньеммесяц , или сравните «дельта часа» междутекущая дата и дата послезавтра, чтобы увидеть, есть ли +1, но мне интересно, есть ли более чистый способ сделать это?

Есть ли что-то привязанное к году, например, зная вводный год2019 тогда мы точно знаем, что "дата изменения" в марте будет 31-го числа?

1 Ответ

0 голосов
/ 05 февраля 2019

Использование dateutil.rrule может помочь (установить с помощью pip install python-dateutil).

Поскольку мы можем выбирать даты по неделям, нам не нужны циклы,

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() возвращает 5 следующих воскресений с первого дня данного month, потому что месяц может иметь максимум 5 воскресений.

Тогда я просто проверяю (в пределах get_(march|october)_switch()), еслипоследнее воскресенье дано из ожидаемого месяца, если не очень хорошо, в этом месяце есть только 4 воскресенья, я взял это.

Наконец я фиксирую часы, секунды и микросекунды.

Вывод:

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