12

Is there any C++ implementation of 64-bit Unix timestamp conversions for 32-bit systems? I need to convert struct tm to 64-bit integer and vice versa, including leap years, time zones, UTC. Also need it portable, at least for GNU/Linux and Windows.

phuclv
  • 37,963
  • 15
  • 156
  • 475
Adam Trhon
  • 2,915
  • 1
  • 20
  • 51
  • What should that timestamp represent? If its just seconds since epoch, then you can just use a 32bit conversion function and copy the result into a 64bit integer (as long as you are before 2038) – PlasmaHH Oct 27 '11 at 10:19
  • Isn't `time_t` already 64 bit on most systems? Windows has most functions also in a 64bit variant. Just google for it. – RedX Oct 27 '11 at 10:22
  • An integer cannot represent timezones as it's a relative offset from an arbitrary epoch (in UNIX that's Jan 01 1970), but the timezone is undefined. If you want to represent these elements you'll have to break them down into a `struct` anyway. Also no one 'represents' leap years; how would they? Hold a meaningless count of them or something? – trojanfoe Oct 27 '11 at 10:25
  • 1
    PlasmaHH: Exactly, just not before 2038 – Adam Trhon Oct 27 '11 at 10:31
  • RedX: I belive that only on 64bit systems. Please correct me if I am wrong. – Adam Trhon Oct 27 '11 at 10:33
  • trojanfoe: You are right, the integer cannot represent any of these. But you have to consider them when converting to `struct tm` – Adam Trhon Oct 27 '11 at 10:35

5 Answers5

14

You need:

typedef long long time64_t; 
time64_t mktime64(struct tm *t); 
struct tm* localtime64_r(const time64_t* t, struct tm* p);

Originally (in 2011) this answer contained links to 2038bug.com where it was possible to download the small pivotal_gmtime_r library, containing the mentioned functions. The library has been removed from 2038bug.com back then, the links became broken and were removed from the answer by a moderator. Seems like that pivotal_gmtime_r code can now be found here:

https://github.com/franklin373/mortage/tree/master/time_pivotal

Also, I've found another, more recent library, called y2038, that also implements mktime64 and localtime64_r:

https://github.com/evalEmpire/y2038

Alexei Khlebnikov
  • 2,126
  • 1
  • 21
  • 21
  • This looks like a perfect solution for me. It just seems to me that mktime64 expects UTC in its parameter. Converting time_t to struct tm by localtime64_r and back using mktime64 doesn't give the original time, while converting time_t to struct tm by gmtime64_r and back by mktime64 does. Can you please confirm it? – Adam Trhon Nov 07 '11 at 23:22
  • Yes, confirming! `localtime` was mentioned so much in this thread that I mixed it up. :) Of course you need `gmtime64_r`. – Alexei Khlebnikov Nov 16 '11 at 10:22
  • But as I understand it, ‘mktime‘ should expect local time, doesn’t it? – Adam Trhon Nov 16 '11 at 15:15
  • Yes, seems like an inconsistency. Standard `mktime` expects local time and will supposedly get timezone from your local settings and convert it to `UTC`. But this `mktime64` is "timezone-agnostic". I.e. it will give you output `time64_t` in `UTC` if you supply input `struct tm` in `UTC`, output in `UTC+10` if you supply input in `UTC+10`, etc. – Alexei Khlebnikov Nov 22 '11 at 12:42
  • Where are those functions? `ack mktime64 /usr/include/` comes back blank on recent Linux – dargaud Dec 18 '19 at 09:16
  • @dargaud, I have updated the answer with links and with some explanation. – Alexei Khlebnikov Jan 08 '20 at 10:37
7

The function converting a struct tm* to a time_t is mktime. You can find many implementations of it, eg. in Glibc and in libvxc's mktime.c file. You could take the code (assuming it is legal to you, so please respect licenses) and change time_t to some 64 bits integer like int64_t.

The functions doing the other conversions from time_t to struct tm* are localtime or gmtime and you could do likewise.

However, you might have a more fundamental issue: your 32 bits machine running in the year 2040 should have some way of giving you the current time (as the time system call does) appropriately in the 64 bits variant of time_t, and that is much harder (it depends upon the kernel and the hardware).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • Is there any implementation which handles `localtime` in a portable manner? – Adam Trhon Nov 05 '11 at 10:34
  • 1
    I don't understand the question. What do you call portable? `time_t` can be a 32 bits or a 64 bits integer type (so the machine code has to be different). – Basile Starynkevitch Nov 05 '11 at 10:51
  • I was thinking about using sources. But when I went through some of them, they used non-standard built-in functions for determining timezone and DST – Adam Trhon Nov 05 '11 at 11:38
  • it is perfectly portable, but they don't care about a difference between UTC and local time – Adam Trhon Nov 05 '11 at 12:14
  • Also notice that in `mktime` they don't adjust ranges in `struct tm` – Adam Trhon Nov 05 '11 at 12:21
  • The version of mktime() that you've linked is very naive. Compare it, for example, with [`mktime()`](http://www.raspberryginger.com/jbailey/minix/html/mktime_8c-source.html) from minix. – jfs Nov 06 '11 at 07:18
  • +1, for my purposes `libvxc` is pretty good. And BTW, to fix thing with local->UTC conversion is just one line of code, so this is not an issue really. – Agnius Vasiliauskas Nov 21 '12 at 13:09
6

You seem to be making the assumption that time_t is 32-bits on 32-bit systems, and this may or may not be true.

On Windows, starting with Visual Studio 2005 the size of time_t is 64-bits, even when you compile for 32-bit Windows.

The unfortunate part is that glibc defines it as long int, which on 32-bit systems is a 32-bit integer. That means that 32-bit Linux and other 32-bit platforms that are based on gcc/glibc (like Cygwin) will not be able to work with 64-bit timestamps.

If your application must run on 32-bit glibc, then you should use your own conversion functions, which could be the same functions in the C library recompiled to use 64-bit timestamps.

If you need source code with a permissive license (BSD), then you can look at these functions in minix3. Here is localtime. The source is hyperlinked, so you can find the others easily.

Miguel Grinberg
  • 65,299
  • 14
  • 133
  • 152
0

64-bit time support on 32-bit Linux was first introduced in the 5.1 kernel with the addition of the new *time64 syscalls (because changing the return type of old system calls breaks old applications). Check this table and you'll see that those syscalls are only available on 32-bit platforms.

But that's only support from the kernel side. You can call clock_gettime64 directly (from inline assembly, or from C with syscall() function) to get the current time but you'll need Linux-specific code because there's no glibc support yet. For full userspace support you must be on Linux 5.6 or higher along with musl 1.2+ or glibc 2.32+. Just rebuild your code and time_t will become 64-bit long. Now code that uses time_t will become completely portable

  • All user space must be compiled with a 64-bit time_t, which will be supported in the coming musl-1.2 and glibc-2.32 releases, along with installed kernel headers from linux-5.6 or higher.

  • Applications that use the system call interfaces directly need to be ported to use the time64 syscalls added in linux-5.1 in place of the existing system calls. This impacts most users of futex() and seccomp() as well as programming languages that have their own runtime environment not based on libc.

https://lkml.org/lkml/2020/1/29/355?anz=web

For more information read

phuclv
  • 37,963
  • 15
  • 156
  • 475
-1

Yeah use stuct tm *_localtime64 ( const __time64_t *timer);

That's if your windows fan.

Taryn
  • 242,637
  • 56
  • 362
  • 405