You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In order to make it possible to interoperate with C structs that contain time_t, add a new type c_time_t to the ctypes module that represents a C time_t.
Pitch
Imagine having a struct in some C library we want to bind using ctypes:
This is quite cumbersome to do right now, as the size of time_t depends on lots of factors:
time_t is special due to the year 2038 problem. Historically on UNIX, time_t was 32-bit. For 64-bit platforms, time_t is usually 64-bit, avoiding the problem. In 2020, some changes have landed in Linux 5.6 to enable 64-bit time_t support in 32-bit Linux. glibc also has some documentation on 64-bit time_t. According to PC/pyconfig.h in CPython, "MS VS2005 changes time_t to a 64-bit type on all platforms".
Also, Lib/test/test_time.py says (in test_insane_timestamps()): "It's possible that some platform maps time_t to double" (I don't know which platform has this, but it might make sense to also take care of that).
Based on my research, something like this (likely wrong, incomplete or inaccurate - definitely untested) needs to be done if one wants to have a ctypestime_t type right now:
import platform
import ctypes
if platform.system() == 'Windows':
# Assume MSVC(?) - what about mingw/clang?
time_t = ctypes.c_int64
elif ctypes.sizeof(ctypes.c_void_p) == ctypes.sizeof(ctypes.c_int64):
# 64-bit platform of any kind - assume 64-bit time_t(?)
time_t = ctypes.c_int64
else:
# assume some kind of 32-bit platform(?)
time_t = ctypes.c_int32
# ... use time_t here ...
Adding a new c_time_t type in ctypes that is the same as one of (depending on how the host system defines it): c_int32, c_uint32, c_int64, c_uint64 would fix this issues, and allow defining the above struct simply as:
The CPython codebase already defines SIZEOF_TIME_T
grep'ing for the word time_t in the current CPython Git head:
% grep '\<time_t\>' **/*.py
Lib/lib2to3/tests/data/infinite_recursion.py:time_t = __darwin_time_t
Lib/lib2to3/tests/data/infinite_recursion.py: ('check_time', time_t),
Lib/lib2to3/tests/data/infinite_recursion.py: ('tv_sec', time_t),
Lib/lib2to3/tests/data/infinite_recursion.py: 'OSUnknownByteOrder', 'BN_MONT_CTX', 'ASN1_NULL', 'time_t',
Lib/test/datetimetester.py: # It's possible that some platform maps time_t to double,
Lib/test/datetimetester.py: # converting a Python int to C time_t can raise a
Lib/test/datetimetester.py: # converting a Python int to C time_t can raise a
Lib/test/datetimetester.py: # It's possible that some platform maps time_t to double,
Lib/test/datetimetester.py: # It's possible that some platform maps time_t to double,
Lib/test/datetimetester.py: # System support for times around the end of 32-bit time_t
Lib/test/test_os.py: # or utime(time_t)
Lib/test/test_time.py: # It's possible that some platform maps time_t to double,
Lib/test/test_time.py: for time_t in (-1, 2**30, 2**33, 2**60):
Lib/test/test_time.py: time.localtime(time_t)
Lib/test/test_time.py: self.skipTest("need 64-bit time_t")
Lib/test/test_time.py: invalid_time_t = time_t
Lib/test/test_time.py: self.skipTest("unable to find an invalid time_t value")
Lib/test/test_time.py: # time_t is a 32-bit or 64-bit signed integer
It seems like some parts of this check for OverflowError with time.localtime() to distinguish between 64-bit and 32-bit time_t.
If nothing else, exposing SIZEOF_TIME_T (seems like it's either 4 or 8 bytes for most (all?) platforms CPython supports) might help a lot in defining proper structs containing time_t for interoperability.
Starting with NetBSD version 6.0 (released in October 2012), the NetBSD operating system uses a 64-bit time_t for both 32-bit and 64-bit architectures.
OpenBSD since version 5.5, released in May 2014, also uses a 64-bit time_t for both 32-bit and 64-bit architectures.
Linux originally used a 64-bit time_t for 64-bit architectures only; the pure 32-bit ABI was not changed due to backward compatibility. Starting with version 5.6, 64-bit time_t is supported on 32-bit architectures, too. This was done primarily for the sake of embedded Linux systems.
FreeBSD uses 64-bit time_t for all 32-bit and 64-bit architectures except 32-bit i386, which uses signed 32-bit time_t instead.
The x32 ABI for Linux (which defines an environment for programs with 32-bit addresses but running the processor in 64-bit mode) uses a 64-bit time_t.
So supporting time_t properly seems to be a bit more involved than "just" checking the pointer size, especially for the BSDs.
Previous discussion
This came up while trying to create ctypes-based bindings for libgpod (which defines structs with time_t) here: gpodder/gpodder#1289
The text was updated successfully, but these errors were encountered:
Adds `ctypes.c_time_t` to represent the C `time_t` type accurately as its size varies.
Primarily-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Co-authored-by: Gregory P. Smith <greg@krypto.org> [Google]
Feature or enhancement
In order to make it possible to interoperate with C structs that contain
time_t
, add a new typec_time_t
to thectypes
module that represents a Ctime_t
.Pitch
Imagine having a struct in some C library we want to bind using
ctypes
:This is quite cumbersome to do right now, as the size of
time_t
depends on lots of factors:time_t
is special due to the year 2038 problem. Historically on UNIX,time_t
was 32-bit. For 64-bit platforms,time_t
is usually 64-bit, avoiding the problem. In 2020, some changes have landed in Linux 5.6 to enable 64-bit time_t support in 32-bit Linux. glibc also has some documentation on 64-bit time_t. According toPC/pyconfig.h
in CPython, "MS VS2005 changes time_t to a 64-bit type on all platforms".Also,
Lib/test/test_time.py
says (intest_insane_timestamps()
): "It's possible that some platform maps time_t to double" (I don't know which platform has this, but it might make sense to also take care of that).Based on my research, something like this (likely wrong, incomplete or inaccurate - definitely untested) needs to be done if one wants to have a
ctypes
time_t
type right now:Adding a new
c_time_t
type inctypes
that is the same as one of (depending on how the host system defines it):c_int32
,c_uint32
,c_int64
,c_uint64
would fix this issues, and allow defining the above struct simply as:The CPython codebase already defines
SIZEOF_TIME_T
grep
'ing for the wordtime_t
in the current CPython Git head:It seems like some parts of this check for
OverflowError
withtime.localtime()
to distinguish between 64-bit and 32-bittime_t
.If nothing else, exposing
SIZEOF_TIME_T
(seems like it's either 4 or 8 bytes for most (all?) platforms CPython supports) might help a lot in defining proper structs containingtime_t
for interoperability.Also the Y2038 Wikipedia article describes some platforms that deal with
time_t
specially:So supporting time_t properly seems to be a bit more involved than "just" checking the pointer size, especially for the BSDs.
Previous discussion
This came up while trying to create ctypes-based bindings for
libgpod
(which defines structs withtime_t
) here: gpodder/gpodder#1289The text was updated successfully, but these errors were encountered: