24

I saw examples for C#, Java, but for C++ i cant find solution to calculate how many days between two dates.

For example between 2012-01-24 and 2013-01-08

Thanks!

Breakdown
  • 1,035
  • 4
  • 16
  • 26
  • 3
    What have you tried so far ? What data type are you using to store this date ? From me it could be as simple as `(date1 - date2).to_days();` or even, using C++11 and appropriate code `("2012-01-24"_date - "2013-01-08"_date).to_days();` – Jaffa Jan 08 '13 at 15:55
  • 3
    If you're going to use this algorithm for historical data, watch out, because the past is surprisingly discontinuous. For example, how many days are there between 1582/10/5 and 1582/10/14? Answer: [1 if you're in Spain, Portugal, or Italy.](http://en.wikipedia.org/wiki/Gregorian_calendar#Adoption_in_Europe) – Kevin Jan 08 '13 at 16:10

5 Answers5

30

This is one way.

#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;
}

my output

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

Here is a ref to Original author post

sharafjaffri
  • 2,134
  • 3
  • 30
  • 47
  • there is a Ref to post, Let me make it bold – sharafjaffri Jan 08 '13 at 16:06
  • I saw this (otherwise I wouldn't have known it), but it's hard to see. – leemes Jan 08 '13 at 16:07
  • Thanks for intimation I will consider this in my next replies – sharafjaffri Jan 08 '13 at 16:08
  • 9
    You should also emphasize that it doesn't work. You may get inconsistent results if the dates span the date where you change between summer and winter time. (Use `12:0:0` for the time, _not_ `0:0:0`.) And of course, the order of the elements in the `struct tm` aren't specified; you need something like `std::tm a; a.tm_year = 104; a.tm_mon = 5; a.tm_mday = 24; a.tm_hour = 12;`. – James Kanze Jan 08 '13 at 16:23
  • 2
    This approach doesn't account for daylight savings time shifts, leap seconds, or holes in the Gregorian calendar. As long as you are always considering midnight of each day and round off to the nearest number of days, the first two pitfalls won't hurt you. As long as you aren't using a date range that spans a hole (any time after 1582 is safe), the third pitfall won't get you either. – Edward Brey May 06 '14 at 18:32
  • If i calculate between `August 15, 1979` and `June 15, 2018` it gives me `14182` which is `2` days short. The correct number of days are `14184`. I'll try to fix this. – chankruze Aug 29 '20 at 19:52
19

Convert your dates to integer denoting the number of days since an epoch, then subtract. In this example i chosed Rata Die, an explanation of the algorithm can be found at <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);
chansen
  • 2,446
  • 15
  • 20
  • what does `(153*m - 457)/5 + d - 306` mean? – immiao Jan 28 '17 at 18:18
  • @immiao, The algorithm shifts February to the end of the year. `(153 * m - 457)/5` computes the number of preceding days of the shifted month. There are 306 days between March 1 of the year zero and December 31. – chansen Mar 07 '17 at 00:05
19

Update for C++20:

#include <chrono>
#include <iostream>

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

Output:

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

If the {year, month, day} data exists in ints, then it just looks like:

int xy = 2012;
int xm = 1;
int xd = 24;
int yy = 2013;
int ym = 1;
int yd = 8;
auto x = year{xy}/xm/xd;
auto y = year{yy}/ym/yd;
// ...

The type of sys_days{y} - sys_days{x} is std::chrono::days which is a type alias for std::chrono::duration<signed integral type, std::ratio<86'400>>.


New answer for an old question:

Using this C++11/C++14 header-only date library, you can now write:

#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";
}

Which outputs:

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

If you don't want to depend on this library, you can write your own, using the same date algorithms that the above date library uses. They are found in this paper: chrono-Compatible Low-Level Date Algorithms. The algorithm from this paper that is being exercised in this example is this one:

// 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;
}

See chrono-Compatible Low-Level Date Algorithms for details about how this algorithm works, unit tests for it, and its range of validity.

This algorithm models the proleptic Gregorian calendar, which extends the Gregorian calendar indefinitely, both forwards and backwards. To model other calendars (such as the Julian calendar), you will need other algorithms, such as the ones shown here. Once you have other calendars set up, and synchronized to the same serial epoch (these algorithms use 1970-01-01 Gregorian, which is also the Unix time epoch), you can easily compute the number of days not only between any two dates, but also between any two calendars which you have modeled.

This gives you the freedom of not having to hard-code in a date for the switch from Julian to Gregorian. You just have to know which calendar your input data is referenced against.

Sometimes dates in historical documents that might otherwise be ambiguous are annotated with Old Style / New Style to indicate the Julian or Gregorian calendar respectively.

If you are also concerned about the time of day with your dates, this same date library seamlessly integrates with the <chrono> library for use of hours, minutes, seconds, milliseconds, microseconds and nanoseconds, and with system_clock::now() to get the current date and time.

If you are concerned about time zones, an additional (separate) timezone library is written on top of the date library to handle time zones using the IANA timezone database. If needed, the timezone library also has a facility for computations that include leap seconds.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
6

you can try the boost date_time library

0

To avoid making your own function you can use date_time from Boost.

Mihai8
  • 3,113
  • 1
  • 21
  • 31