Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any date/time function that handles tomorrow's date including carry over into next month?

I have a function that needs to calculate yesterday's, today's and tomorrow's date. I use localtime to get today's date. I add 1 to tm_mday in order to get tomorrow's date. The issue is if the current date is 3/31, it will become 3/32 if I add 1 to tm_mday. Is there any date package in C++ that handles carry over into next month or will I need to write logic to do this?

string get_local_date(const string &s) {
    time_t rawtime;
    struct tm * timeinfo;
    time (&rawtime);
    timeinfo = localtime(&rawtime);

    if (s == "tomorrow") {
        timeinfo->tm_mday += 3; // day becomes 3/32
    }
    if (s == "yesterday") {
        timeinfo->tm_mday -= 1;
    }

    char buffer[80];
    strftime(buffer,80,"%04Y-%m-%d",timeinfo);
    string str(buffer);

    return str; 
}
like image 284
Tyler Avatar asked Dec 13 '25 11:12

Tyler


2 Answers

On most systems, (std::)time_t is expressed as the integral seconds that have elapsed since the POSIX epoch (Jan 1 1970 00:00 UTC). As there are 86400 seconds in 1 day (not couning leap seconds), you can simply add 86400 for tomorrow, and subtract 86400 for yesterday, eg:

#include <string>
#include <ctime>

std::string get_local_date(const std::string &s) {

    std::time_t rawtime = std::time(nullptr);

    if (s == "tomorrow") {
        rawtime += 86400;
    }
    else if (s == "yesterday") {
        rawtime -= 86400;
    }

    char buffer[80] = {};
    std::strftime(buffer, 80, "%04Y-%m-%d", std::localtime(&rawtime));

    return buffer;
}

However, you really should use the native <chrono> library, which was introduced in C++11, to handle this kind of stuff, eg:

#include <string>
#include <chrono>
#include <ctime>

std::string get_local_date(const std::string &s) {

    using namespace std::literals::chrono_literals;

    auto clock = std::chrono::system_clock::now();

    if (s == "tomorrow") {
        clock += 24h; // clock += std::chrono::hours(24);
        /* alternatively, in C++20 and later:
        clock += std::chrono::days(1);
        */
    }
    else if (s == "yesterday") {
        clock -= 24h; // clock -= std::chrono::hours(24);
        /* alternatively, in C++20 and later:
        clock -= std::chrono::days(1);
        */
    }

    auto rawtime = std::chrono::system_clock::to_time_t(clock);

    char buffer[80] = {};
    std::strftime(buffer, 80, "%04Y-%m-%d", std::localtime(&rawtime));

    /* alternatively, in C++20 and later:
    return std::format("{:%F}", clock);
    */
}
like image 106
Remy Lebeau Avatar answered Dec 15 '25 01:12

Remy Lebeau


Here is a C++20 version that gets the local date for today, as opposed to the UTC date, which can be off by 1 day depending on your local time zone, and the time at which the program is run:

#include <chrono>
#include <format>
#include <iostream>
#include <string>

std::string
get_local_date(std::string const& s)
{
    using namespace std;
    using namespace chrono;

    zoned_time zt_now{current_zone(), system_clock::now()};
    auto date = floor<days>(zt_now.get_local_time());
    if (s == "tomorrow")
        ++date;
    else if (s == "yesterday")
        --date;
    else if (s != "today")
        throw "oops";
    return format("{:%F}", date);
}

int
main()
{
    std::cout << get_local_date("yesterday") << '\n';
    std::cout << get_local_date("today") << '\n';
    std::cout << get_local_date("tomorrow") << '\n';
}

This can easily be customized to another time zone which may output slightly different results by changing one line. For example:

   zoned_time zt_now{"Asia/Tokyo", system_clock::now()};

Demo.

Warning:

Note that the above code performs the arithmetic to find yesterday or tomorrow in local time (std::chrono::local_time<days>). If one instead performs the arithmetic in UTC (time_t or std::chrono::sys_time), then every once in a while, you can get a different answer.

Example:

Consider the local time 2024-03-11 00:15:00 EDT in America/New_York.

This is less than 24 hours after the DST "Spring Forward" transition.

If you convert this time stamp to UTC (2024-03-11 04:15:00 UTC), and then subtract 24h (2024-03-10 04:15:00 UTC), and then convert it back to local time, you get: 2024-03-09 23:15:00 EST. Now the date (2024-03-09) is two days less than where we started instead of 1 day.

Doing arithmetic in UTC is good for when you intend to add or subtract an exact physical time. However when talking about the "local date", not every day is 24 hours. So you should consider if it is more correct for your application to do your arithmetic in local time (as shown in this answer, but not every answer) or in UTC (as shown in another answer).

Don't let convenience dictate where the arithmetic is done (local or UTC). Instead probe the corner cases and decide which is correct for your application.

like image 39
Howard Hinnant Avatar answered Dec 15 '25 01:12

Howard Hinnant