Files
Bubberstation/code/modules/holiday/foreign_calendar.dm
T
Jack LeCroy 2860850635 Add foreign calendar datum
Converted Hebrew calendar to a child of this datum
Foreign calendar is an easy way to support other
calendar systems for the purpose of holidays.
Added Islamic calendar and fixed Ramadan to
be more accurate than it currently is.
2020-04-20 18:22:38 -04:00

137 lines
3.8 KiB
Plaintext

#define BYOND_EPOCH 2451544.5
#define HEBREW_EPOCH 347995.5
#define ISLAMIC_EPOCH 1948439.5
/*
Source for the method of calcuation
https://www.fourmilab.ch/documents/calendar/
by John Walker 2015, released under public domain
*/
/datum/foreign_calendar
var/static/jd
var/yy
var/mm
var/dd
/datum/foreign_calendar/New()
if (!jd)
jd = realtime_to_jd()
set_date(jd)
/datum/foreign_calendar/proc/set_date()
return
/datum/foreign_calendar/proc/realtime_to_jd()
return round(world.realtime / 864000) + BYOND_EPOCH
//////////////////////////////
// Islamic Calendar //
//////////////////////////////
/datum/foreign_calendar/islamic/proc/leap_islamic(yr)
return ((yr * 11 + 14) % 30) < 11
/datum/foreign_calendar/islamic/set_date()
var/jd_adj = round(jd) + 0.5 // adjust julian date so it ends in .5
yy = round(((30 * (jd_adj - ISLAMIC_EPOCH)) + 10646) / 10631)
mm = min(12, CEILING(((jd - (29 + islamic_to_jd(yy, 1, 1))) / 29.5) + 1, 1))
dd = jd - islamic_to_jd(yy, mm, 1) + 1
/datum/foreign_calendar/islamic/proc/islamic_to_jd(year, month, day)
return day + CEILING(29.5 * (month - 1), 1) + (year - 1) * 354 + round((3 + (11 * year)) / 30) + ISLAMIC_EPOCH - 1
//////////////////////////////
// Hebrew Calendar //
//////////////////////////////
/datum/foreign_calendar/hebrew/proc/hebrew_leap(year)
switch (year % 19)
if (0, 3, 6, 8, 11, 14, 17)
return TRUE
else
return FALSE
// Hebrew to Julian
/datum/foreign_calendar/hebrew/proc/hebrew_to_jd(year, month, day)
var/months = hebrew_year_months(year)
var/jd = HEBREW_EPOCH + hebrew_delay_1(year) + hebrew_delay_2(year) + day + 1
if (month < 7)
for (var/mon = 7; mon <= months; mon++)
jd += hebrew_month_days(year, mon)
for (var/mon = 1; mon < month; mon++)
jd += hebrew_month_days(year, mon)
else
for (var/mon = 7; mon < month; mon++)
jd += hebrew_month_days(year, mon)
return jd
// Julian to Hebrew
/datum/foreign_calendar/hebrew/set_date(jd)
if (yy && mm && dd)
return
jd = round(jd) + 0.5
var/count = round(((jd - HEBREW_EPOCH) * 98496) / 35975351)
var/year = count - 1
for (var/i = count; jd >= hebrew_to_jd(i, 7, 1); i++)
year++
var/month = (jd < hebrew_to_jd(year, 1, 1)) ? 7 : 1
for (var/i = month; jd > hebrew_to_jd(year, i, hebrew_month_days(year, i)); i++)
month++
var/day = (jd - hebrew_to_jd(year, month, 1)) + 1
yy = year
mm = month
dd = day
/datum/foreign_calendar/hebrew/proc/hebrew_year_months(year)
if (hebrew_leap(year))
return 13
else
return 12
// Delay based on starting day of the year
/datum/foreign_calendar/hebrew/proc/hebrew_delay_1(year)
var/months = round(((235 * year) - 234) / 19)
var/parts = 12084 + (13753 * months)
var/day = (months * 29) + round(parts / 25920)
if (3 * (day + 1) % 7 < 3)
day++
return day
// Delay based on length of adjacent years
/datum/foreign_calendar/hebrew/proc/hebrew_delay_2(year)
var/last = hebrew_delay_1(year - 1)
var/present = hebrew_delay_1(year)
var/next = hebrew_delay_1(year + 1)
if (next - present == 356)
return 2
else if (present - last == 382)
return 1
else
return 0
/datum/foreign_calendar/hebrew/proc/hebrew_year_days(year)
return hebrew_to_jd(year + 1, 7, 1) - hebrew_to_jd(year, 7, 1)
/datum/foreign_calendar/hebrew/proc/hebrew_month_days(year, month)
switch (month)
// First of all, dispose of fixed-length 29 day months
if (2, 4, 6, 10, 13)
return 29
// If it's not a leap year, Adar has 29 days
if (12)
if (!hebrew_leap(year))
return 29
// If it's Heshvan, days depend on length of year
if (8)
if (hebrew_year_days(year) % 10 != 5)
return 29
// Similarly, Kislev varies with the length of year
if (9)
if (hebrew_year_days(year) % 10 == 3)
return 29
// Nope, it's a 30 day month
return 30
#undef ISLAMIC_EPOCH
#undef BYOND_EPOCH
#undef HEBREW_EPOCH