How to convert gps time to utc in c++? - c++

I am collecting GPS time (in ns) from a sensor and I am looking for a way to convert that to a UTC time in C++.
I have a working code before in python.
time_gps = time_gps * 10**(-9) # Converts ns -> s
gps_epoch = pd.datetime(year=1980, month=1, day=6)
delta = pd.to_timedelta(time_gps, unit='s')
time = gps_epoch + delta - pd.to_timedelta(19, unit='s')
Using the link "Using std::chrono / date::gps_clock for converting a double gps timestamp to utc/tai" helped me figure out how to convert from GPS time to UTC.
uint64_t gps_input_ns = 1281798087485516800;
date::gps_time<std::chrono::nanoseconds> gt_nano{date::round<std::chrono::nanoseconds>(std::chrono::duration<uint64_t, std::nano>{gps_input_ns})};
auto utc_nano = date::clock_cast<date::utc_clock>(gt_nano);
std::cout << utc_nano << " UTC\n";
Output: 2020-08-18 15:01:09.485516800 UTC
My next question is, how can I extract the date and time from the variable "utc_nano"? I'm not very familiar with chrono or the date library and therefore having problems trying to separate the date and time. Any help would be much appreciated.

I'm assuming that leap seconds are important to you since you're dealing with gps time which represents the physical seconds that are labeled leap seconds by UTC. It is fairly tricky to manipulate date/times with leaps seconds, which is why Unix Time is so popular in computer systems.
In the C++20 chrono preview library, Unix Time is modeled by sys_time, whereas true UTC is modeled by utc_time. The only difference between these two models is that sys_time doesn't count leap seconds and utc_time does.
The advantage of sys_time is that there exists a fast and efficient algorithm for translating the time duration since 1970-01-01 00:00:00 into fields: year, month, day, hour, minute, second, subseconds. So if you want to break utc_time into these fields, the trick is to first turn utc_time into sys_time, while remembering whether or not your utc_time is referencing a leap second. Indeed, this is exactly what the streaming operator for utc_time does.
There exists a helper function get_leap_second_info to aid in doing this. This function takes a utc_time and returns a {is leap second, count of leap seconds} struct. The first member is true if the argument refers to a leap second, the second argument tells you how many leap seconds there have been between the argument and 1970. So the first step is to get this information for utc_nano:
auto info = get_leap_second_info(utc_nano);
Now you can create a sys_time with this information. Since sys_time is just like utc_time excluding leap seconds, you can just subtract off the number of leap seconds that have occurred:
sys_time<nanoseconds> sys_nano{utc_nano.time_since_epoch() - info.elapsed};
Now you have a count of nanoseconds in Unix Time. Truncating to days precision gives you a count of days in Unix Time:
auto sys_day = floor<days>(sys_nano);
sys_day is a date. The time of day is simply the difference between the nanoseconds-precision time_point and the days-precision time_point:
auto tod = sys_nano - sys_day;
tod is a time. It is the duration since midnight. It may be short by a second. That information is in info.is_leap_second.
If you want these types as "field types", you could convert sys_day to type year_month_day:
year_month_day ymd = sys_days;
year_month_day has getters for year, month and day.
You can convert tod into a {hours, minutes, seconds, nanoseconds} struct with:
hh_mm_ss hms{tod};
This has getters: hours(), minutes(), seconds(), and subseconds(). The above syntax assumes C++17. If in C++11 or 14, the syntax is:
hh_mm_ss<nanoseconds> hms{tod};
hh_mm_ss doesn't directly support a count of 60s, but that information is still in info.is_leap_second. E.g.
std::cout << hms.seconds().count() + info.is_leap_second << '\n';
That will output 60 if and only if info.is_leap_second is true.

You can even try this code which makes use of C time related functions
uint64_t ns = 1281798087485516800ULL + 315964800000000000ULL; // offset between gps epoch and unix epoch is 315964800 seconds
struct timespec ts;
ts.tv_sec = ns / 1000000000ULL;
ts.tv_nsec = ns % 1000000000ULL;
struct tm stm;
gmtime_r(&ts.tv_sec, &stm);
std::cout << stm.tm_year + 1900 << "-" << stm.tm_mon + 1 << "-" << stm.tm_mday << " " << stm.tm_hour << ":" << stm.tm_min << ":" << stm.tm_sec << std::endl;

Related

Converting a decimal GPS time to UTC

There's many similar questions out there but I haven't found one specific to the GPS output data I am receiving. The data from my GPS is in decimal form:
GPS Week: 2145 and GPS Time: 330374.741371 (the manual says this is a double that represents the "time of week in seconds")
I'm trying to convert this time into human readable UTC time. I'm using old C++14, not 20, so I can't just use the to_utc() function I don't think. I'm mostly confused about the decimal. On this website: https://www.labsat.co.uk/index.php/en/gps-time-calculator it looks like the data is "secondsOfTheWeek.secondsOfTheDay. I'm not sure how to convert this to UTC time...
I believe this output data is the number of seconds since the GPS epoch time of midnight, Jan. 6 1980. And I know it doesn't count leap seconds so that has to be taken into account too. If I had some guidance on how to start getting this into UTC time I think I could figure out the rest, but I'm not really sure where to start...
Eventually I want to convert the time into a string to set an OS system w that time using "date -s "16 AUG 2021 13:51:00" or something like that. But first I just need to convert this GPS time.
There exists a free, open-source preview to the C++20 chrono bits which works with C++14.
#include "date/tz.h"
#include <chrono>
date::utc_seconds
convert(int gps_week, double gps_time)
{
using namespace date;
using namespace std::chrono;
int upper = static_cast<int>(gps_time);
auto gps_t = gps_seconds{} + weeks(gps_week) + seconds{upper};
return clock_cast<utc_clock>(gps_t);
}
This first forms a gps_time by adding the appropriate number of weeks to the gps epoch, and then the seconds.
Next you use clock_cast to transform this into utc_time (which does include leap seconds).
This can be used like so:
#include <iostream>
int
main()
{
using namespace date;
using namespace std;
cout << convert(2145, 330374.741371) << '\n';
}
Which outputs:
2021-02-17 19:45:56
The clock_cast changes the epoch from 1980-01-06 to 1970-01-01 and adds in the number of leap seconds that occur between the gps epoch and the utc time point. If the gps input happens to correspond to a leap second, this will properly print "60" in the seconds field. For example:
cout << convert(1851, 259216) << '\n'; // 2015-06-30 23:59:60
Some installation is required.
Further information
This Wikipedia article says that the time of week actually comes in units of 1.5 seconds, ranging in value from 0 to 403,199.
static_assert(403'200 * 1.5 == 7 * 24 * 60 * 60);
If one finds themself dealing with the data in this form, here is an alternate convert implementation which can deal with this input data directly:
using gps_tow = std::chrono::duration<int, std::ratio<3, 2>>;
auto
convert(date::weeks gps_week_num, gps_tow tow)
{
using namespace date;
return clock_cast<utc_clock>(gps_seconds{} + gps_week_num + tow);
}
The first step is to define a duration unit of 1.5 seconds. This type is called gps_tow above.
The convert function now takes two strictly typed parameters: a count of weeks, and a count of gps_tow. Then one simply adds these parts together, along with the gps epoch, and clock_cast's it to utc_clock.
It can be used like so:
cout << convert(weeks{1851}, gps_tow{172811}) << '\n';
The output for this example is:
2015-06-30 23:59:60.5

Using C++20 chrono, how to compute various facts about a date

https://www.timeanddate.com/date/weekday.html computes various facts about a day of the year, for example:
Given an arbitrary date, how can these numbers be computed with the C++20 chrono specification?
This is remarkably easy with the C++20 chrono specification. Below I show a function which inputs an arbitrary date, and prints this information to cout. Though at the time of this writing, the C++20 chrono specification isn't yet shipping, it is approximated by a free, open-source library. So you can experiment with it today, and even include it in shipping applications as long as you adopt C++11 or later.
This answer will take the form of a function:
void info(std::chrono::sys_days sd);
sys_days is a day-precision time_point in the system_clock family. That means it is simply a count of days since 1970-01-01 00:00:00 UTC. The type alias sys_days is new with C++20, but the underlying type has been available since C++11 (time_point<system_clock, duration<int, ratio<86400>>>). If you use the open-source C++20 preview library, sys_days is in namespace date.
The code below assumes function-local:
using namespace std;
using namespace std::chrono;
to reduce verbosity. If you are experimenting with the open-source C++20 preview library, also assume:
using namespace date;
Heading
To output the first two lines is simple:
cout << format("{:%d %B %Y is a %A}\n", sd)
<< "\nAdditional facts\n";
Just take the date sd and use format with the familiar strftime/put_time flags to print out the date and text. The open-source C++20 preview library hasn't yet integrated the fmt library, and so uses the slightly altered format string "%d %B %Y is a %A\n".
This will output (for example):
26 December 2019 is a Thursday
Additional facts
Common intermediate results computed once
This section of the function is written last, because one doesn't yet know what computations will be needed multiple times. But once you know, here is how to compute them:
year_month_day ymd = sd;
auto y = ymd.year();
auto m = ymd.month();
weekday wd{sd};
sys_days NewYears = y/1/1;
sys_days LastDayOfYear = y/12/31;
We will need the year and month fields of sd, and the weekday (day of the week). It is efficient to compute them once and for all in this manner. We will also need (multiple times) the first and last days of the current year. It is hard to tell at this point, but it is efficient to store these values as type sys_days as their subsequent use is only with day-oriented arithmetic which sys_days is very efficient at (sub-nanosecond speeds).
Fact 1: day number of year, and number of days left in year
auto dn = sd - NewYears + days{1};
auto dl = LastDayOfYear - sd;
cout << "* It is day number " << dn/days{1} << " of the year, "
<< dl/days{1} << " days left.\n";
This prints out the day number of the year, with January 1 being day 1, and then also prints out the number of days remaining in the year, not including sd. The computation to do this is trivial. Dividing each result by days{1} is a way to extract the number of days in dn and dl into an integral type for formatting purposes.
Fact 2: Number of this weekday and total number of weekdays in year
sys_days first_wd = y/1/wd[1];
sys_days last_wd = y/12/wd[last];
auto total_wd = (last_wd - first_wd)/weeks{1} + 1;
auto n_wd = (sd - first_wd)/weeks{1} + 1;
cout << format("* It is {:%A} number ", wd) << n_wd << " out of "
<< total_wd << format(" in {:%Y}.\n}", y);
wd is the day of the week (Monday thru Sunday) computed at the top of this article. To perform this computation we first need the dates of the first and last wd's in the year y. y/1/wd[1] is the first wd in January, and y/12/wd[last] is the last wd in December.
The total number of wds in the year is just the number of weeks between these two dates (plus 1). The sub-expression last_wd - first_wd is the number of days between the two dates. Dividing this result by 1 week results in an integral type holding the number of weeks between the two dates.
The week number is done the same way as the total number of weeks except one starts with the current day instead of the last wd of the year: sd - first_wd.
Fact 3: Number of this weekday and total number of weekdays in month
first_wd = y/m/wd[1];
last_wd = y/m/wd[last];
total_wd = (last_wd - first_wd)/weeks{1} + 1;
n_wd = (sd - first_wd)/weeks{1} + 1;
cout << format("* It is {:%A} number }", wd) << n_wd << " out of "
<< total_wd << format(" in {:%B %Y}.\n", y/m);
This works just like Fact 2, except we start with the first and last wds of the year-month pair y/m instead of the entire year.
Fact 4: Number of days in year
auto total_days = LastDayOfYear - NewYears + days{1};
cout << format("* Year {:%Y} has ", y) << total_days/days{1} << " days.\n";
The code pretty much speaks for itself.
Fact 5 Number of days in month
total_days = sys_days{y/m/last} - sys_days{y/m/1} + days{1};
cout << format("* {:%B %Y} has ", y/m) << total_days/days{1} << " days.\n";
The expression y/m/last is the last day of the year-month pair y/m, and of course y/m/1 is the first day of the month. Both are converted to sys_days so that they can be subtracted to get the number of days between them. Add 1 for the 1-based count.
Use
info can be used like this:
info(December/26/2019);
or like this:
info(floor<days>(system_clock::now()));
Here is example output:
26 December 2019 is a Thursday
Additional facts
* It is day number 360 of the year, 5 days left.
* It is Thursday number 52 out of 52 in 2019.
* It is Thursday number 4 out of 4 in December 2019.
* Year 2019 has 365 days.
* December 2019 has 31 days.
Edit
For those who are not fond of the "conventional syntax", there is a complete "constructor syntax" that can be used instead.
For example:
sys_days NewYears = y/1/1;
sys_days first_wd = y/1/wd[1];
sys_days last_wd = y/12/wd[last];
can be replaced by:
sys_days NewYears = year_month_day{y, month{1}, day{1}};
sys_days first_wd = year_month_weekday{y, month{1}, weekday_indexed{wd, 1}};
sys_days last_wd = year_month_weekday_last{y, month{12}, weekday_last{wd}};

Alternative to mktime in C++

uint64_t timestamp_nanoseconds = 634019142119225390;
time_t result = timestamp_nanoseconds / 1000000000;
struct tm * timeinfo = gmtime(&result);
struct tm dateInfo ;
dateInfo.tm_mday = timeinfo->tm_mday ;
dateInfo.tm_mon = timeinfo->tm_mon ;
dateInfo.tm_year = timeinfo->tm_year ;
dateInfo.tm_hour = 0 ;
dateInfo.tm_min = 0 ;
dateInfo.tm_sec = 0 ;
time_t NoOfSecInDate = mktime ( &dateInfo );
From the input timestamp in nanoseconds, we can get the date as shown in the code which got set in dateInfo structure. From that point, We need to find elapsed time in seconds from the midnight of the input date.
We get input as elapsed time in nanoseconds since epoch Jan 1 1970. Say for example , 634019142119225390. From that we extract date with time set to 00:00:00 , we need to find the elapsed time in unsigned integer representing elapsed time in nanoseconds since Unix epoch 00:00 UTC on 1st January 1970 from midnight of that date.
Solution should be for any given timestamp and not for a current date.
In this above code , we find that mktime function takes about 64 microseconds to complete which is lot of time and is not expected
Do you have any other alternative to mktime function which achieves the same result that returns the elapsed time in seconds since epoch but with lesser amount of time.
This can be done highly efficiently with <chrono> and Howard Hinnant's free, open-source, date-time library.
Given:
uint64_t timestamp_nanoseconds = 634019142119225390;
Form a std::chrono::time_point based on system_clock and nanoseconds. The date-time library makes that very easy with a template type alias for such types:
sys_time<nanoseconds> ts{nanoseconds{timestamp_nanoseconds}};
Next you can truncate this nanosecond-precision time_point to a days precision time_point with:
auto sd = floor<days>(ts);
sd is a system_clock time_point counting days since the epoch (as opposed to nanoseconds). Next you can convert sd into a year_month_day, which is exactly what it sounds like: a {year, month, day} struct with getters for each field:
year_month_day ymd = sd;
And the relevant part for this question, this is how you get nanoseconds since midnight:
auto tod = ts - sd;
And if you want that in terms of seconds, it
auto tod = duration_cast<seconds>(ts - sd);
In all, to go from a uint64_t count of nanoseconds, to seconds in current day (UTC), and time it, it is:
auto t0 = steady_clock::now();
sys_time<nanoseconds> ts{nanoseconds{timestamp_nanoseconds}};
auto tod = duration_cast<seconds>(ts - floor<days>(ts));
auto t1 = steady_clock::now();
Given the input of 634019142119225390, and compiling this using clang on macOS at -O3, this results in:
tod == 15942s
and takes about 200ns.
This formulation will work correctly for both positive and negative inputs, due to the use of floor<days>, as opposed to duration_cast<days>. For example an input of -1'000'000'000 gives a time of day of 86399s.
You are trying to get the time at the start of the same UTC day. To do that, you can just do the calculation in seconds:
struct timezone tz = {0, 0};
struct timeval start, end;
gettimeofday(&start, &tz);
uint64_t timestamp_nanoseconds = 634019142119225390ULL;
time_t result = timestamp_nanoseconds / 1000000000ULL;
time_t day = result - (result % 86400);
gettimeofday(&end, &tz);
struct timeval dsec;
timersub(&end, &start, &dsec);
printf("calc took %ld sec %ld usec.\n",
dsec.tv_sec, dsec.tv_usec, s);
printf("UTC: %s",asctime(gmtime(&now)));
printf("Day: %s",asctime(gmtime(&day)));
This takes much less time:
calc took 0 sec 1 usec. total 0.000000
UTC: Sat Feb 3 04:25:42 1990
Day: Sat Feb 3 00:00:00 1990
If you want to get the start of the day in your local timezone you can add an offset to the calculation of day.

std::chrono: Set clock's epoch to 1/1/0000

Is it possible to manually set the epoch date/time to the January 1, 0000, so I might use the std::chrono::time_point::time_since_epoch to calculate the difference between a given date and January 1, 0000?
I tried the following:
#include <iostream>
#include <chrono>
#include <ctime>
int main(int argc, char*argv[])
{
std::tm epochStart = {};
epochStart.tm_sec = 0;
epochStart.tm_min = 0;
epochStart.tm_hour = 0;
epochStart.tm_mday = 0;
epochStart.tm_mon = 0;
epochStart.tm_year = -1900;
epochStart.tm_wday = 0;
epochStart.tm_yday = 0;
epochStart.tm_isdst = -1;
std::time_t base = std::mktime(&epochStart);
std::chrono::system_clock::time_point baseTp=
std::chrono::system_clock::from_time_t(base);
std::time_t btp = std::chrono::system_clock::to_time_t(baseTp);
std::cout << "time: " << std::ctime(&btp);
}
but this gives me
time: Thu Jan 1 00:59:59 1970
I would avoid std::time_t altogether. Using days_from_civil from chrono-Compatible Low-Level Date Algorithms, you can immediately compute any difference between std::chrono::system_clock::time_point, and any date in the proleptic Gregorian calendar1.
In addition to days_from_civil which takes a year/month/day triple and converts it into a count of days before/since 1970-01-01 (a chrono-compatible epoch), it is also convenient to create a custom chrono::duration to represent 24 hours:
typedef std::chrono::duration
<
int,
std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>
> days;
Now you can create any epoch you want with just:
constexpr days epoch = days(days_from_civil(0, 1, 1)); // 0000-01-01
In C++1y this is even a compile-time computation!
And you can subtract this std::chrono::duration from any other std::chrono::duration:
auto delta = std::chrono::system_clock::now().time_since_epoch() - epoch;
delta is now a std::chrono::duration representing the amount of time between now, and 0000-01-01. You can then print that out however you want, or otherwise manipulate it. For example here is an entire working demo:
#include "../date_performance/date_algorithms"
#include <iostream>
#include <chrono>
typedef std::chrono::duration
<
int,
std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>
> days;
int
main()
{
constexpr days epoch = days(days_from_civil(0, 1, 1));
auto delta = std::chrono::system_clock::now().time_since_epoch() - epoch;
days d = std::chrono::duration_cast<days>(delta);
std::cout << "It has been " << d.count() << " days, ";
delta -= d;
auto h = std::chrono::duration_cast<std::chrono::hours>(delta);
std::cout << h.count() << " hours, ";
delta -= h;
auto m = std::chrono::duration_cast<std::chrono::minutes>(delta);
std::cout << m.count() << " minutes, ";
delta -= m;
auto s = std::chrono::duration_cast<std::chrono::seconds>(delta);
std::cout << s.count() << " seconds ";
std::cout << " since 0000-01-01\n";
}
Which for me output:
It has been 735602 days, 19 hours, 14 minutes, 32 seconds since 0000-01-01
A word of warning about overflow:
The std::chrono::system_clock::time_point::duration is not guaranteed to have a range large enough to do this. It turns out that on my system it does. It is microseconds in a signed long long which will span +/- 292,000 years. If you need to avoid an overflow problem, you could truncate your std::chrono::system_clock::time_point::duration to courser units (e.g. seconds or days) to extend the range prior to subtracting 0000-01-01.
I got to thinking
And that usually leads to a disaster. However in this case I decided I should add to this post anyway. This:
constexpr days epoch = days(days_from_civil(0, 1, 1));
has type days, which is a duration. But it really isn't a duration. It is a point in time. It is a date. It is a time_point with a coarse precision. By introducing a new typedef, the code in this post can be cleaned up just a little bit more:
typedef std::chrono::time_point<std::chrono::system_clock, days> date_point;
Now instead of writing:
constexpr days epoch = days(days_from_civil(0, 1, 1));
One can write:
constexpr date_point epoch{days(days_from_civil(0, 1, 1))};
But even more importantly, instead of:
auto delta = std::chrono::system_clock::now().time_since_epoch() - epoch;
we can now write:
auto delta = std::chrono::system_clock::now() - epoch;
This delta still has exactly the same type and value as it did previously, and everything else in the demo still proceeds as exactly as it did before.
This is both a small change, and a big change. By treating epoch as a time_point instead of a duration, the algebra of time_point's and duration's works for us, both simplifying and type-checking our expressions to help us write cleaner code with fewer mistakes.
For example one can add two duration's together. But it doesn't make any sense at all to:
epoch + epoch
By using time_point instead of duration for the type of epoch, the compiler catches such non-sensical expressions at compile time.
1The proleptic Gregorian calendar has a year 0. In the year 0 it is 2 days behind the Julian calendar. Using a year 0 is also consistent with ISO 8601. As long as all parties involved know what calendar you are using, then everything is fine. Conversion between non-positive years and "BC years" is trivial if desired.
It's possible, the code you've given (minus a small fix, tm_mday starts with 1) yields:
Sat Jan 1 00:00:00 0
Live example
The real problem is: Are you on 32-bit or 64-bit? With a 32-bit system, time_t is also only 32 bits and you are limited to 1970 +/- 68 years.
On a 64-bit system, the limits are given by std::mktime and std::strftime, in my own code I have unit test for those strings and the corresponding values:
"-2147481748-01-01 00:00:00" maps to -67768040609740800
"2147483647-12-31 23:59:59" maps to 67767976233532799
I should probably also mention that there are systems where the above does not work because the underlying OS functions are buggy. For the record: I'm on Linux.
No. mktime and friends are based on UNIX time, which starts on 1st January 1970.
There is in fact no such thing as 0th January, 0000, so it seems likely that you would be better off finding another way to solve whatever is your actual problem.

utc seconds since midnight to datetime

I'm getting radar data as "tracks" and the track data indicates the number of UTC seconds since the last midnight, apparently. This is not the number of seconds since the 1st of jan 1970.
Now I want to convert that to date time, knowing that the clock on the computer could be slightly out of sync with the clock on the radar. I'll assume the radar's seconds are the reference, not the computer's.
I want to convert these seconds to a full date time. Things seem to be a little tricky around
midnight.
Any suggestions? I've got some ideas, but I don't want to miss anything.
I'm working with C++ Qt.
// Function to extend truncated time, given the wall time and period, all
// in units of seconds.
//
// Example: Suppose the truncated period was one hour, and you were
// given a truncated time of 25 minutes after the hour. Then:
//
// o Actual time of 07:40:00 results in 07:25:00 (07:40 + -15)
// o Actual time of 07:10:00 results in 07:25:00 (07:10 + +15)
// o Actual time of 07:56:00 results in 08:25:00 (07:56 + +29)
double extendTruncatedTime(double trunc, double wall, int period) {
return wall + remainder(trunc - wall, period);
}
#define extendTruncatedTime24(t) extendTruncatedTime(t, time(0), 24 * 60 * 60)
Some commentary:
The units of wall are seconds, but its base can be arbitrary. In Unix, it typically starts at 1970.
Leap seconds are not relevant here.
You need #include <math.h> for remainder().
The period in extendTruncatedTime() is almost always twenty-four hours, 24 * 60 * 60, as per the OP's request. That is, given the time of day, it extends it by adding the year, month, and day of month, based on the 'wall' time.
The only exception I know to the previous statement is, since you mention radar, is in the Asterix CAT 1 data item I001/141, where the period is 512 seconds, and for which extendTruncatedTime() as given doesn't quite work.
And there is another important case which extendTruncatedTime() doesn't cover. Suppose you are given a truncated time consisting of the day of month, hour, and minute. How can you fill in the year and the month?
The following code snippet adds the year and month to a time derived from a DDHHMM format:
time_t extendTruncatedTimeDDHHMM(time_t trunc, time_t wall) {
struct tm retval = *gmtime_r(&trunc, &retval);
struct tm now = *gmtime_r(&wall, &now);
retval.tm_year = now.tm_year;
retval.tm_mon = now.tm_mon;
retval.tm_mon += now.tm_mday - retval.tm_mday > 15; // 15 = half-month
retval.tm_mon -= now.tm_mday - retval.tm_mday < -15;
return timegm(&retval);
}
As written, this doesn't handle erroneous inputs. For example, if today is July 4th, then the non-nonsensical 310000 will be quietly converted to July 1st. (This may be a feature, not a bug.)
If you can link against another lib, i'd suggest to use boost::date_time.
It seems you want to take current date in seconds from midnight (epoch) then add the radar time to it, then convert the sum back to a date time, and transform it into a string.
Using boost will help you in:
getting the right local time
calculating the date back
incorporating the drift into the calculation
taking leap seconds into account
since you'll have concept like time intervals and durations at your disposal. You can use something like (from the boost examples):
ptime t4(date(2002,May,31), hours(20)); //4 hours b/f midnight NY time
ptime t5 = us_eastern::local_to_utc(t4);
std::cout << to_simple_string(t4) << " in New York is "
<< to_simple_string(t5) << " UTC time "
<< std::endl;
If you want to calculate the drift by hand you can do time math easily similar to constructs like this:
ptime t2 = t1 - hours(5)- minutes(4)- seconds(2)- millisec(1);
I had the exact same problem but I'm using C#. My implementation is included here if anyone needs the solution in C#. This does not incorporate any clock drift.
DateTime UTCTime = DateTime.UtcNow.Date.AddSeconds(secondSinceMidnightFromRadar);