Home > Net >  Is there a way to compare a date stored as a string with the tm structure included in the ctime libr
Is there a way to compare a date stored as a string with the tm structure included in the ctime libr

Time:04-21

In my c project about an Airline Reservation System, I have a class member variable for the date stored as a string (i.e. "4/20/2022") and now I need to store the time as well so I added ctime library. The problem is I cannot compare them because the ctime structure for date gives the date as separate member variables.

Is there a way to compare them?

Here is an example:

time_t ko = time(nullptr);
struct tm time_date_struct = *localtime(&ko);
struct destination_structure {
    int offer_id,seat[size];
    std::string departure;//store time
    std::string arrival;//store time
    std::string from_day; // date as string (4/20/2022)
    std::string to_day; // date as string (4/21/2022)
    destination_structure* next;
};

//...

if(current->from_day < time_date_struct && current->to_day && current->departure < time_date_struct.tm_hour) {
    //...
}

CodePudding user response:

  • For C 20 <chrono>, see the bottom half of this answer.

ctime structure gives them as separate member variables.

First, there's no structure named ctime. You were describing std::tm.


To create a std::tm from given values(year, month, day), you would do something like:

int year = 2022, month = 2, day = 2;

std::tm calendar_time{};
calendar_time.tm_year = year - 1900;
calendar_time.tm_mon = month - 1;
calendar_time.tm_mday = day;

This would assign year, month, and day correspondingly, while keeping the hour, minute, second as 0. Note that you need to minus a number for year and month, because std::tm uses 1900 as the base year, and January as the base month.

Similarly, you can assign hour/min/sec to calendar_time with .tm_hour/.tm_min/.tm_sec.

However, std::tm can't be used to compare with another std::tm. Instead, you would need to first convert them into a std::time_t:

auto time_since_epoch = std::mktime(&calendar_time);

Now you can compare the time you create with current time:

auto now = std::time(nullptr);

if (now > time_since_epoch)
    std::cout << "time_since_epoch was in the past!";
else
    std::cout << "time_since_epoch will be in the future!";

Demo: https://godbolt.org/z/vocGM4WE8


Alternatively, you can format a string from std::time with the help of std::put_time:

auto now = std::time(nullptr);

std::stringstream ss;
ss << std::put_time(std::localtime(&now), "%D");
auto now_str = ss.str();

This would create a string in the format of mm/dd/yyyy. Now you can do a string comparison between this and other strings. However, this is not recommended, as this could easily fail if your strings are not formatted in the exact same way(which will be a problem in your case, since you stored the date as 4/20/2022 instead of 04/20/2022).

Demo: https://godbolt.org/z/bz36TPfzq


C 20 <chrono>

With the <chrono> library, creating a date/time object became really simple :

auto now = std::chrono::system_clock::now();
auto another_date = std::chrono::month{2} / 22 / 2022;

if (now > std::chrono::sys_days{another_date})
    std::cout << "another_date was in the past!";
else
    std::cout << "another_date will be in the future!";

That's all you need!

Demo: https://godbolt.org/z/bMzv9crxh


And you can easily add the time to the date as well:

auto date_time = sys_days{month{2} / 22 / 2022}   hours{4}   minutes{13}   seconds{40};
std::cout << date_time;  // prints: 2022-02-22 04:13:40

Sad news is not all compilers fully supports the c 20 <chrono> yet. A workaround is to use the date library, written by the same author of <chrono> , for now.

Demo: https://godbolt.org/z/sWzo5GrE1

CodePudding user response:

chrono::time_point data type can be used for comparing time, calculating durations etc.

Your should parse your string into into this data type first, as well as you'll need to format it back to the string according to the fomat you need maually.

For example:

#include <chrono>
#include <iomanip>
#include <iostream>
#include <sstream>


static std::chrono::time_point<std::chrono::system_clock> parse_time(const std::string& str)
{
    std::stringstream in;
    if( '/' == str[1] ) {
        in.put('0');
    }
    in << str;
    std::tm tmp = {};
    in >>  std::get_time(&tmp, "%m/%d/%Y");
    if(in.fail()) {
        throw std::runtime_error("Date parsing failed");
    }
    return std::chrono::system_clock::from_time_t( std::mktime(&tmp) );
}

static std::size_t diff(const std::chrono::time_point<std::chrono::system_clock>& start,const std::chrono::time_point<std::chrono::system_clock>& end)
{
     return std::chrono::duration_cast<std::chrono::days>(end - start).count();
}

std::ostream& operator << (std::ostream& to,const std::chrono::time_point<std::chrono::system_clock>& what)
{
    std::time_t tmp = std::chrono::system_clock::to_time_t(what);
    to << std::put_time( std::localtime(&tmp), "%d %b %Y" );
    return to;
}


int main(int argc, const char** argv)
{
    std::chrono::time_point<std::chrono::system_clock> lhs =  parse_time("4/20/2022");
    std::chrono::time_point<std::chrono::system_clock> rhs = parse_time("4/21/2022");

    std::cout << "Left Hand Statement date: " << lhs << std::endl;

    std::cout << "Right Hand Statement date: " << rhs <<  std::endl;

    std::cout << std::endl;

    if(lhs < rhs) {
        std::cout << lhs << " is before " << rhs << std::endl;
    }

    if(rhs > lhs) {
        std::cout << rhs << " is after " << lhs << std::endl;
    }

    std::cout << diff(lhs,rhs) << " days between " << lhs << " and " << rhs << std::endl;

    return 0;
}
  • Related