Секреты календаря

Многие восхищаются людьми, у которых «вечный календарь в голове» — способность моментально определять день недели, на который приходится произвольная дата, считая даром свыше, недоступным простым людям. Ничуть не принижая достоинств этих людей, хочу отметить, что это не является чем-то сверхъестественным — в основе лежит довольно простая арифметика. Почти каждый может научиться определять день недели, если захочет, без бумажного календаря и калькулятора. За секунду, конечно, это будет получаться далеко не у каждого. Таким качеством могут обладать например люди с синдромом Аспергера, которые способны с огромной скоростью считать в уме.

Что ж, приступим. Скажу сразу, что речь пойдёт о григорианском календаре, применяемом у нас и много где за рубежом.

Пройдут года

Начну пожалуй с годов. Потому что это, пожалуй, самое удивительное по соотношению простоты и масштаба. Определить, на какой день приходит одинаковая дата в прошлом или будущем году, зная день в текущем — проще всего. Если сравнить календари двух соседних годов, то можно легко увидеть, что чаще всего они сдвинуты на один день (например, 1 января 2010 года приходится на пятницу, а в 2011 — уже на субботу), и иногда — на два дня, когда вклинивается 29 февраля. Это значит, что очень просто перепрыгнуть на год вперед или назад с любой даты:

прыгаем на год вперёд — смещаемся на день вперёд (или два, если перепрыгнули через «високосный день» — 29 февраля), прыгаем назад — смещаемся назад.

Вот например: 13 декабря 2011 года — вторник. Значит в 2011 году это будет понедельник, а в 2012 — четверг (помним про 29 февраля 2012 года).

Слегка расширив предыдущее правило можно так прыгать уже на несколько лет вперёд или назад — смещаемся на столько дней, на сколько лет прыгаем, плюс число перепрыгнутых «високосных дней». При этом чтобы не считать много, выкидываем дни семёрками, ведь сдвинувшись на 7 дней мы вернёмся на тот же день. Возвратимся к предыдущему примеру с 13 декабря: какой у нас день будет, скажем, 13 декабря 2017 года? Разница у нас — 6 лет, плюс в этот промежуток попадает два «високосных дня» — 2012 и 2016 года. То есть надо сдвинуться на 6 + 2 = 8 дней. 7 дней выкидываем, остаётся 1. Вторник плюс 1 день — это ж среда! Смотрим в календарь (у нас есть компьютер, где нетрудно «полистать» года — нажмите на часы в углу экрана!) — так и есть.

При этом хочу особо обратить внимание: надо смотреть именно попадание в интервал даты 29 февраля а не просто сам факт високосного года, ведь между 13 декабря 2011 и 2012 будет два дня недели разницы, а между 12 января тех же годов всего один день, именно из-за того, что 29 февраля не попало в интервал.

...а может быть и годы

С тем как на несколько лет перемещаться — разобрались, но осталось несколько моментов:

Первый — как определить, какой год високосный, а какой — нет? В принципе, все хорошо знают, что високосный год бывает раз в 4 года. Но вдруг понадобится на 13 веков посчитать, как определить високосность произвольного года?

Григорианский календарь, введённый в 1582 году определяет високосными годами следующие:

  • те, чей номер делится на 4 и не делится на 100;
  • те, чей номер делится на 400.

При этом, обратите внимание, если год делится на 400 он будет делиться и на 100, так что дважды високосным код быть не может. Так что первым делом определяем делимость на 100, а это элементарно: у такого года два нуля в конце: 1600, 1700, 1800.

Если год не «сотый», остаётся определить делимость на 4. Это пожалуй самое сложное в определении високосности. Но не стоит пугаться! Всё на самом деле очень просто. Смотреть на последние две цифры. Если:

  • цифра десятков чётная и цифра единиц — 0, 4, 8, или
  • цифра десятков нечётная и цифра единиц — 2, 6,

то число делится на 4, то есть год високосный. Вот номера всех високосных годов в течение века:

00* 01 02 03 04 05 06 07 08 09
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99

Если не считать 00 года1), то закономерность чётко прослеживается, не так ли?

А что с «сотыми» годами? Да в общем тоже ничего сложного — отбросим две последние цифры и то, что осталось проверим на делимость на 4. Аналогично, делится — високосный, не делится — не високосный.

Хочу сразу заметить, что 2000 год, который многие приняли за вполне рядовой високосный, является на самом деле очень редким исключением, даже исключением из исключения — он выпадает из 4-летнего цикла, так как делится на 100, но зато оказывается в 400-летнем цикле. Да, такое случается только раз в 400 лет!

Ещё одна небольшая хитрость. В течение века, а если границе веков стоит «400-й» год, то и в течение двух веков подряд календари точно повторяются с циклов 28 лет, а значит если мы не перепрыгиваем невисокосный «100-й», и разница между годами составляет 28, 56, 84, (а также, если повезло, 112, 140 и 196 лет) то дни недели у них совершенно точно совпадают. А если не совпадают, то можно отсчитывать дни не через весь интервал, а только от ближайшего совпадающего года. Кстати прибавлять 28 можно прибавляя 30 и отнимая 2, ну и отнимать аналогично, чтобы не мучиться с переносом.

Ещё разок помучаем пример с 13 февраля. Из вышесказанного совершенно очевидно, что как и в 2011, в 1983, 1955, 1927, а также в 2039, 2067 и 2095 год этот день наступает точно во вторник.

12 месяцев (не сказка)

С месяцами днями всё оказываются немного сложнее, но только немного.

Для осознания того, что будет сказано ниже следует обратить внимание на одну важную вещь: какой бы мы год не взяли разница в днях недели (да и вообще в днях) между двумя одноимённым датами в этом году будет зависеть только от того, попало ли в интервал 29 февраля, и то отличие будет всего в один день. Так что рассматривать стоит всего два варианта календаря вискосного года и невисокосного.

Вот календарь сферического невисокосного года в вакууме:2)

       Январь               Февраль                 Март
Пн Вт Ср Чт Пт Сб Вс  Пн Вт Ср Чт Пт Сб Вс  Пн Вт Ср Чт Пт Сб Вс
 1  2  3  4  5  6  7            1  2  3  4            1  2  3  4
 8  9 10 11 12 13 14   5  6  7  8  9 10 11   5  6  7  8  9 10 11
15 16 17 18 19 20 21  12 13 14 15 16 17 18  12 13 14 15 16 17 18
22 23 24 25 26 27 28  19 20 21 22 23 24 25  19 20 21 22 23 24 25
29 30 31              26 27 28              26 27 28 29 30 31

       Апрель                 Май                   Июнь
Пн Вт Ср Чт Пт Сб Вс  Пн Вт Ср Чт Пт Сб Вс  Пн Вт Ср Чт Пт Сб Вс
                   1      1  2  3  4  5  6               1  2  3
 2  3  4  5  6  7  8   7  8  9 10 11 12 13   4  5  6  7  8  9 10
 9 10 11 12 13 14 15  14 15 16 17 18 19 20  11 12 13 14 15 16 17
16 17 18 19 20 21 22  21 22 23 24 25 26 27  18 19 20 21 22 23 24
23 24 25 26 27 28 29  28 29 30 31           25 26 27 28 29 30
30
        Июль                 Август               Сентябрь
Пн Вт Ср Чт Пт Сб Вс  Пн Вт Ср Чт Пт Сб Вс  Пн Вт Ср Чт Пт Сб Вс
                   1         1  2  3  4  5                  1  2
 2  3  4  5  6  7  8   6  7  8  9 10 11 12   3  4  5  6  7  8  9
 9 10 11 12 13 14 15  13 14 15 16 17 18 19  10 11 12 13 14 15 16
16 17 18 19 20 21 22  20 21 22 23 24 25 26  17 18 19 20 21 22 23
23 24 25 26 27 28 29  27 28 29 30 31        24 25 26 27 28 29 30
30 31
      Октябрь                Ноябрь               Декабрь
Пн Вт Ср Чт Пт Сб Вс  Пн Вт Ср Чт Пт Сб Вс  Пн Вт Ср Чт Пт Сб Вс
 1  2  3  4  5  6  7            1  2  3  4                  1  2
 8  9 10 11 12 13 14   5  6  7  8  9 10 11   3  4  5  6  7  8  9
15 16 17 18 19 20 21  12 13 14 15 16 17 18  10 11 12 13 14 15 16
22 23 24 25 26 27 28  19 20 21 22 23 24 25  17 18 19 20 21 22 23
29 30 31              26 27 28 29 30        24 25 26 27 28 29 30
                                            31

Для того чтобы рассмотреть високосный год, пойдём на хитрость — возьмём год, начинающийся днём раньше, тогда все месяцы, начиная с марта будут совпадать, а сместятся только январь и февраль:

       Январь               Февраль                 Март
Пн Вт Ср Чт Пт Сб Вс  Пн Вт Ср Чт Пт Сб Вс  Пн Вт Ср Чт Пт Сб Вс
                   1         1  2  3  4  5            1  2  3  4
 2  3  4  5  6  7  8   6  7  8  9 10 11 12   5  6  7  8  9 10 11
 9 10 11 12 13 14 15  13 14 15 16 17 18 19  12 13 14 15 16 17 18
16 17 18 19 20 21 22  20 21 22 23 24 25 26  19 20 21 22 23 24 25
23 24 25 26 27 28 29  27 28 29              26 27 28 29 30 31
30 31

Возьмём два последовательных месяца, и взглянем, в чём разница. Смещение последующего месяца оказывается равно числу дней в предыдущем минус 28, то есть 4 целых недели никак не влияют на смещение, и учитывать можно только остаток из 2 или 3 дней, а у февраля вообще остатка нет, ну либо есть из одного дня, если он високосный.

Так что, например, между 13 ноября и 13 декабря будет разница в 2 дня недели. А что такое вторник минус два дня? Это воскресенье.

На что ещё стоит обратить внимание — месяцы, у которых дни, приходящиеся на одинаковые числа, совпадают:

  • январь (невисокосный) и октябрь (начинаются у нас с понедельника);
  • февраль (невисокосный), март и ноябрь (с четверга);
  • январь (вискосный), апрель и июль (с воскресенья);
  • сентябрь и декабрь (с субботы);
  • февраль (високосный) и август (со среды).

А также (если посмотреть на календари соседних лет:

  • январь следующего года совпадёт с маем текущего (со вторника);
  • февраль следующего года совпадёт с июнем текущего (с пятницы).

Так что, если даты с одинаковым числом пришлись на такие месяцы, то их дни недели будут совпадать!

Дни

С днями всё до банальности очевидно. Из разницы в днях просто выкидываем число, кратное неделям (7, 14, 21, 28) и отсчитываем оставшиеся дни недели. Если даты отличаются и годом и месяцем и днём, то просто последовательно суммируем результат.

Описанные выше техники позволяют определить день недели произвольной даты, зная некоторую опорную. Хотя все приведённые шаги достаточно очевидны, тем не менее приведённый способ весьма не быстр. Для того, чтобы вычислять день недели действительно быстро применяется «самый общий алгоритм».

Самый общий алгоритм

Сначала приведу этот самый общий алгоритм вычисления дня недели (подобный алгоритм применяется и в компьютерных программах, работающих с календарём), потом его разберу.

  1. если месяц январь или февраль, то из года вычитается единица.
  2. abcd = цифры года;
  3. e =
    0, если май или январь,
    1, если август,
    2, если март или ноябрь,
    3, если июнь или февраль,
    4, если сентябрь или декабрь,
    5, если апрель,
    6, если октябрь;
  4. fg = цифры дня месяца;
  5. a + 5·b+ ab/4 + 3·c + d + cd/4 + e + 3·f + g по модулю 7 есть номер дня с понедельника (т. е. 1 — понедельник, 2 — вторник,… 6 — суббота, 0 — воскресенье).

Причём совсем не нужно всё сначала перемножать, складывать, а затем искать остаток от деления — сложение по модулю считается довольно быстро и просто, как впрочем и умножение. Разница с обычным сложением лишь в том, что после каждой операции вычитайте ближайшее не большее кратное семи — 7, 14, 21, 28, 35 или 42. Тем не менее приведу таблицы сложения и умножения по модулю 7 — можете проверить:

+0123456 ×0123456
0012345600000000
1123456010123456
2234560120246135
3345601230362514
4456012340415263
5560123450531642
6601234560654321

Разбор алгоритма будет позже.

1) Я знаю, что век начинается с 01 года, но здесь это не имеет ровным счётом никакого значения, просто с 00 удобнее.
2) Выведен командой cal -y -h 2007 в консоли Linux
sledy/sekrety_kalendarja.txt · Последние изменения: 2011/12/02 04:22 — vovanium
За исключением случаев, когда указано иное, содержимое этой вики предоставляется на условиях следующей лицензии: CC Attribution 3.0 Unported