Tuesday, April 7, 2026

Challenges With Ancient Dates in Apple SDKs

Aaron Trickey:

Foundation’s date-handling code has an effective lower bound around January 1, 4713 BC on the Julian calendar. You can create a Date value representing an instant in time below that limit, but many Calendar methods will return unexpected values when you try to do anything with it.

[…]

And NSDatePicker does okay with BC dates. […] UIDatePicker, however, simply cuts off at AD 1.

[…]

When formatting or parsing dates, there is no way to override the built-in era symbols (like “BC” and “AD”) or, in locales where multiple conventions are in use, to choose among them.

[…]

(For going to and from strings, the older DateFormatter type does have such a property [for the Julian to Gregorian transition] defined, but it wasn’t carried forward into the newer Date.FormatStyle API, and it obviously doesn’t affect DateComponents conversions.)

Previously:

4 Comments RSS · Twitter · Mastodon


Graham Dawson

I have experienced similar issues, the worst being that I discovered changes in ancient date behaviour from macOS prior to 26.0 versus post, then further changes in 26.3, all of which resulted in bug reports from my app users depending on which macOS versions they were running. I had to implement some fundamental custom overrides to obtain consistent & correct behaviour of my app across all OS versions.


Pierre Lebeaupin

I am sympathetic to his plight, but to be fair to Foundation, you can't rely on *any* calendar (that is to day, an instrument that marks the time by observing the succession of day and night cycle) being able to represent times prior to recorded history. Period. And more generally, operating system date APIs should be considered iffy when dealing with times before the Gregorian switch, which safely covers the whole industrial era in the western hemisphere, but in Russia occurred under Lenin!

Java's date API famously tried to assign a meaning to an expression like "June 24th 400,000,000 BCE", but you can't actually make this correspond to the dates in our era in any meaningful way:
- the first issue is that an elapsed day as recorded in the calendar, even "between two noons" (which, among events you can reasonably observe — you can't observe "midnights", for instance —, is the most regular), is actually varying in length, due to features of how the Earth spins (that is the source of leap seconds, by the way). Not in a way that matters from one day to the next or even one year to the next, but when you end up following that system a million times (there are already more days than that between the first calendars and now)… it adds up.
- case in point: if we take our current definition of the duration of a day (itself based on observations made in year 1900), and use that to try and predict how many such days ago a predictable astronomical event like an eclipse occurred, the fractional part will be off as soon as you hit past millenia, and worsen as you get to the earliest recorded eclipses.
- an eclipse you'd predict the babylonians (active in the first millenia BCE) would have seen in the afternoon was actually recorded as seen in their morning, even though you had compensated for timezones in your computation
- and for earlier lunar eclipses that occurred in the third millenia BCE, that error would compound (it accumulates quadratically, to be precise) and reach 12 hours, such that observers you'd predict would be at night would actually be in daylight at that time (and obviously fail to catch that eclipse), while observers on the other side of the globe that you'd predict would be unable to observe it would in fact have it in their records, because it did actually occur at night for them.
- other case in point: we know from marine animal fossils (corals, nautiles, etc.), whose shells betray their variations of rate of growth both due to the day/night cycle and due to the seasons cycle, that there were more than 400 "days" per "year" when those lived 400 million years ago.
- The second issue is that even if you consider the duration of the day to be constant for your purposes, you'd best be wary of what you consider a "year". The proleptic (that is to say, "prolonged after and before its original application") Julian calendar is very useful for many purposes if only as a conversion intermediate (its original longevity means we can figure out its relation directly with almost all historial and current calendars), but there is a reason everyone but the orthodox church moved off from it: it doesn't match the tropical year; that is to say, the cycle of the seasons.
- case in point: going backwards in time it will have the shift that was compensated for by Gregory XIII, but in reverse, with the northern hemisphere spring equinox having to be waited for on an absurdly later date in that calendar, such as late april for year -4712 (astronomer year, which corresponds to 4713 BCE: astronomers consider year 1 to have been preceded by year 0, itself preceded by year -1; this simplifies their computations, which are otherwise troublesome when using the convention that year 1 BCE precedes year 1 CE)
- other case in point: as you get farther and farther past from when Caius Julius Caesar actually lived, the usefulness of the calendar decreases in turn, until you get to the point before humans used a calendar, any calendar, at which point its error turns into a full on liability.
- this is so bad that around 50,000 BCE this error amounts to a full year, so you'd best know which definition of the year you're using, actually.

Still, the notion of a year is useful when discussing archeological and geological eras, and for that we turn back to the tropic year, more specifically a duration of it observed in 1900. For these purposes, time computations are solely rooted in physics, most famously isotope decay (of which C14 is but the best known), and no longer the accumulation of day/night cycles or even season cycles; for instance, we are now able to correlate growth rings in trees (whose width varies from year to year according to whether the year was moist or dry) across interesting periods, more than the life of any single tree, but only locally and especially not beyond a few millenia in the past.

All that means I would make the use choose whether he wants:
- a timeline defined by days, for use with events in recorded history, and ultimately backed by Julian day numbers, fractional if need be; those would be translated to and from dates in the OS date API as if dealing with a foreign system (e.g. dates need not be representable in that API)
- or a timeline defined by physics, for event on geological or cosmological scale, and ultimately backed by the atomic second (a 64-bit count of seconds will not overflow for the age of the universe). No conversion to and from OS date APIs would be possible.

It might be feasible to convert from one to the other after the fact in case the original mode was a mistake, but trying to have a universal timeline that works for all such purposes is a fool's errand.

reference: https://www.persee.fr/doc/hism_0982-1783_1986_num_1_3_1534


Graham Dawson

Thanks Pierre Lebeaupin - a good analysis of the problems around date/time handling over vast time frames, and all valid points, although I suspect very few are attempting to build software that deals with quite such massive periods of time.

However, it would be nice, at least for the sake of astronomical calculation software which may well allow exploration across 10k years or more, that we could have *consistent* behaviour from the date/time APIs which allows correct conversion between julian day numbers (including in the -ve range) to year, month, day values in the Julian calendar. Or in the absence of this, at very least some clear statement of the specific date range limitations of each relevant API call, given the lack of consistency.


Pierre Lebeaupin

@Graham Dawson: yeah, it's always disappointing when you just know that the OS frameworks do base themselves off some scientific publication, knowledge grounded on the observation that there is absolutely no other way to explain how some correct behavior, meaning there have to know about the whole publication… but they failed to follow all of it, as the frameworks have bugs they wouldn't otherwise have. I guess your domain knowledge did overtake theirs at some point.

Leave a Comment