Преобразование часовых поясов в примере 5.8 выполняется в два шага. Вначале время преобразуется в UTC, а затем время в UTC преобразуется во второй часовой пояс. Заметьте, что часовые пояса в библиотеке Boost date_time представлены как типы, использующие шаблон класса local_adjustor. Каждый тип содержит функции преобразования, которые преобразуют из данного часового пояса в UTC (функция local_tc_utс) и из UTC в данный часовой пояс (функция utc_to_local).
5.5. Определение номера дня в году
Требуется определить номер дня в году. Например, 1 января — это первый день в году, 5 февраля это 36-й день в году, и так далее. Но так как некоторые годы — високосные, то после 28 февраля указанный день может иметь не такой же номер, как и в другие годы.
Решение этой проблемы требует одновременного решения сразу нескольких проблем. Во-первых, требуется знать, сколько дней в каждом месяце, что в свою очередь требует определить, является ли год високосным. Пример 5.9 содержит процедуры, выполняющие эти вычисления.
#include
using namespace std;
enum MonthEnum {
jan = 0, feb = 1, mar = 2, apr = 3, may = 4, jun = 5,
jul = 6, aug = 7, sep = 8, oct = 9, nov = 10, dec = 11
};
bool isLeapYear(int y) {
return (y % 4 == 0) && ((y % 100 != 0) || (y % 400 == 0));
}
const int arrayDaysInMonth[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int n;
int arrayFirstOfMonth[] = {
n = 0,
n += arrayDaysInMonth[jan],
n += arrayDaysInMonth[feb],
n += arrayDaysInMonth[mar],
n += arrayDaysInMonth[apr],
n += arrayDaysInMonth[may],
n += arrayDaysInMonth[jun],
n += arrayDaysInMonth[jul],
n += arrayDaysInMonth[aug],
n += arrayDaysInMonth[sep],
n += arrayDaysInMonth[::oct],
n += arrayDaysInMonth[nov]
};
int daysInMonth(MonthEnum month, int year) {
if (month == feb) {
return isLeapYear(year) ? 29 : 28;
} else {
return arrayDaysInMonth[month];
}
}
int firstOfMonth(MonthEnum month, int year) {
return arrayFirstOfMonth[month] + isLeapYear(year);
}
int dayOfYear(MonthEnum month, int monthDay, int year) {
return firstOfMonth(month, year) + monthDay - 1;
}
int main() {
cout << "1 июля 1971 г. был " << dayOfYear(jul, 1, 1971);
cout << днем года" << endl;
}
Программа из примера 5.9 выводит следующее.
1 июля 1971 г. был 181 днем года
Код примера 5.9 довольно прост, но содержит набор полезных функций для работы с датами в високосных годах. Обратите внимание, что я отбросил подход, который я называю «задокументируй и молись», использованный в предыдущих рецептах. Под этим я подразумеваю, что месяцы больше не представляются индексами, вместо которых используются перечисления. Это значительно снижает вероятность программистской ошибки при передаче месяца в функцию в качестве ее аргумента.
Вычисление високосного года, показанное в примере 5.9, выполняется в соответствии с современным григорианским календарем. Каждый четвертый год — високосный, за исключением каждого сотого, если он не делится на 400 (т.е. 1896 год был високосным, 1900 не был, 2000 был, 2004 был, 2100 год не будет).
5.6. Определение ограниченных типов значений
Требуются самопроверяющиеся типы числовых данных, представляющие числа в ограниченном диапазоне допустимых значений, гаком как часы в сутках или минуты в часе.