1

I am writing a application which needs the possibility to compare two dates. This is what I have so far:

struct entry {
    string text;
    string date; // format: dd.mm.yyyy
    bool finished; 
};

string addNulls(int number, int cols) {
    string num = to_string(number);
    if (num.size() < cols) {
        int count = cols - num.size();
        for (int i = 0; i < count; i++) {
            num = "0" + num;
        }
    }
    return num;
}

// [...]

entry e = {"here is some text", "21.03.2019", false};

int day2 = atoi(e.date.substr(0, 2).c_str());
int month2 = atoi(e.date.substr(3, 2).c_str());
int year2 = atoi(e.date.substr(6, 4).c_str());

time_t t = time(0);
struct tm * now = localtime(&t);

string date1 = e.date.substr(6, 4) + "-" + e.date.substr(3, 2) + "-" + e.date.substr(0, 2) + " 00:00:00";
string date2 = addNulls(now->tm_year, 4) + "-" + addNulls(now->tm_mon, 2) + "-" + addNulls(now->tm_mday, 2) + " 00:00:00";

if(date2 > date1) {
    // do something
}

the code gets an "entry" struct which contains a date. Than the code compares the date with the actual time. The problem is, it does not work! I run some tests with some example content, but the result (date2 > date1) returns false.

Why?

I read this: C++ compare to string dates

Community
  • 1
  • 1
  • There's no defined `operator>` for `std::string` by means of comparing two dates. What did you expect? – πάντα ῥεῖ Jul 19 '15 at 13:20
  • 1
    @πάνταῥεῖ However if you represent two dates in the ISO format of `YYYY-MM-DD`, then the lexicographic comparison of such strings also happens to order dates correctly. – Igor Tandetnik Jul 19 '15 at 13:26
  • 1
    `tm_year` is stores actual year minus 1900; e.g. year 2015 is represented as 105. Similarly, `tm_month` is zero-based: 0 for January, 11 for December. Had you attempted minimal debugging and actually looked at the contents of `date1` and `date2` before the comparison, you'd have noticed that yourself. – Igor Tandetnik Jul 19 '15 at 13:29
  • @IgorTandetnik Well the OP should make clear what the actual input of the comparison comprises of. – πάντα ῥεῖ Jul 19 '15 at 13:29
  • @πάνταῥεῖ Well the OP shows code by which the two strings are constructed right before the comparison. Looks pretty clear to me. – Igor Tandetnik Jul 19 '15 at 13:33
  • I suggest you print out your dates immediately before the comparison to make sure they are being constructed correctly. – Galik Jul 19 '15 at 14:06

2 Answers2

2

I'm not actually answering your question. However I am offering you a solution. Have you considered a date/time library? Boost datetime is very popular.

If you are compiling in C++11 or later, I recommend this date time library, as it is header-only (eliminating the need to link to a library such as boost), and in my opinion, it has cleaner syntax (that is a very subjective and biased viewpoint).

This latter library builds on the C++11 <chrono> library. Here is your example code using this library:

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

struct entry {
    std::string text;
    date::year_month_day date;
    bool finished; 
};

int
main()
{
    entry e = {"here is some text", date::day(21)/3/2019, false};
    auto day2 = e.date.day();
    auto month2 = e.date.month();
    auto year2 = e.date.year();
    auto t = std::chrono::system_clock::now();
    auto date1 = date::sys_days{e.date};
    auto date2 = t;
    if (date2 > date1)
        std::cout << "It is past " << e.date << '\n';
    else
        std::cout << "It is not past " << e.date << '\n';
}

Which currently outputs:

It is not past 2019-03-21

In C++14, the chrono literals make specifying literal times very compact:

using namespace std::literals;
auto date1 = date::sys_days{e.date} + 0h + 0min + 0s;

Also on the subject of literals, you can make the construction of entry slightly more compact if you drop in a using namespace date;:

entry e = {"here is some text", 21_d/3/2019, false};

Reusing a date or datetime class, or even creating your own, is easier than trying to use a string to hold a date. Additionally you get the type-safety of not accidentally adding a string to a date, when you meant to add a time duration to a time point.

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

Why don't you use strptime to parse your date strings, convert them to epoch times and then compare?

 #include <time.h>

 char *
 strptime(const char *restrict buf, const char *restrict format,
     struct tm *restrict tm);
themoondothshine
  • 2,983
  • 5
  • 24
  • 34
  • There are several reasons not do this. For example, (1) it's not standard C++ and (2) it is C-centric pointer stuff. – Christian Hackl Jul 19 '15 at 13:37
  • Agreed, but @Paul was already using `localtime` and `time` which are C-centric (in fact defined in the same header `time.h` as `strptime`). – themoondothshine Jul 19 '15 at 13:42
  • That's not technically correct. `` is a standard C++ header. `strptime` is a **non-standard** extension of that header's contents. More information: http://stackoverflow.com/questions/321849/strptime-equivalent-on-windows – Christian Hackl Jul 19 '15 at 13:45