Converting epoch time to "real" date/time - c++

What I want to do is convert an epoch time (seconds since midnight 1/1/1970) to "real" time (m/d/y h:m:s)
So far, I have the following algorithm, which to me feels a bit ugly:
void DateTime::splitTicks(time_t time) {
seconds = time % 60;
time /= 60;
minutes = time % 60;
time /= 60;
hours = time % 24;
time /= 24;
year = DateTime::reduceDaysToYear(time);
month = DateTime::reduceDaysToMonths(time,year);
day = int(time);
}
int DateTime::reduceDaysToYear(time_t &days) {
int year;
for (year=1970;days>daysInYear(year);year++) {
days -= daysInYear(year);
}
return year;
}
int DateTime::reduceDaysToMonths(time_t &days,int year) {
int month;
for (month=0;days>daysInMonth(month,year);month++)
days -= daysInMonth(month,year);
return month;
}
you can assume that the members seconds, minutes, hours, month, day, and year all exist.
Using the for loops to modify the original time feels a little off, and I was wondering if there is a "better" solution to this.

Be careful about leap years in your daysInMonth function.
If you want very high performance, you can precompute the pair to get to month+year in one step, and then calculate the day/hour/min/sec.
A good solution is the one in the gmtime source code:
/*
* gmtime - convert the calendar time into broken down time
*/
/* $Header: gmtime.c,v 1.4 91/04/22 13:20:27 ceriel Exp $ */
#include <time.h>
#include <limits.h>
#include "loc_time.h"
struct tm *
gmtime(register const time_t *timer)
{
static struct tm br_time;
register struct tm *timep = &br_time;
time_t time = *timer;
register unsigned long dayclock, dayno;
int year = EPOCH_YR;
dayclock = (unsigned long)time % SECS_DAY;
dayno = (unsigned long)time / SECS_DAY;
timep->tm_sec = dayclock % 60;
timep->tm_min = (dayclock % 3600) / 60;
timep->tm_hour = dayclock / 3600;
timep->tm_wday = (dayno + 4) % 7; /* day 0 was a thursday */
while (dayno >= YEARSIZE(year)) {
dayno -= YEARSIZE(year);
year++;
}
timep->tm_year = year - YEAR0;
timep->tm_yday = dayno;
timep->tm_mon = 0;
while (dayno >= _ytab[LEAPYEAR(year)][timep->tm_mon]) {
dayno -= _ytab[LEAPYEAR(year)][timep->tm_mon];
timep->tm_mon++;
}
timep->tm_mday = dayno + 1;
timep->tm_isdst = 0;
return timep;
}

The standard library provides functions for doing this. gmtime() or localtime() will convert a time_t (seconds since the epoch, i.e.- Jan 1 1970 00:00:00) into a struct tm. strftime() can then be used to convert a struct tm into a string (char*) based on the format you specify.
see: http://www.cplusplus.com/reference/clibrary/ctime/
Date/time calculations can get tricky. You are much better off using an existing solution rather than trying to roll your own, unless you have a really good reason.

An easy way (though different than the format you wanted):
std::time_t result = std::time(nullptr);
std::cout << std::asctime(std::localtime(&result));
Output:
Wed Sep 21 10:27:52 2011
Notice that the returned result will be automatically concatenated with "\n".. you can remove it using:
std::string::size_type i = res.find("\n");
if (i != std::string::npos)
res.erase(i, res.length());
Taken from: http://en.cppreference.com/w/cpp/chrono/c/time

time_t t = unixTime;
cout << ctime(&t) << endl;

This code might help you.
#include <iostream>
#include <ctime>
using namespace std;
int main() {
// current date/time based on current system
time_t now = time(0);
// convert now to string form
char* dt = ctime(&now);
cout << "The local date and time is: " << dt << endl;
// convert now to tm struct for UTC
tm *gmtm = gmtime(&now);
dt = asctime(gmtm);
cout << "The UTC date and time is:"<< dt << endl;
}

To convert a epoch string to UTC
string epoch_to_utc(string epoch) {
long temp = stol(epoch);
const time_t old = (time_t)temp;
struct tm *oldt = gmtime(&old);
return asctime(oldt);
}
and then it can be called as
string temp = "245446047";
cout << epoch_to_utc(temp);
outputs:
Tue Oct 11 19:27:27 1977

If your original time type is time_t, you have to use functions from time.h i.e. gmtime etc. to get portable code. The C/C++ standards do not specify internal format (or even exact type) for the time_t, so you cannot directly convert or manipulate time_t values.
All that is known is that time_t is "arithmetic type", but results of arithmetic operations are not specified - you cannot even add/subtract reliably. In practice, many systems use integer type for time_t with internal format of seconds since epoch, but this is not enforced by standards.
In short, use gmtime (and time.h functionality in general).

Related

Read time from string as GMT in C++

I am writing current GMT time as string as follow :
const std::time_t now = std::time(nullptr);
std::stringstream ss;
ss << std::put_time(std::gmtime(&now), "%Y-%m-%d %H:%M:%S");
Later I want to do the reverse operation, reading time from the stringstream as GMT, and compare it to current timestamp :
std::tm tm = {};
ssTimestamp >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S");
const std::time_t&& time = std::mktime(&tm);
const double timestampDiff((std::difftime(std::time(nullptr), time)));
Something is missing in the code below, because the decoded time is never converted to GMT, thus I end up with 1 hour time difference due to my local timezone
P.S : Can use only standard libraries, and can' t change date string format
The C++20 spec has a convenient way to do this:
using namespace std::chrono;
sys_seconds tp;
ssTimestamp >> parse("%Y-%m-%d %H:%M:%S", tp);
std::time_t time = system_clock::to_time_t(tp);
No vendor has yet implemented this part of C++20, but there is an example implementation here in namespace date.
There is no library support to do this operation in C++ prior to C++20.
The best you can do using only standard libraries is to parse the fields into a tm using std::get_time (as your question shows), and then convert that {y, m, d, h, M, s} structure to a time_t using your own math, and the assumption (which is generally true) that std::time_t is Unix Time with a precision of seconds.
Here is a collection of public domain calendrical algorithms to help you do that. This is not a 3rd party library. It is a cookbook for writing your own date library.
For example:
#include <ctime>
std::time_t
to_time_t(std::tm const& tm)
{
int y = tm.tm_year + 1900;
unsigned m = tm.tm_mon + 1;
unsigned d = tm.tm_mday;
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)*86400 +
tm.tm_hour*3600 + tm.tm_min*60 + tm.tm_sec;
}
The link above has a very in-depth description of this algorithm and unit tests to make sure it works over a range of +/- millions of years.
The above to_time_t is essentially a portable version of timegm that ships on linux and bsd platforms. This function is also called _mkgmtime on Windows.
The tm struct doesn't store the timezone information, it's mktime that by default uses the local timezone.
Following this thread, the best option would be to use:
#include "time.h"
timestamp = mktime(&tm) - timezone; //or _timezone
if timezone or _timezone is available to your compiler. A comment in the linked answer warns that it may raise issues with daylight saving time, but it should not apply to GMT.
I recently tried to solve a very similar problem. I was trying to convert a string to a specific timezone regardless what is the current timezone of a computer. Here is the solution that I came up with and works as expected:
std::time_t from_time_str(std::string time_str) {
std::stringstream ss;
std::tm tm = {};
ss << time_str;
ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S");
std::time_t t = std::mktime(&tm);
std::tm* gm_tm = std::gmtime(&t);
gm_tm->tm_isdst = false;
std::time_t gm_t = std::mktime(gm_tm);
std::time_t gm_offset = (gm_t - t);
std::time_t real_gm_t = t - gm_offset;
return real_gm_t;
}
The idea is use the function gmtime to get the gmtime of the timestamp so we could calculate the offset of the target computer's timezone. We then subtract the offset to get the GM time.
Note that the line gm_tm->tm_isdst = false; is required for any timezone that has daylight saving is enable, otherwise the gmtime is calculated with daylight saving offset (1 hour off) and this should not be the desired effect of calculating the actual GM time.

Convert unix timestamp to human readable date

Is there a contemporary way to convert unix timestamps to a human readable date?
Since I want to circumnavigate the year 2038 problem, I want to use int64s.
I target to convert e. g. 1205812558 to
year = 2008, month = 3, day = 18,
hour = 17, minute = 18, second = 36
All I have is now
auto year = totalSeconds / secondsPerYear + 1970;
// month and day missing
auto hours = totalSeconds / 3600 % 24;
auto minutes = totalSeconds / 60 % 60;
auto seconds = totalSeconds % 60;
In C++20 (according to the draft-spec for C++20 as it stands today), you will be able to say:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std;
using namespace std::chrono;
cout << sys_seconds{1205812558s} << '\n';
cout << sys_seconds{32879409516s} << '\n';
}
and it will output:
2008-03-18 03:55:58
3011-11-28 17:18:36
These are datetimes in UTC.
You can use Howard Hinnant's date library to experiment with this extended <chrono> functionality today by adding:
#include "date/date.h"
and
using namespace date;
to the above program. You can experiment online with this program here.
A comment below asks for what this looks like if the value is stored in uint64_t. The answer is that you need to convert the integral type to seconds, and then the seconds to sys_seconds:
uint64_t i = 1205812558;
cout << sys_seconds{seconds(i)} << '\n';
There do exist limits on this contemporary functionality, but they live out near the years +/-32K (far beyond the limits of the accuracy of the current civil calendar).
To be completely transparent, there do exist ways of doing this using only C++98/11/14/17, but they are more complicated than this, and are subject to multithreading bugs. This is due to the use of an antiquated C API that was designed before things like multithreading and C++ were on the horizon, and when the year 2001 was only associated with science fiction (e.g. gmtime).
Wrapper
#include <chrono>
char* get_time(time_t unix_timestamp)
{
char time_buf[80];
struct tm ts;
ts = *localtime(&unix_timestamp);
strftime(time_buf, sizeof(time_buf), "%a %Y-%m-%d %H:%M:%S %Z", &ts);
return time_buf;
}
Howard Hinnant's date library makes things pretty easy:
#include "date.h"
int main()
{
using namespace date;
time_t time = 32879409516;
auto sysTime = std::chrono::system_clock::from_time_t(time);
auto date = year_month_day(floor<days>(sysTime));
std::cout << date << "\n";
}
A good straight forward solution but could do with some minor changes:
uint32_t days = (uint32_t)floor(subt / 86400);
uint32_t hours = (uint32_t)floor(((subt - days * 86400) / 3600) % 24);
uint32_t minutes = (uint32_t)floor((((subt - days * 86400) - hours * 3600) / 60) % 60);
uint32_t seconds = (uint32_t)floor(((((subt - days * 86400) - hours * 3600) - minutes * 60)) % 60);
printf("Time remaining: %u Days, %u Hours, %u Minutes, %u Seconds\n", days, hours, minutes, seconds);

Wrong time with localtime()

Running dateon my server results in the correct time. But using localtime() in C(++) I'm getting the wrong time.
Running date: Fr 30. Nov 12:15:36 CET 2012
Using localtime(): Fr 30 Nov 2012 11:15:36 CET
What's wrong here?
OS: Debian 5.0.10
Some code:
struct tm* today;
today = localtime(...);
strftime(timeBuffer,50,myConnection.getMetaData().getDateFormat().c_str(),today);
disclaimer : This answer was written before any mention of strftime was added, and was a gut reaction to the 1 hour difference in the timestamps. Looking back at it now, that 1 hour difference couldn't have been due to DST (because the dates are not in summer), but is likely showing a UTC timestamp (1 hour difference between UTC and CET).
Unfortunately, the answer was accepted, and so I can't delete it. Even more unfortunate, is that the question as it stands is not answerable without additional information.
Leaving the original answer here for full transparency, but know that it does not address the question as asked :
The struct tm returned by localtime has a tm_isdst field that indicates whether daylight saving time (DST) is in effect. You need to take that field into account when formatting the time.
Try using asctime to format the time eg. :
puts(asctime(today));
I have experienced the same problem while writing a date adjustment routine. Adding 86400 seconds (= 1 day) to any given datetime value should result in incrementing the datetime value by one day. However in testing, the output value invariably added exactly one hour to the expected output. For instance, '2019-03-20 00:00:00' incremented by 86400 seconds resulted in '2019-03-21 01:00:00'. The reverse also occurred: '2019-03-21 00:00:00' decremented by -86400 resulted in '2019-03-20 01:00:00'.
The solution (inexplicably) was to subtract 3600 seconds (one hour) from the final interval before applying it to the input datetime.
The solution (thanks to helpful comments from #Lightness-Races-in-Orbit) was to set tm_isdst to -1 before calling mktime(). This tells mktime() that the DST status for the input datetime value is unknown, and that mktime() should use the system timezone databases to determine the correct timezone for the input datetime value.
The function (as corrected below) allows for any integer adjustment of days and now produces consistently correct results:
#include <stdio.h>
#include <string.h>
#include <time.h>
/*******************************************************************************
* \fn adjust_date()
*******************************************************************************/
int adjust_date(
char *original_date,
char *adjusted_date,
char *pattern_in,
char *pattern_out,
int adjustment,
size_t out_size)
{
/*
struct tm {
int tm_sec; // seconds 0-59
int tm_min; // minutes 0-59
int tm_hour; // hours 0-23
int tm_mday; // day of the month 1-31
int tm_mon; // month 0-11
int tm_year; // year minus 1900
int tm_wday; // day of the week 0-6
int tm_yday; // day in the year 0-365
int tm_isdst; // daylight saving time
};
*/
struct tm day;
time_t one_day = 86400;
// time_t interval = (one_day * adjustment) - 3600;
time_t interval = (one_day * adjustment);
strptime(original_date, pattern_in, &day);
day.tm_isdst = -1;
time_t t1 = mktime(&day);
if (t1 == -1) {
printf("The mktime() function failed");
return -1;
}
time_t t2 = t1 + interval;
struct tm *ptm = localtime(&t2);
if (ptm == NULL) {
printf("The localtime() function failed");
return -1;
}
strftime(adjusted_date, out_size, pattern_out, ptm);
return 0;
}
/*******************************************************************************
* \fn main()
*******************************************************************************/
int main()
{
char in_date[64] = "20190321000000" ,
out_date[64],
pattern_in[64] = "%Y%m%d%H%M%S",
pattern_out[64] = "%Y-%m-%d %H:%M:%S";
int day_diff = -1,
ret = 0;
size_t out_size = 64;
memset(out_date, 0, sizeof(out_date));
ret = adjust_date(in_date, out_date, pattern_in, pattern_out, day_diff, out_size);
if (ret == 0)
{
printf("Adjusted date: '%s'\n", out_date);
}
return ret;
}
Hopefully, this will be of some help to somebody. Your constructive comments are greatly appreciated.
handling date time is very error prone and usually badly tested. i always recommend using boost::date_time http://www.boost.org/doc/libs/1_52_0/doc/html/date_time.html
here are nice examples http://en.highscore.de/cpp/boost/datetime.html
Did you try this ? :
time_t rawtime;
struct tm * today;
time ( &rawtime );
today= localtime ( &rawtime );
puts(asctime (today));

Convert date and time numbers to time_t AND specify the timezone

I have the following integers:
int y, mon, d, h, min, s;
Their values are: 2012, 06, 27, 12, 47, 53 respectively. I want to represent the date time of "2012/06/27 12:47:53 UTC" if I have selected 'UTC' somewhere else in my application, or "2012/06/27 12:47:53 AEST" if I have selected 'AEST' somewhere else in my application.
I want to convert this into a time_t, and here's the code that I am current using to do so:
struct tm timeinfo;
timeinfo.tm_year = year - 1900;
timeinfo.tm_mon = mon - 1;
timeinfo.tm_mday = day;
timeinfo.tm_hour = hour;
timeinfo.tm_min = min;
timeinfo.tm_sec = sec;
//timeinfo.tm_isdst = 0; //TODO should this be set?
//TODO find POSIX or C standard way to do covert tm to time_t without in UTC instead of local time
#ifdef UNIX
return timegm(&timeinfo);
#else
return mktime(&timeinfo); //FIXME Still incorrect
#endif
So I am using a tm struct and mktime, however this is not working well, because it is always assuming my local time-zone.
What is the correct way of doing this?
So below is the solution that I have come up with so far.
It basically does one of three things:
If UNIX, simply use timegm
If not UNIX
Either, do math using the difference between UTC epoch and local epoch as an offset
Reservation: Math may be incorrect
Or, set the "TZ" environment variable to UTC temporarily
Reservation: will trip up if/ when this code needs to be multithreaded
namespace tmUtil
{
int const tm_yearCorrection = -1900;
int const tm_monthCorrection = -1;
int const tm_isdst_dontKnow = -1;
#if !defined(DEBUG_DATETIME_TIMEGM_ENVVARTZ) && !(defined(UNIX) && !defined(DEBUG_DATETIME_TIMEGM))
static bool isLeap(int year)
{
return
(year % 4) ? false
: (year % 100) ? true
: (year % 400) ? false
: true;
}
static int daysIn(int year)
{
return isLeap(year) ? 366 : 365;
}
#endif
}
time_t utc(int year, int mon, int day, int hour, int min, int sec)
{
struct tm time = {0};
time.tm_year = year + tmUtil::tm_yearCorrection;
time.tm_mon = mon + tmUtil::tm_monthCorrection;
time.tm_mday = day;
time.tm_hour = hour;
time.tm_min = min;
time.tm_sec = sec;
time.tm_isdst = tmUtil::tm_isdst_dontKnow;
#if defined(UNIX) && !defined(DEBUG_DATETIME_TIMEGM) //TODO remove && 00
time_t result;
result = timegm(&time);
return result;
#else
#if !defined(DEBUG_DATETIME_TIMEGM_ENVVARTZ)
//TODO check that math is correct
time_t fromEpochUtc = mktime(&time);
struct tm localData;
struct tm utcData;
struct tm* loc = localtime_r (&fromEpochUtc, &localData);
struct tm* utc = gmtime_r (&fromEpochUtc, &utcData);
int utcYear = utc->tm_year - tmUtil::tm_yearCorrection;
int gmtOff =
(loc-> tm_sec - utc-> tm_sec)
+ (loc-> tm_min - utc-> tm_min) * 60
+ (loc->tm_hour - utc->tm_hour) * 60 * 60
+ (loc->tm_yday - utc->tm_yday) * 60 * 60 * 24
+ (loc->tm_year - utc->tm_year) * 60 * 60 * 24 * tmUtil::daysIn(utcYear);
#ifdef UNIX
if (loc->tm_gmtoff != gmtOff)
{
StringBuilder err("loc->tm_gmtoff=", StringBuilder((int)(loc->tm_gmtoff)), " but gmtOff=", StringBuilder(gmtOff));
THROWEXCEPTION(err);
}
#endif
int resultInt = fromEpochUtc + gmtOff;
time_t result;
result = (time_t)resultInt;
return result;
#else
//TODO Find a way to do this without manipulating environment variables
time_t result;
char *tz;
tz = getenv("TZ");
setenv("TZ", "", 1);
tzset();
result = mktime(&time);
if (tz)
setenv("TZ", tz, 1);
else
unsetenv("TZ");
tzset();
return result;
#endif
#endif
}
N.B. StringBuilder is an internal class, it doesn't matter for the purposes of this question.
More info:
I know that this can be done easily using boost, et al. But this is NOT and option. I need it to be done mathematically, or using a c or c++ standard function, or combinations thereof.
timegm appears to solve this problem, however, it doesn't appear to part of the C / POSIX standard. This code currently is compiled on multiple platforms (Linux, OSX, WIndows, iOS, Android (NDK)), so I need to find a way to make it work across all of these platforms, even if the solution involves #ifdef $PLATFORM type things.
It makes me want to throw up in my mouth a little bit, but you could convert it to a string with strftime(), replace the timezone in the string and then convert it back with strptime() and into a time_t with mktime(). In detail:
#ifdef UGLY_HACK_VOIDS_WARRANTY
time_t convert_time(const struct tm* tm)
{
const size_t BUF_SIZE=256;
char buffer[BUF_SIZE];
strftime(buffer,256,"%F %H:%M:%S %z", tm);
strncpy(&buffer[20], "+0001", 5); // +0001 is the time-zone offset from UTC in hours
struct tm newtime = {0};
strptime(buffer, "%F %H:%M:%S %z", &newtime);
return mktime(&newtime);
}
#endif
However, I would highly recommend you convince the powers that be that boost is an option after all. Boost has great support for custom timezones. There are other libraries that do this elegantly as well.
If all you want is to convert a struct tm given in UTC to a time_t then you can do it like this:
#include <time.h>
time_t utc_to_time_t(struct tm* timeinfo)
{
tzset(); // load timezone information (this can be called just once)
time_t t = mktime(timeinfo);
return t - timezone;
}
This basically converts the UTC time to time_t as if the given time was local, then applies a timezone correction to the result to bring it back to UTC.
Tested on gcc/cygwin and Visual Studio 2010.
I hope this helps!
Update: As you very well pointed out, my solution above may return time_t value that is one hour off when the daylight time savings state of the queried date is different than the one for the current time.
The solution for that problem is to have an additional function that can tell you if a date falls in the DST region or not, and use that and the current DST flag to adjust the time returned by mktime. This is actually easy to do. When you call mktime() you just have to set the tm_dst member to -1 and then the system will do its best to figure out the DST at the given time for you. Assuming we trust the system on this, then you can use this information to apply a correction:
#include <time.h>
time_t utc_to_time_t(struct tm* timeinfo)
{
tzset(); // load timezone information (this can be called just once)
timeinfo->tm_isdst = -1; // let the system figure this out for us
time_t t = mktime(timeinfo) - timezone;
if (daylight == 0 && timeinfo->tm_isdst != 0)
t += 3600;
else if (daylight != 0 && timeinfo->tm_isdst == 0)
t -= 3600;
return t;
}
If you are on Linux or other UNIx or UNIX-like system then you might have a timegm function that does what you want. The linked manual page have a portable implementation so you can make it yourself. On Windows I know of no such function.
After beating my head against this for days trying to get a timegm(1) function that works on Android (which does not ship with one), I finally discovered this simple and elegant solution, which works beautifully:
time_t timegm( struct tm *tm ) {
time_t t = mktime( tm );
return t + localtime( &t )->tm_gmtoff;
}
I don't see why this wouldn't be a suitable cross-platform solution.
I hope this helps!
time_t my_timegm2(struct tm *tm)
{
time_t ret = tm->tm_sec + tm->tm_min*60 + tm->tm_hour*3600 + tm->tm_yday*86400;
ret += ((time_t)31536000) * (tm->tm_year-70);
ret += ((tm->tm_year-69)/4)*86400 - ((tm->tm_year-1)/100)*86400 + ((tm->tm_year+299)/400)*86400;
return ret;
}
There seems to be a simpler solution:
#include <time64.h>
time_t timegm(struct tm* const t)
{
return (time_t)timegm64(t);
}
Actually I have not testet yet if really it works, because I still have a bit of porting to do, but it compiles.
Here's my solution:
#ifdef WIN32
# define timegm _mkgmtime
#endif
struct tm timeinfo;
timeinfo.tm_year = year - 1900;
timeinfo.tm_mon = mon - 1;
timeinfo.tm_mday = day;
timeinfo.tm_hour = hour;
timeinfo.tm_min = min;
timeinfo.tm_sec = sec;
return timegm(&timeinfo);
This should work both for unix and windows

Convert Windows Filetime to second in Unix/Linux

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