Search code examples
c++c++-chrono

Number of seconds since midnight


I wrote the below code to get the number of seconds since midnight.

However, I'm not great with the C time date structs. Is there a simpler way of doing this using a standard C++ library?

// Get today's date
time_t aTime = time(NULL);

// Set the time to midnight
struct tm* tm = localtime(&aTime);
tm->tm_sec = 0;
tm->tm_min = 0;
tm->tm_hour = 0;
tm->tm_isdst = -1;
time_t midnight = mktime(tm);

// Create object representing now
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);

// Number of seconds (now) since Epoch
const uint64_t nowSecsSinceEpoch = now.tv_sec;

// Number of seconds (now) since midnight = seconds (now) since Epoch minus seconds (at midnight) since Epoch
const uint64_t nowSecsSinceMidnight = nowSecsSinceEpoch - midnight;

Solution

  • It depends on if you mean time since midnight UTC, or time since midnight local time, or perhaps in some non-local, far away time zone.

    This is also made much easier in C++20. But there exists a preview of the C++20 parts of the <chrono> library that can be used with C++11-17.

    Time since midnight UTC

    #include <chrono>
    #include <iostream>
    
    int
    main()
    {
        using namespace std;
        using namespace std::chrono;
    
        auto now = system_clock::now();
        auto today = floor<days>(now);
        auto tod = duration_cast<seconds>(now - today);
    }
    

    This simply gets the current time (UTC), truncates it to a days-precision time_point, and then subtracts the two and truncates that difference to seconds precision.

    Time since local midnight

    #include <chrono>
    #include <iostream>
    
    int
    main()
    {
        using namespace std;
        using namespace std::chrono;
    
        auto now = current_zone()->to_local(system_clock::now());
        auto today = floor<days>(now);
        auto tod = duration_cast<seconds>(now - today);
    }
    

    This version finds your computer's currently set local time zone, and then gets the current local time via the time_zone's to_local() member function. And then proceeds as before.

    Time since some other midnight

    #include <chrono>
    #include <iostream>
    
    int
    main()
    {
        using namespace std;
        using namespace std::chrono;
    
        auto now = locate_zone("Australia/Sydney")->to_local(system_clock::now());
        auto today = floor<days>(now);
        auto tod = duration_cast<seconds>(now - today);
    }
    

    Finally, this version finds the time_zone associated with Sydney Australia, and then uses that time zone and proceeds as before.

    The C++20 preview <chrono> library is free and open-source. It puts everything in namespace date, and in two headers (and one source):

    • date.h: A header-only library that will do the UTC part, but has no time zone support.

    • tz.h: For the time zone support. This requires some installation.