About time too
Pun intended.
Venerable Linux distribution Debian is side-stepping the Y2K38 bug – also known as the Unix Epochalypse – by switching to 64-bit time for everything but the oldest of supported hardware, starting with the upcoming Debian 13 "Trixie" release. "[We will] use 64-bit time_t on 32-bit architectures to avoid the 'year 2038 problem' …
What intrigues me about that is that there might quite well have have been, at the time, at least the odd tenured prof still stalking around the campus who was actually born before that lower-bound. Good job it didn't roll straight out into payroll.
We dwell a lot on the future wrt this problem, and how the decision wasn't very forward-looking, but it's equally tickling/embarrassing that nobody considered any applications needing to manage times even at the beginning of their own century.
To be fair, most date storage systems have such problems - and generally programme developers will use techniques appropriate to the function in order to handle it. Of course, some will take shortcuts on the basis that it'll be an SEP*, and a long time after it's their responsibility.
(* someone else's problem)
But the Unix epoch is only one of many time functions with rollover issues - the Windows ecosystem has loads of different ones ! It's something we have to consider in our work as the systems (or rather, the platform they are going to be on, the systems will almost certainly get upgraded) are expected to be in service for more than half a century.
Well, just having looked at Wiki's deep time pages, there's a chance that either the "false vacuum collapse" occurs or the Big Rip happens and the expansion of the universe ends baryonic matter.
But do I see anybody planning for *that* eventuality?! Of course not! Short-term thinking abounds!
Funnily enough, things will break earlier than that. The struct that converts the Unix epoch to a more understandable day month year format has the year itself as a 32-bit integer so by the year 2million something or 4 million something that int will overflow and blow up the time conversion function.
That assumes that nobody is doing any maths using 'long' instead of time_t, nor are they using it in any structure/ABI that is fixed. Obvious example is reading date from a file system, I think ext4 uses 64-bit time stamps but ext3 uses 32-bit so there is some conversion needed there and you can't just compile the file system driver without checking the devilish details.
ext3 uses 32-bit so there is some conversion needed there and you can't just compile the file system driver without checking the devilish details.
As it's impossible that any Unix file was actually created before 1st January 1970(*), 32 bit filesystem times can always be interpreted as unsigned, giving an extra 68 years to deprecate the file system format. I'm not saying it's a no brainer, but it shouldn't be impossible.
(*) Unless someone's been playing silly buggers, which is of course guaranteed to have been done somewhere. They can sort themselves out as punishment.
"That assumes that nobody is doing any maths using 'long' instead of time_t, "
All the code littered with t ≠ (time_t)(-1) I am surprised that there isn't more brokenness 0n 64 bit platforms.
Just t ≠ -1 or t ≠ -1L for starters.
Return valid results and error indications in a single value perhaps not greatest design decision.
"Just t ≠ -1 or t ≠ -1L for starters."
If you really want to initialise with a literal value then its `time_t (-1)`, construct a time_t with the initial value of -1, and the compiler will stop you if that's not legal.
Used to work on a system that had a shit-ton of typedefs for all the common domain types. Vast majority were scalars so just doubles or longs behind the scenes. Which of course most idiot developers assumed meant they could ignore the typedefs and use the built-in types instead in their implementations so long as they returned the "official" one. Especially when they didn't have a grip on the coercion rules of the language so liberally sprinkled casts throughout to "make sure".
The biggest problem I had with the "-1 means error" convention was when we started supporting an asset type where the price actually can go negative (calendar spreads) and I had to track down every freaking instance. Just for good measure there were a few -2's as well to signal other kinds of errors that I stumbled across that no one knew was there. Particularly galling as we had always had a convenience method `isValid` that wrapped up that concept. Did I mention they were all idiots?
At least we're not using that junk as an exemplar for future code, oh no wait, AI...
@LionelB
"Well the actual change would just be in time.h, wouldn't it?
Okay, admittedly you'd have to recompile a sh*t-ton of code ... "Debian's maintainers found the relevant variable, time_t, 'all over the place,' spread across a total of 6,429 packages.""
Possibly but not guaranteed. I might be wrong but there is a length difference between 32bit and 64bit and if it is being loaded into a variable of an assumed shorter size it could cause a problem (do correct me if I am wrong I dont spend a lot of time in the lower languages). How much can and will go wrong I do not know, I did find this description of the issue for Gentoo-
https://blogs.gentoo.org/mgorny/2024/09/28/the-perils-of-transition-to-64-bit-time_t/
As I said I dont envy Debian guys and wish the best of luck
"Well the actual change would just be in time.h, wouldn't it?"
Nope.
Other OS components may assume/rely on time being 32bit - for example the UTMP/WTMP files used to track Unix/Linux logins/logouts (used by "w", "who", "last" etc commands) *rely* on the timestamp being 32bit as the file format is defined as so by the POSIX standard and the UTMP/WTMP files are binary files and so if 64bit values were to used instead then such files would no longer be standards compliant and they also wouldn't be backwards compatible.
One solution to the above is an alternative (i.e. new) way of tracking logins/logouts which some Linux software is starting to support - wtmpdb.
"the file format is defined as so by the POSIX standard"
No it isn't. POSIX only defines the API used to access the utmp file, not the file format. There is no requirement that the file is just a binary containing the utmpx structures used by the API. And anyway the structure has the time as a struct timeval which has a time_t member for the seconds, and POSIX (as of the 2024 revision) requires time_t to be at least 64 bits. So on a system where the file does contain utmpx structures, the file would need to have at least 64-bit for the seconds in order to conform.
https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/utmpx.h.html
"No it isn't. POSIX only defines the API used to access the utmp file, not the file format."
Sorry, you are correct.
The point is that in order to use 64bit time values would mean changing the "standardised" (by existing software) on-disk format of UTMP/WTMP files and this would require changing a lot of software that either writes or reads (or both) these files and also would introduce compatibility issues between "old" format and "new" format files unless software was modified to detect both formats of file and act accordingly.
Some background info here: https://github.com/thkukuk/utmpx/blob/main/Y2038.md
No, Posix doesn't mandate 32 bit time fields in utmp.
So, as with everything else, if all those programs were written properly, just altering time_t and compiling would work (Of course, it would break with historical data)
The main problems are:
1) Providing backwards compatibility (even if you don't care about old programs, there is also old data to cope with)
2) Auditing that every code does indeed use time_t appropriately and not make 32 bit assumptions. However, I suspect this auditing would have been done already when the OS started to support 64 bit architecture.
"having to make"
Already a done deal as far as I can see,. Trixie is Debian Next and also the basis for Devuan Excalibur which I've been running as test for several weeks and is currently my daily driver because the no 1 laptop has suffered a bit of a knock & is in for repair.
Not sure about LMDE.
I know, I'm being pedantic, but why use "The Y2K38 bug"?
For a start, it's not a bug per se; it's how it was programmed.
Secondly, why use five characters, as in Y2K38? What's wrong with just 2038, or if you must use five characters, what's wrong with Y2038?
IT people are well aware of this potential issue and are working on it and have been working on it for years, possibly decades. There's no need to be dramatic and alert the general public, therefore no snazzy "punchline" is required.
And talking of which, yes I am of "a certain age" and was involved in mitigating things the last time and well remember the scare stories of aeroplanes falling out the sky, banks going bust and you losing all your money, etc. Where are the scare stories for this "potential year 2038 32-bit time-related potential issue with Unix systems" thingie? If you're going to be dramatic with the headlines, at least be dramatic with the copy, too. (And I'm not singling out El Reg; other publications are as equally guilty.)
</grumpy_carmudgeon_off>
It's even worse than that. The K as separator has presumably been borrowed from electronics usage, but engineers are expected to know about place values.
So a 2K38 resistor is not 2038 ohms, but 2380 ohms. Any numerate person would have called it the Y2K038 problem, not saving any digits at all.
Firstly, it's piggybacking on the awareness of the issue from the turn of the millennium. People still remember "the Y2K bug", so this is in essence "Y2K 2.0" for them, but that doesn't give any clue as to when it would happen. Maintaining brand recognition is important.
Secondly, trying to be efficient and conserving space is what got us into this mess to begin with. No need to over-compress the nomenclature for it, especially if that makes it ambiguous.
It's only a problem when you measure time from one of the eight corners of the Earth. On the other seven corners of the cube, time proceeds differently, so as we measure time in binary (one corner), it's really advancing in octal, so we have thirty-two times as long to resolve the problem as these so-called "programmers" believe.
In other words, this is a non-story, and everyone can stop panicking. You're welcome.
A mere 10 bit integer codes for weeks since 1980-01-01.
That means roll over is every ~ 19.6 years, i.e 1999, 2019, 2038 ... Client software is supposed to guesstimate somehow(tm) what the epoch is. Which can fail in interesting ways:
- Midnight 2001 (!) our commercial NTP server sent the overly trustful DB servers forward to 2019. Lots of fun ensured going back to 2001...
- Some remote site GPS board had its 1997ish build time burnt in as cutoff date. So at 1999 + 17 years: bingo: back to 1997!
>Come the very precise time of 03:14:07 UTC on January 19, 2038,
That is when the error will occur, but it’s not 2^31-1 seconds since the epoch. It doesn’t count the leap seconds. At present there’s about 37 leap seconds to contend with, and an unknown more to add or subtract before 2038.
The problem is that computers universally do not implement UTC. What they actually implement is the rules of TAI, but aligned to the UTC timescale. When UTC has a leap second, computers bollocks it up.
Thus the definition of the Unix epoch as 00:00:00 1/1/1970UTC is in fact not something that any computer working today actually honours.
Leap seconds: There are two problems. One that Linux and MacOS / iOS cannot represent leap seconds at all, two that time calculations don’t take leap seconds into account at all. So every day is exactly 86,400 seconds.
The last two leap seconds caused considerable problems because different companies used different workarounds. The next leap second is supposed to arrive in 2035 but right now it seems it will be ignored. And a few years later there are leap seconds to be removed, you can imagine what trouble that will be, so don’t expect it to happen.
Personally I’d switch to UT1 (astronomical time) which has no jumps and 25 microseconds precision.
That's not a time "calculation", that's simply a time "rendering", and works on Fedora. On Ubuntu (where there is no right/* timezones available),
$ TZ=Europe/London date -d @$(echo 2^31-1 | bc)
Tue Jan 19 03:14:07 AM GMT 2038
And on a stock Fedora:
date -d @$(echo 2^31-1 | bc)
Tue Jan 19 03:14:07 AM GMT 2038
which demonstrates that although RedHat were thinking about this as far back as 2015 (their page on how to handle that year's leapsecond refers to the right/* tz's), they don't in fact ship Fedora to this day using them.
RedHat's documentation is a bit confusing. By using a "right/*" timezone they say that one is setting the clock to TAI instead of UTC (and warn of applications expecting to be in UTC going wrong). However, I'm not sure this is true. The following show's what a system determines time_t to be for a leap second. There was one at 23:59:60 31/12/2016
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
int main (void)
{
time_t a;
struct tm a_parts;
time_t b;
struct tm b_parts;
tzset();
printf("DST? %i\n", daylight);
printf("timezone %li\n", timezone);
printf("timezone name %s\n", tzname[0]);
printf("timezone name %s\n", tzname[1]);
a_parts.tm_sec = 60;
a_parts.tm_min = 59;
a_parts.tm_hour = 23;
a_parts.tm_mday = 31;
a_parts.tm_mon = 11;
a_parts.tm_year = 116;
a_parts.tm_isdst = 0;
a_parts.tm_wday = 0; // ignored
a_parts.tm_yday = 0; // ignored
a_parts.tm_zone = NULL;
b_parts.tm_sec = 0;
b_parts.tm_min = 0;
b_parts.tm_hour = 0;
b_parts.tm_mday = 1;
b_parts.tm_mon = 0;
b_parts.tm_year = 117;
b_parts.tm_isdst = 0;
b_parts.tm_wday = 0; // ignored
b_parts.tm_yday = 0; // ignored
b_parts.tm_zone = NULL;
a = mktime(&a_parts);
b = mktime(&b_parts);
printf("a=%ld\nb=%ld\n",a,b);
long long x = pow(2,31) - 1;
printf("x=%lld\n", x);
}
Ubuntu, and Fedora (without setting TZ=right/gB)
DST? 1
timezone 0
timezone name GMT
timezone name BST
a=1483228800
b=1483228800
x=2147483647
This is strictly speaking wrong; under UTC the two times are distinctly separate, yet glibc has produced the same time_t for each. However, the value is right for the number of TAI seconds since the epoch on the TAI timescale to that TAI date / time.
Fedora with TZ=right/GB
DST? 1
timezone 0
timezone name GMT
timezone name BST
a=1483228826
b=1483228827
x=2147483647
a and b are the correct number of UTC seconds since the Unix epoch to that 2016 leapsecond. However, The problem is that if a right/GB timezone is in use, there are no leapseconds in TAI. So the program above claiming that there was is out of order in calling mktime with a 61st second, but gets an answer that is right (in so far as the resultant time_t's are one second apart). Modifying it for 23:59:59 produces a=1483228825.
It's clear that the whole system - including glibc - isn't behaving as it should under TAI. Instead it appears to be behaving more in line with UTC's actual rules (i.e. there are leap seconds and library functions know about them), but with a clock aligned to TAI. For the above program in a TAI timezone, the value of b should remain 1483228800. So the system is not in TAI, it's still in UTC (maybe better, accurately implemented UTC).
This is backed up by:
date +%s
1753533615
TZ=right/GB date +%s
1753533615
but is inconsistent with:
date
Sat Jul 26 01:40:37 PM BST 2025 <--- UTC time
TZ=right/GB date
Sat Jul 26 01:40:13 PM BST 2025 <--- TAI Time, but for other programs the use of right/GB seems to result in nearly proper UTC behaviour and not TAI behaviour.
Incidentally, mktime is also wrong. It allowed for tm_sec to be 60. To be strictly compliant with UTC it needs to accept 60, 61 and 58 (1 -ve leapsecond), but doesn't. Why oh Why when ISO were specifying C they went part-way to doing UTC properly, but still messed it up, I don't know. They may have thought they knew better than the metrologists who defined UTC's rules, thinking that "we'll never need a -ve leap second or +2 leapseconds". And yet right now, to continue to have UTC inline with UT1 to better than 0.5 second, we do need a -ve leapsecond.
> That's not a time "calculation"
So conversion from struct tm to time_t is a "calculation" but the opposite conversion is not? Whatever. I could have used either direction to demonstrate my point. Both conversions either use leap seconds or they don't, depending on the timezone.
> On Ubuntu (where there is no right/* timezones available)
The article was about Debian and I ran those commands on a Debian system. Strange that Ubuntu, being a Debian derivative, would remove the right/* timezones. (Or perhaps they are being removed from Debian and the change has made it into Ubuntu already but won't happen for users of Debian stable until they upgrade to trixie.)
> a=1483228826
Thanks for that. Putting it into the reverse conversion demonstrates the leap second with right/GB nicely:
$ TZ=posix/GB date -d @1483228826
Sun Jan 1 00:00:26 GMT 2017
$ TZ=right/GB date -d @1483228826
Sat Dec 31 23:59:60 GMT 2016
> To be strictly compliant with UTC it needs to accept 60, 61
Do you have a citation for that? The original 1989 ANSI (1990 ISO) C standard specified the range as [0,61] but in 1999 they changed it to [0,60], saying that the 61 was the result of a misunderstanding. IIRC, they had thought the fact that there can be two leap seconds in the same year meant tm_sec could be 61 but actually in that case they are added on 30th June and 31st Dec. The POSIX rationale for <time.h> says "The formal definition of UTC does not permit double leap seconds, so all mention of double leap seconds has been removed, and the range shortened from the former [0,61] seconds seen in earlier versions of this standard." This makes sense to me as the purpose of leap seconds is to keep the difference between UTC and UT1 to within 0.9 seconds. If two leap seconds were ever added on the same day, the 0.9 second limit would be broken.
> and 58 (1 -ve leapsecond)
What evidence do you have that glibc's mktime() wouldn't handle a -ve leapsecond correctly (with a right/* timezone) if one ever occurs?
>The article was about Debian and I ran those commands on a Debian system. Strange that Ubuntu, being a Debian derivative, would remove the right/* timezones
I've looked again on my up-to-date Ubuntu 24; they're not there. I'm pretty much only ever on Ubuntu, so was surprised by your reference to them!
>So conversion from struct tm to time_t is a "calculation" but the opposite conversion is not?
I mean calculation, such as T1 - T2 = ? It's difficult to get that right inclusive of leapseconds, and an outta-the-box Linux doesn't get that right (nor does most other software) if T1 and T2 are timestamps taken either side of a leap second (the system clock is not monotonic).
I'm impressed that a program using right/GB as a timezone gets values of time_t that are monotonic over the leapsecond when converting struct tm. A calculation such as T1 - T2 where those are stuct tm's would indeed be correct.
>Do you have a citation for that?
I don't have a citation of that, and indeed I've got that wrong (I was lead astray by 1990's C).
The official documents refer to leap second (singular) plus / minus: REC 460-4, Annex 1, Section 2 "Leap Seconds". Though introductory section C has it as "The UTC scale is adjusted by the insertion or deletion of seconds (positive or negative leap-seconds) to unsure [sic - at least in my copy] approximate agreement with UT1.". Note the plural, possibly the source of the misunderstanding. I can't see anything in the Recommendation that limits leap seconds to only 2 per year; the preferences are for them to occur Dec or Jun, can also be Mar or Sep; the required 8 week pre-announcement time allows IERS to put 4 out a year.
However, I gather that in the debate earlier in the 1970s about UTC, there were those pointing out that if we needed to accomodate 1 leap second at all, the standard ought to also accomodate more than 1 leap second and indeed -ve leapseconds, and wider tolerances. No doubt a component of the debate was the complexity of the timescale's rules. There was comparatively little observsational data to go on to confirm that 1 positive leap second would cover all circumstances. Looking at the rate of leap seconds in the 1970s there were a lot of them (2 within 6 months Jun/72 Dec/72). For a set of rules anticipating no more than 4 leap seconds per year, to be having 2 within 6 months one can see why some might consider 4 to be too few and the 0.8 second tolerance to be too narrow. Apparently, the concept of a negative leap second was only put into the standard more or less to shut people up, despite the wide-held belief at the time that the planet's spin was irrevocably slowing down. Yet here we are, with a planet spinning quicker today than it did 5 years ago.
That's the danger of specifying "for-ever" rules that are limited in the circumstance they can accomodate; if it turns out that the rules are inadequate and they have to be changed, no one will thank one for that. As it happened, no one implemented UTC on a practical basis anyway, with Linux (and possibly other unixes) being the noble exception (Linux + gpsd + GPS works properly).
It's clear that the original intentions of UTC failed; it's not universal (very few computer systems do it properly), and coordination does not reach everywhere or according to the rules. It would have been far better if the world of technology (even back in the 1970s) had just stuck to using TAI as the base timescale and its ruleset. If anyone cared to know what that meant in local mean solar time, that'd be a problem for them. Instead, we've tried for about 50 years and given up the moment it becomes slightly difficult (with the first proposed -ve leap second). Now, we've got UTC's ruleset encoded in law (e.g. the German Time Law). It's going to be a dickens of a job to get all countries to agree on a different ruleset. At some point, someone is going to exploit the difference between common practice and law. My bet is that'll happen in the financial sector (all that high share trading occured precisely when?), and it's probably best if that is prevented.
>What evidence do you have that glibc's mktime() wouldn't handle a -ve leapsecond correctly (with a right/* timezone) if one ever occurs?
It's probably fine.
Though it's interesting that when a negative leap second was mooted by the IERS recently the tech world reacted in horror. Clearly, despite the majority of the tech world running atop Linux, the availability of the right/* timezones hasn't resulted in their widespread adoption. The result is the ugly pause in leapsecond announcements following the heated discussion that broke out following the proposal of a negative leap seconds. Everyone knows it's a problem we're just kicking down the road.
>Thanks for that. Putting it into the reverse conversion demonstrates the leap second with right/GB nicely:
I didn't make my point clearly enough. I'm not suggesting date or glibc gets it wrong. RedHat say here"Note: By using a timezone in the right/* directory the clock is changed to TAI from UTC; any applications that expect the time to be in UTC may encounter issues.". Yet, Running date %s at the same time, one with a Europe/London default timezone and the other with a right/GB timezone producing the same output makes no sense (by RH's definition). The former should be the number of seconds to now from the notional POSIX epoch, following POSIX rules omitting the leapseconds. If the use of TZ=right/GB were to mean "the clock is changed to TAI", the latter should be the number of seconds to now from the actual POSIX epoch (00:00:00 1/1/70UTC), including leapseconds, and should be a bigger number (by 37seconds, that being the current delta between TAI and UTC). That the number of seconds reported is the same indicates that the clock isn't actually TAI. It's still the leap-second free seconds count, it's just being rendered differently.
The apparent difference between date's output with and without TZ=right/GB is 27 seconds. That means that setting the system clock to TAI and TZ to right/GB would not result in date reporting correct time (in either UTC or TAI). It'd be 10 seconds out. Leap seconds accumulated to 10 seconds total UTC<->TAI delta in 1972, the first one after the unix epoch. So it's even more mystifying why RedHat think that the "the clock will be in TAI".
RedHat's documentation of this topic is quite interesting in other things they say. This page says "Leap seconds are a discontinuity of civil time. The time does not continue to increase monotonically but it is stepped by one second.". I find that interesting because there is nothing discontinuous or non-monotonic about a leap second, in the same way there's nothing discontinuous or non-monotonic about a leap day. Civil time nearly everywhere is by statute defined as being UTC (with all its rules including leapseconds), and not the example RedHat use.
> That the number of seconds reported is the same indicates that the clock isn't actually TAI.
The computer's "clock" (internal count of seconds) is what it is. The question is what set it? In order for the clock to be synced to TAI and the right/* timezones to convert that clock to the true wall-clock time, the clock needs to be set by something, e.g. an NTP implementation, that has been told to do that. The origin of the right/* timezones is the IANA timezone database, and the information at https://data.iana.org/time-zones/tz-link.html says "right/UTC can be used by chrony", so maybe that's one way.
Hah! You think you've got problems? I was born on the Unix epoch! All I have to do to find out how many seconds old I am is run date +%s (allowing a bit of rounding, of course). Not that I haven't made the most of it, celebrating back when I both turned a gigasecond and, slightly later, a gibisecond old. But it does lead to the funny experience of often seeing my birth date crop up when things are broken, and default to the epoch in directory listings and such.
OpenBSD fixed this problem in 2014.
And released a song about it.
Linux takes 11 years longer and we don't even get a song.
At least some 32-bit Linux distros will receive a fix. There are a number of orphaned operating systems out there that will never receive a fix, let alone the apps for them. I doubt that my old Commodore Amiga games will care at all when the wrap happens, but maybe that CNC machine running MS-DOS will care.
Worth noting: OpenBSD fixed ALL platforms, including a number of "not really ready for the 21st century", "labor of love" 32 bit platforms, such as VAX, Sparc32, and MVME88k
It's just one of those things...you know you have to do it, just freakin' do it! It only gets harder the longer you wait.
And yes, Linux should fix 32 bit platforms. In 1975, 32 bit time was a design decision. In 2025, it's a bug. How many of us have manage systems running today that were installed more than 13 years ago? (let's just acknowledge that is bad, it shouldn't be, but it is...)
Yikes, that's ... worse. (Why does GPS even need a week counter anyway?)
I want to be charitable and assume these design decisions are down to self-deprecation/utopianism on the part of the developers: "By the time we need more than that, this old thing will have been replaced by something completely new and better anyway" sort of thing.
Which in turn makes me think those devs were rather green, at least in the ways of the relationship between innovation and money, which has illustrations a lot older than the computing sector.
There was no Space Shuttle mission that spanned a 31-December - 1-January transition.
Apparently two different units on board had clocks, one didn't roll-over at year-end, but just kept counting up days, the other rolled over. It was considered too risky to fly when they would get out of sync.
This post has been deleted by its author