I'm the author of the Perl DateTime library. It works correctly as _documented_. Here's the first two paragraphs of the docs:
> DateTime is a class for the representation of date/time combinations, and is part of the Perl DateTime project.
> It represents the Gregorian calendar, extended backwards in time before its creation (in 1582). This is sometimes known as the "proleptic Gregorian calendar". In this calendar, the first day of the calendar (the epoch), is the first day of year 1, which corresponds to the date which was (incorrectly) believed to be the birth of Jesus Christ
Always RTFM.
Edit: I double-checked, and while this was not in the docs in the first release, it _was_ in the docs as of 2015.
It’s funny to see this on HN. I wrote this 11 years ago as an undergraduate.
The afternotes at the end of the post are worth reading; people have sent me various qualifications and corrections over the years.
deathanatos
> In essence, then, those ten days in 1582 never happened and simply do not exist within the Gregorian calendar system used almost universally in the West today.
I find these things so much easier to think about if you consider the change as a change from one calendar system to another calendar system. Those 10 days certainly exist, in both calendar systems, they just represent different points in time. I.e., I think it's easier to just consider both calendar systems as the rules, extended forward & backwards infinitely ("proleptic"). Some people switched from a Julian calendar to a Gregorian one in 1582.
"Some people did not experience days with these labels in some areas of the world" … I get where it's coming from, but it's not how I'd build a library.
If you worry about the switch, then you have to ask "which switch?" which TFA only lightly touches on. The 1582 one is famous, of course, but not everyone switched, and other parts of the worlds switched as time went on, to as late as 1918, when Russia switched.[1] (And you can see other messiness in that table, too.)
Needing to deal with it is niche enough that I think most language std libs should implement the proleptic Gregorian calendar, and let an application whose niche requires it deal with the switch (& whichever switch it requires).
There seems to be disagreement about the year. Two systems I checked assume 1752, not 1582.
(OpenBSD)
$ man cal
[...]
The Gregorian Reformation is assumed to have occurred in
1752 after the 2nd of September. By this time, most
countries had recognized the Reformation (although a few
did not recognize it until the early 1900s). Eleven days
following that date were eliminated by the Reformation, so
the calendar for that month is a bit unusual.
(Ubuntu Linux)
[...]
-s country_code
Assume the switch from Julian to Gregorian Calendar at
the date associated with the country_code. If not
specified, ncal tries to guess the switch date from the
local environment or falls back to September 2, 1752.
This was when Great Britain and her colonies switched
to the Gregorian Calendar.
show comments
pibaker
The article is a bit old. It should have noted a new development in calendar technology if it was written half a year later.
> In A.D. 1582 Pope Gregory XIII found that the existing Julian calendar
insufficiently represented reality, and changed the rules about
calculating leap years to account for this. Similarly, in A.D. 2013
Rockchip hardware engineers found that the new Gregorian calendar still
contained flaws, and that the month of November should be counted up to
31 days instead.
> The Eastern Orthodox church even continued well after that, only switching to the Gregorian calendar in 1929.
Technically, they switched to the Revised Julian[0] calendar, not the Gregorian. Also, it was only some of the churches making up Eastern Orthodoxy that switched; others remain on the Julian calendar to this day, and all of them still use the Julian calendar to calculate the date of Pascha.
This whole story is built on one wrong assumption: that there are some clear rules defining calendar shifts. As the author discovers at the end this history differs in different countries, and what dates exist is not anymore easy to tell universally. But now let's recall countries are not the same anymore, so even ncal's admirably nerdy attempt to be precise is just a rough approximation. Then how about a Catholic town in a Protestant country, or vice versa? How about people using several calendars simultaneously for different purposes? The truth is there's no clear recipe for every case, and for ≈99.9999% cases proleptic Gregorian (which doesn't care) is completely fine.
russdill
This is clearly the wrong way to think about it. Dates forward and backward from this flag date exist in both calendars and it's straightforward to convert between them.
Such a flag day didn't involve removing days from one calendar or the other, it switched between them.
show comments
maxlybbert
This is an interesting detail to learn about history. However, like the article mentions near the end, the Gregorian calendar was adopted at different times in different countries. The Anglican Church didn’t trust the Catholics, so Great Britain adopted the Gregorian calendar in 1752 ( https://en.wikipedia.org/wiki/Calendar_(New_Style)_Act_1750 ). And they did their best to hide the fact that they were adopting a Catholic invention: it’s the “New Style Calendar” and they came up with a different way to choose the same date for Easter.
1752 is late enough that Benjamin Franklin, George Washington, Thomas Jefferson and others were born before that change.
I think that’s the reason that programming languages tend to adopt the proleptic Gregorian calendar and leave it up to the programmer to figure out when the calendar was adopted in the countries they care about.
Except that countries apparently had to answer various questions when they adopted the Gregorian calendar, and they didn’t all chose the same answers. Ideally, we’d have something like tzdb but for calendar adoption. But I guess the need doesn’t come up all that often.
show comments
throwawayk7h
So, the Proleptic Gregorian Calendar[1] refers to what you'd get if you extended the current Gregorian Calendar back in time before its introduction. (It agrees with the Julian calendar only during the 3rd century AD.) Most date libraries use the Proleptic calendar for simplicity. Ruby's DateTime is unusual insofar as, by default, it actually switches to the Julian calendar for dates before Oct 15 1582.
In our Dip (in house db) client library, we built what we called a policy that auto selects partitions based on every crud operations. The policies can be specified once for each collection in collections.json based on fields or query.
So for policies where partition involves the date type fields, be it range or fixed dates, it was incredibly hard to generate universal date names from ranges.
The policy mechanism was finished fairly quickly as Dip is inherently distributed first. But reasoning about date names was so incredibly hard.
The missing dates mentioned in the article did come up during development adding to the woes.
But the upside now is that application code no longer worries about the distributed partitions. Policy handles that. Some sort of architecture as code. Don't know whether AAC is an existing term or whether we coined it.
gmueckl
This article presents a grossly simplified version of events. The truth is that only some catholic countries switched in 1582. Britain and its colonies switched in 1752. Prussia switched in 1610. And so on.
show comments
laveur
I tried to create a date object in Swift from the date October 5, 1582. The resultant date object was October 15th 1582.
show comments
wduquette
Using the proleptic Gregorian calendar for historical dates is only a problem if you want to compute the day of the week (which those missing days will throw off prior to the adoption of the Gregorian calendar in the relevant country) or the number of days between two historical dates (if the two dates span the date when the Gregorian calendar was adopted).
And, frankly, there are other problems to deal with beyond correctly handling the Julian/Gregorian switch. In Nelson's Navy, for example, the new day started at noon rather than midnight as we'd expect. AM could be June 1st, PM could be June 2nd, and both could be Tuesday.
And then there are lots of historical events with dates like "on or about August 6th" or "mid-September" or the "in the Fall of".
Trying to deal with historical dates in what a programmer would consider a perfectly correct way is something of a fool's game.
charlieyu1
Are we really supposed to trace this given how ancient it is? If we really want to do far we would eventually reach ancient Chinese emperor era names that even confuse historians
1313ed01
I wonder how many libraries correctly handles the date 1712-02-30 in the Swedish calendar (according to Wikipedia the only official 30th of February in history)?
Tried using ncal like in the examples in that blog post, but it did not work correctly using either Julian or Gregorian. Of course the Swedish calendar from 1700-1712 was neither, but somewhere in-between, because of the (failed) attempt to gradually move from one to the other.
show comments
JoshTriplett
Is the stack trace in the Ruby transcript invisible for anyone else? It seems to show up as white text on a white background.
show comments
shagie
... And then there was Sweden.
Instead of flipping the switch in the 1500s... or 1700s... they instead did a slow roll out until they finally flipped the switch and did a big leap.
In “The Future of Time,” the authors state that “different countries and religions adopted the reforms [the Gregorian calendar] at different times and in different ways. In 1712 Sweden added a February 30 to its national calendar.” There was a February 30 in Sweden in 1712, but the context in which it is presented in the article is misleading. In 1700 the Swedes decided to switch from the Julian to the Gregorian calendar by eliminating leap-year days for 40 years. So 1700, which is a Julian leap year but not a Gregorian leap year, did not have a leap day. In both 1704 and 1708, through bureaucratic error, there were leap days. In 1712, the situation was resolved by switching back to the Julian calendar; this meant that the missing leap day that would have occurred in 1700 had to be added, and was, as February 30. It wasn’t until 1753 that the Swedes finally adopted the Gregorian calendar by making the date March 1 follow February 17.
tl;dr - ActiveSupport::TimeWithZone used absolute seconds counting to determine dates while DateTime used a proper Gregorian calendar. This means dates before October 15, 1582 have different internal values when compared.
The behavior showed up because a test was using a DateTime value to set a MySQL DATETIME column to the DB minimum value, which is 1000-01-01 00:00:00, and then comparing the DB record attribute to the original variable used to set it.
Something like:
date = DateTime.new(1000, 1, 1, 0, 0, 0, 'UTC')
record.update(happened_at: date)
record.happened_at == date # => false
I "discovered" the missing Gregorian dates when I wrote a loop counting forward in time from Jan 1, 1000 until the corresponding TimeWithZone and DateTime records returned true when compared with ==.
clord
I suppose the Georgian calendar includes this gap officially? Or did the catholic world just jump from system to system? If it includes the gap officially, then yea, error is the right thing. But if we just moved to a new calendar, then arguably there should be no error. both calendars work for all dates continuously, and we could have conversion functions etc. The gap is just a big flag day (week.)
imo, if i am using Georgian i want that system even retroactively, just like projecting a date back into the stone age. I don't care that a particular geography or culture changed calendars.
So I suppose what is really going on is that some libraries are using Georgian consistently, and others are using some hybrid "civic" calendar that tracks what the romans and the catholics were using, so dates in history books make sense.
show comments
zanecodes
Dealing with dates becomes much simpler conceptually when you realize that you are actually dealing with two different ideas masquerading as one: dates, and the actual instants in time which they name. Instants in time can only be unambiguously referenced by measuring some fixed unit of time intervals from some commonly agreed upon event (e.g. seconds since the Unix Epoch).
Dates are a mapping from human-readable labels to instants in time; critically, this mapping is not a total function (there are dates that map to no instant in time in a particular calendar, such as October 5-14 1582 in the Gregorian calendar, or 2:30am March 8 2026 in US timezones due to DST), nor is it in fact a function at all depending on how you define your inputs (1:30am November 1 2026 in US timezones is ambiguous if you don't specify DST/ST).
Furthermore, the mappings (both for past dates and future dates!) can themselves change over time (changes to DST, timezones, and calendars such as in TFA), and you need to keep track of these changes in perpetuity, as well as at which instant in time they were implemented, and we don't necessarily have that information for some of these historical changes, we only have the date as written down, which itself can suffer from the ambiguity problem (is it the date pre- or post- calendar change?).
This makes dealing with past dates tricky, and dealing with future dates speculative at best. For instance, what's February 28th + 1 day? The answer depends on the calendar system and the year; we can answer it definitively for past years but not necessarily for future years (maybe in 2040 we'll move the leap day to December 32nd). This is why it's important to immediately convert past dates (and sometimes future dates, depending on the use case) to unambiguous instants in time, and only convert them back to dates for display purposes.
"Wednesday, August 12th 2026" and "8 days from now" are also semantically distinct for some purposes: if have 8 doses of a daily prescription left, I'm still going to run out in 8 days even if tomorrow the government decides to repeal the Gregorian calendar, thus changing the name of "8 days from now" from "Wednesday, August 12th 2026" to "Sunday, August 2nd 2026". My medication doesn't care what the government decides to call 8 days from now, I'm going to run out either way. The pharmacy, on the other hand, very much does care what the government decides to call 8 days from now, because perhaps they're closed on Sundays. The calendar change means that "8 days from now" went from being not-a-Sunday to a Sunday, affecting their operating hours.
It's really just another instance of one of the two hard problems in computer science: naming things.
show comments
reaperducer
Regarding computers and time, I always liked that in AmigaDOS, you could specify custom relative times.
It would natively display "Future" if the file timestamp was ahead of the system clock, but you could also add dates. I remember seeing directory listings like
xyzzy.foo 49152 ----rw-d Christmas 1988
kfse
Ok now do date math, does the day-of-month accurately jump over the non-existent numbers?
I'm the author of the Perl DateTime library. It works correctly as _documented_. Here's the first two paragraphs of the docs:
> DateTime is a class for the representation of date/time combinations, and is part of the Perl DateTime project.
> It represents the Gregorian calendar, extended backwards in time before its creation (in 1582). This is sometimes known as the "proleptic Gregorian calendar". In this calendar, the first day of the calendar (the epoch), is the first day of year 1, which corresponds to the date which was (incorrectly) believed to be the birth of Jesus Christ
Always RTFM.
Edit: I double-checked, and while this was not in the docs in the first release, it _was_ in the docs as of 2015.
https://metacpan.org/pod/DateTime
It’s funny to see this on HN. I wrote this 11 years ago as an undergraduate.
The afternotes at the end of the post are worth reading; people have sent me various qualifications and corrections over the years.
> In essence, then, those ten days in 1582 never happened and simply do not exist within the Gregorian calendar system used almost universally in the West today.
I find these things so much easier to think about if you consider the change as a change from one calendar system to another calendar system. Those 10 days certainly exist, in both calendar systems, they just represent different points in time. I.e., I think it's easier to just consider both calendar systems as the rules, extended forward & backwards infinitely ("proleptic"). Some people switched from a Julian calendar to a Gregorian one in 1582.
"Some people did not experience days with these labels in some areas of the world" … I get where it's coming from, but it's not how I'd build a library.
If you worry about the switch, then you have to ask "which switch?" which TFA only lightly touches on. The 1582 one is famous, of course, but not everyone switched, and other parts of the worlds switched as time went on, to as late as 1918, when Russia switched.[1] (And you can see other messiness in that table, too.)
Needing to deal with it is niche enough that I think most language std libs should implement the proleptic Gregorian calendar, and let an application whose niche requires it deal with the switch (& whichever switch it requires).
[1] https://en.wikipedia.org/wiki/List_of_adoption_dates_of_the_...
There seems to be disagreement about the year. Two systems I checked assume 1752, not 1582.
(OpenBSD)
(Ubuntu Linux)The article is a bit old. It should have noted a new development in calendar technology if it was written half a year later.
> In A.D. 1582 Pope Gregory XIII found that the existing Julian calendar insufficiently represented reality, and changed the rules about calculating leap years to account for this. Similarly, in A.D. 2013 Rockchip hardware engineers found that the new Gregorian calendar still contained flaws, and that the month of November should be counted up to 31 days instead.
https://lwn.net/Articles/669022/
> The Eastern Orthodox church even continued well after that, only switching to the Gregorian calendar in 1929.
Technically, they switched to the Revised Julian[0] calendar, not the Gregorian. Also, it was only some of the churches making up Eastern Orthodoxy that switched; others remain on the Julian calendar to this day, and all of them still use the Julian calendar to calculate the date of Pascha.
[0] https://en.wikipedia.org/wiki/Revised_Julian_calendar
This whole story is built on one wrong assumption: that there are some clear rules defining calendar shifts. As the author discovers at the end this history differs in different countries, and what dates exist is not anymore easy to tell universally. But now let's recall countries are not the same anymore, so even ncal's admirably nerdy attempt to be precise is just a rough approximation. Then how about a Catholic town in a Protestant country, or vice versa? How about people using several calendars simultaneously for different purposes? The truth is there's no clear recipe for every case, and for ≈99.9999% cases proleptic Gregorian (which doesn't care) is completely fine.
This is clearly the wrong way to think about it. Dates forward and backward from this flag date exist in both calendars and it's straightforward to convert between them.
Such a flag day didn't involve removing days from one calendar or the other, it switched between them.
This is an interesting detail to learn about history. However, like the article mentions near the end, the Gregorian calendar was adopted at different times in different countries. The Anglican Church didn’t trust the Catholics, so Great Britain adopted the Gregorian calendar in 1752 ( https://en.wikipedia.org/wiki/Calendar_(New_Style)_Act_1750 ). And they did their best to hide the fact that they were adopting a Catholic invention: it’s the “New Style Calendar” and they came up with a different way to choose the same date for Easter.
1752 is late enough that Benjamin Franklin, George Washington, Thomas Jefferson and others were born before that change.
I think that’s the reason that programming languages tend to adopt the proleptic Gregorian calendar and leave it up to the programmer to figure out when the calendar was adopted in the countries they care about.
Except that countries apparently had to answer various questions when they adopted the Gregorian calendar, and they didn’t all chose the same answers. Ideally, we’d have something like tzdb but for calendar adoption. But I guess the need doesn’t come up all that often.
So, the Proleptic Gregorian Calendar[1] refers to what you'd get if you extended the current Gregorian Calendar back in time before its introduction. (It agrees with the Julian calendar only during the 3rd century AD.) Most date libraries use the Proleptic calendar for simplicity. Ruby's DateTime is unusual insofar as, by default, it actually switches to the Julian calendar for dates before Oct 15 1582.
[1] https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar
Dates really are a headache.
In our Dip (in house db) client library, we built what we called a policy that auto selects partitions based on every crud operations. The policies can be specified once for each collection in collections.json based on fields or query.
So for policies where partition involves the date type fields, be it range or fixed dates, it was incredibly hard to generate universal date names from ranges.
The policy mechanism was finished fairly quickly as Dip is inherently distributed first. But reasoning about date names was so incredibly hard.
The missing dates mentioned in the article did come up during development adding to the woes.
But the upside now is that application code no longer worries about the distributed partitions. Policy handles that. Some sort of architecture as code. Don't know whether AAC is an existing term or whether we coined it.
This article presents a grossly simplified version of events. The truth is that only some catholic countries switched in 1582. Britain and its colonies switched in 1752. Prussia switched in 1610. And so on.
I tried to create a date object in Swift from the date October 5, 1582. The resultant date object was October 15th 1582.
Using the proleptic Gregorian calendar for historical dates is only a problem if you want to compute the day of the week (which those missing days will throw off prior to the adoption of the Gregorian calendar in the relevant country) or the number of days between two historical dates (if the two dates span the date when the Gregorian calendar was adopted).
And, frankly, there are other problems to deal with beyond correctly handling the Julian/Gregorian switch. In Nelson's Navy, for example, the new day started at noon rather than midnight as we'd expect. AM could be June 1st, PM could be June 2nd, and both could be Tuesday.
And then there are lots of historical events with dates like "on or about August 6th" or "mid-September" or the "in the Fall of".
Trying to deal with historical dates in what a programmer would consider a perfectly correct way is something of a fool's game.
Are we really supposed to trace this given how ancient it is? If we really want to do far we would eventually reach ancient Chinese emperor era names that even confuse historians
I wonder how many libraries correctly handles the date 1712-02-30 in the Swedish calendar (according to Wikipedia the only official 30th of February in history)?
https://en.wikipedia.org/wiki/List_of_non-standard_dates#Feb...
Tried using ncal like in the examples in that blog post, but it did not work correctly using either Julian or Gregorian. Of course the Swedish calendar from 1700-1712 was neither, but somewhere in-between, because of the (failed) attempt to gradually move from one to the other.
Is the stack trace in the Ruby transcript invisible for anyone else? It seems to show up as white text on a white background.
... And then there was Sweden.
Instead of flipping the switch in the 1500s... or 1700s... they instead did a slow roll out until they finally flipped the switch and did a big leap.
https://www.americanscientist.org/article/date-distinctions
I ran into this in a Ruby on Rails test suite a few years ago and wrote up my findings here: https://gist.github.com/abachman/f97806e1c0fe8e4e1849e5f8412...
tl;dr - ActiveSupport::TimeWithZone used absolute seconds counting to determine dates while DateTime used a proper Gregorian calendar. This means dates before October 15, 1582 have different internal values when compared.
The behavior showed up because a test was using a DateTime value to set a MySQL DATETIME column to the DB minimum value, which is 1000-01-01 00:00:00, and then comparing the DB record attribute to the original variable used to set it.
Something like:
I "discovered" the missing Gregorian dates when I wrote a loop counting forward in time from Jan 1, 1000 until the corresponding TimeWithZone and DateTime records returned true when compared with ==.I suppose the Georgian calendar includes this gap officially? Or did the catholic world just jump from system to system? If it includes the gap officially, then yea, error is the right thing. But if we just moved to a new calendar, then arguably there should be no error. both calendars work for all dates continuously, and we could have conversion functions etc. The gap is just a big flag day (week.)
imo, if i am using Georgian i want that system even retroactively, just like projecting a date back into the stone age. I don't care that a particular geography or culture changed calendars.
So I suppose what is really going on is that some libraries are using Georgian consistently, and others are using some hybrid "civic" calendar that tracks what the romans and the catholics were using, so dates in history books make sense.
Dealing with dates becomes much simpler conceptually when you realize that you are actually dealing with two different ideas masquerading as one: dates, and the actual instants in time which they name. Instants in time can only be unambiguously referenced by measuring some fixed unit of time intervals from some commonly agreed upon event (e.g. seconds since the Unix Epoch).
Dates are a mapping from human-readable labels to instants in time; critically, this mapping is not a total function (there are dates that map to no instant in time in a particular calendar, such as October 5-14 1582 in the Gregorian calendar, or 2:30am March 8 2026 in US timezones due to DST), nor is it in fact a function at all depending on how you define your inputs (1:30am November 1 2026 in US timezones is ambiguous if you don't specify DST/ST).
Furthermore, the mappings (both for past dates and future dates!) can themselves change over time (changes to DST, timezones, and calendars such as in TFA), and you need to keep track of these changes in perpetuity, as well as at which instant in time they were implemented, and we don't necessarily have that information for some of these historical changes, we only have the date as written down, which itself can suffer from the ambiguity problem (is it the date pre- or post- calendar change?).
This makes dealing with past dates tricky, and dealing with future dates speculative at best. For instance, what's February 28th + 1 day? The answer depends on the calendar system and the year; we can answer it definitively for past years but not necessarily for future years (maybe in 2040 we'll move the leap day to December 32nd). This is why it's important to immediately convert past dates (and sometimes future dates, depending on the use case) to unambiguous instants in time, and only convert them back to dates for display purposes.
"Wednesday, August 12th 2026" and "8 days from now" are also semantically distinct for some purposes: if have 8 doses of a daily prescription left, I'm still going to run out in 8 days even if tomorrow the government decides to repeal the Gregorian calendar, thus changing the name of "8 days from now" from "Wednesday, August 12th 2026" to "Sunday, August 2nd 2026". My medication doesn't care what the government decides to call 8 days from now, I'm going to run out either way. The pharmacy, on the other hand, very much does care what the government decides to call 8 days from now, because perhaps they're closed on Sundays. The calendar change means that "8 days from now" went from being not-a-Sunday to a Sunday, affecting their operating hours.
It's really just another instance of one of the two hard problems in computer science: naming things.
Regarding computers and time, I always liked that in AmigaDOS, you could specify custom relative times.
It would natively display "Future" if the file timestamp was ahead of the system clock, but you could also add dates. I remember seeing directory listings like
Ok now do date math, does the day-of-month accurately jump over the non-existent numbers?