1

I have dates as strings in this format:

YYYY-MM-DD (2021-07-01, 2021-02-21 etc.)

Now I want to compare them, and the best solution I can think of is converting all of those dates into some number (like unix time), but I don't know how to do it.

It has to be precise with days (so that 2021-01-01 < 2021-01-02).

I found strptime() function on the Internet, but I'm a Windows user (CLion), so I can't use that.

Is it possible to do it in a simple way? Leap years have to accounted for.

EDIT: My input data look like this:

char date1[] = "2021-01-07";
char date2[] = "2021-01-14";
char date3[] = "2021-01-20"; etc.

How I want to use them:

if (date1 < date2 < date3){
    // return "true" if date2 is in the interval (Pseudocode ofc)
    return true;
}
Etoile
  • 161
  • 10
  • 1
    WinX usually has a POSIX compatibility layer/library that should have `strptime`. You may have to do an extra install of that. See: https://stackoverflow.com/questions/321849/strptime-equivalent-on-windows – Craig Estey Jan 24 '21 at 23:06
  • @CraigEstey You're thinking of WSU ("Windows Services for Unix") but it was last available for Windows Server 2003. Windows doesn't come with a POSIX-compatibility layer anymore, now we have to use WSL, which is radically different (it's more of an "alternate platform" than a "compatibility layer"). – Dai Jan 24 '21 at 23:09
  • 3
    With the given format, the date order is the same as the lexicographical order, so no conversion needed. - you can just compare them as strings – dxiv Jan 24 '21 at 23:11
  • @Dai WSL2 is a lightweight VM (like vmware, virtualbox, xen) so you boot a _real_ linux kernel (e.g. ubuntu). The link was for an open source `strptime`. – Craig Estey Jan 24 '21 at 23:12
  • @Etoile Please update your question for a proper example as how the input data looks like. – Jay-Pi Jan 24 '21 at 23:17
  • That was a typo, it's YYYY-MM-DD :) – Etoile Jan 24 '21 at 23:26
  • 3
    @Etoile Then all you need is `strcmp`, as mentioned already. – dxiv Jan 24 '21 at 23:28
  • @Etoile Please update your input examples to the input delimiters etc, if you need a more precise answer. – Jay-Pi Jan 24 '21 at 23:30
  • @Etoile Please describe, what is missing. – Jay-Pi Jan 24 '21 at 23:54
  • @dxiv This could break on malformed dates, ie when you have 2000-01-1 and 2000-01-14. – Jay-Pi Jan 24 '21 at 23:59
  • @Jay-Pi "*could break on malformed dates*" That's correct, but (a) the OP didn't mention validating the dates as a requirement, and (b) if it *is* a requirement then that can be checked by parsing the string, indeed, albeit more thoroughly than your answer does, which would also fail with e.g. `2000--1-99`. – dxiv Jan 25 '21 at 00:06
  • @dxiv Thats not correct, since you specify `--`. The answer is more condensed though and probably referes more to the intention of the poster. `return -1` is also dangerously wrong, since `time_t` is unsigned. Or am I wrong on this as well? – Jay-Pi Jan 25 '21 at 00:13
  • @Jay-Pi Don't know where you got the notion that [`time_t`](https://en.cppreference.com/w/c/chrono/time_t) is unsigned, and `-1` is the documented return value for [`mktime`](https://en.cppreference.com/w/c/chrono/mktime) to indicate an error. – dxiv Jan 25 '21 at 00:16
  • @dxiv `time_t` _could_ be some _unsigned_ integer. C lib uses -1 to indicate error, but it is expressly type `time_t` as in `(time_t)-1`. So returning `(time_t)-1` is not a problem, even on rare implementations with an _unsigned_ `time_t`. – chux - Reinstate Monica Jan 25 '21 at 00:28
  • 1
    @chux-ReinstateMonica Right, thanks for that clarification. I should have probably written "is *necessarily* unsigned" or "is *always* unsigned" instead, to make the point crystal clear. – dxiv Jan 25 '21 at 00:33

2 Answers2

4

How to convert C date string into an integer?

Compare correctly

As OP's date strings are in chronological and lexicographical order, a conversion is not needed (unless one has negative years).

// if (date1 < date2 < date3){ 
if (strcmp(date1, date2) < 0 && strcmp(date2, date3) < 0) {

Convert string to time_t

If one wants to still convert, use sscanf() to parse the string. Pay special attention to possible errors.

Some somewhat tested code:

#include <time.h>

time_t YMD_to_time(const char *ymd) {
  if (ymd == NULL) {
    return (time_t)-1;
  }

  struct tm tm = {0}; // Important: initialize all members to 0
  int n = 0;
  sscanf(ymd, "%4d-%2d-%2d %n", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &n);

  // Scan incomplete or extra junk?
  if (n == 0 || ymd[n]) {
    return (time_t)-1; // Mal-formed string
  }

  // Could add extra checks for months/days outside primary range, spaces in string, etc.

  // Adjust ranges as struct tm uses different references
  tm.tm_year -= 1900;
  tm.tm_mon--;
  tm.tm_isdst = -1; // Important to get right time for Year-Month-Day 00:00:00 _local time_

  // The following conversion assumes tm is in local time.
  return mktime(&tm); // This may return -1;
}

Usage

time_t t1 = YMD_to_time(date1);
time_t t2 = YMD_to_time(date2);
time_t t3 = YMD_to_time(date3);
if (t1 == -1 || t2 == -1 || t3 == -1) return times_are_not_comparable
if (t1 < t2 && t2 < t3) return times_are_in_order;
return times_not_in_order;
mhawke
  • 84,695
  • 9
  • 117
  • 138
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Where can I find the %n option for sscanf? This looks like a hack. – Jay-Pi Jan 25 '21 at 00:06
  • 1
    @Jay-Pi Best ref: [C17dr § 7.21.6.2 12](https://stackoverflow.com/a/83763/2410359) – chux - Reinstate Monica Jan 25 '21 at 00:09
  • You may want to change the -1 as return value for `time_t`, as it may be unsigned. "POSIX requires time_t to be an integer type, but does not mandate that it be signed or unsigned." – Jay-Pi Jan 25 '21 at 00:17
  • 2
    @Jay-Pi Re: "looks like a hack" --> I find the `int n = 0; sscanf(s, format " %n", ....); if (n == 0 || s[n])` a very robust and tight code that detects many errors succinctly. – chux - Reinstate Monica Jan 25 '21 at 00:17
  • 1
    @Jay-Pi True that `time_t` may be some _unsigned_ integer (or `int` or `double` or ...) , but `return -1` is still best. Various standard C functions return `(time_t)(-1).` to indicate error, like this code also does. If `time_t` was say `unsigned long`, `return -1` would simple return `ULONG_MAX`. Could use `return (time_t)-1;` to avoid a conversion warning on your _unsigned_ machine. I'll amend. – chux - Reinstate Monica Jan 25 '21 at 00:21
-1

if (date1 < date2 < date3) it will never work.

To convert to integers learn about sscanf function

0___________
  • 60,014
  • 4
  • 34
  • 74