Определение дня недели для любой даты может быть выполнено с помощью различных алгоритмов . Кроме того, вечные календари не требуют никаких вычислений со стороны пользователя и по сути являются таблицами поиска. Типичное применение — вычисление дня недели , в который кто-то родился или произошло определенное событие.
В числовых расчетах дни недели представлены в виде номеров дней недели. Если понедельник является первым днем недели, дни могут быть закодированы от 1 до 7, с понедельника по воскресенье, как это практикуется в ISO 8601. День, обозначенный как 7, может также считаться как 0 , путем применения арифметики по модулю 7, которая вычисляет остаток числа после деления на 7. Таким образом, число 7 рассматривается как 0, число 8 как 1, число 9 как 2, число 18 как 4 и т. д. Если воскресенье считается днем 1, то 7 дней спустя ( т. е. день 8) также являются воскресеньем, а день 18 совпадает с днем 4, который является средой, поскольку он выпадает на три дня после воскресенья ( т. е . 18 mod 7 = 4 ). [a]
Основной подход почти всех методов расчета дня недели начинается с «базовой даты»: известной пары (например, 1 января 1800 года как среда), определения количества дней между известным днем и днем, который вы пытаетесь определить, и использования арифметики по модулю 7 для нахождения нового числового дня недели.
Один из стандартных подходов заключается в том, чтобы найти (или вычислить, используя известное правило) значение первого дня недели данного столетия, найти (или вычислить, используя метод сравнения) корректировку для месяца, вычислить количество високосных лет с начала столетия, а затем сложить их вместе с количеством лет с начала столетия и номером дня месяца. В конце концов, получается количество дней, к которому применяется модуль 7, чтобы определить день недели даты. [4]
Некоторые методы сначала выполняют все сложения, а затем отбрасывают семерки, тогда как другие отбрасывают их на каждом шаге, как в методе Льюиса Кэрролла. Любой из способов вполне жизнеспособный: первый проще для калькуляторов и компьютерных программ, второй — для умственных вычислений (вполне возможно выполнить все вычисления в уме, немного попрактиковавшись). Ни один из методов, приведенных здесь, не выполняет проверки диапазона, поэтому необоснованные даты дадут ошибочные результаты.
Каждый седьмой день месяца имеет то же название, что и предыдущий:
«Соответствующие месяцы» — это те месяцы в календарном году, которые начинаются в один и тот же день недели. Например, сентябрь и декабрь соответствуют, потому что 1 сентября приходится на тот же день, что и 1 декабря (поскольку между этими двумя датами ровно тринадцать недель по 7 дней). Месяцы могут соответствовать, только если количество дней между их первыми днями делится на 7, или, другими словами, если их первые дни — это целое число недель, отстоящих друг от друга. Например, февраль обычного года соответствует марту, потому что в феврале 28 дней, число, делящееся на 7, а 28 дней — это ровно четыре недели. В високосном году январь и февраль соответствуют другим месяцам, чем в обычном году, поскольку добавление 29 февраля означает, что каждый последующий месяц начинается на день позже.
Январь соответствует октябрю в обычные годы и апрелю и июлю в високосные годы. Февраль соответствует марту и ноябрю в обычные годы и августу в високосные годы. Март всегда соответствует ноябрю, апрель всегда соответствует июлю, а сентябрь всегда соответствует декабрю. Август не соответствует ни одному другому месяцу в обычные годы. Октябрь не соответствует ни одному другому месяцу в високосные годы. Май и июнь никогда не соответствуют ни одному другому месяцу.
В таблице месяцев ниже соответствующие месяцы имеют одинаковые номера, что непосредственно следует из определения.
Существует семь возможных дней, с которых может начаться год, и високосные годы изменят день недели после 29 февраля. Это означает, что существует 14 конфигураций, которые может иметь год. Все конфигурации могут быть обозначены доминиканской буквой , но поскольку 29 февраля не имеет буквы, назначенной ему, високосный год имеет две доминиканские буквы, одну для января и февраля, а другую (на один шаг назад в алфавитной последовательности) для марта и декабря.
2021 год — невисокосный год, начинающийся в пятницу, что означает, что он соответствует календарному году 2010. Первые два месяца 2021 года соответствуют первым двум месяцам 2016 года. 2022 год — невисокосный год, начинающийся в субботу, что означает, что он соответствует календарному году 2011. Последние десять месяцев 2022 года соответствуют последним десяти месяцам 2016 года. 2023 год — невисокосный год, начинающийся в воскресенье, что означает, что он соответствует календарному году 2017. 2024 год — високосный год, начинающийся в понедельник, что означает, что он соответствует календарному году 1996. Первые два месяца 2024 года соответствуют первым двум месяцам 2018 года. Последние десять месяцев 2024 года соответствуют последним десяти месяцам 2019 года.
Каждый високосный год повторяется один раз каждые 28 лет, а каждый обычный год повторяется один раз каждые 6 лет и дважды каждые 11 лет. Например, последний раз високосный год, начинающийся в среду, был в 2020 году, а следующий раз будет в 2048 году. Аналогично, следующие обычные годы, начинающиеся в пятницу, будут в 2027, 2038 и затем в 2049 году. Оба эти утверждения верны, если только не пропустить високосный год, но это произойдет не раньше 2100 года.
Подробную информацию смотрите в таблице ниже.
Примечания:
«Год 000» в обычной хронологии — это 1 год до нашей эры (который предшествует 1 году нашей эры). В астрономической нумерации лет 0 находится между 1 годом до нашей эры и 1 годом нашей эры. В пролептическом юлианском календаре (то есть юлианском календаре, каким он был бы, если бы он использовался правильно с самого начала) 1 год до нашей эры начинается в четверг. В пролептическом григорианском календаре (так называемом, потому что он был разработан только в 1582 году) 1 год до нашей эры начинается в субботу.
Для юлианских дат до 1300 и после 1999 года следует использовать год в таблице, который отличается на точное число, кратное 700 годам. Для григорианских дат после 2299 года следует использовать год в таблице, который отличается на точное число, кратное 400 годам. Значения от « r0 » до « r6 » указывают остаток при делении значения сотен на 7 и 4 соответственно, указывая, как ряд простирается в том или ином направлении. Для удобства показаны как юлианские, так и григорианские значения 1500-1999. Жирные цифры (например, 04 ) обозначают високосный год. Если год заканчивается на 00, а его сотни выделены жирным шрифтом, то это високосный год. Таким образом, 19 указывает, что 1900 год не является григорианским високосным годом (но 19 в юлианском столбце указывает, что это юлианский високосный год, как и все юлианские x 00 годы). 20 указывает, что 2000 год является високосным годом. Используйте янв и фев только в високосные годы.
Для определения дня недели (1 января 2000 г., суббота)
Формула имеет вид w = (d + m + y + c) mod 7.
Обратите внимание, что дата (и, следовательно, день недели) в пересмотренном юлианском и григорианском календарях одинакова с 14 октября 1923 года по 28 февраля 2800 года нашей эры включительно, и что для больших годов можно вычесть 6300 или кратное этому число перед началом, чтобы получить год, который находится в пределах таблицы или ближе к ней.
Чтобы узнать день недели любой даты любого года с помощью таблицы, вычтите 100 из года, разделите разницу на 100, умножьте полученное частное (опуская дроби) на семь и разделите произведение на девять. Запишите частное (опуская дроби). Введите таблицу с юлианским годом и непосредственно перед последним делением добавьте 50 и вычтите частное, указанное выше.
Пример: Какой день недели 27 января 8315 года?
8315−6300=2015, 2015−100=1915, 1915/100=19 остаток 15, 19×7=133, 133/9=14 остаток 7. 2015 на 700 лет опережает 1315, поэтому используется 1315. Из таблицы: для сотен (13): 6. Для оставшихся цифр (15): 4. Для месяца (январь): 0. Для даты (27): 27. 6 + 4 + 0 + 27 + 50 − 14 = 73. 73/7=10 остаток 3. День недели = вторник.
Чтобы найти букву Господню , вычислите день недели 1 января или 1 октября. Если это воскресенье, буква Господня — A, если суббота — B, и так далее в обратном порядке по неделе и вперед по алфавиту до понедельника, который есть G.
Високосные годы имеют две воскресные буквы, поэтому для января и февраля вычисляйте день недели на 1 января, а для марта-декабря вычисляйте день недели на 1 октября.
Високосными являются все годы, которые делятся ровно на четыре, за следующими исключениями:
В григорианском календаре – все годы, которые делятся ровно на 100 (кроме тех, которые делятся ровно на 400).
В пересмотренном юлианском календаре – все годы, которые делятся ровно на 100 (кроме тех, которые дают остаток 200 или 600 при делении на 900).
Это артефакт развлекательной математики. См. правило конца света для объяснения.
Используйте эту таблицу для определения дня недели без каких-либо вычислений.
Примеры:
Декабрь находится в строке F , а 26 — в столбце E , поэтому буква даты — C, расположенная в строке F и столбце E. 93 (год mod 100) находится в строке D (строка года), а буква C в строке года находится в столбце G. 18 ([год/100] в столбце григорианского столетия) находится в строке C (строка столетия), а буква в строке столетия и столбце G — B, поэтому день недели — вторник.
13 октября — день F. Буква F в строке года (07) находится в столбце G. Буква в строке века (13) и столбце G — E, поэтому день недели — пятница.
1 января соответствует G, G в строке года ( 0 0) соответствует F в строке столетия ( 20 ), а F соответствует субботе.
Краткая формула метода: «Буква даты (G), буква (G) находится в строке года ( 0 0), буква (F) — в строке столетия ( 20 ), а для дня буква (F) становится днем недели (суббота)» .
Метод воскресного письма
Каждому дню года (кроме 29 февраля) присвоена буква в повторяющейся последовательности ABCDEFG. Серия начинается с буквы A 1 января и продолжается до буквы A снова 31 декабря. Буква воскресенья — это та, которая стоит против всех воскресений в году. Поскольку у 29 февраля нет буквы, это означает, что буква воскресенья для марта по декабрь на один шаг назад в последовательности по сравнению с январем и февралем. Буква для любой даты будет найдена там, где строка, содержащая месяц (черного цвета) слева от «латинского квадрата», встречается со столбцом, содержащим дату над «латинским квадратом». Буква воскресенья будет найдена там, где столбец, содержащий столетие (под «латинским квадратом»), встречается со строкой, содержащей последние две цифры года справа от «латинского квадрата». Для високосного года найденная таким образом буква воскресенья — это та, которая применяется с марта по декабрь.
Так, например, чтобы найти день недели 16 июня 2020 года:
Столбец "20" встречается со строкой "20" в "D". Строка "Июнь" встречается со столбцом "16" в "F". Поскольку F находится на две буквы дальше от D, то будний день будет через два дня от воскресенья, т. е. во вторник.
Метод Rata Die работает путем сложения количества дней d , прошедших с даты известного дня недели D. Затем день недели определяется как ( D + d ) mod 7 , в соответствии с любым соглашением , использованным для кодирования D.
Например, дата 13 августа 2009 года составляет 733632 дня от 1 января 1 г. н. э. Взяв число по модулю 7, получаем 4, следовательно, четверг.
Карл Фридрих Гаусс описал метод расчета дня недели для 1 января любого года в рукописной заметке в сборнике астрономических таблиц. [5] Он никогда не публиковал его. Он был окончательно включен в его собрание сочинений в 1927 году. [6] По сравнению с Rata Die, результат помогает упростить подсчет лет.
Метод Гаусса был применим к григорианскому календарю. Он пронумеровал дни недели от 0 до 6, начиная с воскресенья. Он определил следующую операцию.
Вышеописанную процедуру можно свести к одному выражению для григорианского календаря:
(D + m + 5(( A −1)%4) + 4(( A −1)%100) + 6(( A −1)%400))%7
Для года номер 2000, A − 1 = 1999 , Y − 1 = 99 и C = 19 , день недели 1 января равен
Будние дни 30 апреля 1777 года и 23 февраля 1855 года:
и
Алгоритм для дня недели 1 января можно доказать с помощью модульной арифметики. Главное в том, что поскольку 365 % 7 = 1 , каждый год добавляет 1 день к прогрессии. Остальное — корректировка на високосный год. Версии на основе столетий имеют 36525 % 7 = 6 .
Таблица смещений месяцев показывает расхождение в феврале из-за високосного года. Распространенный метод (позже использованный Целлером) заключается в сдвиге месяца на начало марта, так что високосный день оказывается в конце подсчета. Кроме того, как позже показал Целлер, таблицу можно заменить арифметическим выражением.
Эта формула была также преобразована в графические и табличные методы для расчета любого дня недели Крайчиком и Швердтфегером. [6] [7]
Следующая формула является примером версии без таблицы поиска. Предполагается, что год начинается в марте, то есть даты в январе и феврале следует рассматривать как часть предыдущего года. Формула для григорианского календаря: [8]
где
В алгоритме Целлера месяцы нумеруются от 3 для марта до 14 для февраля. Предполагается, что год начинается в марте; это означает, например, что январь 1995 года следует рассматривать как 13-й месяц 1994 года. [9]
Формула для григорианского календаря такова
:
Единственное различие между алгоритмом Целлера ( Z ) и алгоритмом Гаусса ( G ) заключается в следующем: Z − G = 1 = воскресенье .
Алгоритм Вана [10] для человеческого расчета григорианского календаря выглядит следующим образом (из формулы следует вычесть 1, если m равно 1, или 2, если год високосный)
, где
Алгоритм для юлианского календаря можно вывести из приведенного выше алгоритма, где — конец света.
В частично табличном методе Швердтфегера год делится на столетие и двузначный год внутри столетия. Подход зависит от месяца. Для m ≥ 3 ,
поэтому g находится в диапазоне от 0 до 99. Для m = 1,2 ,
Формула для дня недели: [6]
где выбран положительный модуль. [6]
Значение e получается из следующей таблицы:
Значение f получается из следующей таблицы, которая зависит от календаря. Для григорианского календаря, [6]
Для юлианского календаря, [6]
Чарльз Лютвидж Доджсон ( Льюис Кэрролл ) разработал метод, напоминающий головоломку, но частично табличный, поскольку использует те же индексные числа для месяцев, что и в «Полной таблице: юлианский и григорианский календари» выше. Он перечисляет те же три корректировки для первых трех месяцев невисокосных лет, одну на 7 больше для последнего, и дает загадочные инструкции для нахождения остальных; его корректировки для столетий должны определяться с помощью формул, похожих на формулы для таблицы столетий. Хотя он явно утверждает, что его метод также работает для дат старого стиля , его пример, воспроизведенный ниже, для определения того, что «1676, 23 февраля» — это среда, работает только в юлианском календаре, который начинает год 1 января, а не 25 марта, как в юлианском календаре «старого стиля» .
Алгоритм: [11]
Разделим данную дату на 4 части: число столетий, число прошедших лет, месяц, день месяца.
Вычислите следующие 4 элемента, добавляя каждый, когда он найден, к сумме предыдущих элементов. Когда элемент или сумма превышает 7, разделите на 7 и сохраните только остаток.
Элемент века: Для « старого стиля » (который закончился 2 сентября 1752 года) вычтите из 18. Для « нового стиля » (который начался 14 сентября 1752 года) разделите на 4, вычтите излишек из 3, остаток умножьте на 2.
Год-элемент: Сложите количество дюжин, остаток и количество четверок в остатке.
Месяц-элемент: Если он начинается или заканчивается на гласную, вычтите число, обозначающее его место в году, из 10. Это, плюс количество дней, дает элемент для следующего месяца. Элемент для января - "0"; для февраля или марта - "3"; для декабря - "12".
День: Полученную таким образом сумму необходимо скорректировать, вычтя «1» (сначала прибавив 7, если сумма равна «0»), если дата приходится на январь или февраль високосного года, помня, что каждый год, делящийся на 4, является високосным, за исключением только вековых годов по «новому стилю», когда число столетий не делится таким образом (например, 1800).
Окончательный результат даёт день недели: «0» означает воскресенье, «1» — понедельник и т. д.
Примеры: [11]
17, деленное на 4, оставляет "1" сверху; 1 из 3 дает "2"; дважды 2 дает "4". 83 это 6 дюжин и 11, что дает 17; плюс 2 дает 19, т.е. (деление на 7) "5". Итого 9, т.е. "2" Элемент для августа - "8 из 10", т.е. "2"; поэтому для сентября это "2 плюс 31", т.е. "5" Итого 7, т.е. "0", который выбывает. 18 дает "4". Ответ: "четверг".
16 из 18 дает "2" 76 - это 6 дюжин и 4, что дает 10; плюс 1 дает 11, т.е. "4". Итого "6" Элемент для февраля - "3". Итого 9, т.е. "2" 23 дает "2". Итого "4" Поправка на високосный год дает "3". Ответ: "Среда".
Даты до 1752 года в Англии будут указываться по старому стилю , а 25 марта — как первый день нового года . Однако метод Кэрролла предполагает 1 января как первый день года, поэтому ему не удается получить правильный ответ, а именно «Пятница».
Если бы он заметил, что 1676, 23 февраля (с 25 марта как Новый год) на самом деле 1677, 23 февраля (с 1 января как Новый год), он бы учел разницу в числах года — точно так же, как различается день рождения Джорджа Вашингтона — в двух календарях. Тогда его метод дает:
16 из 18 дает "2" 77 - это 6 дюжин и 5, что дает 11; плюс 1 дает 12, т. е. "5". Всего "7" Элемент для февраля - "3". Всего 10, т. е. "3" 23 дает "2". Всего "5". Ответ: "Пятница".
Примечательно, что те, кто переиздал метод Кэрролла, не указали на его ошибку, в частности Мартин Гарднер . [12]
В 1752 году Британская империя отказалась от использования юлианского календаря старого стиля , приняв григорианский календарь , который стал сегодня стандартом в большинстве стран мира. Для получения дополнительной информации см. Даты старого и нового стиля .
В выражениях на языке C ниже , y
и m
являются d
, соответственно, целочисленными переменными, представляющими год (например, 1988), месяц (1–12) и день месяца (1–31).
( d += m < 3 ? y -- : y -2 , 23 * m / 9 + d + 4 + y / 4 - y / 100 + y / 400 ) % 7
В 1990 году Майкл Кейт и Том Крейвер опубликовали приведенное выше выражение, которое стремится минимизировать количество нажатий клавиш, необходимых для ввода автономной функции для преобразования григорианской даты в числовой день недели. [13] Оно возвращает 0
= воскресенье, 1
= понедельник и т. д. Это выражение использует менее громоздкий компонент месяца, чем алгоритм Целлера.
Вскоре после этого Ганс Лахман оптимизировал свой алгоритм для простоты использования на бюджетных устройствах. Первоначально разработанный для калькуляторов с четырьмя функциями, его метод требует меньшего количества вводов с клавиатуры, ограничивая его диапазон либо 1905–2099 гг. н. э., либо историческими юлианскими датами. Позднее он был модифицирован для преобразования любой григорианской даты, даже на счетах . На устройствах на базе Motorola 68000 также меньше необходимости в регистрах процессора или кодах операций , в зависимости от предполагаемой цели проектирования. [14]
Табличный предшественник алгоритма Тёндеринга воплощен в следующей функции K&R C. [15] С небольшими изменениями она была адаптирована для других языков программирования высокого уровня, таких как APL2 . [16] Опубликованная Томохико Сакамото в группе новостей Usenet comp.lang.c в 1992 году, она точна для любой даты по григорианскому календарю. [17] [18]
dayofweek ( y , m , d ) /* 1 <= m <= 12, y > 1752 (в Великобритании) */ { static int t [] = { 0 , 3 , 2 , 5 , 0 , 3 , 5 , 1 , 4 , 6 , 2 , 4 }; if ( m < 3 ) { y -= 1 ; } return ( y + y / 4 - y / 100 + y / 400 + t [ m -1 ] + d ) % 7 ; }
Возвращает 0
= воскресенье, 1
= понедельник и т.д.
Сакамото одновременно опубликовал более запутанную версию:
dow ( m , d , y ) { y -= m < 3 ; return ( y + y / 4 - y / 100 + y / 400 + "-bed=pen+mad." [ m ] + d ) % 7 ; }
Эта версия кодирует смещения месяцев в строке и, как следствие, требует компьютера, использующего стандартный ASCII, для корректного выполнения алгоритма, что снижает его переносимость . Кроме того, оба алгоритма опускают int
объявления типов , что разрешено в исходном K&R C , но не разрешено в ANSI C.
(Алгоритм Тёндеринга, опять же, по структуре похож на сравнение Целлера и короткий код Кейта, за исключением того, что компонент, связанный с месяцем, равен 31*m/12
. Алгоритм Сакамото находится где-то между несоизмеримым гауссианом и алгоритмом Швердтфегера, по-видимому, не зная формы выражения.)
% пример ввода даты y1 = 2022 ; m1 = 1 ; d1 = 1 ; month_offset = [ 0 3 3 6 1 4 6 2 5 0 3 5 ]; % общий год % смещение, если y1 високосный год if mod ( y1 , 4 ) == 0 && mod ( y1 , 100 ) == 0 && mod ( y1 , 400 ) == 0 month_offset =[ 0 3 4 0 2 5 0 3 6 1 4 6 ]; % конец високосного года % Грегор_будний_день_Грегор = rem ( d1 + month_offset ( m1 ) + 5 * rem ( y1 - 1 , 4 ) + 4 * rem ( y1 - 1 , 100 ) + 6 * rem ( y1 - 1 , 400 ), 7 ) % Юлианский будний_день_юлианский = rem ( 6 + 5 * rem ( y1 - 1 , 4 ) + 3 * ( y1 - 1 ), 7 )
0: Воскресенье 1: Понедельник .. 6: Суббота
из numpy импортировать остаток как remdef is_leap_year ( year : int ) -> bool : """ Определяет, является ли год високосным. """ возвращает year % 4 == 0 и ( year % 100 != 0 или year % 400 == 0 ) def day_of_week ( y : int , m : int , d : int ) -> str : ''' возвращает день недели указанной даты в виде строки, используя алгоритм Гаусса для его поиска ''' if is_leap_year ( y ): month_offset = ( 0 , 3 , 4 , 0 , 2 , 5 , 0 , 3 , 6 , 1 , 4 , 6 )[ m - 1 ] else : month_offset = ( 0 , 3 , 3 , 6 , 1 , 4 , 6 , 2 , 5 , 0 , 3 , 5 )[ m - 1 ] y -= 1 wd = int ( rem ( d + month_offset + 5 * rem ( y , 4 ) + 4 * бэр ( у , 100 ) \ + 6 * бэр ( у , 400 ) , 7 )) возврат ( 'Вс' , 'Пн' , 'Вт' , 'Ср' , 'Чт' , 'Пт' , 'Сб' )[ wd ]
NWDOSTIP.TXT
Это всеобъемлющая работа по Novell DOS 7 и OpenDOS 7.01 , включающая описание многих недокументированных функций и внутренних компонентов. Она является частью еще более обширной MPDOSTIP.ZIP
коллекции автора, которая поддерживалась до 2001 года и распространялась на многих сайтах в то время. Приведенная ссылка указывает на более старую версию файла, преобразованную в HTML NWDOSTIP.TXT
.)