Для работы с датами полезно определить структуру из следующих полей:
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 |
Пронумеруем все даты подряд, считая, что 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 операций считывания числа, перевода числа в дату и вывода даты.
Научитесь быстро вычислять разницу между двумя датами, складывать даты с целыми числами.
Должны выполняться следующие операции:
date - date
date + int
date - int
date += int
date -= int
Все значения типа int
могут быть положительными, отрицательными или 0.
При вычитании дат первый операнд может быть меньше второго.
Все операции должны выполняться быстро.
Имеется список людей с указанием их фамилии, имени и даты рождения. Напишите эффективную по времени работы и по используемой памяти программу, которая будет определять самого старшего человека из этого списка и выводить его фамилию, имя и дату рождения, а если имеется несколько самых старших людей с одинаковой датой рождения, то определять их количество.
На вход программе в первой строке подается количество людей в списке 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 |
Докажите, что 13-е число месяца чаще всего приходится на пятницу.
Напишите
программу, которая выводит на экран 7 чисел: вероятности выпадения 13
числа каждого месяца на понедельник, вторник, среду, четверг, пятницу,
субботу, воскресенье. Например, если бы данные вероятности были бы
равны, то программа должна вывести следущий текст:
0.142857 |
В следующих трех задачах вам нужно разобраться со стандартными функциями языка 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 |