Skip to content

Instantly share code, notes, and snippets.

@Ratstail91
Created April 25, 2020 21:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ratstail91/da6cc45277518ed8bdf9551b9d34a33e to your computer and use it in GitHub Desktop.
Save Ratstail91/da6cc45277518ed8bdf9551b9d34a33e to your computer and use it in GitHub Desktop.
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