-1

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.

Community
  • 1
  • 1
primeQuestion
  • 51
  • 1
  • 9
  • 1
    Possible duplicate of [Convert Epoch Time string to Time](http://stackoverflow.com/questions/14792658/convert-epoch-time-string-to-time) – RoiHatam May 07 '17 at 15:06
  • You don't suppose that the conversion of that number into a DateTime object might be the slightest bit pertinent to the question, do you? – Mike Nakis May 07 '17 at 15:14
  • Regarding "standard C++ time object". C++11 or more recent an acceptable standard? – user4581301 May 07 '17 at 15:20
  • Best would be C++11 since i am not sure what compiler version i am gonna have on our production servers. But C++14 will also be acceptable i hope – primeQuestion May 07 '17 at 15:23
  • 1
    Groovy. [Howard Hinnant's time libraries may be helpful to you.](https://howardhinnant.github.io/date/date.html) Some Epoch conversion (see @MikeNakis 's answer below) may be necessary. – user4581301 May 07 '17 at 15:25

3 Answers3

1
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.

  • 1
    While this code may solve the question, [including an explanation](//meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – Adrian Mole Oct 20 '21 at 14:22
0

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.

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
  • The way it currently works is by using the DateTime::FromFileTime function to convert the unsigned int64 into a DateTime object. – primeQuestion May 07 '17 at 15:29
  • Same thing, according to [**the documentation of FromFileTime**] (https://msdn.microsoft.com/en-us/library/system.datetime.fromfiletime(v=vs.110).aspx) – Mike Nakis May 07 '17 at 15:30
  • what do yuo mean by: "So, you first need to convert 100-nanosecond intervals to seconds, and then convert from January 1, 0001 to January 1, 1970" - how do i doo this conversion? – primeQuestion May 07 '17 at 15:31
  • 1
    Uh, that's not a programming question. How about taking it to https://math.stackexchange.com/ ? – Mike Nakis May 07 '17 at 15:33
0

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.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • Thanks a lot. But my job doesn't allow the use of third party libraries. Is it possible to do this with the build in chrono library? – primeQuestion May 07 '17 at 16:31
  • @primeQuestion: Yes, my entire library is portably built on top of ``. You'll need to compute the number of `0.1 microseconds` between the two epoch dates, subtract that off your input, then convert that into a `{year, month, day, hour, minute, second, fractional second}` data structure, and then format it. Here is a paper with calendrical formulas to help you: http://howardhinnant.github.io/date_algorithms.html – Howard Hinnant May 07 '17 at 16:36
  • Thanks. Why did you use jan/1/1601 as the epoh date for Windows? Isn't it January 1, 0001 at 00:00:00.000? – primeQuestion May 07 '17 at 16:39
  • Also - the "tt" is supposed to output PM or AM. the proper output for 131274907755873979 in the original code is 9/12/2016 03:12:55.5873979 PM. So it's slightly different form yours. Maybe due to the "tt"? – primeQuestion May 07 '17 at 16:41
  • I used jan/1/1601 because I guessed that you are using something based off of the Windows Filetime epoch (which is 1601-01-01 00:00:00 UTC). When I used that epoch, your sample input gave a reasonable output, and so I assumed my guess was correct. – Howard Hinnant May 07 '17 at 16:48
  • I've reformatted my answer to the style you want (12 hour clock). It still doesn't match your desired output. It is off by 20 days and 2 hours. My best guess is that you've got a 20 day mistake in your computation, and that you would like a 2h timezone offset. My library can handle timezone offsets using the IANA timezone names, or the machine's current local timezone. – Howard Hinnant May 07 '17 at 16:59
  • @ Howard Hinnant - thanks a lot. I made a mistake and copied the wrong timestamp - the value 131274907755873979 gives a timestamp of 29/12/2016 03:12:55.5873979 PM. So it's really close. But for some reason it's still off by 2 hours. I have just checked it in VS using DateTime.FromFileTime. So that's the corresponding timestamp of this number. Is it possible to adjust your code so it outputs the same value? – primeQuestion May 07 '17 at 17:10
  • Done. I needed to add a "timezone" which IANA calls "Etc/GMT-2", which for dumb reasons means UTC _plus_ 2h, not UTC _minus_ 2h. – Howard Hinnant May 07 '17 at 17:15
  • @ Howard Hinnant Thanks a lot. Can you please help me a bit so i can write this using only chrono? I am not sure what you mean in the post when you said "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 from a std::chrono::time_point" - can you explain/give example to what you mean? Also, how do i format the time_point- how do i convert it into text? – primeQuestion May 07 '17 at 18:44
  • What I mean is that it is doable. I didn't say it was easy. I've been perfecting this library for a couple of years now. I don't recommend trying to write it yourself. But if you want to, the underlying formulas are freely available here: http://howardhinnant.github.io/date_algorithms.html . You are welcome to inspect the source code (it is open source). But I ask that you respect the copyright, which means including the copyright in your code if you use the source, or a derivation of it. It is the MIT license which is intended to be as permissive as possible. – Howard Hinnant May 07 '17 at 19:24
  • Thanks a lot. Can you please explain that line - sys_days{jan/1/1970} + (FileTime{static_cast(i)} - offset);? I am not sure why you add sys_days{jan/1/1970}? Wasn't the point to subtract it via offset? – primeQuestion May 09 '17 at 08:49
  • does this project work on Linux? The code i need has to run on a Linux platform. – primeQuestion May 09 '17 at 09:31
  • Yes, with gcc-5 or later and `-std=c++11` or later. – Howard Hinnant May 09 '17 at 13:09
  • Thanks i will try that soon. In the meantime it works on Windows but only witohut the make_zoned function addition. When adding that it crushes. It said in an error message that the tzdata was missing. So i created it and downloaded timezone data from IANA there. But now it throws the error - "Error opening time zone mapping file \"C:\\Users\\ed\\Downloads\\tzdata\\windowsZones.xml\"." Where do i get this file from? – primeQuestion May 09 '17 at 14:00
  • Here are the installation instructions for using the timezone part of this library: https://howardhinnant.github.io/date/tz.html#Installation This includes links for the IANA tzdatabase, and options for installing these files automatically (requires curl and 7-zip on Windows). – Howard Hinnant May 09 '17 at 14:21