UNPKG

luxon

Version:
207 lines (176 loc) 6.47 kB
import { integerBetween, isLeapYear, timeObject, daysInYear, daysInMonth, weeksInWeekYear, isInteger, isUndefined, } from "./util.js"; import Invalid from "./invalid.js"; import { ConflictingSpecificationError } from "../errors.js"; const nonLeapLadder = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334], leapLadder = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]; function unitOutOfRange(unit, value) { return new Invalid( "unit out of range", `you specified ${value} (of type ${typeof value}) as a ${unit}, which is invalid` ); } export function dayOfWeek(year, month, day) { const d = new Date(Date.UTC(year, month - 1, day)); if (year < 100 && year >= 0) { d.setUTCFullYear(d.getUTCFullYear() - 1900); } const js = d.getUTCDay(); return js === 0 ? 7 : js; } function computeOrdinal(year, month, day) { return day + (isLeapYear(year) ? leapLadder : nonLeapLadder)[month - 1]; } function uncomputeOrdinal(year, ordinal) { const table = isLeapYear(year) ? leapLadder : nonLeapLadder, month0 = table.findIndex((i) => i < ordinal), day = ordinal - table[month0]; return { month: month0 + 1, day }; } export function isoWeekdayToLocal(isoWeekday, startOfWeek) { return ((isoWeekday - startOfWeek + 7) % 7) + 1; } /** * @private */ export function gregorianToWeek(gregObj, minDaysInFirstWeek = 4, startOfWeek = 1) { const { year, month, day } = gregObj, ordinal = computeOrdinal(year, month, day), weekday = isoWeekdayToLocal(dayOfWeek(year, month, day), startOfWeek); let weekNumber = Math.floor((ordinal - weekday + 14 - minDaysInFirstWeek) / 7), weekYear; if (weekNumber < 1) { weekYear = year - 1; weekNumber = weeksInWeekYear(weekYear, minDaysInFirstWeek, startOfWeek); } else if (weekNumber > weeksInWeekYear(year, minDaysInFirstWeek, startOfWeek)) { weekYear = year + 1; weekNumber = 1; } else { weekYear = year; } return { weekYear, weekNumber, weekday, ...timeObject(gregObj) }; } export function weekToGregorian(weekData, minDaysInFirstWeek = 4, startOfWeek = 1) { const { weekYear, weekNumber, weekday } = weekData, weekdayOfJan4 = isoWeekdayToLocal(dayOfWeek(weekYear, 1, minDaysInFirstWeek), startOfWeek), yearInDays = daysInYear(weekYear); let ordinal = weekNumber * 7 + weekday - weekdayOfJan4 - 7 + minDaysInFirstWeek, year; if (ordinal < 1) { year = weekYear - 1; ordinal += daysInYear(year); } else if (ordinal > yearInDays) { year = weekYear + 1; ordinal -= daysInYear(weekYear); } else { year = weekYear; } const { month, day } = uncomputeOrdinal(year, ordinal); return { year, month, day, ...timeObject(weekData) }; } export function gregorianToOrdinal(gregData) { const { year, month, day } = gregData; const ordinal = computeOrdinal(year, month, day); return { year, ordinal, ...timeObject(gregData) }; } export function ordinalToGregorian(ordinalData) { const { year, ordinal } = ordinalData; const { month, day } = uncomputeOrdinal(year, ordinal); return { year, month, day, ...timeObject(ordinalData) }; } /** * Check if local week units like localWeekday are used in obj. * If so, validates that they are not mixed with ISO week units and then copies them to the normal week unit properties. * Modifies obj in-place! * @param obj the object values */ export function usesLocalWeekValues(obj, loc) { const hasLocaleWeekData = !isUndefined(obj.localWeekday) || !isUndefined(obj.localWeekNumber) || !isUndefined(obj.localWeekYear); if (hasLocaleWeekData) { const hasIsoWeekData = !isUndefined(obj.weekday) || !isUndefined(obj.weekNumber) || !isUndefined(obj.weekYear); if (hasIsoWeekData) { throw new ConflictingSpecificationError( "Cannot mix locale-based week fields with ISO-based week fields" ); } if (!isUndefined(obj.localWeekday)) obj.weekday = obj.localWeekday; if (!isUndefined(obj.localWeekNumber)) obj.weekNumber = obj.localWeekNumber; if (!isUndefined(obj.localWeekYear)) obj.weekYear = obj.localWeekYear; delete obj.localWeekday; delete obj.localWeekNumber; delete obj.localWeekYear; return { minDaysInFirstWeek: loc.getMinDaysInFirstWeek(), startOfWeek: loc.getStartOfWeek(), }; } else { return { minDaysInFirstWeek: 4, startOfWeek: 1 }; } } export function hasInvalidWeekData(obj, minDaysInFirstWeek = 4, startOfWeek = 1) { const validYear = isInteger(obj.weekYear), validWeek = integerBetween( obj.weekNumber, 1, weeksInWeekYear(obj.weekYear, minDaysInFirstWeek, startOfWeek) ), validWeekday = integerBetween(obj.weekday, 1, 7); if (!validYear) { return unitOutOfRange("weekYear", obj.weekYear); } else if (!validWeek) { return unitOutOfRange("week", obj.weekNumber); } else if (!validWeekday) { return unitOutOfRange("weekday", obj.weekday); } else return false; } export function hasInvalidOrdinalData(obj) { const validYear = isInteger(obj.year), validOrdinal = integerBetween(obj.ordinal, 1, daysInYear(obj.year)); if (!validYear) { return unitOutOfRange("year", obj.year); } else if (!validOrdinal) { return unitOutOfRange("ordinal", obj.ordinal); } else return false; } export function hasInvalidGregorianData(obj) { const validYear = isInteger(obj.year), validMonth = integerBetween(obj.month, 1, 12), validDay = integerBetween(obj.day, 1, daysInMonth(obj.year, obj.month)); if (!validYear) { return unitOutOfRange("year", obj.year); } else if (!validMonth) { return unitOutOfRange("month", obj.month); } else if (!validDay) { return unitOutOfRange("day", obj.day); } else return false; } export function hasInvalidTimeData(obj) { const { hour, minute, second, millisecond } = obj; const validHour = integerBetween(hour, 0, 23) || (hour === 24 && minute === 0 && second === 0 && millisecond === 0), validMinute = integerBetween(minute, 0, 59), validSecond = integerBetween(second, 0, 59), validMillisecond = integerBetween(millisecond, 0, 999); if (!validHour) { return unitOutOfRange("hour", hour); } else if (!validMinute) { return unitOutOfRange("minute", minute); } else if (!validSecond) { return unitOutOfRange("second", second); } else if (!validMillisecond) { return unitOutOfRange("millisecond", millisecond); } else return false; }