Replace hour of chrono::time_point? - c++

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.

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

Fractional day of the year computation in C++14

I wrote the following code using Howard Hinnants date.h library, to compute the fractional day of the year of the current time. I was wondering if there are shorter ways of doing it, because my code feels like an overkill of std::chrono and date calls. Can I directly calculate the number of fractional days since the start of the year (at microsecond precision) and avoid my two-step approach?
#include <iostream>
#include <chrono>
#include "date.h"
int main()
{
// Get actual time.
auto now = std::chrono::system_clock::now();
// Get the number of days since start of the year.
auto ymd = date::year_month_day( date::floor<date::days>(now) );
auto ymd_ref = date::year{ymd.year()}/1/1;
int days = (date::sys_days{ymd} - date::sys_days{ymd_ref}).count();
// Get the fractional number of seconds of the day.
auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(now - date::floor<date::days>(now));
double seconds_since_midnight = 1e-6*microseconds.count();
// Get fractional day number.
std::cout << "Fractional day of the year: " << days + seconds_since_midnight / 86400. << std::endl;
return 0;
}
Good question (upvoted).
I think first we need to decide on what the right answer is. There's your answer, and currently the only other answer is Matteo's. For demonstration purposes, I've modified both answers to substitute in a "fake now" so that we can compare apples to apples:
using namespace std::chrono_literals;
auto now = date::sys_days{date::March/27/2019} + 0h + 32min + 22s + 123456us;
(approximately now at the time I'm writing this)
Chiel's code gives:
Fractional day of the year: 85.0225
Matteo's code gives:
Fractional day of the year: 85.139978280740735
They are close, but not close enough to both be considered right.
Matteo's code works with "average years":
auto this_year = date::floor<date::years>(now);
The length of a date::years is 365.2425 days, which is exactly right if you average all civil years over a 400 year period. And working with the average year length can be very useful, especially when dealing with systems that don't care about human made calendars (e.g. physics or biology).
I'm going to guess that because of the way Chiel's code is written, he would prefer a result that refers more precisely to this specific year. Therefore the code presented below is Chiel's's algorithm, resulting in exactly the same result, only slightly more efficient and concise.
// Get actual time.
auto now = std::chrono::system_clock::now();
// Get the number of days since start of the year.
auto sd = date::floor<date::days>(now);
auto ymd = date::year_month_day( sd );
auto ymd_ref = ymd.year()/1/1;
std::chrono::duration<double, date::days::period> days = sd - date::sys_days{ymd_ref};
// Get the fractional number of seconds of the day.
days += now - sd;
// Get fractional day number.
std::cout << "Fractional day of the year: " << days.count() << std::endl;
The first thing I noted was that date::floor<date::days>(now) was being computed in 3 places, so I'm computing it once and saving it in sd.
Next, since the final answer is a double-based representation of days, I'm going to let <chrono> do that work for me by storing the answer in a duration<double, days>. Any time you find yourself converting units, it is better to let <chrono> do it for you. It probably won't be faster. But it definitely won't be slower, or wrong.
Now it is a simple matter to add the fractional day to the result:
days += now - sd;
using whatever precision now has (microseconds or whatever). And the result is now simply days.count().
Update
And with just a little bit more time to reflect ...
I noticed that with the simplified code above, one can more easily see the entire algorithm as a single expression. That is (removing namespace qualification in order to get everything on one line):
duration<double, days::period> days = sd - sys_days{ymd_ref} + now - sd;
And this clearly algebraically simplifies down to:
duration<double, days::period> days = now - sys_days{ymd_ref};
In summary:
using namespace std::chrono;
using namespace date;
// Get actual time.
auto now = system_clock::now();
// Get the start of the year and subract it from now.
using ddays = duration<double, days::period>;
ddays fd = now - sys_days{year_month_day{floor<days>(now)}.year()/1/1};
// Get fractional day number.
std::cout << "Fractional day of the year: " << fd.count() << '\n';
In this case, letting <chrono> do the conversions for us, allowed the code to be sufficiently simplified such that the algorithm itself could be algebraically simplified, resulting in cleaner and more efficient code that is provably equivalent to the original algorithm in the OP's question.

What is the best way to represent intraday time HH:MM:SS in c++11

C++11 chrono provides concepts: clock, time_point, duration and in Howard Hinnant's date.h library there are additional functions to manipulate dates and time with motivating examples/reciepes. However I have trouble to express general time-points such as ten o'clock.
Should general intraday time point be expressed
with duration: today + duration
creating custom clock choosing epoch of any given day ie: today
????
what is the best way in c++11 to get good representation of a general intraday time in the format of HH:MM:SS?
seq = [2018-01-01 09:29:00UTC, 2018-01-01 09:29:58UTC,..., 2018-01-01 09:35:00UTC, ..., 2018-01-01 16:29:00UTC, 2018-01-01 16:30:00UTC]
for time in seq
time > "09:30:00" and time < "16:00:00" do some work;
Using Howard Hinnant's date/time library, 10am local today is:
#include "date/tz.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
auto zt = make_zoned(current_zone(), local_days{2018_y/jan/15} + 10h);
std::cout << zt << '\n';
}
which just output for me:
2018-01-15 10:00:00 EST
local_days is used to convert a year/month/day into a local_time with a precision of days. You can add any chrono::duration to that, using any units you want. Then you can pair that local_time with any time_zone you want to get the local time in that time_zone.

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);

C++ DateTime class

I have my own C++ DateTime class defined as:
class DateTime
{
public:
int year;
int month;
int day;
int hour;
int min;
int sec;
int millisec;
};
I have 2 DateTime which I need to compare to see which one is greater than (more recent) the other.
Is there any freely available C++ DateTime class that I can use to
Convert my DateTime class to their DateTime class
Their class should provide < , > , <= , >= operators for comparison
If a concrete example could be provided that would be great. Note that I need to compare down to millisecond.
I was thinking about Boost or Qt. Preferred Boost though.
See Boost Date Time library
And your class looks very much like struct tm
EDIT:
You're right that struct tm doesn't support millisecond precision.
Take a look at a Boost example. Does that help?
You may want to check out QDateTime from Qt, wich has the required operators and ms accuracy.
Conversion from your class could be done via
class DateTime
{
public:
int year;
int month;
int day;
int hour;
int min;
int sec;
int millisec;
QDateTime toQDateTime() {
return QDateTime(QDate(year, month, day), QTime(hour, min, sec, millisec));
}
};
The other way around is similar ;-)
I don't know of any off the top of my head. But I'd consider rewriting your date class to hold a single 64-bit integer describing milliseconds since the conventional epoch (1970 is it?). Then you are free to simply divide by 1000 and use the normal CRT functions for formatting as a string, plus you can take the value modulo 1000 to get the millisecond part.
Comparison operators then become easy..
I ditch storing dates in gregorian ages ago.
I store dates as an 32bit integer (sort of like a Julian date).
So the date is composed as (Year * 1000) + DOY (DOY is day of year).
I.e.
- 2009001 Is Jan 1 2009
- 2009365 is Dec 31 2009
My date class of course provides methods for getting the Year, Month and Day, adding, subtracting, incrementing and decrementing, comparing, getting the number of days between dates etc..
For date and time, I use 64bit float where the integer portion of the real number is the same as integer (Julian like) dates described above, and the fraction represents the time in fraction of a day.
I.e.
2009001.04166666666~ is Jan 1,2009 1:00am
2009001.06249999999~ is Jan 1,2009 1:30am
2009001.95833333333~ is Jan 1,2009 11:00pm
If you only need minute accuracy, you can use 32bit float
for date and time but you can't adequately accurately
store seconds and milliseconds.
The advantages of storing dates (and time) in this manner are:
You only need 8bytes to represent the data and time
as compared to 28bytes (assuming 32bit integers)
used by the DateTime class in the question.
Compared with dates stored as seconds from an epoch,
when looking at the number (for example in the debugger)
you can more or less identify from
the number the year and the day of year, and the approximate time of day
(to get the hour, minute, second
after midnight simply mulitply by 24, 1440, 86400 respectively).
Comparing dates is trivial, simply compare the numbers
(A single CPU operation compared to the several it
would take for the example DateTime).
Fewer comparison operations to do date arithmetic.
The disadvange of this (for time time) is a slight loss of accuracy (this is practically a mute point) and you have to do some simple rounding to get nice integer values when convering to integer values of hours minutes and seconds.
Okay, here's the final code snippet that answers my own question. I thought of sharing this in case it might helpful to some other people in the future. Thanks to Fred Larson for pointing the Boost example.
I chose Boost to do the DateTime calculation because my application already makes use of Boost somewhere else. I think I might have been able to use Qt as well, though I cant completely confirm.
Assuming DateTime is defined as:
class DateTime
{
public:
int year;
int month;
int day;
int hour;
int min;
int sec;
int millisec;
};
To do a simple DateTime comparison
bool DateTime::operator < (const DateTime& dt_)
{
using namespace boost::posix_time;
using namespace boost::gregorian;
ptime thisTime( date(this->year,this->month,this->day),
hours(this->hour) +
minutes(this->min) +
seconds(this->sec) +
boost::posix_time::millisec(int(this->millisec)) );
ptime thatTime( date(dt_.year,dt_.month,dt_.day),
hours(dt_.hour) +
minutes(dt_.min) +
seconds(dt_.sec) +
boost::posix_time::millisec(int(dt_.millisec)) );
return thisTime < thatTime;
}
To add 2 DateTime together to return a new DateTime
DateTime DateTime::operator + ( const DateTime& dt_ )
{
using namespace boost::posix_time;
using namespace boost::gregorian;
date thisDate( this->year, this->month, this->day );
date newDate = thisDate + years(dt_.year) + months(dt_.month) + days(dt_.day);
ptime newDateTime( newDate,
hours(this->hour) + hours(dt_.hour) +
minutes(this->min) + minutes(dt_.min) +
seconds(this->sec) + seconds(dt_.sec) +
boost::posix_time::millisec(int(this->millisec)) +
boost::posix_time::millisec(int(dt_.millisec))
);
DateTime dateTime;
date t1_date = newDateTime.date();
dateTime.year = t1_date.year();
dateTime.month = t1_date.month();
dateTime.day = t1_date.day();
time_duration t1_time = newDateTime.time_of_day();
dateTime.hour = t1_time.hours();
dateTime.min = t1_time.minutes();
dateTime.sec = t1_time.seconds();
dateTime.millisec = t1_time.fractional_seconds()/1000.0f;
return dateTime;
}
What's wrong with using the content of <time.h> for implementing your class? It's standard C90.
GNU R uses a struct tm replacement with microsecond precision -- instead of (integer) seconds since the epoch, it now uses a floating point number. That is really really useful. For many of my applications, I just past doubles around and yet get the time conversions.
See R-2.9.1/src/main/datetime.c in the current R sources.
Having that in a standalone C++ class would be handy though.
Look at
MFC datetime classes CTime and COleDateTime classes
More at http://www.codeproject.com/KB/datetime/datetimedisc.aspx