zero-deps-prayer-times
Version:
A lightweight, embeddable Islamic prayer times calculator based on date and coordinates, with zero external dependencies.
92 lines (77 loc) • 2.24 kB
text/typescript
import { round } from "./formatting";
export function getDayOfYear(date: Date) {
const startOfYear = new Date(Date.UTC(date.getUTCFullYear(), 0, 1));
const diff = date.getTime() - startOfYear.getTime();
return Math.floor(round(diff / (1000 * 60 * 60 * 24)) + 1);
}
export function isDateInRamadan(date: Date) {
const hijri = toHijri(date);
if (hijri.month === 9) {
return true;
}
return false;
}
type DateInput = Date | [number, number, number];
type HijriDate = {
year: number;
month: number;
day: number;
};
const ISLAMIC_EPOCH = 1948439.5;
function toHijri(input: DateInput): HijriDate {
let gYear: number, gMonth: number, gDay: number;
if (input instanceof Date) {
if (isNaN(input.getTime())) {
throw new Error("Invalid Gregorian date");
}
gYear = input.getFullYear();
gMonth = input.getMonth() + 1;
gDay = input.getDate();
} else if (Array.isArray(input) && input.length === 3) {
[gYear, gMonth, gDay] = input;
} else {
throw new Error(
"Invalid input. Please provide a Date object or an array [year, month, day]"
);
}
if (gYear < 1 || gMonth < 1 || gMonth > 12 || gDay < 1 || gDay > 31) {
throw new Error("Invalid Gregorian date");
}
const jd = gregorianToJulian(gYear, gMonth, gDay);
return julianToHijri(jd);
}
function gregorianToJulian(year: number, month: number, day: number): number {
if (month < 3) {
year -= 1;
month += 12;
}
const a = Math.floor(year / 100);
const b = 2 - a + Math.floor(a / 4);
return (
Math.floor(365.25 * (year + 4716)) +
Math.floor(30.6001 * (month + 1)) +
day +
b -
1524.5
);
}
function julianToHijri(jd: number): HijriDate {
jd = Math.floor(jd) + 0.5;
const year = Math.floor((30 * (jd - ISLAMIC_EPOCH) + 10646) / 10631);
const month = Math.min(
12,
Math.ceil((jd - (29 + julianToHijriDay(year, 1, 1))) / 29.5) + 1
);
const day = jd - julianToHijriDay(year, month, 1) + 1;
return { year, month, day };
}
function julianToHijriDay(year: number, month: number, day: number): number {
return (
day +
Math.ceil(29.5 * (month - 1)) +
(year - 1) * 354 +
Math.floor((3 + 11 * year) / 30) +
ISLAMIC_EPOCH -
1
);
}