Количество дней между двумя датами C++

Я видел примеры для С#, Java, но для С++ я не могу найти решение, чтобы вычислить, сколько дней между двумя датами.

Например, между 24 января 2012 г. и 08 января 2013 г.

Спасибо!


person Breakdown    schedule 08.01.2013    source источник
comment
Что ты уже испробовал ? Какой тип данных вы используете для хранения этой даты? От меня это может быть так же просто, как (date1 - date2).to_days(); или даже с использованием C++11 и соответствующего кода ("2012-01-24"_date - "2013-01-08"_date).to_days();   -  person Geoffroy    schedule 08.01.2013
comment
Если вы собираетесь использовать этот алгоритм для исторических данных, будьте осторожны, потому что прошлое удивительно прерывисто. Например, сколько дней между 15.10.1582 и 1582.10.14? Ответ: 1, если вы находитесь в Испании, Португалии или Италии.   -  person Kevin    schedule 08.01.2013


Ответы (5)


Это один из способов.

#include <iostream>
#include <ctime>

int main()
{
    struct std::tm a = {0,0,0,24,5,104}; /* June 24, 2004 */
    struct std::tm b = {0,0,0,5,6,104}; /* July 5, 2004 */
    std::time_t x = std::mktime(&a);
    std::time_t y = std::mktime(&b);
    if ( x != (std::time_t)(-1) && y != (std::time_t)(-1) )
    {
        double difference = std::difftime(y, x) / (60 * 60 * 24);
        std::cout << std::ctime(&x);
        std::cout << std::ctime(&y);
        std::cout << "difference = " << difference << " days" << std::endl;
    }
    return 0;
}

мой вывод

Thu Jun 24 01:00:00 2004
Mon Jul 05 01:00:00 2004
difference = 11 days

Вот ссылка на исходное сообщение автора

person sharafjaffri    schedule 08.01.2013
comment
есть ссылка для публикации, позвольте мне выделить ее жирным шрифтом - person sharafjaffri; 08.01.2013
comment
Я это видел (иначе бы не знал), но плохо видно. - person leemes; 08.01.2013
comment
Спасибо за предупреждение, я учту это в своих следующих ответах. - person sharafjaffri; 08.01.2013
comment
Вы также должны подчеркнуть, что это не работает. Вы можете получить противоречивые результаты, если даты охватывают дату, когда вы переключаетесь между летним и зимним временем. (Используйте 12:0:0 для времени, не 0:0:0.) И, конечно же, порядок элементов в struct tm не указан; вам нужно что-то вроде std::tm a; a.tm_year = 104; a.tm_mon = 5; a.tm_mday = 24; a.tm_hour = 12;. - person James Kanze; 08.01.2013
comment
Этот подход не учитывает переходы на летнее время, дополнительные секунды или пробелы в григорианском календаре. Пока вы всегда считаете полночь каждого дня и округляете до ближайшего числа дней, первые две ловушки вам не повредят. Пока вы не используете диапазон дат, который охватывает дыру (любое время после 1582 года безопасно), третья ловушка вас тоже не достанет. - person Edward Brey; 06.05.2014
comment
Если я посчитаю между August 15, 1979 и June 15, 2018, это даст мне 14182, что составляет 2 дней меньше. Правильное количество дней 14184. Я постараюсь это исправить. - person chankruze; 29.08.2020

Преобразуйте свои даты в целое число, обозначающее количество дней, прошедших с эпохи, а затем вычтите. В этом примере я выбрал Rata Die, объяснение алгоритма можно найти по адресу ‹http://mysite.verizon.net/aesir_research/date/rata.htm>.

int
rdn(int y, int m, int d) { /* Rata Die day one is 0001-01-01 */
    if (m < 3)
        y--, m += 12;
    return 365*y + y/4 - y/100 + y/400 + (153*m - 457)/5 + d - 306;
}

int days = rdn(2013, 1, 8) - rdn(2012, 1, 24);
person chansen    schedule 08.01.2013
comment
что означает (153*m - 457)/5 + d - 306? - person immiao; 28.01.2017
comment
@immiao, алгоритм смещает февраль на конец года. (153 * m - 457)/5 вычисляет количество предыдущих дней сдвинутого месяца. Между 1 марта нулевого года и 31 декабря 306 дней. - person chansen; 07.03.2017

Новый ответ на старый вопрос:

Используя эту библиотеку дат только для заголовков C++11/C++14, вы можете теперь пиши:

#include "date.h"
#include <iostream>

int
main()
{
    using namespace date;
    using namespace std;
    auto x = 2012_y/1/24;
    auto y = 2013_y/1/8;
    cout << x << '\n';
    cout << y << '\n';
    cout << "difference = " << (sys_days{y} - sys_days{x}).count() << " days\n";
}

Что выводит:

2012-01-24
2013-01-08
difference = 350 days

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

// Returns number of days since civil 1970-01-01.  Negative values indicate
//    days prior to 1970-01-01.
// Preconditions:  y-m-d represents a date in the civil (Gregorian) calendar
//                 m is in [1, 12]
//                 d is in [1, last_day_of_month(y, m)]
//                 y is "approximately" in
//                   [numeric_limits<Int>::min()/366, numeric_limits<Int>::max()/366]
//                 Exact range of validity is:
//                 [civil_from_days(numeric_limits<Int>::min()),
//                  civil_from_days(numeric_limits<Int>::max()-719468)]
template <class Int>
constexpr
Int
days_from_civil(Int y, unsigned m, unsigned d) noexcept
{
    static_assert(std::numeric_limits<unsigned>::digits >= 18,
             "This algorithm has not been ported to a 16 bit unsigned integer");
    static_assert(std::numeric_limits<Int>::digits >= 20,
             "This algorithm has not been ported to a 16 bit signed integer");
    y -= m <= 2;
    const Int era = (y >= 0 ? y : y-399) / 400;
    const unsigned yoe = static_cast<unsigned>(y - era * 400);      // [0, 399]
    const unsigned doy = (153*(m + (m > 2 ? -3 : 9)) + 2)/5 + d-1;  // [0, 365]
    const unsigned doe = yoe * 365 + yoe/4 - yoe/100 + doy;         // [0, 146096]
    return era * 146097 + static_cast<Int>(doe) - 719468;
}

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

Этот алгоритм моделирует пролептический григорианский календарь, который бесконечно расширяет григорианский календарь как вперед, так и назад. Для моделирования других календарей (например, юлианского календаря) вам потребуются другие алгоритмы, таких, как показанные здесь. Как только вы настроите другие календари и синхронизируете их с той же последовательной эпохой (эти алгоритмы используют 1970-01-01 по григорианскому календарю, который также является время Unix эпоха), вы можете легко вычислить количество дней не только между любыми двумя датами, но и между любыми двумя смоделированными вами календарями.

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

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

Если вас также беспокоит время суток с вашими датами, эта одинаковая библиотека дат легко интегрируется с библиотекой <chrono> для использования hours, minutes, seconds, milliseconds, microseconds и nanoseconds и с system_clock::now() для получения текущей даты и времени.

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

person Howard Hinnant    schedule 10.08.2015

вы можете попробовать библиотеку boost date_time

person Community    schedule 08.01.2013

Чтобы не создавать собственную функцию, вы можете использовать date_time от Boost.

person Mihai8    schedule 08.01.2013