333 lines
8.2 KiB
JavaScript
333 lines
8.2 KiB
JavaScript
|
|
/**
|
||
|
|
* Date utilities - ES Module Version
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { isDate, isNumber, isString, isUndefined } from './Type.js';
|
||
|
|
import { mod } from './Math.js';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the name of the day of the week for a given date
|
||
|
|
*/
|
||
|
|
export function getDayName(date, utc) {
|
||
|
|
const names = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
||
|
|
return names[getDayOfWeek(date, utc)];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the day of the week (0-6) for a given date
|
||
|
|
*/
|
||
|
|
export function getDayOfWeek(date, utc) {
|
||
|
|
date = makeDate(date);
|
||
|
|
return utc ? date.getUTCDay() : date.getDay();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the day of the year (1-366) for a given date
|
||
|
|
*/
|
||
|
|
export function getDayOfYear(date, utc) {
|
||
|
|
date = makeDate(date);
|
||
|
|
const startOfYear = new Date(Date.UTC(
|
||
|
|
getFullYear(date, utc),
|
||
|
|
0, 1
|
||
|
|
));
|
||
|
|
const diff = date - startOfYear;
|
||
|
|
return Math.floor(diff / 86400000) + 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the number of days in a month
|
||
|
|
*/
|
||
|
|
export function getDaysInMonth(year, month) {
|
||
|
|
return new Date(year, month + 1, 0).getDate();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the number of days in a year
|
||
|
|
*/
|
||
|
|
export function getDaysInYear(year) {
|
||
|
|
return isLeapYear(year) ? 366 : 365;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the first day of the week for a given date
|
||
|
|
*/
|
||
|
|
export function getFirstDayOfWeek(date, utc) {
|
||
|
|
date = makeDate(date);
|
||
|
|
const day = getDayOfWeek(date, utc);
|
||
|
|
return new Date(date.getTime() - day * 86400000);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the full year from a date
|
||
|
|
*/
|
||
|
|
export function getFullYear(date, utc) {
|
||
|
|
date = makeDate(date);
|
||
|
|
return utc ? date.getUTCFullYear() : date.getFullYear();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get hours from date
|
||
|
|
*/
|
||
|
|
export function getHours(date, utc) {
|
||
|
|
date = makeDate(date);
|
||
|
|
return utc ? date.getUTCHours() : date.getHours();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the ISO date string (YYYY-MM-DD)
|
||
|
|
*/
|
||
|
|
export function getISODate(date, utc) {
|
||
|
|
return formatDate(date, '%Y-%m-%d', utc);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the ISO week number
|
||
|
|
*/
|
||
|
|
export function getISOWeek(date, utc) {
|
||
|
|
date = makeDate(date);
|
||
|
|
const year = getFullYear(date, utc);
|
||
|
|
const firstThursday = getFirstThursday(year, utc);
|
||
|
|
const week = Math.floor((date - firstThursday) / 604800000) + 1;
|
||
|
|
|
||
|
|
if (week < 1) {
|
||
|
|
return getISOWeek(new Date(year - 1, 11, 31), utc);
|
||
|
|
} else if (week > 52) {
|
||
|
|
const nextFirstThursday = getFirstThursday(year + 1, utc);
|
||
|
|
if (date >= nextFirstThursday) {
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return week;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the ISO year
|
||
|
|
*/
|
||
|
|
export function getISOYear(date, utc) {
|
||
|
|
date = makeDate(date);
|
||
|
|
const year = getFullYear(date, utc);
|
||
|
|
const week = getISOWeek(date, utc);
|
||
|
|
|
||
|
|
if (week === 1 && getMonth(date, utc) === 11) {
|
||
|
|
return year + 1;
|
||
|
|
} else if (week >= 52 && getMonth(date, utc) === 0) {
|
||
|
|
return year - 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
return year;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get minutes from date
|
||
|
|
*/
|
||
|
|
export function getMinutes(date, utc) {
|
||
|
|
date = makeDate(date);
|
||
|
|
return utc ? date.getUTCMinutes() : date.getMinutes();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get month from date (0-11)
|
||
|
|
*/
|
||
|
|
export function getMonth(date, utc) {
|
||
|
|
date = makeDate(date);
|
||
|
|
return utc ? date.getUTCMonth() : date.getMonth();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get month name
|
||
|
|
*/
|
||
|
|
export function getMonthName(date, utc) {
|
||
|
|
const names = [
|
||
|
|
'January', 'February', 'March', 'April', 'May', 'June',
|
||
|
|
'July', 'August', 'September', 'October', 'November', 'December'
|
||
|
|
];
|
||
|
|
return names[getMonth(date, utc)];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get seconds from date
|
||
|
|
*/
|
||
|
|
export function getSeconds(date, utc) {
|
||
|
|
date = makeDate(date);
|
||
|
|
return utc ? date.getUTCSeconds() : date.getSeconds();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get milliseconds from date
|
||
|
|
*/
|
||
|
|
export function getMilliseconds(date, utc) {
|
||
|
|
date = makeDate(date);
|
||
|
|
return utc ? date.getUTCMilliseconds() : date.getMilliseconds();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get timezone offset in minutes
|
||
|
|
*/
|
||
|
|
export function getTimezoneOffset(date) {
|
||
|
|
return makeDate(date).getTimezoneOffset();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get timezone offset string (+HH:MM or -HH:MM)
|
||
|
|
*/
|
||
|
|
export function getTimezoneOffsetString(date) {
|
||
|
|
const offset = getTimezoneOffset(date);
|
||
|
|
const sign = offset <= 0 ? '+' : '-';
|
||
|
|
const hours = Math.floor(Math.abs(offset) / 60);
|
||
|
|
const minutes = Math.abs(offset) % 60;
|
||
|
|
return sign + pad(hours, 2) + ':' + pad(minutes, 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get Unix timestamp (seconds since epoch)
|
||
|
|
*/
|
||
|
|
export function getUnixTime(date) {
|
||
|
|
return Math.floor(makeDate(date).getTime() / 1000);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get week number (1-53)
|
||
|
|
*/
|
||
|
|
export function getWeek(date, utc) {
|
||
|
|
date = makeDate(date);
|
||
|
|
const firstDayOfYear = new Date(Date.UTC(
|
||
|
|
getFullYear(date, utc), 0, 1
|
||
|
|
));
|
||
|
|
const days = Math.floor((date - firstDayOfYear) / 86400000);
|
||
|
|
return Math.ceil((days + getDayOfWeek(firstDayOfYear, utc) + 1) / 7);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Check if a year is a leap year
|
||
|
|
*/
|
||
|
|
export function isLeapYear(year) {
|
||
|
|
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Check if a date is valid
|
||
|
|
*/
|
||
|
|
export function isValidDate(date) {
|
||
|
|
date = makeDate(date);
|
||
|
|
return !isNaN(date.getTime());
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Make a date object from various inputs
|
||
|
|
*/
|
||
|
|
export function makeDate(date) {
|
||
|
|
if (isDate(date)) {
|
||
|
|
return date;
|
||
|
|
} else if (isString(date)) {
|
||
|
|
return new Date(date);
|
||
|
|
} else if (isNumber(date)) {
|
||
|
|
return new Date(date);
|
||
|
|
} else if (isUndefined(date)) {
|
||
|
|
return new Date();
|
||
|
|
}
|
||
|
|
return new Date(date);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Format a date according to a format string
|
||
|
|
*/
|
||
|
|
export function formatDate(date, format, utc) {
|
||
|
|
date = makeDate(date);
|
||
|
|
format = format || '%Y-%m-%d %H:%M:%S';
|
||
|
|
|
||
|
|
const replacements = {
|
||
|
|
'%a': () => getDayName(date, utc).substr(0, 3),
|
||
|
|
'%A': () => getDayName(date, utc),
|
||
|
|
'%b': () => getMonthName(date, utc).substr(0, 3),
|
||
|
|
'%B': () => getMonthName(date, utc),
|
||
|
|
'%c': () => date.toLocaleString(),
|
||
|
|
'%d': () => pad(getDate(date, utc), 2),
|
||
|
|
'%e': () => pad(getDate(date, utc), 2, ' '),
|
||
|
|
'%H': () => pad(getHours(date, utc), 2),
|
||
|
|
'%I': () => pad(((getHours(date, utc) + 11) % 12) + 1, 2),
|
||
|
|
'%j': () => pad(getDayOfYear(date, utc), 3),
|
||
|
|
'%k': () => pad(getHours(date, utc), 2, ' '),
|
||
|
|
'%l': () => pad(((getHours(date, utc) + 11) % 12) + 1, 2, ' '),
|
||
|
|
'%m': () => pad(getMonth(date, utc) + 1, 2),
|
||
|
|
'%M': () => pad(getMinutes(date, utc), 2),
|
||
|
|
'%p': () => getHours(date, utc) < 12 ? 'AM' : 'PM',
|
||
|
|
'%S': () => pad(getSeconds(date, utc), 2),
|
||
|
|
'%u': () => getDayOfWeek(date, utc) || 7,
|
||
|
|
'%U': () => pad(getWeek(date, utc), 2),
|
||
|
|
'%V': () => pad(getISOWeek(date, utc), 2),
|
||
|
|
'%w': () => getDayOfWeek(date, utc),
|
||
|
|
'%W': () => pad(getWeek(date, utc), 2),
|
||
|
|
'%x': () => date.toLocaleDateString(),
|
||
|
|
'%X': () => date.toLocaleTimeString(),
|
||
|
|
'%y': () => pad(getFullYear(date, utc) % 100, 2),
|
||
|
|
'%Y': () => getFullYear(date, utc),
|
||
|
|
'%z': () => getTimezoneOffsetString(date),
|
||
|
|
'%Z': () => '', // Timezone abbreviation not easily available
|
||
|
|
'%%': () => '%'
|
||
|
|
};
|
||
|
|
|
||
|
|
return format.replace(/%[a-zA-Z%]/g, (match) => {
|
||
|
|
return replacements[match] ? replacements[match]() : match;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Parse a date string
|
||
|
|
*/
|
||
|
|
export function parseDate(string, format, utc) {
|
||
|
|
// Basic implementation - can be enhanced
|
||
|
|
return new Date(string);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get date (day of month)
|
||
|
|
*/
|
||
|
|
export function getDate(date, utc) {
|
||
|
|
date = makeDate(date);
|
||
|
|
return utc ? date.getUTCDate() : date.getDate();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Helper functions
|
||
|
|
function getFirstThursday(year, utc) {
|
||
|
|
const jan1 = new Date(Date.UTC(year, 0, 1));
|
||
|
|
const dayOfWeek = getDayOfWeek(jan1, utc);
|
||
|
|
const daysToThursday = (11 - dayOfWeek) % 7;
|
||
|
|
return new Date(jan1.getTime() + daysToThursday * 86400000);
|
||
|
|
}
|
||
|
|
|
||
|
|
function pad(number, length, padding) {
|
||
|
|
padding = padding || '0';
|
||
|
|
const str = String(number);
|
||
|
|
return padding.repeat(Math.max(0, length - str.length)) + str;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Export all functions
|
||
|
|
export default {
|
||
|
|
getDayName,
|
||
|
|
getDayOfWeek,
|
||
|
|
getDayOfYear,
|
||
|
|
getDaysInMonth,
|
||
|
|
getDaysInYear,
|
||
|
|
getFirstDayOfWeek,
|
||
|
|
getFullYear,
|
||
|
|
getHours,
|
||
|
|
getISODate,
|
||
|
|
getISOWeek,
|
||
|
|
getISOYear,
|
||
|
|
getMinutes,
|
||
|
|
getMonth,
|
||
|
|
getMonthName,
|
||
|
|
getSeconds,
|
||
|
|
getMilliseconds,
|
||
|
|
getTimezoneOffset,
|
||
|
|
getTimezoneOffsetString,
|
||
|
|
getUnixTime,
|
||
|
|
getWeek,
|
||
|
|
isLeapYear,
|
||
|
|
isValidDate,
|
||
|
|
makeDate,
|
||
|
|
formatDate,
|
||
|
|
parseDate,
|
||
|
|
getDate
|
||
|
|
};
|