Как правильно добавить год в COledateTime, учитывая високосные годы? - PullRequest
1 голос
/ 01 марта 2020

У меня есть этот код:

COleDateTime datStart = COleDateTime::GetCurrentTime(), datEnd;

// Update end date (one year later)
datEnd.SetDateTime(datStart.GetYear() + 1,
    datStart.GetMonth(),
    datStart.GetDay(),
    datStart.GetHour(),
    datStart.GetMinute(),
    datStart.GetSecond());

Указанный выше код не удался вчера (29 февраля 2020 г.), поскольку datEnd привел к 29 февраля 2021 , что недопустимо.

Как правильно добавить год к datStart с учетом високосных годов?

C# имеет:

DateTime theDate = DateTime.Now;
DateTime yearInTheFuture = theDate.AddYears(1);

Что является эквивалентом для MFC / C ++?

Одна из возможностей:

COleDateTimeSpan spnYear;
spnYear.SetDateTimeSpan(365, 0, 0, 0);

datEnd = datStart + spnYear;

Но она все еще потенциально несовершенна из-за високосных лет, имеющих 366 дней. Так какой же правильный путь?

Я вижу этот похожий вопрос:

C ++ добавить 1 год к дате

Это подразумевает использование boost. У меня есть повышение в моем проекте, хотя я никогда не использовал его для манипулирования датами. Интересно, можно ли это использовать с COleDateTime объектом?

Использование boost:

boost::gregorian::date dStart{ datStart.GetYear(), datStart.GetMonth(), datStart.GetDay() };
boost::gregorian::date dEnd = dStart + boost::gregorian::years(1);

datEnd.SetDateTime(
    dEnd.year(),
    dEnd.month(),
    dEnd.day(),
    datStart.GetMonth(),
    datStart.GetMinute(),
    datStart.GetSecond());

Не компилируется.

4>D:\My Programs\2019\MeetSchedAssist\Meeting Schedule Assistant\PublishersDatabaseDlg.cpp(354,49): error C2398: Element '1': conversion from 'int' to 'boost::gregorian::date::year_type' requires a narrowing conversion
4>D:\My Programs\2019\MeetSchedAssist\Meeting Schedule Assistant\PublishersDatabaseDlg.cpp(354,70): error C2398: Element '2': conversion from 'int' to 'boost::gregorian::date::month_type' requires a narrowing conversion
4>D:\My Programs\2019\MeetSchedAssist\Meeting Schedule Assistant\PublishersDatabaseDlg.cpp(354,89): error C2398: Element '3': conversion from 'int' to 'boost::gregorian::date::day_type' requires a narrowing conversion

1 Ответ

3 голосов
/ 02 марта 2020

COleDateTime - это обертка вокруг (удивительно удивительно) типа DATE. Внутри он хранит 64-битное значение с плавающей запятой, где целые числа представляют дни с 30 декабря 1899 года (полночь). Дробная часть представляет время суток (например, 0.25 означает 6 часов утра, а 0.5 - полдень). Каждое значение с плавающей запятой является допустимым значением и представляет уникальный 1 момент времени.

Добавление года к значению COleDateTime равносильно добавлению значения 365.0 (или любого другого значения) соответствует вашим потребностям) для его внутреннего представления. Это может быть сделано путем прямого доступа к элементу m_dt

COleDateTime datEnd{ datStart.m_dt + 365.0 };

или с помощью COleDateTimeSpan

datEnd = datStart + COleDateTimeSpan{ 365.0 };
// or
datEnd = datStart + COleDateTimeSpan{ 365, 0, 0, 0 };

This Операция всегда четко определена и даст действительный момент времени независимо от високосных лет. Под капотом просто добавляются значения с плавающей запятой, которые не имеют представления о календарных свойствах. Следующий код

COleDateTime datStart{ 2020, 2, 29, 0, 0, 0 };
COleDateTime datEnd{ datStart + COleDateTimeSpan{ 365.0 } };

создаст момент времени, который представляет 28 февраля 2021 года (обратите внимание, что если вы добавите 366.0 дней, он вернется 1 марта 2021 года).


Первоначальное решение, которое пытается построить COleDateTime, выполняя арифметику c для отдельных компонентов даты, терпит неудачу во время построения. Конструктор проверяет свой ввод. При пропуске (2021, 2, 29, 0, 0, 0) он определяет недопустимую дату и устанавливает m_status на invalid.


1 Это не совсем правильно , Значения в диапазоне (-1 .. 0] отображаются в тот же момент времени, что и их абсолютные значения. Обратите внимание, что, например, COleDateTime{-0.25} == COleDateTime{0.25} оценивается как false, даже если они представляют один и тот же момент времени.

...