How to cast from utc_time<seconds> to utc_time<days> - c++

I want to load utc_time< days > variable with year, month, day.
I do not know how to cast the result 'x' from date::utc_seconds to utc_time< days > and in general how to cast e.g. utc_time< milliseconds > to utc_time< days >...
auto x = to_utc_time(sys_days(year_month_day{ year{y}, month(m), day(d) }));
utc_time<days> utc_tp = ?x?; // now x => date::utc_seconds
Solved:
utc_time< days > utc_tp = time_point_cast< days >(x);
time_point_cast casts from fine precision time_point to a coarser precision time_point.

In addition to time_point_cast<days>, which truncates towards the epoch, there is also available:
floor<days>(x) : truncate to the beginning of the current day.
ceil<days>(x) : truncate to the beginning of the next day.
round<days>(x) : truncate to the closest day boundary.
time_point_cast<days>(x) is equivalent to floor<days>(x) when x is after the 1970-01-01 epoch, and equivalent to ceil<days>(x) when x is prior to the 1970-01-01 epoch.

Related

C++: get time zone deviation

So I want to creata a time stamp (as a string) with the format HH:MM:SS in C++. I use std::chrono to get a unix time stamp and then calculate the hours, minutes and seconds.
// Get unix time stamp in seconds.
const auto unix_time_stamp = std::chrono::system_clock::now();
long long seconds_since_epoch = std::chrono::duration_cast<std::chrono::seconds>(unix_time_stamp.time_since_epoch()).count();
// Calculate current time (hours, minutes, seconds).
uint8_t hours = (seconds_since_epoch % 86400) / 3600;
uint8_t minutes = (seconds_since_epoch % 3600) / 60;
uint8_t seconds = (seconds_since_epoch % 60);
// Create strings for hours, minutes, seconds.
std::string hours_string = std::to_string(hours);
std::string minutes_string = std::to_string(minutes);
std::string seconds_string = std::to_string(seconds);
// Check if the number is only one digit. If it is, add a 0 in the beginning (5:3:9 --> 05:03:09).
if(hours_string.size() == 1)
{
hours_string = "0" + hours_string;
}
if(minutes_string.size() == 1)
{
minutes_string = "0" + minutes_string;
}
if(seconds_string.size() == 1)
{
seconds_string = "0" + seconds_string;
}
// Append to a final string.
std::string time_stamp = hours_string + ":" + minutes_string + ":" + seconds_string;
This is all working fine and great but there is one big problem: time zones.
With this way, I'm only calculating the time stamp for GMT. Is there any easy, fast and, most importantly, portable way to get the "offset" in seconds or minutes or hours for your system's time zone? By "portable" I mean platform-independent.
Please note: I know you can do all of this more easily with std::strftime and so on, but I really want to implement this by myself.
Some implementations of std::tm will contain a member that has the local offset as a member. ... But it isn't portable.
One trick is to take your seconds_since_epoch, and either assign it to a std::time_t, or just make its type std::time_t in the first place instead of long long.
... Oh, wait that isn't quite portable. Some platforms still use a 32 bit time_t. But assuming a 64 bit time_t ...
Then use localtime to get a std::tm:
std::tm tm = *localtime(&seconds_since_epoch);
This isn't officially portable because system_clock and time_t aren't guaranteed to have the same epoch. But in practice they do.
Now take the {year, month, day, hour, minute, second} fields out of the tm and compute a "local epoch". The hard part of this computation is converting the {year, month, day} part into a count of days. You can use days_from_civil from here to do that computation efficiently. Be sure to take the weird offsets into account for tm_year and tm_mon when doing this.
After you get this then subtract seconds_since_epoch from it:
auto offset = local_epoch - seconds_since_epoch;
This is your signed UTC offset in seconds. Positive is east of the prime meridian.
In C++20 this simplifies down to:
auto offset = std::chrono::current_zone()->get_info(system_clock::now()).offset;
and offset will have type std::chrono::seconds.
You can get a free, open-source preview of this here. It does require some installation.

Error in comparing two std::chrono::time_point instances

I have two std::chrono::time_point instances in variables exp and time. exp has a time in the future and time is the current time. But when I compare them as in this snippet:
std::time_t t_exp = std::chrono::system_clock::to_time_t(exp);
std::time_t t_time = std::chrono::system_clock::to_time_t(time);
std::cout << std::ctime(&t_exp) << std::ctime(&t_time) << (time > exp) << std::endl;
I get output:
Sat Apr 26 01:39:43 4758
Fri May 29 18:11:59 2020
1
Which is wrong because exp is in the year 4758 and time is in the year 2020.
Where am I going wrong?
t_exp is -4243023785
This value of time_t corresponds to 1835-07-18 22:16:55 (assuming the Unix epoch and a precision of seconds, neither of which are specified by the standard, but are common).
Apparently the implementation of ctime on your platform can't handle dates this far in the past, which is a little surprising as 1835 is not very far in the past.
The value of exp is -4243023785 times a million or a billion (depending on the precision of system_clock on your platform) and is stored with a signed 64 bit integer (there is no overflow). Thus time > exp == 1 is correct (time is 1590775919s converted to the precision of system_clock).
Sat Apr 26 01:39:43 4758 corresponds to a time_t of 87990716383.
I see nothing wrong with your use of the chrono library in the above code.
Update
The value 87990716383 is being converted to a time_point using from_time_t()
Ah, this combined with the knowledge that on your platform the precision of system_clock is nanoseconds tells me that you are experiencing overflow on the construction of exp.
This is not the code you have:
std::time_t t_exp = std::chrono::system_clock::to_time_t(exp);
std::time_t t_time = std::chrono::system_clock::to_time_t(time);
std::cout << std::ctime(&t_exp) << std::ctime(&t_time) << (time > exp) << std::endl;
The code you have looks something like:
// ...
std::time_t t_exp = 87990716383;
auto exp = std::chrono::system_clock::from_time_t(t_exp);
std::cout << std::ctime(&t_exp) << std::ctime(&t_time) << (time > exp) << std::endl;
On your platform, system_clock stores nanoseconds since 1970-01-01 00:00:00 UTC in a signed 64 bit integer. The maximum storable date (system_clock::time_point::max()) on your platform is:
2262-04-11 23:47:16.854775807
Beyond this, the underlying storage of nanoseconds overflows.
When 87990716383 (seconds) is converted in from_time_t, it is multiplied by a billion which overflows. The overflowed value is -4243003985547758080 which corresponds to the date 1835-07-19 03:46:54.452241920.
You can get a larger range by using a coarser precision, for example:
std::time_t t_exp = 87990716383;
time_point<system_clock, microseconds> exp{seconds{t_exp}};
// exp == 4758-04-26 01:39:43.000000

Convert long int seconds to double precision floating-point value

I have a long int variable wich containes seconds since Jan. 1, 1970 in this format:
long int seconds = 1231241242144214;
i need to convert this seconds to double precision floating-point value. The integer part of the value is the number of days since midnight, 30 December 1899.
The fractional part of the value represents time. .5 is equal to 12:00 PM.
how can i convert?
There are 86400 seconds in a day, and 25569 days between these epochs. So the answer is:
double DelphiDateTime = (UnixTime / 86400.0) + 25569;
You really do need to store the Unix time in an integer variable though.

C++ time difference in military time

I'm trying to create a program that takes the difference of two military times and get its time difference.
Example:
**AM to PM**
Time 1: 0900
Time 2: 1730
Time Difference: 8 hours 30 minutes
**PM to AM**
Time 1: 1200
Time 2: 1100
Time Difference: 23 hours 0 minutes
Using a couple of if than else statements, I was able to figure out how to convert from military hours into standard hours but I'm stuck with how to go about subtracting time. I was trying to come up with a way to do with on paper just with addition and subtraction but I haven't developed a method that works in all cases. Any help?
One option might be to split the time into two elements, the hours and the minutes.
First, take the time, ie. 1730 and divide by 100. If its an integer or similar, it should result in 17 hours (it will automatically round down).
Then take 1730 and mod it by 100 to get 30 minutes.
int time1 = 900;
int time2 = 1730;
int diffHours = time2 / 100 - time1 / 100;
int diffMinutes = time2 % 100 - time1 % 100;
If you're unfamiliar with modulus (%), it just returns the remainder after dividing the two numbers, so 7 % 3 would be 1.
Assuming your military times are stored as int values in the range 0000..2400, then the following function will return the difference between two such values.
#include <cassert>
extern int timediff_minutes(int t1, int t2);
int timediff_minutes(int t1, int t2)
{
assert(t1 >= 0 && t1 <= 2400);
assert(t2 >= 0 && t2 <= 2400);
assert(t1 % 100 < 60 && t2 % 100 < 60);
int t1_mins = (t1 / 100) * 60 + (t1 % 100);
int t2_mins = (t2 / 100) * 60 + (t2 % 100);
return(t2_mins - t1_mins);
}
Note that 2400 is useful for representing the end of the day — and using 2400 is sanctioned by ISO 8601:2004 Data elements and interchange formats — Information interchange — Representation of dates and times.
4.2.3 Midnight
The complete representations in basic and extended format for midnight, in accordance with 4.2.2, shall be
expressed in either of the two following ways:
Basic format Extended format
a) 000000 00:00:00 (the beginning of a calendar day)
b) 240000 24:00:00 (the end of a calendar day)
The representations may have reduced accuracy in accordance with 4.2.2.3 or may be designated as a time
expression in accordance with 4.2.2.5. To represent midnight the representations may be expanded with a
decimal fraction containing only zeros in accordance with 4.2.2.4.
NOTE 1 Midnight will normally be represented as [00:00] or [24:00].
NOTE 2 The end of one calendar day [24:00] coincides with [00:00] at the start of the next calendar day, e.g. [24:00] on
12 April 1985 is the same as [00:00] on 13 April 1985. If there is no association with a date or a time interval both a) and b)
represent the same local time in the 24-hour timekeeping system.
NOTE 3 The choice of representation a) or b) will depend upon any association with a date, or a time interval.
Representations where [hh] has the value [24] are only preferred to represent the end of a time interval in accordance with
4.4 or recurring time interval in accordance with 4.5.

Converting number of 100 ns since 1601 to boost posix time in C++

I am receiving from a data provider timestamps that follow this specification:
number of 100 nanoseconds since 1601
I am using boost::posix_time::ptime and I would like to convert the timestamps to posix time. Is there a simple way to do that ?
When did the switch from the Julian to Gregorian calendar occur for this system? Some countries switched before 1st January 1601; others didn't switch until much later. This will critically affect your calculation - by 11 days or so.
Since there are 107 units of 100 ns each in one second, you divide the starting number by 107 to produce the number of seconds since the reference time (the remainder is the fraction of a second). You then divide that by 86400 to give the number of days (the remainder is the time of day). Then you can compute the date from the number of days.
Since POSIX time uses 1970-01-01 00:00:00 as the reference, you may simply need to compute the correct number of seconds between 1601-01-01 00:00:00 and the POSIX epoch (as it is known), and subtract that number from the number of seconds you calculated.
number of 100 nanoseconds since 1601
It is Windows FILETIME value.
Boost.DateTime actually use Windows FILETIME for Windows platform.
Below is the relevant Boost source code that convert FILETIME to boost::posix_time::ptime:
(from boost/date_time/microsec_time_clock.hpp)
static time_type create_time(time_converter converter)
{
winapi::file_time ft;
winapi::get_system_time_as_file_time(ft);
uint64_t micros = winapi::file_time_to_microseconds(ft); // it will not wrap, since ft is the current time
// and cannot be before 1970-Jan-01
std::time_t t = static_cast<std::time_t>(micros / 1000000UL); // seconds since epoch
// microseconds -- static casts supress warnings
boost::uint32_t sub_sec = static_cast<boost::uint32_t>(micros % 1000000UL);
std::tm curr;
std::tm* curr_ptr = converter(&t, &curr);
date_type d(curr_ptr->tm_year + 1900,
curr_ptr->tm_mon + 1,
curr_ptr->tm_mday);
//The following line will adjust the fractional second tick in terms
//of the current time system. For example, if the time system
//doesn't support fractional seconds then res_adjust returns 0
//and all the fractional seconds return 0.
int adjust = static_cast< int >(resolution_traits_type::res_adjust() / 1000000);
time_duration_type td(curr_ptr->tm_hour,
curr_ptr->tm_min,
curr_ptr->tm_sec,
sub_sec * adjust);
return time_type(d,td);
}
You can browse your Boost installation for the detailed implementation.