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);
Related
How can I change just the hour of an existing std::chrono::system_clock::time_point?
For example, say I wanted to implement this function:
void set_hour(std::chrono::system_clock::time_point& tp, int hour) {
// Do something here to set the hour
}
std::chrono::system_clock::time_point midnight_jan_1_2022{std::chrono::seconds{1640995200}};
set_hour(midnight_jan_1_2022, 11);
// midnight_jan_1_2022 is now 11am on Jan 1 2022
....
The answer depends on exactly what you mean. The simplest interpretation is that you want to take whatever date tp points to (say yyyy-mm-dd hh:MM:ss.fff...), and create: yyyy-mm-dd hour:00:00.000....
Another possible interpretation is that yyyy-mm-dd hh:MM:ss.fff... is transformed into yyyy-mm-dd hour:MM:ss.fff....
In either event C++20 makes this easy, and if you don't yet have access to C++20 <chrono>, then there exists a free, open-source header-only library that emulates C++20 <chrono> and works with C++11/14/17.
If you want to zero the minute, second and subsecond fields as described in the first interpretation that is:
void
set_hour(std::chrono::system_clock::time_point& tp, int hour)
{
using namespace std::chrono;
auto day = floor<days>(tp);
tp = day + hours{hour};
}
I.e. you simply floor the time_point to days-precision and then add the desired hours.
The second interpretation is slightly more complicated:
void
set_hour(std::chrono::system_clock::time_point& tp, int hour)
{
using namespace std::chrono;
auto day = floor<days>(tp);
hh_mm_ss hms{tp - day};
tp = day + hours{hour} + hms.minutes() + hms.seconds() + hms.subseconds();
}
Here you have to discover and recover the {minutes, seconds, subseconds} fields to re-apply them to the desired date (along with the desired hour). hh_mm_ss is a C++20 {hours, minutes, seconds, subseconds} data structure that automates the conversion from a duration into a field structure so that you can more easily replace the hours field.
Both of these solutions will give the same answer for your example input:
2022-01-01 11:00:00.000000
since the input has zeroed minutes, seconds and subseconds fields already.
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
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;
I have a loop and in every loop I get the current seconds the application has been running for I then want to convert this time into how many, Days, Hours and Seconds that the seconds calculate to but not 'real time' I need to be able to customize how many seconds are in a day, I have tried examples on SO and the web but nothing seems to be out there for this. I have some defines
#define DAY 1200
#define HOUR DAY / 24
#define MINUTE HOUR / 60
#define SECOND MINUTE / 60
So in my define a day would last for 1200 seconds. I have then been trying to convert elapsed seconds into 'my' seconds
seconds_passed = fmodf(SECOND, (float)(GetTicks() / 1000));
Which returns what SECOND equals (0.013889) but then every loop is the same, it never changes I was thinking I would just be able to convert for example: 1real second into 1.25fake seconds then
Minute = (seconds_passed / MINUTE);
seconds_passed = fmodf(seconds_passed, MINUTE);
work out how many (fake)minutes, (fake)hours and (fake)days have elapsed since the application started.
Hope that makes sense, thank you for your time.
Since you want to customise how many seconds are in a day, all you're really doing is changing the ratio of 1 second : 1 second.
For instance, if you did was 1200 seconds in a day your ratio is:
1:72
that is, for every 1 second that passes in your day, it is the equivilent of 72 real seconds.
So yes basically all you need to do in your program is find the ratio of 1 second to 1 second, times your elapsed seconds by that to get the 'fake' seconds, and then use that value...
The code may look something like this:
// get the ratio second:fake_second
#define REAL_DAY_SECONDS 86400
int ratio = REAL_DAY_SECONDS / DAY;
fake_to_real = fake_second*ratio;
real_to_fake = real_second/ratio;
You can make your own time durations with one line in chrono:
using fake_seconds = std::chrono::duration<float, std::ratio<72,1>>;
Some sample code
#include <iostream>
#include <chrono>
using namespace std::chrono_literals;
using fake_seconds = std::chrono::duration<float, std::ratio<72,1>>;
int main()
{
auto f_x = fake_seconds(350s);
std::cout << "350 real seconds are:\n" << f_x.count() << " fake_seconds\n";
}
https://godbolt.org/z/f5G86avxr
I know the Current system time.
I know the estimated time of arrival of a place in the form of hours minutes and seconds.
I need to find the duration of travel. But the estimated time of arrival is in 12 hour format.
I have to write a program to find the time difference between these two ?
I thought of using difftime(time1,time2)
but this requires the datatype time_t. I know the time in parts. i.e. i know the hours, minutes and seconds separatley. Both current system time and Estimated time of arrival.
I need to find the time difference between the two. The ETA can be after 24 hours. then is there any way i can find out the number of days of travel. Because after 12PM time is set back. hence i'm not able to keep track of the days.
Any solution ?
I work on C++
A straight forward way using C/C++. This is not very robust, but should meet your given requirements.
#include <ctime>
tm source;
memset(&source, 0, sizeof(tm));
tm.tm_hour = hour; // 24 hour format, 0 = midnight, 23 = 11pm
tm.tm_min = min;
tm.tm_sec = sec;
tm.tm_mon = month; // 0 based, 0 = jan, 11 = dec
tm.tm_mday = 10;
tm.tm.year = year; // current - 1900
time_t src_t = mktime(&source);
time_t now = time(NULL);