128 years? Hypothetical leap year reform

23

2

The solar year is 365 days, 5 hours, 48 minutes, 45 seconds, and 138 milliseconds, according to this video. With the current Gregorian calendar, the rules for leap years are as follows:

if      year is divisible by 400, LEAP YEAR
else if year is divisible by 100, COMMON YEAR
else if year is divisible by 4,   LEAP YEAR
else,                             COMMON YEAR

Unfortunately, this method is off by one day every 3216 years.

One possible method of reforming the calendar is the following rule:

if      year is divisible by 128, COMMON YEAR
else if year is divisible by 4,   LEAP YEAR
else,                             COMMON YEAR

This has the benefit of not requiring us to change our calendars again for another 625,000 years, give or take.

Say the entire world decides that, starting now, we use this system of every fourth year is a leap year except every 128th year, changing our calendars as follows:

YEAR    GREGORIAN    128-YEAR
2044    LEAP         LEAP
2048    LEAP         COMMON
2052    LEAP         LEAP
 ...
2096    LEAP         LEAP
2100    COMMON       LEAP
2104    LEAP         LEAP
 ...
2296    LEAP         LEAP
2300    COMMON       LEAP
2304    LEAP         COMMON
2308    LEAP         LEAP

How would this affect our day of the week algorithms?

The challenge

  • Given a date from the year 2000 to the year 100000, find the day of the week under this new calendar.
  • Any input and output format is allowed as long as you clearly specify which formats you are using.
  • This is code golf so try to make your solutions as golfy as possible!

Test cases

"28 February 2048" -> "Friday"
"March 1, 2048"    -> "Sat"
(2100, 2, 29)      -> 0           # 0-indexed with Sunday as 0
"2100-02-29"       -> 7           # 1-indexed with Sunday as 7
"28 Feb. 2176"     -> "Wednesday"
"1-Mar-2176"       -> "Th"
"28/02/100000"     -> "F"         # DD/MM/YYYYYY
"Feb. 29, 100000"  -> 6           # 1-indexed with Sunday as 7
"03/01/100000"     -> 1          # MM/DD/YYYYYY and 1-indexed with Sunday as 1

Suggestions and feedback on the challenge are welcome. Good luck and good golfing!

Sherlock9

Posted 2017-11-30T18:16:12.180

Reputation: 11 664

For test case #4, you mean 1-indexed, right? Otherwise there would have to be 8 days in that week. – Sebastian – 2017-11-30T20:37:02.550

Also, you say "good golfing", so is this a #code-golf challenge? If so, put in the winning criteria (e.g. lowest number of bytes/characters) and add that as a tag. – Sebastian – 2017-11-30T20:40:47.507

@Sebastian You are correct on both counts. I've already edited the challenge. Thank you for your feedback – Sherlock9 – 2017-11-30T20:46:27.853

My answer disagrees with the test cases from the year 100000 (labeling them Friday and Sunday, respectively), but I believe my answer over the test cases. I've brute-force checked my answer in two respects over the range 2000 to 100000: that Jan 1 is always the day after Dec 31 of the previous year, and that the years in which Mar 1 is not the day after Feb 28 are precisely the years divisible by 4 but not 128. Can you double-check those test cases? – Misha Lavrov – 2017-11-30T22:20:53.323

1When reading the title I immeadiately though of Matt Parker's video. Nice to see it linked in the thread as well :D – PattuX – 2017-11-30T22:22:22.023

@MishaLavrov I'm getting Saturday for both – ericw31415 – 2017-12-01T01:30:30.940

@ericw31415 They can't both be Saturday, they're two days apart. – Misha Lavrov – 2017-12-01T01:53:38.673

@MishaLavrov Whoops, that was due to a careless "simplification" on my part. I'm now getting Friday and Sunday like you. – ericw31415 – 2017-12-01T02:03:01.767

1Just take the standard day-of-the-week libraries and modify the global constants accordingly, right? ;) – Wildcard – 2017-12-01T04:18:12.477

@MishaLavrov I figured I had 100000 wrong somehow. Thanks for the feedback. – Sherlock9 – 2017-12-01T06:20:48.750

I enjoy seeing how the order of the function parameters is m, d, y for some answers and d, m, y for others––and then there are those implicit parameter answers that apparently like to keep an air of mystery about them. – Daniel – 2017-12-03T02:06:09.037

Answers

8

C (gcc), 60 bytes

f(m,d,y){y-=m<3;return(y+y/4-y/128+"-bed=pen+mad."[m]+d)%7;}

Try it online!

Simple modification of Sakamoto's method. Takes input as integer arguments in the order month, day, year, and outputs the number of the day (0-indexed on Sunday).

notjagan

Posted 2017-11-30T18:16:12.180

Reputation: 4 011

What does the "-bed=pen+mad." part do? – ericw31415 – 2017-12-01T00:48:05.923

@ericw31415 It accounts for the length of each month in days, and simply for the sake of appearance it is shifted up by multiples of 7 instead of being characters at ordinals (31, 28...). – notjagan – 2017-12-01T00:52:59.560

Right, I forgot that char still represents a number, so you can do mod 7 directly. – ericw31415 – 2017-12-01T01:04:03.250

6

Wolfram Language (Mathematica), 57 55 53 bytes

DayName@{m=#~Mod~128;6+Mod[(9#-m)/8-6Clip@m,28],##2}&

Try it online!

Takes three inputs: the year, the month, and the day, in that order. For example, if you save the above function as fun, then fun[2048,2,28] tells you the day of week of February 28, 2048.

How it works

The formula m=#~Mod~128;6+Mod[(9#-m)/8-6Clip@m,28] converts the year into an equivalent year (a year with exactly the same days of week) between 6 AD and 33 AD. To do this, we subtract an offset and then take the year mod 28; but the offset changes every 128 years, and for years divisible by 128, we have to make a further adjustment because the equivalent year shouldn't be a leap year.

Anyway, once that's done, we look up the month and day in that equivalent year using the built-in DayName.

Misha Lavrov

Posted 2017-11-30T18:16:12.180

Reputation: 4 846

3

JavaScript, 65 59 bytes

(d,m,y)=>(y-=m<3,(+"0032503514624"[m]+y+(y>>2)-(y>>7)+d)%7)

(d,m,y)=>(y-=m<3,(+"0032503514624"[m]+~~y+~~(y/4)-~~(y/128)+d)%7)

Uses Sakamoto's method. Gives 0=Sunday, 1=Monday, 2=Tuesday...

-2 bytes thanks to Misha Lavrov
-4 bytes thanks to Arnauld

ericw31415

Posted 2017-11-30T18:16:12.180

Reputation: 2 229

1I think ~~y can just be changed to y. You're not going to get a fractional year in the input, right? But I admit I'm not fluent in JavaScript. – Misha Lavrov – 2017-12-01T06:23:02.887

2How about +y+(y>>2)-(y>>7)? – Arnauld – 2017-12-01T07:22:26.460

@MishaLavrov Yes, that is true. For some reason I decided I should floor everything. – ericw31415 – 2017-12-01T21:44:02.393

3

Python 2, 67 bytes

def f(m,d,y):y-=m<3;return(y+y/4-y/128+int("0032503514624"[m])+d)%7

Try it online!

int("..."[m]) can be replaced by ord("-bed=pen+mad."[m]).

Mr. Xcoder

Posted 2017-11-30T18:16:12.180

Reputation: 39 774

2

Actually, 37 bytes

This is a port of notjagan's modification of Sakamoto's algorithm, but with a few stack-based tricks as described below. Input format is day, year, month. Output format is 0-indexed with Sunday as 0. Golfing suggestions welcome! Try it online!

;"0032503514624"Ei)3>±+;¼L;¼¼½L±kΣ7@%

Explanation

                     Implicit input: day, year, month (month is at TOS)
;"0032503514624"Ei)  Get the month code, convert to float, rotate to bottom of the stack
3>±+                 If 3>month, add -1 to year
;¼L                  Push floor(year/4) to stack
;¼¼½L±               Push floor(year/4) and append -floor(year/128) to stack.
kΣ                   Wrap the stack (y/128, y/4, y, month_code, d) in a list and sum
7@%                  Get the sum modulo 7
                     Implicit return

Sherlock9

Posted 2017-11-30T18:16:12.180

Reputation: 11 664

2

Jelly, 32 31 30 28 bytes

Another port of notjagan's modification of Sakamoto's algorithm but with a base-250 number in place of 032503514624 (don't need the extra 0 because Jelly is 1-indexed). Input format is month, year, day. Output format is 0-based with Sunday as 0. Golfing suggestion are very welcome as the way the links were tough to arrange and may still be golfable. Try it online!

Edit: -1 byte from using bit shift instead of integer division. -1 byte from rearranging the beginning and the input format. -2 bytes thanks to Erik the Outgolfer and caird coinheringaahing.

3>_@µæ»7,2I+µ“Ṿ⁵Ḥ9{’D³ị+⁵+%7

Explanation

         Three arguments: month, year, day
3>_@     Subtract (month<3) from year. Call it y.
µ        Start a new monadic chain.
æ»7,2    Bit shift y by both 7 and 2 (equivalent to integer division by 128 and by 4).
I+       y + y/4 - y/128
µ        Start a new monadic chain.
“Ṿ⁵Ḥ9{’  The number 732573514624 in base 250.
D        The list [7, 3, 2, 5, 7, 3, 5, 1, 4, 6, 2, 4].
³ị       Get the month code from the list (1-based indexing).
+⁵+      Add y, our month code, and day together.
%7       Modulus 7.

Sherlock9

Posted 2017-11-30T18:16:12.180

Reputation: 11 664

29 bytes – caird coinheringaahing – 2017-12-02T19:40:28.770