Created
April 25, 2020 21:01
-
-
Save Ratstail91/da6cc45277518ed8bdf9551b9d34a33e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
public static class Calendar { | |
public enum Month { | |
JANUARY = 1, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER | |
} | |
public enum EventType { | |
NONE, | |
CHRISTMAS, | |
EASTER, | |
//... | |
} | |
//assume events last for two weeks at a time | |
public static EventType GetEvent(int day, Month month, int year, bool ignoreEaster = false) { | |
//check the input | |
if (!CheckValidDate(day, month, year)) { | |
throw new Exception("Date is invalid: " + day + ", " + month + ", " + year); | |
} | |
//first, since Easter is so *special* that it feels like moving around a lot, let's calculate it separately | |
//this will override any other events that might fall on these dates, so ignoreEaster is a parameter | |
if (!ignoreEaster) { //if there's more moving events, you might want to add a list of strings to signal what to ignore | |
//fallback on C#'s DateTime because holy crap I don't wanna touch that algorithm | |
DateTime easterSunday = CalculateEasterSunday(year); | |
//two weeks | |
DateTime start = easterSunday.AddDays(-7); | |
DateTime end = easterSunday.AddDays(6); | |
DateTime now = new DateTime(year, (int)month, day); | |
if (start <= now && end >= now) { | |
return EventType.EASTER; | |
} | |
} | |
//jump to the month | |
switch(month) { | |
case Month.JANUARY: | |
case Month.FEBRUARY: | |
case Month.MARCH: | |
case Month.APRIL: | |
case Month.MAY: | |
case Month.JUNE: | |
case Month.JULY: | |
case Month.AUGUST: | |
case Month.SEPTEMBER: | |
case Month.OCTOBER: | |
case Month.NOVEMBER: | |
break; | |
case Month.DECEMBER: | |
//christmas period | |
if (day >= 18 && day <= 31) { | |
return EventType.CHRISTMAS; | |
} | |
break; | |
} | |
return EventType.NONE; | |
} | |
//helper functions | |
public static bool CheckValidDate(int day, Month month, int year) { | |
return day > 0 && day <= MaxDays(month, year); | |
} | |
public static int MaxDays(Month month, int year) { | |
switch(month) { | |
case Month.JANUARY: | |
case Month.MARCH: | |
case Month.MAY: | |
case Month.JULY: | |
case Month.AUGUST: | |
case Month.OCTOBER: | |
case Month.DECEMBER: | |
return 31; | |
case Month.APRIL: | |
case Month.JUNE: | |
case Month.SEPTEMBER: | |
case Month.NOVEMBER: | |
return 30; | |
case Month.FEBRUARY: | |
return CheckLeapYear(year) ? 29 : 28; | |
default: | |
throw new Exception("Unknown month"); | |
} | |
} | |
public static bool CheckLeapYear(int year) { | |
//accurate up to about eight thousand years, apparently | |
if (year % 400 == 0) { | |
return true; //leap | |
} | |
if (year % 100 == 0) { | |
return false; | |
} | |
return year % 4 == 0; //leap | |
} | |
public static DateTime CalculateEasterSunday(int year) { | |
//praise jebus! | |
int g = year % 19; | |
int c = year / 100; | |
int h = (c - (int)(c / 4) - (int)((8 * c + 13) / 25) + 19 * g + 15) % 30; | |
int i = h - (int)(h / 28) * (1 - (int)(h / 28) * (int)(29 / (h + 1)) * (int)((21 - g) / 11)); | |
int day = i - ((year + (int)(year / 4) + i + 2 - c + (int)(c / 4)) % 7) + 28; | |
int month = 3; | |
if (day > 31) | |
{ | |
month++; | |
day -= 31; | |
} | |
return new DateTime(year, month, day); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment