datezone
Version:
A lightweight and comprehensive date and timeZone utility library for JavaScript.
166 lines • 5.67 kB
JavaScript
import { calendarToTimestamp } from "./calendar.pub.js";
import { getUTCtoTimezoneOffsetMinutes } from "./offset.pub.js";
import { isDST, isUTC } from "./timezone.pub.js";
/**
* Extracts the year from a timestamp.
*
* @param ts - The timestamp to extract the year from
* @param tz - Optional timeZone (defaults to local time)
* @returns The year as a number
* @see https://datezone.dev/docs/reference/year#year
*/
export function year(ts, tz) {
if (!tz) {
return new Date(ts).getFullYear();
}
if (isUTC(tz) || !isDST(tz)) {
const offset = getUTCtoTimezoneOffsetMinutes(ts, tz);
const d = new Date(ts + offset * 60000);
return d.getUTCFullYear();
}
// DST zone: only apply offset once, do not double-check
const offset = getUTCtoTimezoneOffsetMinutes(ts, tz);
const d = new Date(ts + offset * 60000);
return d.getUTCFullYear();
}
/**
* Checks if leap year.
*
* @param ts - The timestamp to check
* @param tz - Optional timeZone (defaults to local time)
* @returns True if the year is a leap year, false otherwise
* @see https://datezone.dev/docs/reference/year#isleapyear
*/
export function isLeapYear(ts, tz) {
const y = year(ts, tz);
return isLeapYearBase(y);
}
/**
* Checks if leap year base.
*
* @param year - The year to check
* @returns True if the year is a leap year, false otherwise
* @see https://datezone.dev/docs/reference/year#isleapyearbase
*/
export function isLeapYearBase(year) {
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
}
/**
* Start of year.
*
* @param ts - The timestamp to get the start of year for
* @param tz - Optional timeZone (defaults to local time)
* @returns Timestamp for the start of the year (January 1st, 00:00:00.000)
* @see https://datezone.dev/docs/reference/year#startofyear
*/
export function startOfYear(ts, tz) {
if (!tz) {
const y = new Date(ts).getFullYear();
return new Date(y, 0, 1).getTime();
}
const y = year(ts, tz);
return calendarToTimestamp(y, 1, 1, 0, 0, 0, 0, tz);
}
/**
* End of year.
*
* @param ts - The timestamp to get the end of year for
* @param tz - Optional timeZone (defaults to local time)
* @returns Timestamp for the end of the year (December 31st, 23:59:59.999)
* @see https://datezone.dev/docs/reference/year#endofyear
*/
export function endOfYear(ts, tz) {
if (!tz) {
const y = new Date(ts).getFullYear();
return new Date(y, 11, 31, 23, 59, 59, 999).getTime();
}
const y = year(ts, tz);
return calendarToTimestamp(y, 12, 31, 23, 59, 59, 999, tz);
}
/**
* Add years.
*
* @param ts - The timestamp to add years to
* @param amount - Number of years to add (can be negative)
* @param tz - Optional timeZone (defaults to local time)
* @returns New timestamp with years added
* @see https://datezone.dev/docs/reference/year#addyears
*/
export function addYears(ts, amount, tz) {
if (!tz) {
const d = new Date(ts);
const originalMonth = d.getMonth();
d.setFullYear(d.getFullYear() + amount);
if (d.getMonth() !== originalMonth) {
d.setDate(0);
}
return d.getTime();
}
if (isUTC(tz) || !isDST(tz)) {
const offset = getUTCtoTimezoneOffsetMinutes(ts, tz);
const d = new Date(ts + offset * 60000);
const targetYear = d.getUTCFullYear() + amount;
let targetDay = d.getUTCDate();
const month = d.getUTCMonth() + 1;
if (month === 2 && targetDay === 29 && !isLeapYearBase(targetYear)) {
targetDay = 28;
}
const newDate = Date.UTC(targetYear, month - 1, targetDay, d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
return newDate - offset * 60000;
}
// DST zone: single offset calculation for both extraction and composition
const offset = getUTCtoTimezoneOffsetMinutes(ts, tz);
const d = new Date(ts + offset * 60000);
const targetYear = d.getUTCFullYear() + amount;
let targetDay = d.getUTCDate();
const month = d.getUTCMonth() + 1;
if (month === 2 && targetDay === 29 && !isLeapYearBase(targetYear)) {
targetDay = 28;
}
const newDate = Date.UTC(targetYear, month - 1, targetDay, d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
return newDate - offset * 60000;
}
/**
* Subtract years.
*
* @param ts - The timestamp to subtract years from
* @param amount - Number of years to subtract
* @param tz - Optional timeZone (defaults to local time)
* @returns New timestamp with years subtracted
* @see https://datezone.dev/docs/reference/year#subyears
*/
export function subYears(ts, amount, tz) {
return addYears(ts, -amount, tz);
}
/**
* Days in year.
*
* @param ts - The timestamp to check
* @param tz - Optional timeZone (defaults to local time)
* @returns 366 for leap years, 365 for non-leap years
* @see https://datezone.dev/docs/reference/year#daysinyear
*/
export function daysInYear(ts, tz) {
return isLeapYear(ts, tz) ? 366 : 365;
}
/**
* Days in year base.
*
* @param year - The year to check
* @returns 366 for leap years, 365 for non-leap years
* @see https://datezone.dev/docs/reference/year#daysinyearbase
*/
export function daysInYearBase(year) {
return isLeapYearBase(year) ? 366 : 365;
}
/**
* Extracts the quarter from a timestamp.
*
* @param month - The month number (1-12)
* @returns The quarter number (1-4)
* @see https://datezone.dev/docs/reference/year#quarter
*/
export function quarter(month) {
return Math.floor((month - 1) / 3) + 1;
}
//# sourceMappingURL=year.pub.js.map