Даты

В этом листке вам нужно будет решать задачи, связанные с датами и временем, поэтому прежде всего нужно понять, как хранить даты и время в программе. Конечно, лучше всего для типа данных “Дата” создать класс.

class Date:

У объектов этого класса будет три поля: day, month, year.

Подумайте, какие операции можно выполнять с датами. Например, можно преобразовывать даты в строки для удобного вывода или, наоборот, преобразовывать строки в даты. К датам можно прибавлять (вычитать) целые числа (например, прибавить число 1 — это получить следующую дату). Наконец, можно брать разность двух дат (это количество дней между ними).

Для преобразования номера месяца в строку лучше всего использовать список строк-названий:

MonthNames = ('', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')
Для вывода названия дней недели также лучше использовать список:
DayOfTheWeek = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday')

Данные списки лучше всего сделать глобальными и объявить в самом начале программы.

А вот для преобразования строки-названия месяца в число лучше использовать словарь:

MonthNums = {'January': 1, 'February': 2, 'March': 3, ...}

Инкапсуляция

Если имя поля начинается с двух символов подчеркивания, например, __day, __month, __year, то эти поля являются “скрытыми”, то есть доступ к ним можно получить только из методов класса. Для работы с этими полями нужно использовать методы класса: конструкторы, метод __str__, перегруженные операции и т.д. При необходимости явно получить или изменить значение поля пишутся специальные методы типа get_day или set_day.

Слоты классов

Если специальному атрибуту класса с именем __slots__ присвоить значение, в виде списка из нескольких текстовых строк, то только перечисленные в данном списке имена могут использоваться в качестве имен полей (атрибутов) классов. Например:

class Date:
    __slots__ = ['__day', '__month', '__year']

Это также приведет к уменьшению времени обращения к атрибутам класса за счет другого способа хранения атрибутов в экземпляре класса.

Упражнения

A: День года

По заданному числу n от 1 до 365 определите, на какое число какого месяца приходится день невисокосного года с номером n. Программа получает на вход целое число n и должна вывести число месяца (от 1 до 31) и название месяца, на которое приходится данный день.

Для определения номера дня в году лучше всего использовать константный массив количества дней в каждом месяце:

Months = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)

Пример

Ввод Вывод
1
January 1
365
December 31

B: Обратная задача

Решите обратную предыдущей задачу: по записи названия месяца и дня определите номер дня в году.
Алгоритм решения задачи оформите в виде отдельной функции.

Пример

Ввод Вывод
January 1
1
December 31
365

C: Перевод формата даты - 1

Дата задана в формате dd.mm.yyyy. Выведите ее в формате "Month d, y", где Month - английское название месяца, d - номер дня в месяце, без лидирующих нулей, y - номер года без лидирующих нулей.

Считывание и преобразование даты оформляйте в виде отдельных методов класса.

Пример

Ввод Вывод
12.10.2008
October 12, 2008
01.01.0001
January 1, 1

D: Перевод формата даты - 2

Решите обратную задачу.

Считывание и преобразование даты оформляйте в виде отдельных методов класса.

Пример

Ввод Вывод
October 12, 2008
12.10.2008
January 1, 1
01.01.0001

E: Tomorrow

Дата задана в формате dd.mm.yyyy. Выведите дату, следующую за ней в том же формате. Учтите правило формирования високосных годов. Следует считать, что григорианский календарь действовал всегда.

Алгоритм решения задачи оформите в виде метода NextDate() класса

Пример

Ввод Вывод
12.10.2008
13.10.2008
31.12.2008
01.01.2009

F: Yesterday

Дата задана в формате dd.mm.yyyy. Выведите дату, предшестующую ей в том же формате. Учтите правило формирования високосных годов. Следует считать, что григорианский календарь действовал всегда.
Алгоритм решения задачи оформите в виде отдельного метода PrevDate() класса.

Пример

Ввод Вывод
13.10.2008
12.10.2008
01.01.2009
31.12.2008

G: Разница дат

Две даты заданы в формате dd.mm.yyyy, каждая дата - в новой строке. Определите количество дней между этими датами. Вторая дата больше первой.
Алгоритм решения задачи оформите в виде метода __sub__

Пример

Ввод Вывод
01.01.0001
02.01.0001
1
29.02.2004
01.03.2005
366

H: День недели

Дата задана в формате dd.mm.yyyy. Выведите название дня недели, на который приходится эта дата.
Алгоритм решения задачи оформите в виде отдельного метода.
Ввод Вывод
12.10.2008
Sunday
13.10.2008
Monday

I: День рождения

Задан день и месяц рождения в формате dd.mm. Задана текущая дата в формате dd.mm.yyyy. Определите, сколько дней осталось до дня рождения. Если сегодня - день рождения, то необходимо вывести 0.

Ввод Вывод
19.04
19.04.2002
0
05.05
19.04.2002
16
29.02
28.02.2001
1096

J: Номер дня по дате

Пронумеруем все даты подряд, считая, что 01.01.0001 имеет номер 1, 02.01.0001 - номер 2 и т.д. По заданной дате определите ее порядковый номер.

Программа получает на вход число дат \(N\le 200000\), затем заданы \(N\) дат. Для каждой из них выведите ее порядковый номер.

Данную функцию лучше всего оформить в виде метода __int__, вызываемым при преобразовании объекта к типу int.

Ввод Вывод
2
01.01.0001
01.01.0002
1
366

K: Дата по номеру дня

Решите обратную задачу: определите дату по номеру дня.

Данную функцию лучше всего оформить в форме конструктора, принимающего один параметр типа int.

Ввод Вывод
2
1
366
01.01.0001
01.01.0002

L: Разница дат - 2

Научитесь быстро вычислять разницу между двумя датами.

Программа получает на вход число N, не превосходящее 105. Далее идет 2N дат, при этом не гарантируется, что первая дата меньше второй.

Выведите N чисел: для каждой пары дат входного файла выведите их разность (которая может быть как положительной, так и отрицательной).

Ввод Вывод
2
01.01.0001
02.01.0001
01.03.2005
29.02.2004
1
-366

Время

Для хранения времени удобно создать класс Time с полями hours, minutes, seconds.

Времена будут, как правило, задаваться в формате hh:mm:ss, где hh принимает значения от 00 до 23, mm и ss - значения от 00 до 59 или в формате hh:mm.

Упражнения

M: Количество секунд

Часы показывают время в формате hh:mm:ss. Определите количество секунд, которое прошло с начала суток.
Программа не должна содержать циклов для решения этой задачи.

Пример

Ввод Вывод
00:01:01
61

N: Таймер

Часы показывают время в формате hh:mm:ss. На этих часах запустили таймер, который прозвенит через n секунд. Определите время, которое будет на часах, когда прозвенит таймер. n может принимать значения от 0 до 109. Решение задачи не дожно содержать циклов. Постарайтесь также не использовать условную инструкцию.

Пример

Ввод Вывод
09:00:00
90
09:01:30
23:59:59
1
00:00:00

O: Разница времен

Профессор лег спать, когда на часах было время h1:m1:s1, а когда он проснулся было время h2:m2:s2. Определите, сколько времени спал профессор, если известно, что он проспал не более суток. Время выведите в формате hh:mm:ss.
Решение задачи не должно содержать циклы. Постарайтесь также не использовать условную инструкцию.

Пример

Ввод Вывод
14:00:00
21:10:30
07:10:30
22:00:00
07:00:00
09:00:00

P: Будильники

Будильник в сотовом телефоне можно настроить так, чтобы он звонил каждый день в одно и то же время, либо в указанное время в определенный день недели. Независимо можно настроить несколько будильников.

По информации о будильниках и текущему времени и дню недели определите, когда прозвонит очередной будильник.

В первой строке вводится текущий день недели (число от 1 до 7), затем через пробел, текущее время в формате HH:MM.

Во второй строке вводится одно натуральное число N, не превосходящее 100 – количество будильников.

В следующих N строках вводится описание N будильников в таком же формате. Значение дня недели, равное 0, означает, что будильник звонит каждый день.

Выведите номер дня недели и время, когда будильник зазвонит в следующий раз, в таком же формате.

Ввод Вывод
2 10:20
2
1 23:15
0 10:10
3 10:10
7 01:01
3
7 00:59
7 23:59
7 01:01
7 01:01

Q: Таймер-2

Таймер - это часы, которые умеют подавать звуковой сигнал по прошествии некоторого периода времени. Напишите программу, которая определяет, когда должен быть подан звуковой сигнал.

Первая строка входных данных содержит текущее время в формате HH:MM:SS (с ведущими нулями). При этом оно удовлетворяет ограничениям: HH — от 00 до 23, MM и SS - от 00 до 59.

Вторая строка входных данных содержит интервал времени, который должен быть измерен. Интервал записывается в формате H:M:S (где H, M и S — от 0 до 109, без ведущих нулей). При этом если H=0 (или H=0 и M=0), то они могут быть опущены. Например, 100:60 может быть записано и как 101:0, 1:41:0, 0:100:60, 0:101:0 и т.д. Запись 42 — это то же самое, что 0:0:42, а 100:100:100 то же самое, что 101:41:40.

Выведите в формате HH:MM:SS время, во сколько прозвучит звуковой сигнал. При этом если сигнал прозвучит не в текущие сутки, то дальше должна следовать запись +<кол во> days. Например, если сигнал прозвучит на следующий день – то +1 days.

Ввод Вывод
01:01:01
48:0:0
01:01:01+2 days
01:01:01
58:119
02:01:00
23:59:59
1
00:00:00+1 days

R: Кассы

На одном из московских вокзалов билеты продают N касс. Каждая касса работает без перерыва определенный промежуток времени по фиксированному расписанию (одному и тому же каждый день). Требуется определить, на протяжении какого времени в течение суток работают все кассы одновременно.

Программа получает на вход целое число N (0<N≤1000).

В каждой из следующих N строк записано время начало и время окончания работы кассы в формате HH:MM через пробел.

Время открытия означает, что в соответствующую ему минуту касса уже работает, а время закрытия что в соответствующую минуту касса уже не работает. Например, касса, открытая с 10:30 18:30 ежесуточно работает 480 минут.

Если время открытия совпадает с временем закрытия, то касса работает круглосуточно. Если первое время больше второго, то касса начинает работу до полуночи, а заканчивает на следующий день.

Требуется вывести одно число суммарное время за сутки (в минутах), на протяжении которого работают все N касс.

Ввод Вывод
3
01:00 23:00
12:00 12:00
22:00 02:00
120
2
09:30 14:00
14:15 21:00
0
2
14:00 18:00
10:00 14:01
1

S: Самый старший

Имеется список людей с указанием их фамилии, имени и даты рождения. Напишите эффективную по времени работы и по используемой памяти программу, которая будет определять самого старшего человека из этого списка и выводить его фамилию, имя и дату рождения, а если имеется несколько самых старших людей с одинаковой датой рождения, то определять их количество.

На вход программе в первой строке подается количество людей в списке N. В каждой из последующих N строк находится информация в следующем формате:

<Фамилия> <Имя> <Дата рождения>

где <Фамилия> – строка, состоящая не более, чем из 20 символов без пробелов, <Имя> – строка, состоящая не более, чем из 20 символов без пробелов, <Дата рождения> – строка, имеющая вид DD.MM.YYYY.

Программа должна вывести дату рождения самого старшего человека в списке, затем через пробел его фамилию и имя. Если таких людей, несколько, то вместо фамилии и имени выводится их количество.

Ввод Вывод
3
Ivan Petrov 01.05.1995
Petr Sergeev 29.04.1995
Sergey Ivanov 01.01.1996
29.04.1995 Petr Sergeev
3
Ivan Petrov 01.05.1995
Petr Sergeev 29.05.1995
Sergey Ivanov 01.05.1995
01.05.1995 2

T: Дни рождения

Имеется список сотрудников организации с указанием их фамилии, имени и даты рождения. Администрация ежедневно поздравляет всех сотрудников, родившихся в этот день. Напишите эффективную по времени работы и по используемой памяти программу, которая будет определять, в какой из дней года родилось больше всего сотрудников и выводить этот день (или несколько дней).

Формат входных данных аналогичен предыдущей задаче. Программа должна вывести список дат, в которые наибольшее число сотрудников отмечает дни рождения в формате DD.MM по возрастанию дат, каждая дата в отдельной строке.

Ввод Вывод
5
Ivan Petrov 01.05.1995
Petr Sergeev 29.04.1995
Sergey Romanov 01.01.1996
Roman Grigoriev 01.01.1995
Grigoriy Ivanov 01.05.1995
01.01
01.05

U: Ближайшие дни рождения

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

На вход программе в первой сроке подается текущая дата, заданная в формате DD.MM.YYYY.

Во второй строке подается количество людей в списке N. В каждой из последующих N строк находится информация о каждом сотруднике, как в задаче T.

Известно, что у всех сотрудников даты рождения различаются. Программа должна вывести фамилию и имя самого молодого сотрудника, празднующего день рождения в ближайшие 7 дней или сообщение No birthdays in next week, если никто из сотрудников не празднует день рождения в ближайшие 7 дней.

Ввод Вывод
25.11.2010
3
Ivan Petrov 01.12.1994
Petr Sergeev 25.11.1994
Sergey Romanov 02.12.1994
Ivan Petrov
25.11.2010
1
Sergey Romanov 02.12.1994
No birthdays in next week

V: Пятница, 13-е

Докажите, что 13-е число месяца чаще всего приходится на пятницу.
Напишите программу, которая выводит на экран 7 чисел: вероятности выпадения 13 числа каждого месяца на понедельник, вторник, среду, четверг, пятницу, субботу, воскресенье. Например, если бы данные вероятности были бы равны, то программа должна вывести следущий текст:
0.142857
0.142857
0.142857
0.142857
0.142857
0.142857
0.142857

W: Кассы - 2

Решите задачу про кассы в следующих ограничениях: число касс до 10000, время задано с точностью до секунд в формате HH:MM:SS. Требуется определить, на протяжении какого времени (в секундах) в течение суток работают все кассы одновременно.

Ввод Вывод
3
01:00:00 23:00:00
12:00:00 12:00:00
22:00:00 02:00:00
7200
2
09:30:00 14:00:00
14:15:00 21:00:00
0
2
14:00:00 18:00:00
10:00:00 14:00:01
1

X: Игра с датами

Играет два человека. Задается какая-то дата високосного года. Каждый игрок на своем ходу называет более позднюю дату, увеличивая на 1 или на 2 либо день в месяце, либо месяц, но не то и другое сразу. При этом результат должен оставаться корректной датой. Игрок, назвавший 31 декабря, проигрывает. Кто выигрывает при правильной игре: первый или второй.

Программа получает на вход дату в формате DD.MM и должна вывести одно число: номер выигрывающего игрока.

Ввод Вывод
30.12
2
29.12
1
29.11
2

Z: Выходные дни

Для каждого данного года посчитайте количество выходных дней в этом году (то есть количество суббот и воскресений).

Программа получает на вход число \(N\) (\(1\le N\le 10^6\)). В каждой из следующих \(N\) строк записано по одному числу от 2000 до \(10^9\) — номера годов.

Для каждого номера года выведите количество выходных дней в соответствующем годе.

Для ускорения ввода-вывода используйте для чтения объект sys.stdin, результат выводите в sys.stdout.

Ввод Вывод
2
2013
2014
104
104

ZZ: Календарь на год

Напишите программу, которая выводит на экран календарь на год примерно в таком виде, как это делает программа cal.

Календарь состоит из блоков, каждый из которых соответствует одному месяцу. Блоки расположены в виде таблицы из k столбцов и 12/k строк (k выбирается делителем числа 12). Месяцы выводятся в следующем порядке: первая строка содержит блоки, соответствующие месяцам с первого по k-ый, следующая – с (k + 1)-го по 2k-ый, и т. д.

Ширина всех блоков в столбце должна быть одинакова, высота всех блоков равна семи (числу дней в неделе). Между блоками различных строк таблицы выводится пустая строка, в каждой строке между соседними блоками из разных столбцов выводится три пробела.

Блок, соответствующий месяцу, устроен следующим образом. Каждой (в том числе неполной) неделе данного месяца в блоке соответствует столбец, имеющий ширину, равную двум. Между двумя соседними столбцами в каждой строке выводится один пробел. Если несколько блоков располагаются в одном столбце календаря, то для выравнивания ширины в те блоки, которые содержат меньше недель, в конец добавляется необходимое число пустых столбцов-недель. При этом разные столбцы календаря могут иметь разную ширину.

Все числа месяца заносятся в блок, соответствующий этому месяцу. Число заносится в строку блока, соответствующую дню недели, на который приходится число в этом месяце. Число заносится в столбец блока, соответствующий неделе, к которой относится данное число. Однозначные числа дополняются слева одним пробелом. Таким образом, числа в столбце оказываются выравнены по правому краю.

 

Программа получает на вход описание года, календарь для которого следует вывести. Оно содержит три числа: \(d\) – день недели, на который приходится первое января (\(1\le d \le 7\)), \(l\); – является ли год високосным (\(l=1\) означает, что год является високосными, \(l=0\) – что не является) и \(k\) – количество столбцов в календаре (\(k\) – одно из чисел 1, 2, 3, 4, 6, 12).

Выведите календарь, отформатированный в соответствии с условием задачи. Проверяющая программа в этой задаче игнорирует пробелы в конце строк. В остальном календарь должен быть отформатирован в точности так, как описано в условии.

Ввод Вывод
4 1 4
    5 12 19 26          2  9 16 23    1  8 15 22 29       5 12 19 26   
    6 13 20 27          3 10 17 24    2  9 16 23 30       6 13 20 27   
    7 14 21 28          4 11 18 25    3 10 17 24 31       7 14 21 28   
 1  8 15 22 29          5 12 19 26    4 11 18 25       1  8 15 22 29   
 2  9 16 23 30          6 13 20 27    5 12 19 26       2  9 16 23 30   
 3 10 17 24 31          7 14 21 28    6 13 20 27       3 10 17 24      
 4 11 18 25          1  8 15 22 29    7 14 21 28       4 11 18 25      
                                                                       
    3 10 17 24 31       7 14 21 28       5 12 19 26       2  9 16 23 30
    4 11 18 25       1  8 15 22 29       6 13 20 27       3 10 17 24 31
    5 12 19 26       2  9 16 23 30       7 14 21 28       4 11 18 25   
    6 13 20 27       3 10 17 24       1  8 15 22 29       5 12 19 26   
    7 14 21 28       4 11 18 25       2  9 16 23 30       6 13 20 27   
 1  8 15 22 29       5 12 19 26       3 10 17 24 31       7 14 21 28   
 2  9 16 23 30       6 13 20 27       4 11 18 25       1  8 15 22 29   
                                                                       
    6 13 20 27          4 11 18 25    1  8 15 22 29       6 13 20 27   
    7 14 21 28          5 12 19 26    2  9 16 23 30       7 14 21 28   
 1  8 15 22 29          6 13 20 27    3 10 17 24       1  8 15 22 29   
 2  9 16 23 30          7 14 21 28    4 11 18 25       2  9 16 23 30   
 3 10 17 24          1  8 15 22 29    5 12 19 26       3 10 17 24 31   
 4 11 18 25          2  9 16 23 30    6 13 20 27       4 11 18 25      
 5 12 19 26          3 10 17 24 31    7 14 21 28       5 12 19 26