react-day-picker
Version:
Customizable Date Picker for React
160 lines (159 loc) • 6.62 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createNoonOverrides = createNoonOverrides;
const tz_1 = require("@date-fns/tz");
const date_fns_1 = require("date-fns");
/**
* Creates `dateLib` overrides that keep all calendar math at noon in the target
* time zone. This avoids second-level offset changes (e.g., historical zones
* with +03:41:12) from pushing dates backward across midnight.
*/
function createNoonOverrides(timeZone, options = {}) {
const { weekStartsOn, locale } = options;
const fallbackWeekStartsOn = (weekStartsOn ??
locale?.options?.weekStartsOn ??
0);
// Keep all internal math anchored at noon in the target zone to avoid
// historical second-level offsets from crossing midnight.
const toNoonTZDate = (date) => {
const normalizedDate = typeof date === "number" || typeof date === "string"
? new Date(date)
: date;
return new tz_1.TZDate(normalizedDate.getFullYear(), normalizedDate.getMonth(), normalizedDate.getDate(), 12, 0, 0, timeZone);
};
// Convert a value into a host `Date` that represents the same calendar day
// as the target-zone noon. This is useful for helpers (e.g., date-fns week
// utilities) that expect local `Date` instances rather than `TZDate`s.
const toCalendarDate = (date) => {
const zoned = toNoonTZDate(date);
return new Date(zoned.getFullYear(), zoned.getMonth(), zoned.getDate(), 0, 0, 0, 0);
};
return {
today: () => {
return toNoonTZDate(tz_1.TZDate.tz(timeZone));
},
newDate: (year, monthIndex, date) => {
return new tz_1.TZDate(year, monthIndex, date, 12, 0, 0, timeZone);
},
startOfDay: (date) => {
return toNoonTZDate(date);
},
startOfWeek: (date, options) => {
const base = toNoonTZDate(date);
const weekStartsOnValue = (options?.weekStartsOn ??
fallbackWeekStartsOn);
const diff = (base.getDay() - weekStartsOnValue + 7) % 7;
base.setDate(base.getDate() - diff);
return base;
},
startOfISOWeek: (date) => {
const base = toNoonTZDate(date);
const diff = (base.getDay() - 1 + 7) % 7;
base.setDate(base.getDate() - diff);
return base;
},
startOfMonth: (date) => {
const base = toNoonTZDate(date);
base.setDate(1);
return base;
},
startOfYear: (date) => {
const base = toNoonTZDate(date);
base.setMonth(0, 1);
return base;
},
endOfWeek: (date, options) => {
const base = toNoonTZDate(date);
const weekStartsOnValue = (options?.weekStartsOn ??
fallbackWeekStartsOn);
const endDow = (weekStartsOnValue + 6) % 7;
const diff = (endDow - base.getDay() + 7) % 7;
base.setDate(base.getDate() + diff);
return base;
},
endOfISOWeek: (date) => {
const base = toNoonTZDate(date);
const diff = (7 - base.getDay()) % 7;
base.setDate(base.getDate() + diff);
return base;
},
endOfMonth: (date) => {
const base = toNoonTZDate(date);
base.setMonth(base.getMonth() + 1, 0);
return base;
},
endOfYear: (date) => {
const base = toNoonTZDate(date);
base.setMonth(11, 31);
return base;
},
eachMonthOfInterval: (interval) => {
const start = toNoonTZDate(interval.start);
const end = toNoonTZDate(interval.end);
const result = [];
const cursor = new tz_1.TZDate(start.getFullYear(), start.getMonth(), 1, 12, 0, 0, timeZone);
const endKey = end.getFullYear() * 12 + end.getMonth();
while (cursor.getFullYear() * 12 + cursor.getMonth() <= endKey) {
result.push(new tz_1.TZDate(cursor, timeZone));
cursor.setMonth(cursor.getMonth() + 1, 1);
}
return result;
},
// Normalize to noon once before arithmetic (avoid DST/midnight edge cases),
// mutate the same TZDate, and return it.
addDays: (date, amount) => {
const base = toNoonTZDate(date);
base.setDate(base.getDate() + amount);
return base;
},
addWeeks: (date, amount) => {
const base = toNoonTZDate(date);
base.setDate(base.getDate() + amount * 7);
return base;
},
addMonths: (date, amount) => {
const base = toNoonTZDate(date);
base.setMonth(base.getMonth() + amount);
return base;
},
addYears: (date, amount) => {
const base = toNoonTZDate(date);
base.setFullYear(base.getFullYear() + amount);
return base;
},
eachYearOfInterval: (interval) => {
const start = toNoonTZDate(interval.start);
const end = toNoonTZDate(interval.end);
const years = [];
const cursor = new tz_1.TZDate(start.getFullYear(), 0, 1, 12, 0, 0, timeZone);
while (cursor.getFullYear() <= end.getFullYear()) {
years.push(new tz_1.TZDate(cursor, timeZone));
cursor.setFullYear(cursor.getFullYear() + 1, 0, 1);
}
return years;
},
getWeek: (date, options) => {
const base = toCalendarDate(date);
return (0, date_fns_1.getWeek)(base, {
weekStartsOn: options?.weekStartsOn ?? fallbackWeekStartsOn,
firstWeekContainsDate: options?.firstWeekContainsDate ??
locale?.options?.firstWeekContainsDate ??
1,
});
},
getISOWeek: (date) => {
const base = toCalendarDate(date);
return (0, date_fns_1.getISOWeek)(base);
},
differenceInCalendarDays: (dateLeft, dateRight) => {
const left = toCalendarDate(dateLeft);
const right = toCalendarDate(dateRight);
return (0, date_fns_1.differenceInCalendarDays)(left, right);
},
differenceInCalendarMonths: (dateLeft, dateRight) => {
const left = toCalendarDate(dateLeft);
const right = toCalendarDate(dateRight);
return (0, date_fns_1.differenceInCalendarMonths)(left, right);
},
};
}