Skip to content

y2038 #9429

@ThomasWaldmann

Description

@ThomasWaldmann

Borg has still some support code for 32bit timestamps (but also supports 64bit timestamps). The remaining question was whether we can get rid of the 32bit compatibility code.

This is also mentioned in #6602, but let's focus on that here exclusively.

I had an exchange with claude.ai, see below:

Y2038 and BorgBackup: Summary

What is Y2038?

The Y2038 problem affects systems that store Unix timestamps as 32-bit signed integers.
These overflow on January 19, 2038 (Unix time 2,147,483,647), potentially corrupting
time-based data.


Python 3 and 64-bit Platforms: Largely Safe

Python 3 uses 64-bit integers for timestamps internally. On 64-bit operating systems:

  • time.time() returns a 64-bit float — no overflow.
  • datetime objects use 64-bit internally.
  • Python int is arbitrary precision — timestamp arithmetic is safe.
  • os.stat() wraps the OS struct stat, which uses 64-bit time_t on all modern 64-bit platforms.

The os.stat() float precision caveat

st_mtime is returned as a Python float (C double, 53-bit mantissa). For post-2038
timestamps, sub-millisecond precision can be lost. Solution: use st_mtime_ns
(available since Python 3.3), which returns a plain Python int with full nanosecond
precision and no size limit. Borg already does this.


Where the Real Risk Is: Your Own Archive Format

The most significant Y2038 risk for Borg is not at the OS or Python level — it is in
how timestamps are serialized to disk in archive metadata.

  • Borg uses msgpack for metadata. msgpack integers are variable-width and can hold
    64-bit values, but you must ensure timestamps are written as 64-bit when values
    exceed the 32-bit range.
  • Any struct.pack('i', ts) or struct.pack('l', ts) call on a timestamp will overflow
    post-2038. Use 'q' (64-bit signed) instead.
  • Recommendation: audit the archive format, test with synthetic post-2038 dates
    (e.g. touch -t 203901010000), and ensure 64-bit storage throughout.

32-bit Platforms

OS/libc Y2038 fixes (already shipped)

System Fixed in Details
Linux glibc glibc 2.31 (2020) _FILE_OFFSET_BITS=64 now default on 32-bit
musl libc musl 1.2 (2020) 64-bit time_t on all arches
FreeBSD FreeBSD 12 (2018) 64-bit time_t on 32-bit arches
NetBSD NetBSD 10 (2024) 64-bit time_t on 32-bit arches

Which 32-bit systems with ≥1 GB RAM still have meaningful user bases?

Applying a practical filter (≥1 GB RAM, real user base, capable of running Borg):

  • 32-bit Raspberry Pi OS on Pi 2 (1 GB RAM) — real user base, but ships glibc 2.31+ → already safe
  • armhf Debian/Ubuntu — supported arch, can run on ≥1 GB hardware, but modern glibc → already safe
  • Genuinely broken time_t systems are too old to run a current Borg release in practice.

Conclusion on 32-bit

Essentially no platform with a meaningful Borg user base has an outstanding OS-level
Y2038 problem.
The ecosystem fixed 32-bit time_t between 2018 and 2024. Any system
old enough to still be affected is also too old to realistically run current Borg.

If you wish to document a requirement: Borg requires 64-bit time_t at the OS/libc
level; on 32-bit platforms ensure glibc ≥ 2.31, musl ≥ 1.2, or FreeBSD ≥ 12.


Recommendations for BorgBackup Developers

  1. Audit archive format — verify all timestamps are serialized as 64-bit (msgpack
    int64 or nanosecond timespec pairs). This is the highest-priority item.
  2. Use st_mtime_ns instead of st_mtime for file metadata — already done in Borg,
    but worth confirming throughout.
  3. Search for struct.pack calls using 'i' or 'l' format codes on timestamps;
    replace with 'q'.
  4. Test with post-2038 synthetic dates to verify correct store/restore behavior.
  5. No special action needed for 64-bit platforms or modern 32-bit platforms at the
    OS level — the problem has been solved upstream.

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions