Как узнать день недели для любой даты н.э.
Подвернулась интересная задача.
Написать программу, которая по заданной любой дате выводит день недели. Первый
вариант алгоритма:
1.
Посчитать сколько дней прошло до заданной даты с
момента начала отсчета.
2.
Взять остаток от деления на 7 (количество дней в
неделе).
3.
Полученный результат и соответствует дню недели.
0 – воскресение, 1 – понедельник, 2 – вторник и т.д.
По сути, всего-то 2 шага. Третий
уже обработка результатов. Предлагаю реализовать.
Итак, первый шаг – посчитать
сколько прошло дней до заданной даты. Что для этого нужно? Что бы было проще
возьмем какой-нибудь пример. Пусть это будет 31.12.2011. Сразу можем сказать,
что до 2011 года прошло 2010 полных лет. Знаем так же, что в году 365 дней.
Значит умножим 2010 на 365. Но сразу же возникает проблема, Каждый високосный
год содержит не 365, а 366 дней. Что же делать? Конечно, проще всего 2010
разделить на 4 (мы же знаем, что каждый четвертый год високосный), взять целое
от деления, и это число прибавить к результату умножения 2010*365. Получим 2 010 / 4 = 502, 5; 2 010 * 365 =
733 650; 733 650+502 = 734 152;
Значит до начала 2011 года прошло
734 152 дня. Теперь нужно прибавить к этому числу сколько дней пошло в
2011 году до 31 декабря. Мы, конечно же, сразу понимаем, что рас это последний
день в году и год не високосный, то он 365й. Но нам же нужен алгоритм в общем
виде, поэтому забудем о том что мы это знаем и будем считать.
Количество дней в месяцах не постоянно , значит, просто
30*12 не поучится. Единственный выход – завести массив, где индексу массива
соответствует номер месяца, а соответствующий элемент равен количеству дней в
этом месяце. Значения массива приведены в таблице. Нас интересует из нее только
второй и третий столбец. Нумерация начинается с 0, что соответствует языкам
программирования С и др.
Месяц
|
№
|
дней
|
Январь
|
0
|
31
|
Февраль
|
1
|
28
|
Март
|
2
|
31
|
Апрель
|
3
|
30
|
Май
|
4
|
31
|
Июнь
|
5
|
30
|
Июль
|
6
|
31
|
Август
|
7
|
31
|
Сентябрь
|
8
|
30
|
Октябрь
|
9
|
31
|
Ноябрь
|
10
|
30
|
Декабрь
|
11
|
31
|
Тогда алгоритм выглядит следующим
образом. Складываем количество дней в месяце до заданного месяца, не включая
его. Значит в нашем случае: 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 +
30 = 334.
Осталось только прибавить к этой
сумме номер введенного дня и это все
прибавить к количеству дней до нового года. В нашем случае: 734 152 + 334 + 31 = 734 517. Это
число должно соответствовать количеству дней с начал отсчета до 31 декабря 2011
года. Не думаю, что мы сможем это как то проверить. Если только найти все
календари за 2011 лет и посчитать. Думаю, у нас не получится.
Возьмемся за следующий шаг.
Разделим это число на 7 и возьмем остаток.
В нашем случае остаток 0. Значит, новый год в 2011 году выпадает на
воскресение. Вот и всё! Задача решена. Но давайте проверим. Не составит труда
открыть календарь 2011 и посмотреть.

Итак, у нас есть новое правило
определения високосного года. Високосный
год если его номер кратен 400 или если номер кратен 4 и не кратен 100. И это
действует только… будем считать, с 1918 года.
Приведу сразу код. Эта проверка
не самая быстрая, но точно работает.
Здесь реализован совсем другой подход. Теперь
мы не прибавляем количество високосных лет до заданной даты, а считаем сумму в
дней в цикле. Если год високосный, то
прибавляем 366, иначе – 365. Теперь sum равно количество дней до года year.
Прибавляем количество дней прошедших с начала
года и номер введенного дня. Для этого сначала проверим является ли введенный
год високосным, а так введенный месяц
больше 2. Ведь даже если год високосный, но месяц январь, то прибавлять 1 не
надо, а если месяц больше января, то надо. В приведенном листинге i означает введенный месяц.
Ну а теперь вспомним про сдвиги.
Теперь мы посчитали количество
дней с учетом всех правил, которые я нашли при беглом просмотре Интернета.
Вот и всё! Делим sum на 7 и проверяем остаток.
Вот листинг:
Осталось проверить. Введем наш
пример 31 декабря 2011 года.
Все верно. С другими данными тоже
работает правильно. Уверен, что если покопаться, то можно будет найти еще какие-нибудь
особенности, уточняющие календарь, но лично мне это уже не интересно.
Спасибо за внимание. J
int Date( int D, int M, int Y )
ОтветитьУдалить{
int a, y, m, R;
a = ( 14 - M ) / 12;
y = Y - a;
m = M + 12 * a - 2;
R = 7000 + ( D + y + y / 4 - y / 100 + y / 400 + (31 * m) / 12 );
return R % 7;
}