> 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.
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_...
Thanks. I haven’t known that countries switched in different years.
Gregorian calendar is just one piece.
https://en.wikipedia.org/wiki/Civil_calendar
Eighteen countries use another calendar alongside the Gregorian calendar…
Not in the standard Gregorian calendar. Those dates only exist in the proleptic Gregorian calendar. The standard Gregorian calendar explicitly skips them. That's because you can't feasibly go back and change all the Julian dates that had been physically written down for centuries. That's why it's called the Gregorian "shift".
The afternotes at the end of the post are worth reading; people have sent me various qualifications and corrections over the years.
> 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.
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.
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.
Such a flag day didn't involve removing days from one calendar or the other, it switched between them.
I wouldn't say it's it's straightforward to convert between them, either. The Gregorian calendar was first adopted in 1582, but the UK and it's colonies didn't follow suit until 1752. Russia didn't convert until 1918, and Greece didn't switch until 1923. We're just over 100 years out from active use of the Julian calendar. So you have to know who the speaker is and where they are or where they are from to know what they mean.
Since these places switched at different times, they had to skip a different number of days. It was 10 in the 16th century. It was 13 in the 20th!
If you're reading a journal by a British man who lived in Russia through the end of the Great War and then moved to Greece in 1920, what does he mean when he's talking about a lunar eclipse he just witnessed?
(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.1582 is Catholic Europe
1700 or 1701 is Protestant Europe
1752 is Great Britain and its colonies which include USA
1918 is Russia
1923 Greece
https://en.wikipedia.org/wiki/Adoption_of_the_Gregorian_cale...
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.
Dates are messy.
[1] https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar
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
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.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.
Meta: one can also link to this article, which redirects:
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.
Also, there is an unofficial "Old New Year" eve on 1/13, which people recognize as the "old style" New Year eve, even though more than 100 years have passed since the calendar change.
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 1988We also go through the same hour twice when the clocks go back going back to standard time.
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 ==.If not I'd argue the system should disallow dates before the switchover.
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.
I’ll draft a Dubia so that when future popes change the calendar they will include a representative code sample and details about how we handle this.
(It’s important to remember that the pope and friends were operating much more like an international standards body than a religious leader when doing things like this.)
I maintain an Elixir library (Calendrical) that does this. England, for example, is just three segments spliced onto a Julian base:
defmodule England do
use Calendrical.Composite,
calendars: [
~D[1155-03-25 Calendrical.Julian.March25], # year starts on Lady Day
~D[1751-03-25 Calendrical.Julian.Jan1], # New Year moved to Jan 1
~D[1752-09-14 Calendrical.Gregorian] # the 11-day jump
],
base_calendar: Calendrical.Julian
end
The "missing" days simply aren't valid dates, and stepping across the boundary jumps: England.days_in_month(1752, 9) #=> 19
England.valid_date?(1752, 9, 3) #=> false
Date.shift(~D[1752-09-02 England], day: 1) #=> ~D[1752-09-14 England]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.