Для работы с датами полезно определить структуру из следующих полей:
struct date { int day, month, year; };
Операции, которые полезно переопределить для дат:
==
, !=
, <
,
<=
, >
, >=
,
++
, --
. Также будут полезны операции сложения
даты и числа и разности двух дат.
Удобно также переводить даты в числа типа int
, пронумеровавав все даты подряд.
Для перевода даты в число желательно определить оператор int
,
для перевода числа в дату желательно определить конструктор от одного
значения типа int
.
Для вывода названия месяца по его номеру лучше всего использовать
константный массив строк-названий:
const char * MONTH_NAMES[] = {"", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};Для вывода названия дня недели лучше всего использовать константный массив строк-названий:
const char * DAY_OF_WEEK[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
Основным способом ввода-вывода дат должны быть переопределенные операторы
<<
и >>
, даты вводятся и выводятся
в формате dd.mm.yyyy
. Кроме этого будет ещё и текстовое
представление даты вида January 1, 2017
, для считывания
которого необходимо реализовать метод from_text
,
а для вывода которого — метод to_text
.
По заданному числу n от 1 до 365 определите, на какое число какого месяца приходится день невисокосного года с номером n. Программа получает на вход целое число n и должна вывести два числа: число месяца (от 1 до 31) и номер месяца (от 1 до 12), на которое приходится данный день.
На вход программа получает одно число от 1 до 365. Программа должна вывести ответ в формате "Месяц день" (через один пробел), где "Месяц" - название месяца по-английски с заглавной буквы, "день" - число от 1 до 31.
Для определения номера дня в году лучше всего использовать константный
массив количества дней в каждом месяце:
const int Months[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
Ввод | Вывод |
---|---|
1 |
January 1 |
365 |
December 31 |
Решите обратную предыдущей задачу: по записи названия месяца и дня определите номер дня в году.
Ввод | Вывод |
---|---|
January 1 |
1 |
December 31 |
365 |
Дата задана в формате dd.mm.yyyy
.
Выведите ее в формате "Month d, y",
где Month - английское название месяца, d - номер дня в месяце, без
лидирующих нулей, y - номер года без лидирующих нулей.
Для вывода даты в строку удобно использовать вспомогательный объект класса ostringstream.
Класс должен содержать оператор считывания даты из потока:
istream & operator>> (istream &, date &);
Класс должен содержать метод
string to_text() const;возвращающую строку с данным представлением.
Ввод | Вывод |
---|---|
12.10.2008 |
October 12, 2008 |
01.01.0001 |
January 1, 1 |
Решите обратную задачу.
Для считывания даты из строки удобно использовать вспомогательный объект класса istringstream.
Класс должен содержать оператор вывода даты в поток:
ostream & operator<< (ostream &, const date &);
Класс должен содержать метод
void from_text(const string & s);получающую на вход строку с описанием даты и устанавливающую дату на данное значение в соответствии со строкой.
Ввод | Вывод |
---|---|
October 12, 2008 |
12.10.2008 |
January 1, 1 |
01.01.0001 |
Реализуйте операторы ==
и !=
для сравнения дат.
Эти операторы должны возвращать значение типа bool
.
Реализуйте оператор префиксного инкремента ++
,
который увеличивает дату на один день и возвращает ссылку на объект.
Префиксный оператор инкремента или декремента — это оператор, который пишется
перед объектом (++a
), он возвращает новое значение объекта.
Например, если оператор инкремента объявляется, как член класса, то объявление должно быть таким:
class date { date & operator++() { // Put your code here return *this; } };
Ввод | Вывод |
---|---|
12.10.2008 |
13.10.2008 |
31.12.2008 |
01.01.2009 |
Реализуйте операторы <
, <=
, >
, >=
для сравнения дат.
Эти операторы должны возвращать значение типа bool
.
Реализуйте оператор постфиксного декремента --
,
который уменьшает дату на один день и возвращает ссылку на объект.
Постфиксный оператор инкремента или декремента — это оператор, который пишется
после объекта (a--
), он изменяет значение объекта, но возвращает ссылку на старое значение.
Например, если оператор декремента объявляется, как член класса, то объявление должно быть таким:
class date { date operator--(int) { // Put your code here return /* old saved value */; } };
Параметр int
, передаваемый оператору декремента,
не используется. Он нужен для того, чтобы компилятор отличал
префиксную и постфиксную форму записи оператора.
Также обратите внимание на то, что постфиксный инкремент должен возвращать не ссылку на объект, а сохраненное значение объекта, т.к. объект был изменен.
Ввод | Вывод |
---|---|
13.10.2008 |
12.10.2008 |
01.01.2009 |
31.12.2008 |
Реализуйте оператор вычитания двух дат. Его можно оформить в виде метода:
class date { int operator-(const date &) const; };
или в виде функции
int operator-(const date &, const date &);
Оператор возвращает разность — на сколько дней различаются две даты.
При этом допускаются следующие ограничения: дата, соответствующая левому операнду не раньше даты правого операнда, вычитание может производиться при помощи операций инкремента или декремента.
В примере ниже из второй даты вычитается первая.
Ввод | Вывод |
---|---|
01.01.0001 |
1 |
29.02.2004 |
366 |
По дате определите день недели, на который она приходится. Реализуйте алгоритм в виде метода
class date { string day_of_the_week() const; };
который возвращает строку, содержащую английское название дня недели с заглавной буквы.
Ввод | Вывод |
---|---|
12.10.2008 |
Sunday |
13.10.2008 |
Monday |
Задан день и месяц рождения в формате dd.mm. Задана текущая дата в формате dd.mm.yyyy. Определите, сколько дней осталось до дня рождения. Если сегодня день рождения, то необходимо вывести 0.
Ввод | Вывод |
---|---|
19.04 |
0 |
05.05 |
16 |
29.02 | 1096 |
На проверку нужно сдать программу целиком.
Пронумеруем все даты подряд, считая, что 01.01.0001 имеет номер 1, 02.01.0001 — номер 2 и т.д. По заданной дате определите ее порядковый номер.
Решение оформите в виде оператора int
.
class date { operator int() const; };
Обратите внимание, что при таком объявлении нельзя указывать тип
возвращаемого значения, это должен быть int
.
Пример использования: (int)date(1, 1, 2)
возвращает 366.
Решение должно иметь сложность \(O(1)\), то есть не должно содержать циклы.
Научитесь быстро вычислять разницу между двумя датами.
Необходимо реализовать оператор вычитания для дат, который не содержит циклов. Также левый операнд может быть меньше правого — в этом случае возвращается отрицательное число.
Решите обратную задачу — определите дату по номеру дня.
Решение оформите в виде конструктора
class date { date(int); };
Не забудьте про существование других конструкторов: от трёх целых чисел и конструктора по умолчанию (без аргументов).
В решении допускаются циклы, ограничение по времени — 1 секунда на 200.000 операций считывания числа, перевода числа в дату и вывода даты.
Имеется список людей с указанием их фамилии, имени и даты рождения. Напишите эффективную по времени работы и по используемой памяти программу, которая будет определять самого старшего человека из этого списка и выводить его фамилию, имя и дату рождения, а если имеется несколько самых старших людей с одинаковой датой рождения, то определять их количество.
На вход программе в первой строке подается количество людей в списке N. В каждой из последующих N строк находится информация в следующем формате:
<Фамилия> <Имя> <Дата рождения>
где <Фамилия>
– строка, состоящая не более, чем из 20 символов без пробелов,
<Имя>
– строка, состоящая не более, чем из 20 символов без пробелов,
<Дата рождения>
– строка, имеющая вид DD.MM.YYYY
.
Программа должна вывести дату рождения самого старшего человека в списке, затем через пробел его фамилию и имя. Если таких людей, несколько, то вместо фамилии и имени выводится их количество.
На проверку нужно сдать программу целиком.
Ввод | Вывод |
---|---|
3 |
29.04.1995 Petr Sergeev |
3 |
01.05.1995 2 |
Имеется список сотрудников организации с указанием их фамилии, имени и даты рождения. Администрация ежедневно поздравляет всех сотрудников, родившихся в этот день. Напишите эффективную по времени работы и по используемой памяти программу, которая будет определять, в какой из дней года родилось больше всего сотрудников и выводить этот день (или несколько дней).
Формат входных данных аналогичен предыдущей задаче.
Программа должна вывести список дат, в которые наибольшее число сотрудников отмечает дни рождения
в формате DD.MM
по возрастанию дат, каждая дата в отдельной строке.
На проверку нужно сдать программу целиком.
Ввод | Вывод |
---|---|
5 |
01.01 |
Имеется список сотрудников организации с указанием их фамилии, имени и даты рождения. Напишите эффективную по времени работы и по используемой памяти программу, которая будет определять фамилию и имя самого молодого сотрудника, празднующего свой день рождения в течение ближайших семи дней от текущей даты (включая текущую дату).
На вход программе в первой сроке подается текущая дата,
заданная в формате DD.MM.YYYY
.
Во второй строке подается количество людей в списке N. В каждой из последующих N строк находится информация о каждом сотруднике, как в задаче T.
Известно, что у всех сотрудников даты рождения различаются. Программа должна вывести фамилию
и имя самого молодого сотрудника, празднующего день рождения в ближайшие 7 дней
или сообщение No birthdays in next week
, если никто из сотрудников не празднует
день рождения в ближайшие 7 дней.
На проверку нужно сдать программу целиком.
Ввод | Вывод |
---|---|
25.11.2010 |
Ivan Petrov |
25.11.2010 |
No birthdays in next week |
В этих задачах специальных требований к решениям нет, на проверку сдаётся программа целиком. Но для хранения времени удобно создать:
class Time { int hours; int minutes; int seconds; };
Использовать для названия структуры идентификатор time
нельзя, так как такое имя
уже используется в стандартной библиотеке языка C.
Времена будут, как правило, задаваться в формате hh:mm:ss
, где hh
принимает значения от 00 до 23, mm
и ss
- значения от 00 до 59
или в формате hh:mm
.
Часы показывают время в формате hh:mm:ss. На этих часах запустили таймер, который прозвенит через n секунд. Определите время, которое будет на часах, когда прозвенит таймер. n может принимать значения от 0 до 109. Решение задачи не дожно содержать циклов. Постарайтесь также не использовать условную инструкцию.
Ввод | Вывод |
---|---|
09:00:00 |
09:01:30 |
23:59:59 |
00:00:00 |
Ввод | Вывод |
---|---|
14:00:00 |
07:10:30 |
22:00:00 |
09:00:00 |
Будильник в сотовом телефоне можно настроить так, чтобы он звонил каждый день в одно и то же время, либо в указанное время в определенный день недели. Независимо можно настроить несколько будильников.
По информации о будильниках и текущему времени и дню недели определите, когда прозвонит очередной будильник.
В первой строке вводится текущий день недели (число от 1 до 7), затем через пробел,
текущее время в формате HH:MM
.
Во второй строке вводится одно натуральное число N, не превосходящее 100 – количество будильников.
В следующих N строках вводится описание N будильников в таком же формате. Значение дня недели, равное 0, означает, что будильник звонит каждый день.
Выведите номер дня недели и время, когда будильник зазвонит в следующий раз, в таком же формате.
Ввод | Вывод |
---|---|
2 10:20 |
3 10:10 |
7 01:01 |
7 01:01 |
Таймер - это часы, которые умеют подавать звуковой сигнал по прошествии некоторого периода времени. Напишите программу, которая определяет, когда должен быть подан звуковой сигнал.
Первая строка входных данных содержит текущее время в формате 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 |
01:01:01+2 days |
01:01:01 |
02:01:00 |
23:59:59 |
00:00:00+1 days |
В следующих трех задачах вам нужно разобраться со стандартными функциями языка C, работающими со временем, а не реализовывать их самостоятельно. Эти функции описаны в заголовочном файле time.h.
В операционной системе UNIX, и во всех системах, имеющих сходную архитектуру
(удовлетворяющих стандарту POSIX), например, Linux, Android, macOS, iOS,
время хранится, как целое число, равное количеству секунд, прошедших с полуночи 1 января 1970 года,
то есть число 0 соответствует времени 0:00:00 01.01.1970
.
Секунды координации не учитываются.
Увидеть текущее время в формате UNIX (называется также Unix timestamp) и перевести время из формата UNIX в человекочитаемый формат можно на сайте unixtimestamp.com.
Для хранения времени используется 32-битное знаковое целое число, что приведёт к концу света в 03:14:07 19 января 2038 UTC. Поэтому в 64-битных системах UNIX time хранится в 64-битной переменной. Соответствующий тип данных в языке C называется time_t, он является 32-битным или 64-битным знаковым целым числом.
Структура данных tm хранит дату и время в виде нескольких полей: год, месяц, день, часы, минуты, секунды, день недели, количество дней с начала года, флаг использования летнего времени. Эта структура также используется многими функциями, работающих с временем.
Напечатайте на экран текущее значение UNIX timestamp (в примере вывод соответствует вызову программы в 0:00:00 1 января 2017 UTC).
Используйте функцию time.
Ввод | Вывод |
---|---|
1483228800 |
Переведите значение из формата UNIX timestamp
в обычную дату и время. Выведите результат в формате dd.mm.yyyy hh:mm:ss
.
Разберитесь с функциями gmtime и strftime.
Обратите внимание, что time_t
в тестирующей системе
является 64-битным типом данных, а у вас на компьютере он может
быть 32-битным.
Ввод | Вывод |
---|---|
1483228800 |
01.01.2017 00:00:00 |
Решите обратную задачу. Вам поможет функция mktime. Обратите внимание на то, что функия mktime работает с местным временем, а вам нужно время в UTC. Обратите внимание на вызов функции setenv в примере на cppreference.com. Подробней о переменной TZ в GNU C Library.
Ввод | Вывод |
---|---|
01.01.2017 00:00:00 |
1483228800 |
На одном из московских вокзалов билеты продают N касс. Каждая касса работает без перерыва определенный промежуток времени по фиксированному расписанию (одному и тому же каждый день). Требуется определить, на протяжении какого времени в течение суток работают все кассы одновременно.
Программа получает на вход целое число N (0<N≤1000).
В каждой из следующих N строк записано время начало
и время окончания работы кассы в формате HH:MM
через пробел.
Время открытия означает, что в соответствующую ему минуту касса уже работает, а время закрытия что в соответствующую минуту касса уже не работает. Например, касса, открытая с 10:30 18:30 ежесуточно работает 480 минут.
Если время открытия совпадает с временем закрытия, то касса работает круглосуточно. Если первое время больше второго, то касса начинает работу до полуночи, а заканчивает на следующий день.
Требуется вывести одно число суммарное время за сутки (в минутах), на протяжении которого работают все N касс.
Ввод | Вывод |
---|---|
3 |
120 |
2 |
0 |
2 |
1 |
Докажите, что 13-е число месяца чаще всего приходится на пятницу.
Напишите
программу, которая выводит на экран 7 чисел: вероятности выпадения 13
числа каждого месяца на понедельник, вторник, среду, четверг, пятницу,
субботу, воскресенье. Например, если бы данные вероятности были бы
равны, то программа должна вывести следущий текст:
0.142857 |
Играет два человека. Задается какая-то дата високосного года. Каждый игрок на своем ходу называет более позднюю дату, увеличивая на 1 или на 2 либо день в месяце, либо месяц, но не то и другое сразу. При этом результат должен оставаться корректной датой. Игрок, назвавший 31 декабря, проигрывает. Кто выигрывает при правильной игре: первый или второй.
Программа получает на вход дату в формате DD.MM
и должна вывести
одно число: номер выигрывающего игрока.
Ввод | Вывод |
---|---|
30.12 |
2 |
29.12 |
1 |
29.11 |
2 |
Для каждого данного года посчитайте количество выходных дней в этом году (то есть количество суббот и воскресений).
Программа получает на вход число \(N\) (\(1\le N\le 10^6\)). В каждой из следующих \(N\) строк записано по одному числу от 2000 до \(10^9\) — номера годов.
Для каждого номера года выведите количество выходных дней в соответствующем годе.
Ввод | Вывод |
---|---|
2 |
104 |
Напишите программу, которая выводит на экран календарь на год примерно в таком виде,
как это делает программа 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 |