3

I have the negative timestamp (that is date older 1970, e.g. 15.04.1896). How to convert the given timestamp to the correct date string.

As I'm trying to do it

#include <ctime>
#include <string>
#include <iostream>


int _tmain(int argc, _TCHAR* argv[])
{
    time_t t = std::atol("-2326924800");
    struct tm * ptm;
    ptm = gmtime ( &t );

    std::cout << ptm->tm_year;
    std::cin.get();
    return 0;
}
Artem Zubkov
  • 559
  • 1
  • 14
  • 29
  • 1
    Do you need to account for the calendar changes, which, btw, occurred at different times in different countries? – Alexey Frunze Jun 27 '12 at 09:52
  • 1
    Have you even tried to use the functions you use normally for positive values? I don't know if its standard behaviour, but on my system they work well for negative numbers too. – PlasmaHH Jun 27 '12 at 09:55
  • @artzub What does your `Something like that.` refer to? My comment? If mine, what other data have you got? Country name? – Alexey Frunze Jun 27 '12 at 09:59
  • @PlasmaHH i used `strftime`, problem in `timeinfo` after convert timestamp to timeinfo the normal date turns into 2038. I don't know another methods. – Artem Zubkov Jun 27 '12 at 10:01
  • @Alex How does this relate to the issue? – Artem Zubkov Jun 27 '12 at 10:05
  • 1
    @artzub: I don't know what function `timeinfo` is, but using things like `gmtime()` returns proper years for me. Maybe you can show us a self-contained minimal example of what you are doing, that people can take, compile, and see for themselves what you see? – PlasmaHH Jun 27 '12 at 10:06
  • 2
    It relates to the issue very directly. In Russia the Gregorian calendar was accepted in 1918. The last country of Eastern Orthodox Europe to adopt the Gregorian calendar was Greece (1923). There's a [good article on the Gregorian calendar on Wikipedia](http://en.wikipedia.org/wiki/Gregorian_calendar). So, depending on the place, the seconds elapsed from a date in the past until now can vary quite a bit. – Alexey Frunze Jun 27 '12 at 10:15
  • @PlasmaHH I'm added my code. But him make error. – Artem Zubkov Jun 27 '12 at 10:18
  • @Alex Thanks, I realized... But I think the problem is not the case. – Artem Zubkov Jun 27 '12 at 10:21
  • It wasn't clear if you wanted a calendar-correct value or not because for the kind of date you specified in the question getting the right value is tricky and usually standard functions don't do those tricks. – Alexey Frunze Jun 27 '12 at 10:23
  • @Alex thx for explanation, but mine the issue in a different plane. – Artem Zubkov Jun 27 '12 at 10:32
  • @PlasmaHH How you are doing? Give me, please, your example. – Artem Zubkov Jun 27 '12 at 10:34
  • @artzub: What error are you getting? When replacing the _tmain by a proper main, it compiles fine and returns the expected result (-4) – PlasmaHH Jun 27 '12 at 11:05

2 Answers2

2

Since it looks like you're using Windows (I'm inferring it from TCHAR), you probably want to use FileTimeToSystemTime(). It works with years since 1601.

Example:

#include <windows.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
  SYSTEMTIME sysTime;
  FILETIME fileTime;
  long long seconds;

  sysTime.wYear = 1896;
  sysTime.wMonth = 4;
  sysTime.wDayOfWeek = 0;
  sysTime.wDay = 15;
  sysTime.wHour = 0;
  sysTime.wMinute = 0;
  sysTime.wSecond = 0;
  sysTime.wMilliseconds = 0;

  if (SystemTimeToFileTime(&sysTime, &fileTime))
  {
    seconds = *(long long*)&fileTime;
    seconds /= 10000000; // 100-nanoseconds to seconds since Jan 1st 1601
    seconds -= 11644473600; // 1601 to 1970
    printf("%d.%d.%d is %lld seconds from Jan 1st 1970\n",
           sysTime.wDay,
           sysTime.wMonth,
           sysTime.wYear,
           seconds);
  }
  else
  {
    printf("SystemTimeToFileTime() failed with error 0x%X\n", GetLastError());
  }

  // Now, convert it back...

  seconds += 11644473600; // 1970 to 1601
  seconds *= 10000000; // seconds since Jan 1st 1601 to 100-nanoseconds
  *(long long*)&fileTime = seconds;

  memset(&sysTime, 0, sizeof(sysTime));

  if (FileTimeToSystemTime(&fileTime, &sysTime))
  {
    seconds /= 10000000; // 100-nanoseconds to seconds since Jan 1st 1601
    seconds -= 11644473600; // 1601 to 1970
    printf("%lld seconds from Jan 1st 1970 is %d.%d.%d\n",
           seconds,
           sysTime.wDay,
           sysTime.wMonth,
           sysTime.wYear);
  }
  else
  {
    printf("FileTimeToSystemTime() failed with error 0x%X\n", GetLastError());
  }

  return 0;
}

Output:

15.4.1896 is -2326147200 seconds from Jan 1st 1970
-2326147200 seconds from Jan 1st 1970 is 15.4.1896

A rough estimation (1896-1970+3.5/12)*365.2425*24*3600 gives -2326010337. So, we're good.

EDIT:

If you want a DIY solution without involving any OS- or compiler-specific functions, use my seconds to date converter from this answer.

This snippet shows how to use it:

  struct tm t;
  SecondsSinceEpochToDateTime(&t, -2326924800LL);
  printf("-2326924800 is %d.%d.%d %d:%d:%d\n",
         t.tm_mday,
         t.tm_mon + 1,
         t.tm_year + 1900,
         t.tm_hour,
         t.tm_min,
         t.tm_sec);

And this is the output of it:

-2326924800 is 6.4.1896 0:0:0

Yeah, -2326924800 is not 15.4.1896 by the Gregorian calendar. It's 6.4.

Community
  • 1
  • 1
Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
1

I'd suggest using boost::posix_time.

std::cout << boost::posix_time::to_simple_string(boost::posix_time::from_time_t(0) + boost::posix_time::seconds(-2326924800));

time_t is unsuitable because it is not specified to accept negative values (see What is ultimately a time_t typedef to?)

Community
  • 1
  • 1
ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • 1
    No, it's not specified :). See http://stackoverflow.com/questions/471248/what-is-ultimately-a-time-t-typedef-to – ecatmur Jun 27 '12 at 10:39
  • 1
    I meant quote that proves "ISO C defines time_t as an arithmetic type, but does not specify any particular type, range, resolution, or encoding for it." is true, but fair enough. – Griwes Jun 27 '12 at 10:49
  • My God, it's just amazing that `time_t` can't take negative values. Because obviously, when defining the specification for `time_t`, it was obvious to those making the specification that no programmer, ever, would want to do a calculation with a date less than Jan 1, 1970. But of course. – Dan Nissenbaum Oct 06 '14 at 06:37