How to convert unsigned int 64 into time in C++? - c++

I am converting CLI C++ code to standard C++, and i have a piece of code that gets a UINT64 number (from a remote server - so i can't change to format/precision of the time i get) and converts it into DateTime object and later outputs the following value: myDatetime.ToString("dd/MM/yyyy hh:mm:ss.fffffff tt").
I haven't found a way to convert unsigned int 64 into time in C++.
The following code does nothing for numbers so big (that's the 64bit number i get from the server).
time_t rawtime=131274907755873979
localtime_s(&timeinfo, &rawtime);
I need some help :)
My question wan't answered in the thread Convert Epoch Time string to Time since it doesn't work for numbers as large as i need. For example the number 131274907755873979 which is what i get from the server. The function ctime for that value simply returns NULL.
I need a way to convert between the time i get as a unsigned int64 into standard C++ time object.

std::string LongToString(int64_t longDate) {
char buff[128];
std::chrono::duration<int64_t, std::milli> dur(longDate);
auto tp = std::chrono::system_clock::time_point(
std::chrono::duration_cast<std::chrono::system_clock::duration>(dur));
std::time_t in_time_t = std::chrono::system_clock::to_time_t(tp);
strftime(buff, 128, "%Y-%m-%d %H:%M:%S", localtime(&in_time_t));
std::string resDate(buff);
return resDate;
}
This is a case with bsoncxx::types::b_date get_date().to_int64() MongoDB.
The DateTime saved with int64_t.

You have not told us how the existing code converts that number into a DateTime. Let us suppose that it does so by invoking this constructor: DateTime( long long ticks ).
According to the documentation of that constructor of DateTime,
long long ticks A date and time expressed in the number of 100-nanosecond intervals that have elapsed since January 1, 0001 at 00:00:00.000 in the Gregorian calendar.
On the other hand, according to the documentation of localtime_s and the documentation of time_t, localtime_s() requires
the number of seconds (not counting leap seconds) since 00:00, Jan 1 1970 UTC.
So, you first need to convert 100-nanosecond intervals to seconds, and then convert from January 1, 0001 to January 1, 1970.

Using Howard Hinnant's datetime library this computation can be done quite easily. It works with VS 2013 and later.
#include "tz.h"
#include <cstdint>
#include <string>
#include <iostream>
std::string
FILETIME_to_string(std::uint64_t i)
{
using namespace std;
using namespace std::chrono;
using namespace date;
using FileTime = duration<int64_t, ratio<1, 10000000>>;
auto const offset = sys_days{jan/1/1970} - sys_days{jan/1/1601};
auto tp = sys_days{jan/1/1970} + (FileTime{static_cast<int64_t>(i)} - offset);
return format("%d/%m/%Y %I:%M:%S %p", make_zoned("Etc/GMT-2", tp));
}
int
main()
{
std::cout << FILETIME_to_string(131274907755873979) << '\n';
}
This skips DateTime and goes straight to the string. I wasn't sure what you are wanting with tt in the format. But whatever it is, it can be handled.
This library builds on the C++11 <chrono> library. So the first thing to do is to create a duration to represent the windows tick size (100 ns). Then just compute the offset between the two epochs and subtract it from the input, and form a std::chrono::time_point. Now you can format that time_point however you want.
The program above outputs:
29/12/2016 03:12:55.5873979 PM
If you use VS 2017 you'll be able to make offset constexpr, making the conversion more efficient.

Related

Seconds since epoch for a specific date

Currently, I have A solution and another semi-solution. The semi-solution is linked here, Get seconds since epoch in Linux but that gives the time since epoch for the current datetime. I need to have it tell me the seconds since epoch for a specified date instead. I do have a function for this, however I can't find the original post for it,
std::tm t = {};
std::istringstream ss(dateBuf);
ss >> std::get_time(&t, "%Y-%m-%d");
double seconds = (double)(std::mktime(&t));
There are a few issues I have with it though. Currently, dateBuf = "2020-01-01"; and I require it to be able to handle not just days, but hours, minutes, seconds... Also, I am hoping there is another way of doing this without allocating memory every time to make a new std::tm and std::istringstream and then pushing ss into it. I am wondering if there is a way to go straight from char datebuf[] to a double/long double with the seconds as the value. For all intensive purposes, the program will go over this statement many, many times to convert the dates to seconds and this just seems inefficient. Something such as
long double SecondsSinceEpoch(const char* date){
//Taking in a date such as "2020-01-01 00:00:00" (Local Time)
//Will return the value 1577836800 (GMT) and Local time of 1577797200
//And also be able to take in a simpler date such as "2020-01-01"
}
Here's the general purpose solution using the preview C++20 chrono library:
#include "date/tz.h"
#include <iostream>
#include <sstream>
long double
SecondsSinceEpoch(const char* date)
{
//Taking in a date such as "2020-01-01 00:00:00" (Local Time)
//And also be able to take in a simpler date such as "2020-01-01"
//returns -1 on error
using namespace date;
using namespace std;
using namespace std::chrono;
istringstream in{date};
local_days tpd;
in >> parse("%F", tpd);
if (in.fail())
return -1;
seconds s{};
in >> parse(" %T", s);
zoned_time zt{current_zone(), tpd + s};
return zt.get_sys_time().time_since_epoch().count();
}
The expensive parts are calling current_zone() and parsing out of an istringstream (which may create a long string on the heap, depending on the implementation and the input).
The above can be made faster if we can substitute in a constant UTC offset for the time zone, and if we create customized parsing logic that doesn't have to do much error checking.
What this library excels at is taking the {y, m, d, h, M, s} integral values and turning them into a count of seconds. So if you can obtain those integral values more efficiently than strptime (or it's equivalent in this library), including applying the UTC offset to the local time, then this library can translate those 6 fields into a count of seconds with very few cpu clock cycles.
Update
One thing you can do if your time zone is constant is to just look it up once:
static auto tz = current_zone();
zoned_time zt{tz, tpd + s};
or:
static auto tz = locate_zone("Australia/Sydney");
zoned_time zt{tz, tpd + s};
Both of these options are roughly equivalent to each other in terms of performance (assuming your current time zone is always "Australia/Sydney".
If you do your own scanning into integral types, then turning those ints into dates looks more like:
// Return {y, m, d, h, M, s}
std::array<int, 6>
scan(const char* date);
long double
SecondsSinceEpoch(const char* date)
{
//Taking in a date such as "2020-01-01 00:00:00" (Local Time)
//And also be able to take in a simpler date such as "2020-01-01"
//returns -1 on error
using namespace date;
using namespace std::chrono;
auto a = scan(date); // where you write scan
auto tp = local_days{year{a[0]}/a[1]/a[2]} + hours{a[3]}
+ minutes{a[4]} + seconds{a[5]};
static auto tz = locate_zone("Australia/Sydney");
zoned_time zt{tz, tp};
return zt.get_sys_time().time_since_epoch().count();
}
Use of the timezone lib does require some installation.

Convert the seconds since "midnight 1904-1-1" to a date-time string

In some multimedia metadata, there may be date-time in seconds since
midnight, Jan. 1, 1904, in UTC time.
As I know, the date time function is normally based on 1970-1-1 midnight in C/C++ standard library, at least in Visual C++, is there a function in C/C++/Win32-API to convert the seconds since "1904-1-1 midnight" to a date time string, like as "hh:mm:ss MM. dd, yyyy" or other format string or a structure like as "struct tm"?
struct tm
{
int tm_sec; // seconds after the minute - [0, 60] including leap second
int tm_min; // minutes after the hour - [0, 59]
int tm_hour; // hours since midnight - [0, 23]
int tm_mday; // day of the month - [1, 31]
int tm_mon; // months since January - [0, 11]
int tm_year; // years since 1900
int tm_wday; // days since Sunday - [0, 6]
int tm_yday; // days since January 1 - [0, 365]
int tm_isdst; // daylight savings time flag
};
Solution#1:
int main()
{
SYSTEMTIME systm;
memset(&systm, 0, sizeof(systm));
systm.wYear = 1904;
systm.wMonth = 1;
systm.wDay = 1;
FILETIME filetm;
if (SystemTimeToFileTime(&systm, &filetm) == FALSE){
printf("Failed to convert system time to file-time.\n");
return 0;
}
ULARGE_INTEGER nanoSeconds;
nanoSeconds.HighPart = filetm.dwHighDateTime;
nanoSeconds.LowPart = filetm.dwLowDateTime;
nanoSeconds.QuadPart += 3600ULL * 10000000; // add 1hour based on 1904/1/1 midnight
filetm.dwHighDateTime = nanoSeconds.HighPart;
filetm.dwLowDateTime = nanoSeconds.LowPart;
if (FileTimeToSystemTime(&filetm, &systm) == FALSE){
printf("Failed to convert file-time to system time.\n");
return 0;
}
printf("New system time by adding 1 hour: %d-%02d-%02d %02d:%02d:%02d.%03d\n",
systm.wYear, systm.wMonth, systm.wDay,
systm.wHour, systm.wMinute, systm.wSecond, systm.wMilliseconds);
return 0;
}
The output is
New system time by adding 1 hour: 1904-01-01 01:00:00.000
Solution#2:
With #Howard Hinnant's date.h, it can also solve this issue, please see the sample code provided by him https://stackoverflow.com/a/49733937/3968307
This would be a good time to use Howard Hinnant's free, open-source date/time library:
#include "date/date.h"
#include <cstdint>
#include <iostream>
#include <string>
std::string
convert(std::int64_t seconds_since_1904)
{
using namespace date;
using namespace std::chrono;
constexpr auto offset = sys_days{January/1/1970} - sys_days{January/1/1904};
return format("%T %m.%d, %Y", sys_seconds{seconds{seconds_since_1904}} - offset);
}
int
main()
{
std::cout << convert(3'606'124'378) << '\n';
}
Output:
13:12:58 04.09, 2018
Update
The above code will port to C++20 (when it ships) by:
Change #include "date/date.h" to #include <chrono>
Change using namespace date; to using namespace std;
Change "%T %m.%d, %Y" to "{:%T %m.%d, %Y}"
As you can easily calculate with any available spreadsheet application in your system, the difference in seconds between those two timestamps (assumed both are in UTC time) the difference in seconds from 1/1/1904 to 1/1/1970 is 2,082,844,800 sec. So the conversion function from a unix timestamp to your time, consists in adding 2082844800 to the unix timestamp you receive from any of the time functions. In case you want to pass back from a timestamp in your time to unix timestamp, then subtract that fixed value from your timescale. Beware that that number does not fit in a signed int so you must use probably a 64bit number to manage properly all those timestamps. Worse if you want to use nanoseconds resolution.
I don't guess the reason of using that strange epoch timestamp, but to illustrate a practical and in use application of such differences, there's a timestamp in internet that uses an epoch close to that, that is the NTP (Network Time Protocol) timestamp, that is based on 1/1/1900 epoch and has a resolution of 1/2**32 sec. that is around 232 ps. for a specification of this protocol, see RFC-5905
The time problem here practically begs you to write your own code for it. The year 1900 is an exception since it is divisible by 4 but still is not a leap year, so by starting in 1904 you can avoid that particular exception and use the fact that there are 1461 days in every four-year period starting with 1904.

What is the best way to parse a millisecond date time in C++11

What would be the next best thing for strptime when we have the datetime string with millisseconds?
Given:
"30/03/09 16:31:32.121"
we can't use the regular strptime because struct tm doesn't store millisseconds. Is there a new class that can achieve this?
I would parse these fields manually (reading into int and double for the seconds), then use days_from_civil to convert the year/month/day into a chrono::system_clock::time_point:
std::chrono::system_clock::time_point t(days(days_from_civil(y, m, d)));
where days is:
using days = std::chrono::duration<int, std::ratio<86400>>;
Then you can add to that the hours, minutes and seconds. To handle the fractional seconds you'll need to do a slight dance:
double s;
your_stream >> s; // 32.121
using namespace std::chrono;
duration<double> dsecs(s);
seconds sec = duration_cast<seconds>(dsecs);
milliseconds ms = duration_cast<milliseconds>(dsecs - sec);
t += sec + ms;
If you prefer, use round from here for your milliseconds conversion:
milliseconds ms = round<milliseconds>(dsecs - sec);
duration_cast is truncate towards zero. There are other rounding modes: floor, round, ceil, at this link.
Wrap it all up in a neat function for easy reuse. :-)
The above code all assumes UTC. If your date/time that you are parsing is known to be offset from UTC, you can add/subtract that offset. All known implementations of system_clock track Unix time, which is seconds since 1970-01-01 in the UTC time zone.
Update
Since writing this answer I've developed a more general library that the OP seemed to be seeking at that time. It can parse a wide variety of sub second precisions directly into a std::chrono::system_clock::time_point like this:
#include "date/date.h"
#include <iostream>
#include <sstream>
int
main()
{
std::istringstream in{"30/03/09 16:31:32.121\n"
"30/03/09 16:31:32.1214"};
std::chrono::system_clock::time_point tp;
in >> date::parse("%d/%m/%y %T", tp);
using namespace date;
std::cout << tp << '\n';
in >> date::parse(" %d/%m/%y %T", tp);
std::cout << tp << '\n';
}
This outputs:
2009-03-30 16:31:32.121000
2009-03-30 16:31:32.121400
This library uses the same techniques and tools as I originally described, but is packaged up and ready to go as a single header library.

Creating a boost::posix_time::ptime object from a 64 bit integer second count

I have a 32 bit Linux system in which I have to record data that is timestamped with a UINT32 second offset from an epoch of 1901-01-01 00:00:00.
Calculating the timestamp is ok for me as I can use the 64 bit ticks() counter and ticks_per_second() functions to generate the seconds since epoch as follows (I only require second level resolution)
const ptime ptime_origin(time_from_string("1901-01-01 00:00:00"));
time_duration my_utc = microsec_clock::universal_time() - ptime_origin;
boost::int64_t tick_per_sec = my_utc.ticks_per_second();
boost::int64_t tick_count = my_utc.ticks();
boost::int64_t sec_since_epoch = tick_count/tick_per_sec;
This works for me since I know that as an unsigned integer, the seconds count will not exceed the maximum UINT32 value (well not for many years anyway).
The problem I have is that my application can receive a modbus message containing a UINT32 value for which I have to set the hardware and system clock with an ioctl call using RTC_SET_TIME. This UINT32 is again the offset in seconds since my epoch 1901-01-01 00:00:00.
My problem now is that I have no way to create a ptime object using 64 bit integers - the ticks part of the time_duration objects is private and I am restricted to using long which on my 32 bit system is just a 4-byte signed integer not large enough to store the seconds offset from my epoch.
I have no control over the value of the epoch and so I am really stumped as to how I can create my required boost::posix_time::ptime object from the data I have.
I can probably obtain a dirty solution by calculating hard second counts to particular time intervals and using an additional epoch to make a bridge to allow this but I was wondering if there is something in the boost code that will allow me to solve the problem entirely using the boost datetime library.
I have read all the documentation I can find but I cannot see any obvious way to do this.
EDIT: I found this related question Convert int64_t to time_duration but the accepted answer there does NOT work for my epoch
Although boost::posix_time::seconds cannot be used if the seconds represent a number greater than 32 bits (as of Oct 2014), it turns out that boost::posix_time::milliseconds can easily be used (without workarounds), as follows:
inline std::string convertMsSinceEpochToString(std::int64_t const ms)
{
boost::posix_time::ptime time_epoch(boost::gregorian::date(1970, 1, 1));
boost::posix_time::ptime t = time_epoch + boost::posix_time::milliseconds(ms);
return boost::posix_time::to_simple_string(t);
}
So, just convert your 64-bit seconds to (64-bit) milliseconds, and you're good to go!
Note Be /very/ aware of compiler dependent behaviour with the capacity of builting integral types:
uint64_t offset = 113ul*365ul*24ul*60ul*60ul*1000ul; // 113 years give or take some leap seconds/days etc.?
would work on GCC or Clang, but it would simply overflow the calculations in MSVC2013. You'd need to explicitly coerce the calulation to 64 bits:
uint64_t offset = uint64_t(113ul)*365*24*60*60*1000;
You could apply time_durations in the maximum allowable increments (which is std::numeric_limits<long>::max()) since the total_seconds field is limited to long (signed).
Note: I worded it as int32_t below so that it will still work correctly if compiled on a 64-bit platform.
Here's a small demonstration:
#include "boost/date_time.hpp"
#include <iostream>
using namespace boost::gregorian;
using namespace boost::posix_time;
int main()
{
uint64_t offset = 113ul*365ul*24ul*60ul*60ul; // 113 years give or take some leap seconds/days etc.?
static const ptime time_t_epoch(date(1901,1,1));
static const uint32_t max_long = std::numeric_limits<int32_t>::max();
std::cout << "epoch: " << time_t_epoch << "\n";
ptime accum = time_t_epoch;
while (offset > max_long)
{
accum += seconds(max_long);
offset -= max_long;
std::cout << "accumulating: " << accum << "\n";
}
accum += seconds(offset);
std::cout << "final: " << accum << "\n";
}
Prints:
epoch: 1901-Jan-01 00:00:00
accumulating: 1969-Jan-19 03:14:07
final: 2013-Dec-04 00:00:00
See it Live on Coliru

Boost parse date/time string and yield .NET-compatible Ticks value

I'd like to use C++/Boost to parse time strings such as 1980.12.06 21:12:04.232 and acquire a ticks value that would correspond to the tick count( used to initialize .NET's System.DateTime). How can I do it?
Update: I do need to use C++; I cannot use C++/CLI for this.
in .Net Date time starts from 01.01.01 00:00:00
in boost ptime starts from 1400.01.01 00.00.00
//c++ code
#include <boost/date_time/posix_time/posix_time.hpp>
int main(int argc, char* argv[])
{
using namespace boost::posix_time;
using namespace boost::gregorian;
//C# offset till 1400.01.01 00:00:00
uint64_t netEpochOffset = 441481536000000000LL;
ptime ptimeEpoch(date(1400,1,1), time_duration(0,0,0));
//note: using different format than yours, you'll need to parse the time in a different way
ptime time = from_iso_string("19801206T211204,232");
time_duration td = time - netEpoch;
uint64_t nano = td.total_microseconds() * 10LL;
std::cout <<"net ticks = " <<nano + netEpochOffset;
return 0;
}
// outputs 624805819242320000
in c# to test
static void Main(string[] args)
{
DateTime date = new DateTime(1400,1,1);
Console.WriteLine(date.Ticks);
DateTime date2 = new DateTime(624805819242320000L); //C++ output
Console.WriteLine(date2);
/*output
* 441481536000000000
* 6/12/1980 21:12:04
* */
return;
}
.Net's "Ticks" is in 100-nanosecond intervals.
http://msdn.microsoft.com/en-us/library/z2xf7zzk.aspx
ticksType: System.Int64 A date and time expressed in the number of
100-nanosecond intervals that have elapsed since January 1, 0001 at
00:00:00.000 in the Gregorian calendar
So you need the tick count of a known epoch (e.g. the Unix epoch), the number of days between the epoch and the desired date/time, and the time of day (the total_nanoseconds accessor may help). Then you can easily calculate the .Net equivalent tick count, with simple addition and multiplication.
You may still have issues to do with the representable range of dates.