datezone
Version:
A lightweight and comprehensive date and timeZone utility library for JavaScript.
340 lines • 11.2 kB
JavaScript
import { getCachedFormatterLocale } from "./cache.js";
import { calendarToTimestamp, timestampToCalendar } from "./calendar.pub.js";
import { isLeapYearBase } from "./year.pub.js";
/**
* Extracts the month from a timestamp.
*
* @param ts - The timestamp to get the month for
* @param timeZone - Optional timeZone (defaults to local time)
* @returns The month of the year (1-12)
* @see https://datezone.dev/docs/reference/month#month
*/
export function month(ts, timeZone) {
if (!timeZone) {
const d = new Date(ts);
return d.getMonth() + 1;
}
return timestampToCalendar(ts, timeZone).month;
}
/**
* Start of month.
*
* @param ts - The timestamp to get the start of month for
* @param timeZone - Optional timeZone (defaults to local time)
* @returns Timestamp for the start of the month
* @see https://datezone.dev/docs/reference/month#startofmonth
*/
export function startOfMonth(ts, timeZone) {
if (!timeZone) {
const d = new Date(ts);
d.setDate(1);
d.setHours(0, 0, 0, 0);
return d.getTime();
}
const { year, month } = timestampToCalendar(ts, timeZone);
return startOfMonthBase(year, month, timeZone);
}
/**
* Start of month base.
*
* @param year - The year
* @param month - The month (1-12)
* @param timeZone - The timeZone
* @returns Timestamp for the start of the month
* @see https://datezone.dev/docs/reference/month#startofmonthbase
*/
export function startOfMonthBase(year, month, timeZone) {
return calendarToTimestamp(year, month, 1, 0, 0, 0, 0, timeZone);
}
/**
* End of month.
*
* @param ts - The timestamp to get the end of month for
* @param timeZone - Optional timeZone (defaults to local time)
* @returns Timestamp for the end of the month (last millisecond)
* @see https://datezone.dev/docs/reference/month#endofmonth
*/
export function endOfMonth(ts, timeZone) {
if (!timeZone) {
const d = new Date(ts);
d.setMonth(d.getMonth() + 1, 1);
d.setHours(0, 0, 0, 0);
return d.getTime() - 1;
}
return startOfNextMonth(ts, timeZone) - 1;
}
/**
* End of month base.
*
* @param year - The year
* @param month - The month (1-12)
* @param timeZone - The timeZone
* @returns Timestamp for the end of the month (last millisecond)
* @see https://datezone.dev/docs/reference/month#endofmonthbase
*/
export function endOfMonthBase(year, month, timeZone) {
return startOfNextMonthBase(year, month, timeZone) - 1;
}
/**
* Add months.
*
* @param ts - The timestamp to add months to
* @param months - Number of months to add (can be negative)
* @param timeZone - Optional timeZone (defaults to local time)
* @returns New timestamp with months added
* @see https://datezone.dev/docs/reference/month#addmonths
*/
export function addMonths(ts, months, timeZone) {
if (!timeZone) {
const d = new Date(ts);
const originalDay = d.getDate();
d.setMonth(d.getMonth() + months);
if (d.getDate() !== originalDay) {
d.setDate(0); // Go to last day of previous month
}
return d.getTime();
}
const parts = timestampToCalendar(ts, timeZone);
return addMonthsBase(parts.year, parts.month, parts.day, parts.hour, parts.minute, parts.second, parts.millisecond, months, timeZone);
}
/**
* Add months base.
*
* @param year - The year
* @param month - The month (1-12)
* @param day - The day
* @param hour - The hour
* @param minute - The minute
* @param second - The second
* @param millisecond - The millisecond
* @param monthsToAdd - Number of months to add (can be negative)
* @param timeZone - The timeZone
* @returns New timestamp with months added
* @see https://datezone.dev/docs/reference/month#addmonthsbase
*/
export function addMonthsBase(year, month, day, hour, minute, second, millisecond, monthsToAdd, timeZone) {
const [newYear, newMonth] = calculateYearMonth(year, month, monthsToAdd);
const maxDay = daysInMonthBase(newYear, newMonth);
const newDay = day > maxDay ? maxDay : day;
return calendarToTimestamp(newYear, newMonth, newDay, hour, minute, second, millisecond, timeZone);
}
/**
* Subtract months.
*
* @param ts - The timestamp to subtract months from
* @param months - Number of months to subtract
* @param timeZone - Optional timeZone (defaults to local time)
* @returns New timestamp with months subtracted
* @see https://datezone.dev/docs/reference/month#submonths
*/
export function subMonths(ts, months, timeZone) {
return addMonths(ts, -months, timeZone);
}
/**
* Start of nth month.
*
* @param ts - The reference timestamp
* @param n - Number of months to offset (0 = current month, 1 = next month, -1 = previous month)
* @param timeZone - Optional timeZone (defaults to local time)
* @returns Timestamp for the start of the nth month
* @see https://datezone.dev/docs/reference/month#startofnthmonth
*/
export function startOfNthMonth(ts, n, timeZone) {
if (!timeZone) {
const d = new Date(ts);
d.setMonth(d.getMonth() + n, 1);
d.setHours(0, 0, 0, 0);
return d.getTime();
}
const { year, month } = timestampToCalendar(ts, timeZone);
return startOfNthMonthBase(year, month, n, timeZone);
}
/**
* Helper function to calculate the start of nth month from year/month values.
* @param year - The base year
* @param month - The base month
* @param n - Number of months to offset
* @param timeZone - The timeZone to use
* @returns Timestamp for the start of the nth month
*/
function startOfNthMonthBase(year, month, n, timeZone) {
const [nextYear, nextMonth] = calculateYearMonth(year, month, n);
return calendarToTimestamp(nextYear, nextMonth, 1, 0, 0, 0, 0, timeZone);
}
/**
* Gets the start of the next month from year/month values.
* @param year - The year
* @param month - The month (1-12)
* @param timeZone - The timeZone
* @returns Timestamp for the start of the next month
*/
function startOfNextMonthBase(year, month, timeZone) {
return startOfNthMonthBase(year, month, 1, timeZone);
}
/**
* End of nth month.
*
* @param ts - The reference timestamp
* @param n - Number of months to offset (0 = current month, 1 = next month, -1 = previous month)
* @param timeZone - Optional timeZone (defaults to local time)
* @returns Timestamp for the end of the nth month (last millisecond)
* @see https://datezone.dev/docs/reference/month#endofnthmonth
*/
export function endOfNthMonth(ts, n, timeZone) {
return startOfNthMonth(ts, n + 1, timeZone) - 1;
}
/**
* Start of next month.
*
* @param ts - The reference timestamp
* @param timeZone - Optional timeZone (defaults to local time)
* @returns Timestamp for the start of the next month
* @see https://datezone.dev/docs/reference/month#startofnextmonth
*/
export function startOfNextMonth(ts, timeZone) {
return startOfNthMonth(ts, 1, timeZone);
}
/**
* End of next month.
*
* @param ts - The reference timestamp
* @param timeZone - Optional timeZone (defaults to local time)
* @returns Timestamp for the end of the next month (last millisecond)
* @see https://datezone.dev/docs/reference/month#endofnextmonth
*/
export function endOfNextMonth(ts, timeZone) {
return startOfNthMonth(ts, 2, timeZone) - 1;
}
/**
* Start of prev month.
*
* @param ts - The reference timestamp
* @param timeZone - Optional timeZone (defaults to local time)
* @returns Timestamp for the start of the previous month
* @see https://datezone.dev/docs/reference/month#startofprevmonth
*/
export function startOfPrevMonth(ts, timeZone) {
return startOfNthMonth(ts, -1, timeZone);
}
/**
* End of prev month.
*
* @param ts - The reference timestamp
* @param timeZone - Optional timeZone (defaults to local time)
* @returns Timestamp for the end of the previous month (last millisecond)
* @see https://datezone.dev/docs/reference/month#endofprevmonth
*/
export function endOfPrevMonth(ts, timeZone) {
return startOfNthMonth(ts, 0, timeZone) - 1;
}
const DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
/**
* Days in month.
*
* @param ts - The timestamp
* @param timeZone - Optional timeZone (defaults to local time)
* @returns Number of days in the month
* @see https://datezone.dev/docs/reference/month#daysinmonth
*/
export function daysInMonth(ts, timeZone) {
let year;
let month;
if (!timeZone) {
const d = new Date(ts);
year = d.getFullYear();
month = d.getMonth() + 1;
}
else {
({ year, month } = timestampToCalendar(ts, timeZone));
}
return daysInMonthBase(year, month);
}
/**
* Days in month base.
*
* @param year - The year
* @param month - The month (1-12)
* @returns Number of days in the month
* @see https://datezone.dev/docs/reference/month#daysinmonthbase
*/
export function daysInMonthBase(year, month) {
const maxDay = DAYS_IN_MONTH[month - 1];
if (maxDay === undefined) {
throw new RangeError(`Invalid month: ${month}`);
}
if (month === 2 && isLeapYearBase(year)) {
return 29;
}
return maxDay;
}
/**
* Calculate year month.
*
* @param year - The starting year
* @param month - The starting month (1-12)
* @param monthsToAdd - Number of months to add (can be negative)
* @returns Tuple with the new year and month [year, month]
* @see https://datezone.dev/docs/reference/month#calculateyearmonth
*/
export function calculateYearMonth(year, month, monthsToAdd) {
const totalMonths = year * 12 + (month - 1) + monthsToAdd;
let newYear = Math.floor(totalMonths / 12);
let newMonth = (totalMonths % 12) + 1;
if (newMonth < 1) {
newMonth += 12;
newYear -= 1;
}
if (newYear < 1) {
throw new RangeError(`Invalid year: ${newYear}`);
}
if (newMonth < 1 || newMonth > 12) {
throw new RangeError(`Invalid month: ${newMonth}`);
}
return [newYear, newMonth];
}
/**
* Get month name.
*
* @param locale - The locale string (e.g., 'en-US', 'fr-FR')
* @param type - The format type: 'long' (January), 'short' (Jan), or 'narrow' (J)
* @param month - The month number (1-12)
* @returns The localized month name
* @see https://datezone.dev/docs/reference/month#getmonthname
*/
export function getMonthName(locale, type, month) {
const fmt = getCachedFormatterLocale(locale, {
month: type,
timeZone: "UTC",
});
return fmt.format(new Date(Date.UTC(2000, month - 1, 1)));
}
/**
* Get quarter.
*
* @param ts - The timestamp
* @param timeZone - Optional timeZone (defaults to local time)
* @returns The quarter number (1-4)
* @see https://datezone.dev/docs/reference/month#getquarter
*/
export function getQuarter(ts, timeZone) {
let month;
if (!timeZone) {
const d = new Date(ts);
month = d.getMonth() + 1;
}
else {
month = timestampToCalendar(ts, timeZone).month;
}
return getQuarterBase(month);
}
/**
* Get quarter base.
*
* @param month - The month (1-12)
* @returns The quarter number (1-4)
* @see https://datezone.dev/docs/reference/month#getquarterbase
*/
export function getQuarterBase(month) {
return Math.floor((month - 1) / 3) + 1;
}
//# sourceMappingURL=month.pub.js.map