Algorithm Search⌘K

Proofs: Gregorian calendar computation

These are the human proofs of Gregorian calendar computation, at full length.

The fixed-date conversions of the Gregorian calendar are inverse bijections full

This proof shows: correctness.

Claim. Let G\mathcal{G} be the set of valid proleptic Gregorian dates (y,m,d)(y, m, d) with y∈Zy \in \mathbb{Z}. FIXED-FROM-GREGORIAN numbers the days of G\mathcal{G} consecutively with 11 on 1 January of year 11, so it is a bijection from G\mathcal{G} to Z\mathbb{Z}. GREGORIAN-FROM-FIXED is its inverse, and DAY-OF-WEEK(r)(r) is 00 for Sunday through 66 for Saturday.

Throughout, ⌊⋅⌋\lfloor \cdot \rfloor is floor division and x mod q=x−q⌊x/q⌋∈{0,…,q−1}x \bmod q = x - q\lfloor x/q \rfloor \in \{0, \ldots, q - 1\}, defined for all integers xx.

Notation. Let χ(z)=1\chi(z) = 1 if 4∣z4 \mid z and (100∤z100 \nmid z or 400∣z400 \mid z), and χ(z)=0\chi(z) = 0 otherwise; this is LEAP (line L1). Year zz has 365+χ(z)365 + \chi(z) days. Let L(x)=⌊x/4⌋−⌊x/100⌋+⌊x/400⌋L(x) = \lfloor x/4 \rfloor - \lfloor x/100 \rfloor + \lfloor x/400 \rfloor and F(x)=365x+L(x)F(x) = 365x + L(x). For q≥1q \ge 1, ⌊z/q⌋−⌊(z−1)/q⌋=[q∣z]\lfloor z/q \rfloor - \lfloor (z - 1)/q \rfloor = [q \mid z], so L(z)−L(z−1)=[4∣z]−[100∣z]+[400∣z]=χ(z)L(z) - L(z - 1) = [4 \mid z] - [100 \mid z] + [400 \mid z] = \chi(z) by cases, and

F(z)−F(z−1)=365+χ(z).F(z) - F(z - 1) = 365 + \chi(z).

With F(0)=0F(0) = 0, F(x)F(x) is the number of days in the years 11 to xx for x≥0x \ge 0, and minus the number of days in the years x+1x + 1 to 00 for x<0x < 0. In both cases, the days before 1 January of year yy, counted from 1 January of year 11, number F(y−1)F(y - 1).

Month offsets. Let g(m)=⌊(367m−362)/12⌋g(m) = \lfloor (367m - 362)/12 \rfloor. Direct evaluation gives g(1),…,g(13)=0,31,61,92,122,153,183,214,245,275,306,336,367g(1), \ldots, g(13) = 0, 31, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336, 367. The differences g(m+1)−g(m)g(m + 1) - g(m) for m=1,…,12m = 1, \ldots, 12 are 31,30,31,30,31,30,31,31,30,31,30,3131, 30, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31: the true month lengths, except 3030 for February. For year yy, let cy(m)=0c_y(m) = 0 for m≤2m \le 2 and cy(m)=−2+χ(y)c_y(m) = -2 + \chi(y) for m≥3m \ge 3 (line L2). Then hy(m)=g(m)+cy(m)h_y(m) = g(m) + c_y(m) is the number of days in year yy before month mm, because February has 28+χ(y)28 + \chi(y) days, which is 30−(2−χ(y))30 - (2 - \chi(y)).

Forward (lines L2 and L3). Line L3 returns F(y−1)+hy(m)+dF(y - 1) + h_y(m) + d, which is the number of days from 1 January of year 11 to the date, plus 11. So two consecutive days get consecutive numbers, and 1 January of year 11 gets F(0)+0+1=1F(0) + 0 + 1 = 1. Every date is reached from 1 January of year 11 by finitely many steps forward or backward, so the map is a bijection from G\mathcal{G} to Z\mathbb{Z}.

Mixed-radix form of FF. Every integer xx has a unique form x=400a+100b+4c+ex = 400a + 100b + 4c + e with a∈Za \in \mathbb{Z}, 0≤b≤30 \le b \le 3, 0≤c≤240 \le c \le 24 and 0≤e≤30 \le e \le 3. Then ⌊x/4⌋=100a+25b+c\lfloor x/4 \rfloor = 100a + 25b + c, ⌊x/100⌋=4a+b\lfloor x/100 \rfloor = 4a + b and ⌊x/400⌋=a\lfloor x/400 \rfloor = a, because e≤3e \le 3, 4c+e≤994c + e \le 99 and 100b+4c+e≤399100b + 4c + e \le 399. So L(x)=97a+24b+cL(x) = 97a + 24b + c and

F(x)=146097a+36524b+1461c+365e.F(x) = 146097a + 36524b + 1461c + 365e.

Also x+1x + 1 is a leap year exactly when e=3e = 3 and (c≠24c \ne 24 or b=3b = 3), since x+1=400a+100b+4(c+1)x + 1 = 400a + 100b + 4(c + 1) is then a multiple of 44, of 100100 exactly when c=24c = 24, and of 400400 exactly when c=24c = 24 and b=3b = 3.

Backward, the year (lines L4 to L10). Let rr be an integer with date (y∗,m∗,d∗)(y^*, m^*, d^*). By the forward part, r=F(y∗−1)+hy∗(m∗)+d∗r = F(y^* - 1) + h_{y^*}(m^*) + d^*. Let x∗=y∗−1=400a+100b+4c+ex^* = y^* - 1 = 400a + 100b + 4c + e in the form above, and t=hy∗(m∗)+d∗−1t = h_{y^*}(m^*) + d^* - 1, the day of the year counted from 00, so 0≤t≤364+χ(y∗)0 \le t \le 364 + \chi(y^*). Line L4 gives d0=r−1=F(x∗)+t=146097a+36524b+1461c+365e+td0 = r - 1 = F(x^*) + t = 146097a + 36524b + 1461c + 365e + t.

  • Line L5. The part after 146097a146097a is at most 36524⋅3+1461⋅24+365⋅3+365=14609636524 \cdot 3 + 1461 \cdot 24 + 365 \cdot 3 + 365 = 146096, so n400=an400 = a and d1=36524b+1461c+365e+td1 = 36524b + 1461c + 365e + t.
  • Line L6. The part 1461c+365e+t1461c + 365e + t is at most 35064+1095+365=3652435064 + 1095 + 365 = 36524, with equality only if c=24c = 24, e=3e = 3 and t=365t = 365. Then y∗y^* is a leap year, so b=3b = 3. Case A: not all of these hold. Then n100=bn100 = b and d2=1461c+365e+td2 = 1461c + 365e + t. Case B: b=3b = 3, c=24c = 24, e=3e = 3, t=365t = 365. Then d1=146096d1 = 146096, n100=4n100 = 4 and d2=0d2 = 0, so lines L7 and L8 give n4=n1=0n4 = n1 = 0, line L9 gives y=400a+400=x∗+1=y∗y = 400a + 400 = x^* + 1 = y^*, and line L10 keeps it.
  • Line L7, Case A. The part 365e+t365e + t is at most 1095+365=1460<14611095 + 365 = 1460 < 1461, so n4=cn4 = c and d3=365e+td3 = 365e + t.
  • Line L8, Case A. If t≤364t \le 364, then n1=e≤3n1 = e \le 3, line L9 gives y=x∗y = x^*, and line L10 adds one: y=y∗y = y^*. If t=365t = 365, then y∗y^* is a leap year, e=3e = 3, d3=1460d3 = 1460 and n1=4n1 = 4, so line L9 gives y=x∗+1=y∗y = x^* + 1 = y^* and line L10 keeps it.

In every case the year after line L10 is y∗y^*.

Backward, the month and the day (lines L11 to L14). Line L11 gives p=r−(F(y∗−1)+1)=tp = r - (F(y^* - 1) + 1) = t. The test of line L12 holds exactly when m∗≤2m^* \le 2, so c=−cy∗(m∗)c = -c_{y^*}(m^*) and p+c=g(m∗)+d∗−1p + c = g(m^*) + d^* - 1. Since 0≤d∗−10 \le d^* - 1 and d∗d^* is at most the true length of month m∗m^*, which is at most g(m∗+1)−g(m∗)g(m^* + 1) - g(m^*), we get g(m∗)≤p+c<g(m∗+1)g(m^*) \le p + c < g(m^* + 1). The function gg is strictly increasing, so m∗m^* is the largest mm with g(m)≤p+cg(m) \le p + c. For integers, g(m)≤T  ⟺  367m−362≤12T+11  ⟺  m≤(12T+373)/367g(m) \le T \iff 367m - 362 \le 12T + 11 \iff m \le (12T + 373)/367, so this largest mm is ⌊(12(p+c)+373)/367⌋\lfloor (12(p + c) + 373)/367 \rfloor, which is line L13. Line L14 returns r−(F(y∗−1)+hy∗(m∗)+1)+1=d∗r - (F(y^* - 1) + h_{y^*}(m^*) + 1) + 1 = d^*.

Day of the week (line L15). R.D. 11 is a Monday, and consecutive days have consecutive numbers, so R.D. rr is r−1r - 1 days after a Monday and its weekday is (1+(r−1)) mod 7=r mod 7(1 + (r - 1)) \bmod 7 = r \bmod 7 with 00 for Sunday, for every integer rr. ■\blacksquare

Back to Gregorian calendar computation