Вчера получил календарь на 2016 год. Мне в голову пришёл интересный вопрос: когда я смогу повторно использовать этот календарь, и для какого года можно повторно использовать какой старый календарь?
1 января 2015 года был четверг. Тот же день в 2016 году — пятница. Как только вы проследите эту закономерность, вы быстро заметите, что базовый период в семь лет нарушается високосными годами.
Быстро выясняется, что для некоторых лет требуются десятилетия, прежде чем вы сможете повторно использовать календарь: 2016 — високосный год, поэтому вы не можете повторно использовать его для 2044.
Однако есть одна особенность, которая в настоящее время не реализована в онлайн-сервисах вроде whencanireusethiscalendar.com: Вы можете частично повторно использовать календарь.
Причина, по которой два календаря не совпадают, часто — високосный день в одном из них. Однако довольно часто они совпадают либо до високосного дня, либо начиная с дня после високосного дня. Мы называем эти годы годами частичного повторного использования (A) и (B) соответственно. Как только вы рассматриваете эту опцию (т.е. вы меняете календарь где-то около високосного дня, предполагая, что у нас есть как (A), так и (B) пригодные для повторного использования календари на один год), вы сможете повторно использовать календари — особенно календари високосных лет, такие как 2016.
Основываясь на этом понимании, я написал простой python-скрипт полного перебора, использующий только основные библиотеки. Вы можете просто вызвать его из командной строки с годом календаря, который вы хотите повторно использовать:
python3 reuse-calendars.py 2015Скрипт использует подход проб и ошибок, поскольку пространство поиска довольно мало для современного компьютера:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Вычислить список лет, когда можно повторно использовать календарь.
Этот скрипт вычисляет три типа лет повторного использования:
- Годы полного повторного использования, где каждый день недели совпадает
- Годы частичного повторного использования (A), где каждый день до
високосного дня (29 фев) совпадает
- Годы частичного повторного использования (B), где каждый день начиная с дня
после високосного дня (29 фев) совпадает
Годы частичного повторного использования не включают годы полного повторного использования по замыслу.
"""
__copyright__ = "Copyright (c) 2015 Uli Köhler"
__license__ = "Apache License v2.0"
__version__ = "1.1"
from datetime import date
from collections import namedtuple
ReuseYears = namedtuple('ReuseYears',
['year', 'fullReuseYears',
'partialReuseYearsA', 'partialReuseYearsB'])
def getReuseYears(year, startYear=2005, stopYear=2050):
"""
Получить годы, когда можно повторно использовать календарь, как объект ReuseYears.
"""
# Получить номер дня недели ISO для одной из двух опорных дат
# Опорная дата 1 — первый день года
# Опорная дата 2 — любая дата ПОСЛЕ високосного дня
refdate1 = lambda y: date(y, 1, 1).isoweekday()
refdate2 = lambda y: date(y, 5, 1).isoweekday()
fullYears = []
partialYearsA = [] # До високосного дня
partialYearsB = [] # С високосного дня
for otherYear in range(startYear, stopYear + 1):
if otherYear == year: continue
aMatch = refdate1(year) == refdate1(otherYear)
bMatch = refdate2(year) == refdate2(otherYear)
if aMatch and bMatch:
fullYears.append(otherYear)
elif aMatch:
partialYearsA.append(otherYear)
elif bMatch:
partialYearsB.append(otherYear)
return ReuseYears(year, fullYears, partialYearsA, partialYearsB)
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('year', type=int, help='Год для получения ')
args = parser.parse_args()
print(getReuseYears(args.year))