Blackwolf23
Blackwolf23

Reputation: 93

Whats the way to compare dates in c++

Whats the best way to compare dates in c++ which are made into a structure that has a day,month and year variable i.e how to check that 30 days have passed since a event and so on. I personally found that when comparing 2 dates in the same year I make both dates into "days-dates" using a array that holds the day count of all the months of the year and then convert the dates into days and do the calculations I need. Is there a easier way to compare the dates ?

Upvotes: 1

Views: 3410

Answers (3)

Howard Hinnant
Howard Hinnant

Reputation: 218720

Here is a very good C++11/14 library for handling dates1. It allows you to have {year, month, day} structures (called date::year_month_day), and {count-of-days} structures (called sys_days). It also allows easy and efficient conversions between these two structures. And naturally there are comparison operators.

The entire library is essentially an extension of <chrono> into calendar types.

Video introduction found here:

https://www.youtube.com/watch?v=tzyGjOm8AKo

Lots of example code here.

Here is a detailed explanation of the underlying algorithms to convert between the {year, month, day} structure and the {count-of-days} structure:

http://howardhinnant.github.io/date_algorithms.html

Here are some date creation and comparison examples for both field (year_month_day) and serial (sys_days) data structures:

#include "date.h"

int
main()
{
    using namespace date::literals;

    // create and compare {year, month, day} structures
    constexpr auto ymd1 = 2017_y/jan/21;
    constexpr auto ymd2 = ymd1 + date::months{15};
    static_assert(ymd2 > ymd1, "ymd2 is 15 months after ymd1");
    static_assert(ymd2 == 2018_y/apr/21, "ymd2 is 2018-04-21");

    // create and compare {count_of_days} structures
    constexpr date::sys_days sd2 = ymd2;
    static_assert(sd2 == ymd2, "sd2 is the same day as ymd2");
    static_assert(sd2.time_since_epoch().count() == 17642, "sd2 is day 17642");
    constexpr date::sys_days sd1 = sd2 - date::days{465};
    static_assert(sd1 < sd2, "sd1 is 465 days before sd2");
    static_assert(sd1.time_since_epoch().count() == 17177, "sd1 is day 17177");
    static_assert(sd1 == 2017_y/jan/11, "sd1 is 2017-01-11");
}

The constexpr / static_assert requires a fully conforming C++14 compiler. For C++11, remove the constexpr and change static_assert to assert (and eliminate the static_assert message).

date::sys_days is a typedef for the chrono::time_point:

time_point<system_clock, duration<int, ratio<86400>>

The above example code requires only "date.h", and no other C++ source files (no installation). There is also available a timezone library at this same github location, but that does require some installation.


1 I am the principal author of this library.

Upvotes: 3

Slava
Slava

Reputation: 44238

If you need to implement it yourself then simplest way is to keep date as a single integer - Julian day As you can see on the article calculation from month/day/year into Julian day and back is pretty trivial (from computer perspective of course). When you keep dates as a single number calculate difference in days or compare them is trivial. Or if you say that it is already implemented as a structure you can convert your dates into Julian day on the fly (or keep mutable field to cache that value).

Upvotes: 1

Rob K
Rob K

Reputation: 8926

For what you describe, the standard C style routines are probably going to work best: http://en.cppreference.com/w/cpp/chrono/c

Here is a rough example using C style coding

#include <ctime>

const int SECONDS_PER_DAY = 24 * 60 * 60;

tm day1;
memset( &day1, 0, sizeof(day1) );
day1.tm_year = 2016 - 1900; // tm_year is the years since 1900 
                            // so to represent 2016, the value is 116.
day1.tm_mon  = 0;
day1.tm_mday = 20;

time_t day1a = mktime( &day1 );

tm day2;
memset( &day2, 0, sizeof(day2) );
day1.tm_year = 2008 - 1900; 
day1.tm_mon  = 0;
day1.tm_mday = 20;

time_t day2a = mktime( &day2 );

double day_delta = difftime( day1, day2 ); // returns number of seconds
double days_past = (day_delta / SECONDS_PER_DAY)

This is standard and will work on everywhere.

N.B. the POSIX standard defines time_t as an integral type

Upvotes: 1

Related Questions