import SunCalc from "suncalc";
const athens = [37.9795, 23.7162];
const newcastle = [54.9738, -1.6132];
const oneDay = 24 * 60 * 60 * 1000;
const oneMonth = 29.53 * oneDay;
const sundial = (date, location) => {
let x = SunCalc.getTimes(date, ...location);
x.length = x.sunset - x.sunrise;
return x;
};
const phase = date => SunCalc.getMoonIllumination(date).phase;
const noon = date => {
let x = new Date(date);
x.setHours(12, 0, 0, 0);
if (date > sundial(x, newcastle).sunset) {
x.setDate(x.getDate() + 1);
}
return x;
};
const addDays = (date, days) => {
let x = new Date(date);
x.setDate(x.getDate() + days);
return x;
};
const scanNights = date => {
const today = noon(date);
const dawn = d => sundial(d, athens).dawn;
let results = {
lastNewMoon: undefined,
nextNewMoon: undefined,
dayOfMonth: undefined,
signedDate: undefined
};
let currentNext = phase(dawn(today));
let currentLast = phase(dawn(today));
for (let i = 1; results.lastNewMoon === undefined && i < 50; i++) {
const yester = addDays(today, -i);
if (phase(dawn(yester)) > currentLast) {
results.lastNewMoon = addDays(today, -(i - 1));
}
currentLast = phase(dawn(yester));
}
for (let i = 1; results.nextNewMoon === undefined && i < 50; i++) {
const morrow = addDays(today, i);
if (phase(dawn(morrow)) < currentNext) {
results.nextNewMoon = addDays(today, i);
}
currentNext = phase(dawn(morrow));
}
results.dayOfMonth = Math.round((today - results.lastNewMoon) / oneDay) + 1;
if (Math.round((results.nextNewMoon - today) / oneDay) == 1) {
results.signedDate = 0;
} else {
results.signedDate =
results.dayOfMonth > 20
? results.dayOfMonth - 31
: results.dayOfMonth;
}
return results;
};
const solstice = year => {
let dates = [20, 21, 22].map(x => new Date(`${year}-06-${x}T12:00:00`));
let dayLengths = dates.map(x => sundial(x, athens).length);
let results = {
midsummer: noon(dates[dayLengths.indexOf(Math.max(...dayLengths))])
};
results.newYear = scanNights(results.midsummer).nextNewMoon;
return results;
};
const years = date => {
const currentYear = date.getFullYear();
const surroundingYears = [
solstice(currentYear - 1).newYear,
solstice(currentYear).newYear,
solstice(currentYear + 1).newYear
];
if (date < surroundingYears[1]) {
return surroundingYears.slice(0, 2);
} else {
return surroundingYears.slice(1, 3);
}
};
const attic = gregorian => {
gregorian = noon(gregorian);
let output = {
olympiad: undefined,
year: undefined,
month: undefined,
rawDate: undefined,
signedDate: undefined,
weekday: gregorian.getDay()
};
const scanned = scanNights(gregorian);
output.rawDate = scanned.dayOfMonth;
output.signedDate = scanned.signedDate;
const noumenia = scanned.lastNewMoon;
const newYear = years(noumenia)[0];
const isLeapYear =
Math.round((years(noumenia)[1] - newYear) / oneMonth) == 13;
output.month = Math.round((noumenia - newYear) / oneMonth);
if (!isLeapYear && output.month >= 6) {
output.month += 1;
}
const rawYear = newYear.getFullYear() - -775;
output.olympiad = Math.floor(rawYear / 4) + 1;
output.year = (rawYear % 4) + 1;
return output;
};
export default attic;