I made two functions that are to calculate beginning timestamp of the day (i.e. at 00:00:00 of the day) and the hour (starting from 1 and up to 24) of a given epoch timestamp.
#include <cstdint>
#include <ctime>
const uint8_t FIRST_HOUR = 0x01; // 01, 02, ..., 24
const uint32_t SECS_PER_HOUR = 3600; // 3600 secs per hour
uint32_t CalcDaiBaseTimestamp(uint32_t in_ts) {
time_t ts = in_ts;
struct tm timeinfo = *localtime(&ts);
timeinfo.tm_hour = 0;
timeinfo.tm_min = 0;
timeinfo.tm_sec = 0;
time_t tmp_base_ts = mktime(&timeinfo);
return (uint32_t)tmp_base_ts;
}
void CalcDaiBaseTimestampAndHour(uint32_t in_ts,
uint32_t& base_ts,
uint8_t& hour_nth) {
base_ts = CalcDaiBaseTimestamp(in_ts);
hour_nth = (in_ts - base_ts) / SECS_PER_HOUR + FIRST_HOUR;
}
CalcDaiBaseTimestampAndHour is invoked from multiple threads.
The code is compiled with g++ (Ubuntu 4.8.4-2ubuntu1~14.04.4) 4.8.4 and the program runs on Ubuntu 14.04 x64.
Most of time my program works well, but I have sometimes observed some "weird" result as shown below:
(timestamp: 1554459477.500) -> (base: 1553990400, hour_nth: 131)
While the correct result should be:
(timestamp: 1554459477.500) -> (base: 1554422400 / hour_nth: 11)
Because:
1554459477.500 = 2019-04-05 10:17:57.500
base_ts = 2019-04-05 00:00:00 = 1554422400
hour_nth = 11
Since the issue happens sometimes so I would suppose that the reason could be thread-safety of some ctime - related functions.
What could cause the "weird" results? Please help me troubleshoot this! If the reason is actually thread-safety of the ctime - related functions then how could I work around this (with some C++ 11 standard library e.g.)?
Could you please show me how to work around this using the date library?
Reference link: https://github.com/HowardHinnant/date
Code:
#include "date/date.h"
#include <iomanip>
#include <iostream>
int
main()
{
using namespace std::chrono;
using namespace date;
using dsec = duration<double>;
sys_time<dsec> tp{dsec{1554459477.500}};
std::cout << std::setprecision(3) << std::fixed
<< tp.time_since_epoch().count()
<< " = " << round<milliseconds>(tp) << '\n';
sys_seconds base_ts = floor<days>(tp);
std::cout << "base_ts = " << base_ts << " = "
<< base_ts.time_since_epoch().count() << '\n';
auto hour_nth = floor<hours>(tp - base_ts) + hours{1};
std::cout << "hour_nth = " << hour_nth.count() << '\n';
}
Output:
1554459477.500 = 2019-04-05 10:17:57.500
base_ts = 2019-04-05 00:00:00 = 1554422400
hour_nth = 11
Notes:
There exist no thread safety issues here.
As long as you don't need time zone support, "date/date.h" is a single-header, header-only library.
Everything above is UTC.
Documentation: https://howardhinnant.github.io/date/date.html
Related
::tm tm{0, 0, 0, 29, 10, 2022 - 1900, 0, 0}; // 10 for November
auto time_t = ::mktime(&tm);
cout << "milliseconds = " << time_t * 1000 << endl;
Above code outputs 1669660200000, which is equivalent to 2022 November 29, 00:00:00. But it is in local timezone. How to get the UTC time for the aforementioned date?
A modern c++17 way with thread-safety will be appreciated.
There's a nit picky weak point in your solution (besides the thread safety issue): The members of tm are not guaranteed to be in the order you are assuming.
The tm structure shall contain at least the following members, in any order.
Using C++17 you can use this C++20 chrono preview library. It is free, open-source and header-only. Your program would look like:
#include "date/date.h"
#include <chrono>
#include <iostream>
int
main()
{
using namespace std;
using namespace chrono;
using namespace date;
sys_time<milliseconds> tp = sys_days{2022_y/11/29};
cout << "milliseconds = " << tp.time_since_epoch().count() << '\n';
}
And the output would be:
milliseconds = 1669680000000
One of the nice advantages of using this library is that it will easily port to C++20. The C++20 version looks like:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std;
using namespace chrono;
sys_time<milliseconds> tp = sys_days{2022y/11/29};
cout << "milliseconds = " << tp.time_since_epoch() << '\n';
}
And outputs:
milliseconds = 1669680000000ms
Demo:
One old school C-style way is to first get the timezone difference and offset it with the value in the question.
static const auto TIMEZONE_OFFSET = [] (const ::time_t seconds)
{ // This method is to be called only once per execution
::tm tmGMT = {}, tmLocal = {};
::gmtime_r(&seconds, &tmGMT); // ::gmtime_s() for WINDOWS
::localtime_r(&seconds, &tmLocal); // ::localtime_s() for WINDOWS
return ::mktime(&tmGMT) - ::mktime(&tmLocal);
}(10000);
::tm tm{0, 0, 0, 29, 10, 2022 - 1900}; // set fields 1 by 1 as the order is not guaranteed
cout << " start of day = " << (::mktime(&tm) - TIMEZONE_OFFSET) << endl;
This question already has answers here:
Converting seconds to hours and minutes and seconds
(11 answers)
Closed 9 months ago.
I am trying to solve a problem where I have a total seconds variable, from which I am trying to determine the hours, minutes and seconds.
I do not want to use any external libraries for this task.
What I have noticed is that my seconds variable seems to result in 1 less than the actual value when it is in int form,
but when it is in double form the answer is correct. Why is this?
I would welcome a different approach, perhaps using the remainder operator.
// Example program
#include <iostream>
#include <string>
int main()
{
int total_seconds;
total_seconds = 3870;
int hours, minutes, seconds;
double total_h, total_m, total_s;
int total_hours_int, total_minutes_int;
total_h = (double)total_seconds / 3600;
total_hours_int = total_seconds / 3600;
hours = total_hours_int;
total_m = (total_h - total_hours_int) * 60;
total_minutes_int = (total_h - total_hours_int) * 60;
minutes = total_minutes_int;
total_s = ((double)total_m - total_minutes_int) * 60;
seconds = ((double)total_m - total_minutes_int) * 60;
//seconds = (double)total_s;
std:: cout << hours;
std:: cout << minutes;
std:: cout << total_s;
std:: cout << seconds;
}
Output : 143029
Update:
The answer below was given before the C++98 tag was added to the question.
The chono library is available since C++11, so you can use it only from that version onwards.
You haven't given any context for this task.
My asnwer below assumes you need to solve the problem in any valid C++ manner (i.e. that it is not mandatory the caculate the numbers "by hand").
If this is the case, you can use the C++ chrono library for that, as shown below. This solution is shorter and less error-prone, and avoids the type issues you had altogether.
The main class I used is std::chrono::duration and it's helper types (as you can see in the link), as well as std::chrono::duration_cast.
#include <iostream>
#include <chrono>
int main()
{
int total_seconds = 3870;
std::chrono::seconds total_secs(total_seconds);
auto hours = std::chrono::duration_cast<std::chrono::hours>(total_secs);
auto mins = std::chrono::duration_cast<std::chrono::minutes>(total_secs - hours);
auto secs = std::chrono::duration_cast<std::chrono::seconds>(total_secs - hours - mins);
std::cout << "totals seconds: " << total_secs.count() << std::endl;
std::cout << " hours: " << hours.count() << std::endl;
std::cout << " minutes: " << mins.count() << std::endl;
std::cout << " seconds: " << secs.count() << std::endl;
}
Output:
totals seconds: 3870
hours: 1
minutes: 4
seconds: 30
I've reopened answear since it was updated to C++98.
Before C++11 it can be done nicely using standard library:
#include <iostream>
#include <string>
#include <ctime>
int main()
{
int seconds;
while (std::cin >> seconds) {
std::tm t = {};
t.tm_sec = seconds;
t.tm_mday = 1;
mktime(&t);
t.tm_hour += t.tm_yday * 24;
char buf[32];
strftime(buf, sizeof(buf), "%H:%M:%S", &t);
std::cout << t.tm_yday << ' ' << seconds << " = " << buf << '\n';
}
return 0;
}
https://godbolt.org/z/ceWWfoP6P
I have a collection of unix timestamps I am converting to boost (1.65.1) dates but the conversions seem to break down when they get too far in the future. Anything around 2040 and beyond seems to be wrapping in some way back to post 1900.
Given the following code...
{
std::time_t t = 1558220400;
boost::gregorian::date date = boost::posix_time::from_time_t(t).date();
std::cout << "Date: " << date << std::endl;
}
{
std::time_t t = 2145500000;
boost::gregorian::date date = boost::posix_time::from_time_t(t).date();
std::cout << "Date: " << date << std::endl;
}
{
std::time_t t = 2500000000;
boost::gregorian::date date = boost::posix_time::from_time_t(t).date();
std::cout << "Date: " << date << std::endl;
}
... I get the following output...
Date: 2019-May-18
Date: 2037-Dec-27
Date: 1913-Feb-13
... however I am expecting the following output...
Expected output:
Date: 2019-May-18
Date: 2037-Dec-27
Date: 2049-Mar-22
Is there something I am doing wrong here?
It appears that you're experiencing the Year 2038 problem.
The largest number representable by 32 bit signed integer is 2'147'483'647. 2'147'483'647 seconds since 00:00:00 UTC on 1st of January 1970 (the UNIX epoch) is 03:14:07 UTC on 19th of January 2038. Any UNIX time after that is unrepresentable using a 32 bit signed integer.
Either std::time_t on the system is 32 bits, or it is converted into 32 bits inside the boost library. You can see from the source that boost converts the input into long using static_cast (and still does in version 1.70). long is 32 bits for example on windows, even on 64 bit architectures. It is 64 bits on many other systems such as 64 bit Linux.
In C++20 this can now look like:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
{
std::time_t t = 1558220400;
auto date = floor<days>(system_clock::from_time_t(t));
std::cout << "Date: " << date << '\n';
}
{
std::time_t t = 2145500000;
auto date = floor<days>(system_clock::from_time_t(t));
std::cout << "Date: " << date << '\n';
}
{
std::time_t t = 2500000000;
auto date = floor<days>(system_clock::from_time_t(t));
std::cout << "Date: " << date << '\n';
}
}
Output:
Date: 2019-05-18
Date: 2037-12-27
Date: 2049-03-22
If your time_t is 32 bits, then the above isn't quite sufficient to fix the problem. In that case, you must avoid the C API completely. This looks like:
{
auto t = 1558220400;
auto date = floor<days>(sys_seconds{seconds{t}});
std::cout << "Date: " << date << '\n';
}
{
auto t = 2145500000;
auto date = floor<days>(sys_seconds{seconds{t}});
std::cout << "Date: " << date << '\n';
}
{
auto t = 2500000000;
auto date = floor<days>(sys_seconds{seconds{t}});
std::cout << "Date: " << date << '\n';
}
If your vendor isn't shipping this part of C++20 yet, a free, open-source preview that works with C++11/14/17 is available.1
Just add:
#include "date/date.h"
...
using namespace date;
1 Full disclosure: I am the lead author of this library. I am not pursuing any financial gain from this effort. But sometimes people get grumpy if I don't fully disclose this information.
As noted by eerorika this is caused by integer overflow since the boost::posix_time::from_time_t is casting the 64bit time_t value to a 32 bit long (on Windows).
If you are in a pinch and find yourself in the same position then you can use the following function to perform the conversion:
boost::gregorian::datetimet_to_date(time_t t)
{
auto time = boost::posix_time::ptime(boost::gregorian::date(1970,1,1));
int64_t current_t = t;
long long_max = std::numeric_limits<long>::max();
while(current_t > 0)
{
long seconds_to_add = 0;
if(current_t >= long_max)
seconds_to_add = long_max;
else
seconds_to_add = static_cast<long>(current_t);
current_t -= seconds_to_add;
time += boost::posix_time::seconds(seconds_to_add);
}
return time.date();
}
What's a standard way to get a date time in ISO8601 format on Windows using C++? Specifically, I would like it to be formatted as:
2017-02-22T10:00:00.123-05:00
2017-02-22T10:00:00.123 >>> -05:00 <<< # how to print the offset?
I was looking into combining the output of GetLocalTime and GetTimeZoneInformation, but this looks esoteric. There are similar questions on SO, however, I've not found a single one that prints UTC offset in a desired format. Is there a better approach?
The format specifier %z gives you the timezone offset as described in the documentation (e.g. MSDN on strftime) but lefts out the ':'. You can use it like this to get the ':' into your string:
struct tm tmNow;
time_t now = time(NULL); // Get the current time
_localtime64_s(&tmNow, &now);
char bufferTime[26];
char bufferTimezoneOffset[6];
size_t tsizTime = strftime(bufferTime, 26, "%Y-%m-%dT%H:%M:%S", &tmNow); // The current time formatted "2017-02-22T10:00:00"
size_t tsizOffset = strftime(bufferTimezoneOffset, 6, "%z", &tmNow); // The timezone offset -0500
strncpy_s(&bufferTime[tsizTime], 26, bufferTimezoneOffset, 3); // Adds the hour part of the timezone offset
bufferTime[tsizTime + 3] = ':'; // insert ':'
strncpy_s(&bufferTime[tsizTime + 4], 26, &bufferTimezoneOffset[3], 3); // Adds the minutes part of the timezone offset
puts(bufferTime); // Your output: "2017-02-22T10:00:00-05:00"
I left out the milliseconds, as they are not part of the localtime as far as I know.
Maybe something like this. We call GetLocalTime and GetTimeZoneInformation then pass it to the function which returns formatted string.
This is written quickly, not tested besides observing the fact it returns correct result on my machine now. It operates on the fact that SYSTEMTIME has a member Bias where UTC = Localtime + Bias and Bias is set in minutes. So get hours by dividing by 60 and taking absolute value of that. Then we get the minutes in similar way and set the sign depending on if Bias > 0
#include <Windows.h>
#include <string>
#include <sstream>
#include <iomanip>
#include <cmath>
std::string format_system_time(const SYSTEMTIME& sys_time, const TIME_ZONE_INFORMATION& time_zone)
{
std::ostringstream formatted_date_time;
formatted_date_time << std::setfill('0');
formatted_date_time << sys_time.wYear << "-" << std::setw(2) << sys_time.wMonth << "-" <<
std::setw(2) << sys_time.wDay << "T" << std::setw(2) << sys_time.wHour << ":" <<
std::setw(2) << sys_time.wMinute << ":" << std::setw(2) << sys_time.wSecond << "." <<
std::setw(3) << sys_time.wMilliseconds;
//UTC = localtime + bias; bias is in minutes
int utc_offset_hours = time_zone.Bias / 60;
int utc_offset_minutes = std::abs(time_zone.Bias - (utc_offset_hours * 60));
char offset_sign = time_zone.Bias > 0 ? '-' : '+';
formatted_date_time << offset_sign << std::setw(2) << std::abs(utc_offset_hours) << ":" << utc_offset_minutes;
return formatted_date_time.str();
}
int main(int argc, char* argv[])
{
SYSTEMTIME date_and_time;
GetLocalTime(&date_and_time);
TIME_ZONE_INFORMATION time_zone;
GetTimeZoneInformation(&time_zone);
auto& formatted_date_time = format_system_time(date_and_time, time_zone);
return 0;
}
I don't think there is a drop-in solution for c++ on Windows. The closest you can get is InternetTimeFromSystemTime but it is only documented to support RFC1123.
You probably have to code it yourself with GetLocalTime + GetTimeZoneInformation + wsprintf (or GetTimeZoneInformationForYear if you are not dealing with the current time).
Using Howard Hinnant's free, open-source timezone library, which works on VS-2013 and later, but does require some installation:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace std;
using namespace std::chrono;
using namespace date;
auto zt = make_zoned(current_zone(), floor<milliseconds>(system_clock::now()));
cout << format("%FT%T%Ez\n", zt);
}
This just output for me:
2017-02-22T17:29:03.859-05:00
I have a project about cars with GPS. I need to return the start and the finish moment for each car.
So we have:
time_t x, y;
Because I will use later them for a transformation.
I have a problem. I read from an external file data in this format:
auto1
1439467747492
auto1
1439467748512
...etc.
auto1->name of the car;
1439467747492->the moment in time of the car
I tried to get the first position of the first moment and the last moment for each car. This is the code in C++:
long test = momenti[choice1]/1000;
time_t x = test;
cout << " Momentul initial:\n " << ctime(&x) << endl;
long test1 = momentf[choice1] / 1000;
time_t y = test1;
cout << " Momentul final:\n " << ctime(&y) << endl;
I receive the same date for every car. Is something like momenti[i]=momentf[i]
What did I do wrong?
It is not good. According epoch converter we should get this : GMT: Thu, 13 Aug 2015 12:09:07 GMT
Here is how you can get this output with C++11/14 and using this free, open source date library which extends the C++ <chrono> library to handle dates.
#include "date.h"
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
using namespace std;
using namespace date;
using time_point = std::chrono::time_point<system_clock, milliseconds>;
auto tp = time_point{1439467747492ms};
auto dp = floor<days>(tp);
auto time = make_time(tp - dp);
auto ymd = year_month_day{dp};
cout << "GMT: " << weekday{dp} << ", " << ymd.day() << ' ' << ymd.month()
<< ' ' << ymd.year() << ' ' << time << " GMT\n";
}
Output:
GMT: Thu, 13 Aug 2015 12:09:07.492 GMT
I threw in the fractional seconds for fun, and it seemed a shame to waste them (the C lib won't give them to you). If you really don't want them, it is easy to fix:
auto time = make_time(floor<seconds>(tp) - dp);
Now the output is:
GMT: Thu, 13 Aug 2015 12:09:07 GMT
You need C++14 for the 1439467747492ms above. If you only have C++11 you can sub in this instead: milliseconds{1439467747492}. If you only have C++03, then you are 13 years behind the times and stuck with ctime. ;-)
The chrono solution will offer you greater type safety, more flexibility, and greater performance.
If i can fix and the latitude and longitude problem would be great lol
If you can translate latitude and longitude into an IANA timezone name (and there are tools to do this), I've got a IANA timezone database parser for you which interoperates with <chrono> and "date.h".
#include <iostream>
#include <cstring>
#include <time.h>
using namespace std;
int main()
{
long test = 1439467747492;
time_t x = test;
cout << ctime( &x ) << endl;
return 0;
}
Produces
Tue Sep 18 20:15:32 1990