I want to convert a time_duration to a DATE format, which is the number of days since 1899, 12, 30.
DATE date_from_duration(time_duration td)
{
double days = td.hours()/24.+td.minutes()/(24.*60.)+td.seconds()/(24.*60.*60.);
return days;
}
This code almost works but gives sometimes rounding errors, f.i the time_duration(1007645, 15, 0) should result in 2014-12-12 00:15:00, but is actually 2014-12-12 00:14:59.
The check of DATE is done with this method, stolen from here:
ptime pTime_from_DATE(double date)
{
using boost::math::modf;
static const ptime::date_type base_date(1899, Dec, 30);
static const ptime base_time(base_date, ptime::time_duration_type(0,0,0));
int dayOffset, hourOffset, minuteOffset, secondOffset;
double fraction = fabs(modf(date, &dayOffset)) * 24; // fraction = hours
fraction = modf(fraction, &hourOffset) * 60; // fraction = minutes
fraction = modf(fraction, &minuteOffset) * 60; // fraction = seconds
modf(fraction, &secondOffset);
ptime t(base_time);
t += ptime::time_duration_type(hourOffset, minuteOffset, secondOffset);
t += ptime::date_duration_type(dayOffset);
return t;
}
Any ideas how to correct this rounding issue efficiently?
I might be missing some of the complexity, but it seems really simple to me:
Live On Coliru
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
using DATE = double;
boost::posix_time::ptime pTime_from_DATE(double date)
{
static const boost::posix_time::ptime::date_type base_date(1899, boost::gregorian::Dec, 30);
return boost::posix_time::ptime(
base_date,
boost::posix_time::milliseconds(date * 1000 * 60 * 60 * 24));
}
int main() {
boost::posix_time::time_duration duration(1007645, 15, 0);
DATE date = duration.total_milliseconds() / 1000.0 / 60 / 60 / 24;
std::cout << date << ": " << pTime_from_DATE(date);
}
Prints
41985.2: 2014-Dec-12 05:15:00
See it Live On Coliru
That kind of depends on your circumstances.
The general problem is that 1 / (24. * 60. * 60.) is not exactly representable as a binary float (because 86400 is not a power of two). The DATE you get is very nearly exact, but there will be a rounding error. Sometimes this means that it is very little more, sometimes very little less, but there's really not a lot you can do to make it more precise; it is as perfectly alright as you can get. That you see a discrepancy of a second is arguably a problem with your check, in that you stop looking at seconds -- if you check the milliseconds, you're likely to get 999, making the rounding error look a lot less extreme. This will continue for microseconds and possibly nanoseconds, depending on the resolution of time_duration.
So quite possibly there's nothing to do because the data is alright. If, however, you don't care about milliseconds and beyond and only want the seconds value to be stable in conversions back and forth, the simplest way to achieve that is to add an epsilon value:
DATE date_from_duration(time_duration td)
{
double days =
td.hours () / 24.
+ td.minutes() / (24. * 60.)
+ td.seconds() / (24. * 60. * 60.)
+ 1e-8; // add roughly a millisecond
return days;
}
This increases the overall rounding error but ensures that the error is in a "safe" direction, i.e., that converting it back to time_duration will give the same seconds() value and the visible changes will be at the milliseconds() level.
Related
I'm trying to represent NTP timestamps (including the NTP epoch) in C++ using std::chrono. Therefore, I decided to use a 64-bit unsigned int (unsigned long long) for the ticks and divide it such that the lowest 28-bit represent the fraction of a second (accepting trunction of 4 bits in comparison to the original standard timestamps), the next 32-bit represent the seconds of an epoch and the highest 4-bit represent the epoch. This means that every tick takes 1 / (2^28 - 1) seconds.
I now have the following simple implementation:
#include <chrono>
/**
* Implements a custom C++11 clock starting at 1 Jan 1900 UTC with a tick duration of 2^(-28) seconds.
*/
class NTPClock
{
public:
static constexpr bool is_steady = false;
static constexpr unsigned int era_bits = 4; // epoch uses 4 bits
static constexpr unsigned int fractional_bits = 32-era_bits; // fraction uses 28 bits
static constexpr unsigned int seconds_bits = 32; // second uses 32 bits
using duration = std::chrono::duration<unsigned long long, std::ratio<1, (1<<fractional_bits)-1>>;
using rep = typename duration::rep;
using period = typename duration::period;
using time_point = std::chrono::time_point<NTPClock>;
/**
* Return the current time of this. Note that the implementation is based on the assumption
* that the system clock starts at 1 Jan 1970, which is not defined with C++11 but seems to be a
* standard in most compilers.
*
* #return The current time as represented by an NTP timestamp
*/
static time_point now() noexcept
{
return time_point
(
std::chrono::duration_cast<duration>(std::chrono::system_clock::now().time_since_epoch())
+ std::chrono::duration_cast<duration>(std::chrono::hours(24*25567)) // 25567 days have passed between 1 Jan 1900 and 1 Jan 1970
);
};
}
Unfortunately, a simple test reveals this does not work as expected:
#include <chrono>
#include <iostream>
#include <catch2/catch.hpp>
#include "NTPClock.h"
using namespace std::chrono;
TEST_CASE("NTPClock_now")
{
auto ntp_dur = NTPClock::now().time_since_epoch();
auto sys_dur = system_clock::now().time_since_epoch();
std::cout << duration_cast<hours>(ntp_dur) << std::endl;
std::cout << ntp_dur << std::endl;
std::cout << duration_cast<hours>(sys_dur) << std::endl;
std::cout << sys_dur << std::endl;
REQUIRE(duration_cast<hours>(ntp_dur)-duration_cast<hours>(sys_dur) == hours(24*25567));
}
Output:
613612h
592974797620267184[1/268435455]s
457599h
16473577714886015[1/10000000]s
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PackageTest.exe is a Catch v2.11.1 host application.
Run with -? for options
-------------------------------------------------------------------------------
NTPClock_now
-------------------------------------------------------------------------------
D:\Repos\...\TestNTPClock.cpp(10)
...............................................................................
D:\Repos\...\TestNTPClock.cpp(18): FAILED:
REQUIRE( duration_cast<hours>(ntp_dur)-duration_cast<hours>(sys_dur) == hours(24*25567) )
with expansion:
156013h == 613608h
===============================================================================
test cases: 1 | 1 failed
assertions: 1 | 1 failed
I also removed the offset of 25567 days in NTPClock::now asserting equality without success. I'm not sure what is going wrong here. Can anybody help?
Your tick period: 1/268'435'455 is unfortunately both extremely fine and also doesn't lend itself to much of a reduced fraction when your desired conversions are used (i.e. between system_clock::duration and NTPClock::duration. This is leading to internal overflow of your unsigned long long NTPClock::rep.
For example, on Windows the system_clock tick period is 1/10,000,000 seconds. The current value of now() is around 1.6 x 1016. To convert this to NTPClock::duration you have to compute 1.6 x 1016 times 53,687,091/2,000,000. The first step in that is the value times the numerator of the conversion factor which is about 8 x 1023, which overflows unsigned long long.
There's a couple of ways to overcome this overflow, and both involve using at least an intermediate representation with a larger range. One could use a 128 bit integral type, but I don't believe that is available on Windows, except perhaps by a 3rd party library. long double is another option. This might look like:
static time_point now() noexcept
{
using imd = std::chrono::duration<long double, period>;
return time_point
(
std::chrono::duration_cast<duration>(imd{std::chrono::system_clock::now().time_since_epoch()
+ std::chrono::hours(24*25567)})
);
};
That is, perform the offset shift with no conversion (system_clock::duration units), then convert that to the intermediate representation imd which has a long double rep, and the same period as NTPClock. This will use long double to compute 1.6 x 1016 times 53,687,091/2,000,000. Then finally duration_cast that to NTPClock::duration. This final duration_cast will end up doing nothing but casting long double to unsigned long long as the conversion factor is simply 1/1.
Another way to accomplish the same thing is:
static time_point now() noexcept
{
return time_point
(
std::chrono::duration_cast<duration>(std::chrono::system_clock::now().time_since_epoch()
+ std::chrono::hours(24*25567)*1.0L)
);
};
This takes advantage of the fact that you can multiply any duration by 1, but with alternate units and the result will have a rep with the common_type of the two arguments, but otherwise have the same value. I.e. std::chrono::hours(24*25567)*1.0L is a long double-based hours. And that long double carries through the rest of the computation until the duration_cast brings it back to NTPClock::duration.
This second way is simpler to write, but code reviewers may not understand the significance of the *1.0L, at least until it becomes a more common idiom.
Question
I want to parse a date-time given as string (UTC) into seconds since epoch. Example (see EpochConverter):
2019-01-15 10:00:00 -> 1547546400
Problem
The straightforward solution, which is also accepted in a very related question C++ Converting a time string to seconds from the epoch goes std::string -> std::tm -> std::time_t using std::get_time and then std::mktime:
std::tm tm;
std::stringstream ss("2019-01-15 10:00:00");
ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S");
std::time_t epoch = std::mktime(&tm);
// 1547546400 (expected)
// 1547539200 (actual, 2 hours too early)
But std::mktime seems to mess up the hours due to timezone. I am executing the code from UTC+01:00, but we also had DST at that date, so its +2 here.
The tm shows 15 for the hour field after std::get_time. It gets messed up as soon as it enters std::mktime.
So again, the string is to be interpreted as UTC timestamp, no timezones whatsoever should be involved. But all solutions I came up with seem to interpret it as local timestamp and add offsets to it.
Restrictions
I have some restrictions for this:
C++17
platform/compiler independent
no environment variable hacking
no external libraries (like boost)
Feel free to post answers involving those for the sake of Q&A though, but I wont accept them.
Research
I found various attempts to solve this problem, but none met my requirements:
std::mktime (as mentioned above), messes up the time because it assumes local time
strptime, not available on my platform, not part of the standard
timegm (thats exactly what I would need), not platform independent
_mkgmtime, not platform independent
boost::posix_time::from_iso_string, is an external library
std::chrono::date::parse, not available with C++17
clear and reset the timezone variable with tzset, uses environment variable hacking
manually countering the offset with mktime(localtime(×tamp)) - mktime(gmtime(×tamp)), computes the wrong offset since it does not account for DST (1 hour on my platform but it would need to be 2 hours)
Solution prior to C++20: Roll your own.
Given the right documentation, it really is much easier than it sounds, and can even be lightning fast if you don't need much error detection.
The first problem is to parse the numbers without manipulating any of them. You only need to read unsigned values of length 2 and 4 digits, so just do that bare minimum:
int
read2(std::string const& str, int pos)
{
return (str[pos] - '0')*10 + (str[pos+1] - '0');
}
int
read4(std::string const& str, int pos)
{
return (str[pos] - '0')*1000 + (str[pos+1] - '0')*100 +
(str[pos+2] - '0')*10 + (str[pos+3] - '0');
}
Now given a string, it is easy to parse out the different values you will need:
// yyyy-mm-dd hh:MM:ss -> count of non-leap seconds since 1970-01-01 00:00:00 UTC
// 0123456789012345678
long long
EpochConverter(std::string const& str)
{
auto y = read4(str, 0);
auto m = read2(str, 5);
auto d = read2(str, 8);
...
The part that usually trips people up is how to convert the triple {y, m, d} into a count of days since/prior 1970-01-01. Here is a collection of public domain calendrical algorithms that will help you do this. This is not a 3rd party date/time library. It is a tutorial on the algorithms you will need to write your own date/time library. And these algorithms are efficient. No iteration. No large tables. That makes them very pipeline and cache friendly. And they are unit tested over a span of +/- a million years. So you don't have to worry about hitting any correctness boundaries with them. These algorithms also have a very in-depth derivation if you are interested in how they work.
So just go to the collection of public domain calendrical algorithms, pick out the algorithms you need (and customize them however you want), and roll your own converter.
For example:
#include <cstdint>
#include <limits>
#include <string>
int
days_from_civil(int y, unsigned m, unsigned d) noexcept
{
static_assert(std::numeric_limits<unsigned>::digits >= 18,
"This algorithm has not been ported to a 16 bit unsigned integer");
static_assert(std::numeric_limits<int>::digits >= 20,
"This algorithm has not been ported to a 16 bit signed integer");
y -= m <= 2;
const int era = (y >= 0 ? y : y-399) / 400;
const unsigned yoe = static_cast<unsigned>(y - era * 400); // [0, 399]
const unsigned doy = (153*(m + (m > 2 ? -3 : 9)) + 2)/5 + d-1; // [0, 365]
const unsigned doe = yoe * 365 + yoe/4 - yoe/100 + doy; // [0, 146096]
return era * 146097 + static_cast<int>(doe) - 719468;
}
int
read2(std::string const& str, int pos)
{
return (str[pos] - '0')*10 + (str[pos+1] - '0');
}
int
read4(std::string const& str, int pos)
{
return (str[pos] - '0')*1000 + (str[pos+1] - '0')*100 +
(str[pos+2] - '0')*10 + (str[pos+3] - '0');
}
// yyyy-mm-dd hh:MM:ss -> count of non-leap seconds since 1970-01-01 00:00:00 UTC
// 0123456789012345678
long long
EpochConverter(std::string const& str)
{
auto y = read4(str, 0);
auto m = read2(str, 5);
auto d = read2(str, 8);
auto h = read2(str, 11);
auto M = read2(str, 14);
auto s = read2(str, 17);
return days_from_civil(y, m, d)*86400LL + h*3600 + M*60 + s;
}
#include <iostream>
int
main()
{
std::cout << EpochConverter("2019-01-15 10:00:00") << '\n';
}
This just output for me:
1547546400
Sprinkle in whatever error detection is appropriate for your application.
I had the same requirement recently. I was disappointed to find that the handling of DST and timezones seemed inconsistent between writing timestamps and parsing them.
The code I came up with was this:
void time_point_from_stream(std::istream &is, system_clock::time_point &tp)
{
std::tm tm {};
is >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S");
// unhappily, mktime thinks it's reading local time with DST adjustments
auto my_time_t = std::mktime(&tm);
my_time_t += tm.tm_gmtoff;
if (tm.tm_isdst == 1)
my_time_t -= 3600;
tp = system_clock::from_time_t(my_time_t);
if (not is)
return;
auto ch = is.peek();
if (std::isspace(ch))
return;
if (ch == '.')
{
double zz;
is >> zz;
auto zseconds = std::chrono::duration< double >(zz);
tp += chrono::duration_cast< system_clock::duration >(zseconds);
if (not is)
return;
ch = is.peek();
}
if (ch == 'Z')
is.get();
else if (not isspace(ch))
{
is.setstate(std::ios::failbit);
}
}
Essentially, the steps are:
Use std::get_time to fill a tm
use std::mktime to convert that to a time_t
reverse out timezone and DST adjustments
convert to a std::chrono::system_clock::time_point
Parse the fractional seconds and adjust the result.
I believe c++20 improves on the situation.
Howard Hinnant has also written an improved date/time library. There is also boost::posix_time which I have always found easier to use than the std offering.
(i'm using C++Builder 2006, if this matters)
I'm not able to solve this problem:
What i have (and i cannot change this):
typedef struct {
uint16_t Leaps; // How many Leaps from the previous event (see below)
uint16_t Ticks; // Event "machine ticks" (see below)
uint16_t Code;
} sMachineEvents;
typedef struct {
TDateTime Date;
uint16_t Code;
} sConvertEvents;
TDateTime Sync // Contains the date and time of Ev1
TICKS_PER_SECOND // #defined elsewhere: How many Ticks in a second
TICKS_PER_LEAP // #defined elsewhere: How many ticks to make a "Leap"
// (this means that when the Tick counter reaches TICKS_PER_LEAP
// it becomes 0 and the Leaps counter increases by 1)
sMachineEvents Ev[3];
sConvertEvents cEv[3];
Ev[0].Leaps = 0x0005;
Ev[0].Ticks = 0x5975;
Ev[0].Code = 0x0001;
Ev[1].Leaps = 0x0001;
Ev[1].Ticks = 0x0124;
Ev[1].Code = 0x0002;
Ev[2].Leaps = 0x0000;
Ev[2].Ticks = 0x70AC;
Ev[2].Code = 0x0003;
I need to "convert" these "MachineEvents" in "ConvertEvents".
The first one is easy:
cEv[0].Date = Sync;
cEv[0].Code = Ev[0].Code;
Now: Ev[1] happened BEFORE Ev[0].
How much? I need to go "back in time" by Ev[0].Leaps+Ev[0].Ticks and then go "forward in time" by Ev[1].Ticks.
Ev[2] is the same: it happened
Ev[1].Leaps + Ev[1].Ticks - Ev[2].Ticks
BEFORE Ev[1]....
HOW should I compute the DateTime for Ev[1] and Ev[2]?
TDateTime is actually a floating point value representing the number of days; an hour is represented by 1.0 / 24.0, and a second is represented by 1.0 / SecsPerDay (SecsPerDay is a constant equal to 60 * 60 * 24 = 86400).
So, if one tick is 1.0 / TICKS_PER_SECOND seconds:
TDateTime TimeAsTDateTime = TimeInTicks / (SecsPerDay * TICKS_PER_SECOND)
Also, I think your code is not correct: instead of Ev[0].Leaps+Ev[0].Ticks, as far as I can see you need to use Ev[0].Leaps * TICKS_PER_LEAP + Ev[0].Ticks.
If I understand you correct, you compare "ticks" with "time".
You have to convert the ticks in time format, done by tick_count / TICKS_PER_SECOND
So float Seconds = Tick / TICKS_PER_SECOND. As it is a float, you might better use Milliseconds
int ms = (int)(ticks / TICKS_PER_SECOND * 1000);
With the Seconds (or Milliseconds) you can create a new Date object and add the two Date Objects, or simply add the seconds to the old Date.
Another way would be saving all Ticks since start of the program and simply using this as "Date Reference".
My current pattern (for unix) is to call gettimeofday, cast the tv_sec field to a time_t, pass that through localtime, and combine the results with tv_usec. That gives me a full date (year, month, day, hour, minute, second, nanoseconds).
I'm trying to update my code to C++11 for portability and general good practice. I'm able to do the following:
auto currentTime = std::chrono::system_clock::now( );
const time_t time = std::chrono::system_clock::to_time_t( currentTime );
const tm *values = localtime( &time );
// read values->tm_year, etc.
But I'm stuck on the milliseconds/nanoseconds. For one thing, to_time_t claims that rounding is implementation defined (!) so I don't know if a final reading of 22.6 seconds should actually be 21.6, and for another I don't know how to get the number of milliseconds since the previous second (are seconds guaranteed by the standard to be regular? i.e. could I get the total milliseconds since the epoch and just modulo it? Even if that is OK it feels ugly).
How should I get the current date from std::chrono::system_clock with milliseconds?
I realised that I can use from_time_t to get a "rounded" value, and check which type of rounding occurred. This also doesn't rely on every second being exactly 1000 milliseconds, and works with out-of-the-box C++11:
const auto currentTime = std::chrono::system_clock::now( );
time_t time = std::chrono::system_clock::to_time_t( currentTime );
auto currentTimeRounded = std::chrono::system_clock::from_time_t( time );
if( currentTimeRounded > currentTime ) {
-- time;
currentTimeRounded -= std::chrono::seconds( 1 );
}
const tm *values = localtime( &time );
int year = values->tm_year + 1900;
// etc.
int milliseconds = std::chrono::duration_cast<std::chrono::duration<int,std::milli> >( currentTime - currentTimeRounded ).count( );
Using this free, open-source library you can get the local time with millisecond precision like this:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << make_zoned(current_zone(),
floor<milliseconds>(system_clock::now())) << '\n';
}
This just output for me:
2016-09-06 12:35:09.102 EDT
make_zoned is a factory function that creates a zoned_time<milliseconds>. The factory function deduces the desired precision for you. A zoned_time is a pairing of a time_zone and a local_time. You can get the local time out with:
local_time<milliseconds> lt = zt.get_local_time();
local_time is a chrono::time_point. You can break this down into date and time field types if you want like this:
auto zt = make_zoned(current_zone(), floor<milliseconds>(system_clock::now()));
auto lt = zt.get_local_time();
local_days ld = floor<days>(lt); // local time truncated to days
year_month_day ymd{ld}; // {year, month, day}
time_of_day<milliseconds> time{lt - ld}; // {hours, minutes, seconds, milliseconds}
// auto time = make_time(lt - ld); // another way to create time_of_day
auto y = ymd.year(); // 2016_y
auto m = ymd.month(); // sep
auto d = ymd.day(); // 6_d
auto h = time.hours(); // 12h
auto min = time.minutes(); // 35min
auto s = time.seconds(); // 9s
auto ms = time.subseconds(); // 102ms
Instead of using to_time_t which rounds off you can instead do like this
auto tp = std::system_clock::now();
auto s = std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch());
auto t = (time_t)(s.count());
That way you get the seconds without the round-off. It is more effective than checking difference between to_time_t and from_time_t.
I read the standard like this:
It is implementation defined whether the value is rounder or truncated, but naturally the rounding or truncation only occurs on the most detailed part of the resulting time_t. That is: the combined information you get from time_t is never more wrong than 0.5 of its granularity.
If time_t on your system only supported seconds, you would be right that there could be 0.5 seconds systematic uncertainty (unless you find out how things were implemented).
tv_usec is not standard C++, but an accessor of time_t on posix. To conclude, you should not expect any rounding effects bigger than half of the smallest time value difference your system supports, so certainly not more than 0.5 micro seconds.
The most straight forward way is to use boost ptime. It has methods such as fractional_seconds()
http://www.boost.org/doc/libs/1_53_0/doc/html/date_time/posix_time.html#date_time.posix_time.ptime_class
For interop with std::chrono, you can convert as described here: https://stackoverflow.com/a/4918873/1149664
Or, have a look at this question: How to convert std::chrono::time_point to calendar datetime string with fractional seconds?
I have a trace file that each transaction time represented in Windows filetime format. These time numbers are something like this:
128166372003061629
128166372016382155
128166372026382245
Would you please let me know if there are any C/C++ library in Unix/Linux to extract actual time (specially second) from these numbers ? May I write my own extraction function ?
it's quite simple: the windows epoch starts 1601-01-01T00:00:00Z. It's 11644473600 seconds before the UNIX/Linux epoch (1970-01-01T00:00:00Z). The Windows ticks are in 100 nanoseconds. Thus, a function to get seconds from the UNIX epoch will be as follows:
#define WINDOWS_TICK 10000000
#define SEC_TO_UNIX_EPOCH 11644473600LL
unsigned WindowsTickToUnixSeconds(long long windowsTicks)
{
return (unsigned)(windowsTicks / WINDOWS_TICK - SEC_TO_UNIX_EPOCH);
}
FILETIME type is is the number 100 ns increments since January 1 1601.
To convert this into a unix time_t you can use the following.
#define TICKS_PER_SECOND 10000000
#define EPOCH_DIFFERENCE 11644473600LL
time_t convertWindowsTimeToUnixTime(long long int input){
long long int temp;
temp = input / TICKS_PER_SECOND; //convert from 100ns intervals to seconds;
temp = temp - EPOCH_DIFFERENCE; //subtract number of seconds between epochs
return (time_t) temp;
}
you may then use the ctime functions to manipulate it.
(I discovered I can't enter readable code in a comment, so...)
Note that Windows can represent times outside the range of POSIX epoch times, and thus a conversion routine should return an "out-of-range" indication as appropriate. The simplest method is:
... (as above)
long long secs;
time_t t;
secs = (windowsTicks / WINDOWS_TICK - SEC_TO_UNIX_EPOCH);
t = (time_t) secs;
if (secs != (long long) t) // checks for truncation/overflow/underflow
return (time_t) -1; // value not representable as a POSIX time
return t;
New answer for old question.
Using C++11's <chrono> plus this free, open-source library:
https://github.com/HowardHinnant/date
One can very easily convert these timestamps to std::chrono::system_clock::time_point, and also convert these timestamps to human-readable format in the Gregorian calendar:
#include "date.h"
#include <iostream>
std::chrono::system_clock::time_point
from_windows_filetime(long long t)
{
using namespace std::chrono;
using namespace date;
using wfs = duration<long long, std::ratio<1, 10'000'000>>;
return system_clock::time_point{floor<system_clock::duration>(wfs{t} -
(sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1}))};
}
int
main()
{
using namespace date;
std::cout << from_windows_filetime(128166372003061629) << '\n';
std::cout << from_windows_filetime(128166372016382155) << '\n';
std::cout << from_windows_filetime(128166372026382245) << '\n';
}
For me this outputs:
2007-02-22 17:00:00.306162
2007-02-22 17:00:01.638215
2007-02-22 17:00:02.638224
On Windows, you can actually skip the floor, and get that last decimal digit of precision:
return system_clock::time_point{wfs{t} -
(sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1})};
2007-02-22 17:00:00.3061629
2007-02-22 17:00:01.6382155
2007-02-22 17:00:02.6382245
With optimizations on, the sub-expression (sys_days{1970_y/jan/1} - sys_days{1601_y/jan/1}) will translate at compile time to days{134774} which will further compile-time-convert to whatever units the full-expression requires (seconds, 100-nanoseconds, whatever). Bottom line: This is both very readable and very efficient.
The solution that divides and adds will not work correctly with daylight savings.
Here is a snippet that works, but it is for windows.
time_t FileTime_to_POSIX(FILETIME ft)
{
FILETIME localFileTime;
FileTimeToLocalFileTime(&ft,&localFileTime);
SYSTEMTIME sysTime;
FileTimeToSystemTime(&localFileTime,&sysTime);
struct tm tmtime = {0};
tmtime.tm_year = sysTime.wYear - 1900;
tmtime.tm_mon = sysTime.wMonth - 1;
tmtime.tm_mday = sysTime.wDay;
tmtime.tm_hour = sysTime.wHour;
tmtime.tm_min = sysTime.wMinute;
tmtime.tm_sec = sysTime.wSecond;
tmtime.tm_wday = 0;
tmtime.tm_yday = 0;
tmtime.tm_isdst = -1;
time_t ret = mktime(&tmtime);
return ret;
}
Assuming you are asking about the FILETIME Structure, then FileTimeToSystemTime does what you want, you can get the seconds from the SYSTEMTIME structure it produces.
Here's essentially the same solution except this one encodes negative numbers from Ldap properly and lops off the last 7 digits before conversion.
public static int LdapValueAsUnixTimestamp(SearchResult searchResult, string fieldName)
{
var strValue = LdapValue(searchResult, fieldName);
if (strValue == "0") return 0;
if (strValue == "9223372036854775807") return -1;
return (int)(long.Parse(strValue.Substring(0, strValue.Length - 7)) - 11644473600);
}
If somebody need convert it in MySQL
SELECT timestamp,
FROM_UNIXTIME(ROUND((((timestamp) / CAST(10000000 AS UNSIGNED INTEGER)))
- CAST(11644473600 AS UNSIGNED INTEGER),0))
AS Converted FROM events LIMIT 100
Also here's a pure C#ian way to do it.
(Int32)(DateTime.FromFileTimeUtc(129477880901875000).Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
Here's the result of both methods in my immediate window:
(Int32)(DateTime.FromFileTimeUtc(long.Parse(strValue)).Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
1303314490
(int)(long.Parse(strValue.Substring(0, strValue.Length - 7)) - 11644473600)
1303314490
DateTime.FromFileTimeUtc(long.Parse(strValue))
{2011-04-20 3:48:10 PM}
Date: {2011-04-20 12:00:00 AM}
Day: 20
DayOfWeek: Wednesday
DayOfYear: 110
Hour: 15
InternalKind: 4611686018427387904
InternalTicks: 634389112901875000
Kind: Utc
Millisecond: 187
Minute: 48
Month: 4
Second: 10
Ticks: 634389112901875000
TimeOfDay: {System.TimeSpan}
Year: 2011
dateData: 5246075131329262904