Oscar K
Oscar K

Reputation: 305

Get current time of day in c++

case

I need to write a program that moves files around at times that are set in a configuration file. The time can be 00:00:01 seconds untill 24:00:00 hours. This is converted into seconds. So if somebody wants to move a file at 12:00:00 pm today, the move time is 12 * 60 * 60 = 43200 seconds. This is done every day and the program needs to check if that time is reached.

I use the chrono library to get the time now since epoch in seconds using:

auto dayInSeconds = 86400;
auto currentTime = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock().now().time_since_epoch());
auto timeWithoutDays = currentTime % dayInSeconds;

std::cout << "time in seconds today: " << timeWithoutDays.count() << std::endl;

problem

This shows me the current time since epoch in seconds. But now for example ( 13:45 Amsterdam time) it returns a number of: 42294. If I run it exactly five seconds later in a loop it returns 42299. So the counting seems to be correct. What is not correct, is that 42299 seconds is 1174 hours (42299/ 60 /60). Which should mean that is now 11:somewhat AM but its 13:32 PM. Or not? What am I doing wrong? I just need to know, how many seconds have passed since 00:00:00 this day. So i can check if the user set time is passed and stuff needs to be done.

I would like to keep using the chrono library for all sorts of reasons, but mainly because I understand that one. So if answers use that library, it would be a great help. I have a feeling i'm doing something completely stupid.

fix

For any other that seeks the same answer. I fixed it like this, it seems to work:

auto dayInSeconds = 86400;
auto amsterdamUTCPlusTime = 7200;
auto currentTime = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock().now().time_since_epoch());
auto timeWithoutDays = currentTime % dayInSeconds;
auto currentTimeInSeconds = timeWithoutDays.count() + amsterdamUTCPlusTime;
std::cout << "time in seconds today: " << currentTimeInSeconds << std::endl;

Upvotes: 0

Views: 2972

Answers (2)

Howard Hinnant
Howard Hinnant

Reputation: 218770

C++20 brings extensions to <chrono> to deal with timezones. It isn't shipping yet (to the best of my knowledge). But here is what it will look like:

#include <chrono>
#include <iostream>

int
main()
{
    using namespace std;
    using namespace std::chrono;

    zoned_time zt{"Europe/Amsterdam", floor<seconds>(system_clock::now())};
    auto lt = zt.get_local_time();
    auto tod = lt - floor<days>(lt);
    cout << "time in seconds today: " << tod.count() << '\n';
    cout << hh_mm_ss{tod} << '\n';
}

Example output:

time in seconds today: 71923
19:58:43

If your computer's local time zone setting is already set to "Europe/Amsterdam", then "Europe/Amsterdam" above can be replaced with current_zone().

This gets the current time in UTC, truncates it to seconds precision, and then pairs it with the "Europe/Amsterdam" time_zone to create a zoned_time. Then the local time is extracted from the zoned_time. The local time of day is simply the local time minus the beginning of that day (floor<days>(lt)). This is stored in tod which has type seconds. Wrapping it in a hh_mm_ss prints it out in a hh:mm:ss format.

There exists a free, open-source C++20 <chrono> preview library which can be used with C++11/14/17 to do this. To use it, it must be installed. There's a single source file to be compiled, tz.cpp, and it needs to have access to the IANA time zone database, which can be automatically downloaded with specific build settings.

The source code above must be trivially modified by adding #include "date/tz.h" and using namespace date;. In C++11 and 14, change zoned_time to zoned_seconds, and hh_mm_ss to hh_mm_ss<seconds>.

Another possibility is to build your own UTC offset calculator for just Amsterdam (assuming current rules). The advantage of this is that it can use of subset of the free, open-source C++20 <chrono> preview library which is header-only, and thus requires no installation, and does not need the IANA time zone database. That could like this:

#include "date/date.h"
#include <chrono>
#include <iostream>

int
main()
{
    using namespace date;
    using namespace std;
    using namespace std::chrono;

    auto AmsterdamOffset = [](system_clock::time_point tp)
        {
            auto const y = year_month_day{floor<days>(tp)}.year();
            auto const start = sys_days{Sunday[last]/March/y} + 1h;
            auto const end = sys_days{Sunday[last]/October/y} + 1h;
            if (start <= tp && tp < end)
                return 2h;
            return 1h;
        };

    auto now = floor<seconds>(system_clock::now());
    auto local_now = now + AmsterdamOffset(now);
    auto tod = local_now - floor<days>(local_now);
    cout << "time in seconds today: " << tod.count() << '\n';
    cout << hh_mm_ss{tod} << '\n';
}

This program hardcodes the fact that Amsterdam daylight saving begins on the last Sunday of March at 01:00:00 UTC and ends on the last Sunday of October at 01:00:00 UTC.

After that, the program logic is much like the C++20 solution shown above. In C++11, 1h and 2h will have to be changed to hours{1} and hours{2} respectively.

And yet another approach: Posix time zones

There is also a Posix time zone library at this link in ptz.h. This is also a header-only library, so no install issues. It allows you to use the C++20 zoned_time combined with Posix time zones. This will give you the same results as the example above with the "hard coded" rules for Amsterdam (which are valid back through 1978).

#include "date/ptz.h"
#include <chrono>
#include <iostream>

int
main()
{
    using namespace date;
    using namespace std;
    using namespace std::chrono;

    // Amsterdam rules
    Posix::time_zone tz{"CET-1CEST,M3.5.0,M10.5.0/3"};
    zoned_time zt{tz, floor<seconds>(system_clock::now())};
    auto lt = zt.get_local_time();
    auto tod = lt - floor<days>(lt);
    cout << "time in seconds today: " << tod.count() << '\n';
    cout << hh_mm_ss{tod} << '\n';
}

The above assumes C++17. If in C++11 or 14 the syntax becomes a little messier:

zoned_time<seconds, Posix::time_zone> zt{tz, floor<seconds>(system_clock::now())};

The Posix::time_zone is not part of the C++20 <chrono> library, but is compatible with it. It can be used with the C++20 std::chrono::zoned_time class template as shown above.

Upvotes: 3

Farhad Sarvari
Farhad Sarvari

Reputation: 1081

You can use localtime function and get the current time from system.

 int getIntTime()
 {
  struct timeb now;
  struct tm *curtime;
  curtime = localtime(&now);
  return(curtime->tm_hour * 10000L + curtime->tm_min * 100L + curtime->tm_sec);
 }

And also you should convert the set time in confgi file to same as output of this function and compare them as follow:

if(getIntTime()  >= converted_time_configfile )
{
   //do processing
}

Upvotes: 1

Related Questions