Files
chill-bundles/src/Bundle/ChillMainBundle/Resources/public/chill/js/date.ts
Julie Lenaerts 90d3bf32e6 fix date formatting and parsing logic
- Support time formatting in `formatDate` with `time` option.
- Improve parsing in `ISOToDate` to handle time information or date-only strings.
2025-08-11 15:52:22 +02:00

170 lines
4.1 KiB
TypeScript

/**
* Some utils for manipulating dates
*
* **WARNING** experimental
*/
/**
* Return the date to local ISO date, like YYYY-mm-dd
*
* The date is valid for the same timezone as the date's locale
*
* Do not take time into account
*
*/
export const dateToISO = (date: Date | null): string | null => {
if (null === date) {
return null;
}
return [
date.getFullYear(),
(date.getMonth() + 1).toString().padStart(2, "0"),
date.getDate().toString().padStart(2, "0"),
].join("-");
};
/**
* Return a date object from iso string formatted as YYYY-mm-dd
*
* **Experimental**
*/
export const ISOToDate = (str: string | null): Date | null => {
if (null === str) {
return null;
}
if ("" === str.trim()) {
return null;
}
// If the string already contains time info, use it directly
if (str.includes('T') || str.includes(' ')) {
return new Date(str);
}
// Otherwise, parse date only
const [year, month, day] = str.split("-").map((p) => parseInt(p));
return new Date(year, month - 1, day, 0, 0, 0, 0);
};
/**
* Return a date object from iso string formatted as YYYY-mm-dd:HH:MM:ss+01:00
*
*/
export const ISOToDatetime = (str: string | null): Date | null => {
if (null === str) {
return null;
}
const [cal, times] = str.split("T"),
[year, month, date] = cal.split("-").map((s) => parseInt(s)),
[time, timezone] = times.split(times.charAt(8)),
[hours, minutes, seconds] = time.split(":").map((s) => parseInt(s));
if ("0000" === timezone) {
return new Date(
Date.UTC(year, month - 1, date, hours, minutes, seconds),
);
}
return new Date(year, month - 1, date, hours, minutes, seconds);
};
/**
* Convert a date to ISO8601, valid for usage in api
*
*/
export const datetimeToISO = (date: Date): string => {
let cal, time, offset;
cal = [
date.getFullYear(),
(date.getMonth() + 1).toString().padStart(2, "0"),
date.getDate().toString().padStart(2, "0"),
].join("-");
time = [
date.getHours().toString().padStart(2, "0"),
date.getMinutes().toString().padStart(2, "0"),
date.getSeconds().toString().padStart(2, "0"),
].join(":");
offset = [
date.getTimezoneOffset() <= 0 ? "+" : "-",
Math.abs(Math.floor(date.getTimezoneOffset() / 60))
.toString()
.padStart(2, "0"),
":",
Math.abs(date.getTimezoneOffset() % 60)
.toString()
.padStart(2, "0"),
].join("");
const x = cal + "T" + time + offset;
return x;
};
export const intervalDaysToISO = (days: number | string | null): string => {
if (null === days) {
return "P0D";
}
return `P${days}D`;
};
export const intervalISOToDays = (str: string | null): number | null => {
if (null === str) {
return null;
}
if ("" === str.trim()) {
return null;
}
let days = 0;
let isDate = true;
let vstring = "";
for (let i = 0; i < str.length; i = i + 1) {
if (!isDate) {
continue;
}
switch (str.charAt(i)) {
case "P":
isDate = true;
break;
case "T":
isDate = false;
break;
case "0":
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
vstring = vstring + str.charAt(i);
break;
case "Y":
days = days + Number.parseInt(vstring) * 365;
vstring = "";
break;
case "M":
days = days + Number.parseInt(vstring) * 30;
vstring = "";
break;
case "D":
days = days + Number.parseInt(vstring);
vstring = "";
break;
default:
throw Error(
"this character should not appears: " + str.charAt(i),
);
}
}
return days;
};