/** * Transforme une date du format français (DD/MM/YYYY) au format iso (YYYY-MM-DD) * Exemple d'utilisation : * new Date(Date.fromFRA("30/06/2024")) -> new Date("2024-06-30") * @param {string} dateFra * @returns {string} dateIso */ Date.fromFRA = function (dateFra) { if (dateFra == "") return ""; // Expression régulière pour valider le format de date ISO (YYYY-MM-DD) const regexDateFra = /^(0[1-9]|[12][0-9]|3[01])\/(0[1-9]|1[0-2])\/\d{4}$/; // Vérification du format de la date ISO if (!regexDateFra.test(dateFra)) { throw new Error( `La date (format français) passée en paramètre [${dateFra}] n'est pas valide.` ); } // Conversion du format français (DD/MM/YYYY) au format ISO (YYYY-MM-DD) return `${dateFra.substring(6, 10)}-${dateFra.substring( 3, 5 )}-${dateFra.substring(0, 2)}`; }; /** * Transforme une date du format iso (YYYY-MM-DD) au format français (DD/MM/YYYY) * Exemple d'utilisation : * Date.toFRA("2024-06-30") -> "30/06/2024" * @param {string} dateIso * @returns {string} dateFra */ Date.toFRA = function (dateIso) { if (dateIso == "") return ""; // Expression régulière pour valider le format de date ISO (YYYY-MM-DD) const regexDateIso = /^\d{4}-(0\d|1[0-2])-([0-2]\d|3[01])$/; // Vérification du format de la date ISO if (!regexDateIso.test(dateIso)) { throw new Error( `La date ISO passée en paramètre [${dateIso}] n'est pas valide.` ); } // Conversion du format ISO (YYYY-MM-DD) en format français (DD/MM/YYYY) return `${dateIso.substring(8, 10)}/${dateIso.substring( 5, 7 )}/${dateIso.substring(0, 4)}`; }; /** * Vérifie si le début de l'une des périodes est avant la fin de l'autre * et si la fin de cette période est après le début de l'autre. * @param {Object} period {deb:Object, fin:Object} * @param {Object} interval {deb:Object, fin:Object} * @returns vrai si la periode et l'interval ont une intersection commune */ Date.intersect = function (period, interval) { return period.deb <= interval.fin && period.fin >= interval.deb; }; Date.removeUTC = function (isoString) { const reg = new RegExp(/[+-][\d:]+$/); return isoString.replace(reg, ""); }; Object.defineProperty(Date.prototype, "isValid", { value: function () { return !Number.isNaN(this.getTime()); }, }); Object.defineProperty(Date.prototype, "startOf", { /** * Génère u la date à la plus petite valeur pour la précision donnée. * @param {string} precision - La précision souhaitée (year, month, day, hours, minutes, seconds, milliseconds). * @returns {Date} - Une nouvelle date ajustée. */ value: function (precision) { const newDate = this.clone(); switch (precision) { case "year": newDate.setMonth(0); case "month": newDate.setDate(1); case "day": newDate.setHours(0); case "hours": newDate.setMinutes(0); case "minutes": newDate.setSeconds(0); case "seconds": newDate.setMilliseconds(0); break; case "milliseconds": break; default: throw new Error( `Invalid precision for startOf function [${precision}]` ); } return newDate; }, }); Object.defineProperty(Date.prototype, "endOf", { /** * Ajuste la date à la plus grande valeur pour la précision donnée. * @param {string} precision - La précision souhaitée (year, month, day, hours, minutes, seconds, milliseconds). * @returns {Date} - Une nouvelle date ajustée. */ value: function (precision) { const newDate = this.clone(); switch (precision) { case "year": newDate.setMonth(11); // Décembre est le 11ème mois (0-indexé) case "month": newDate.setDate(0); // Le jour 0 du mois suivant est le dernier jour du mois courant newDate.setMonth(newDate.getMonth() + 1); case "day": newDate.setHours(23); // 23 heures est la dernière heure de la journée case "hours": newDate.setMinutes(59); // 59 minutes est la dernière minute de l'heure case "minutes": newDate.setSeconds(59); // 59 secondes est la dernière seconde de la minute case "seconds": newDate.setMilliseconds(999); // 999 millisecondes est la dernière milliseconde de la seconde break; case "milliseconds": // Rien à faire pour les millisecondes break; default: throw new Error("Invalid precision for endOf function"); } return newDate; }, }); Object.defineProperty(Date.prototype, "isBefore", { /** * Retourne vrai si la date est située avant la date fournie * @param {Date} date * @returns {boolean} */ value: function (date) { return this.valueOf() < date.valueOf(); }, }); Object.defineProperty(Date.prototype, "isAfter", { /** * Retourne vrai si la date est située après la date fournie * @param {Date} date * @returns {boolean} */ value: function (date) { return this.valueOf() > date.valueOf(); }, }); Object.defineProperty(Date.prototype, "isSame", { /** * Retourne vrai si les dates sont les mêmes * @param {Date} date * @param {string} precision default : "milliseconds" * @returns boolean */ value: function (date, precision = "milliseconds") { return ( this.startOf(precision).valueOf() == date.startOf(precision).valueOf() ); }, }); Object.defineProperty(Date.prototype, "isBetween", { /** * Vérifie si la date est comprise dans une période avec une précision et une inclusivité optionnelles * @param {Date} deb - La date de début de la période * @param {Date} fin - La date de fin de la période * @param {String} bornes - L'inclusivité/exclusivité de la comparaison ("[]", "()", "[)", "(]") * - bornes incluses : [] * - bornes excluses : () * - borne gauche incluse et borne droit excluse : [) * - borne gauche excluse et borne droit incluse : (] */ value: function (deb, fin, bornes = "[]") { // Ajuste la date actuelle, la date de début et la date de fin à la précision spécifiée // Vérifie les bornes en fonction de l'inclusivité/exclusivité spécifiée dans 'bornes' const check_deb = bornes[0] === "(" ? this.valueOf() > deb.valueOf() : this.valueOf() >= deb.valueOf(); const check_fin = bornes[1] === ")" ? fin.valueOf() > this.valueOf() : fin.valueOf() >= this.valueOf(); return check_deb && check_fin; }, }); Object.defineProperty(Date.prototype, "toIsoUtcString", { /** * @returns date au format iso utc (yyyy-mm-ddThh:MM±oo:oo:oo) */ value: function () { // Formater la date et l'heure const date = this; var tzo = -date.getTimezoneOffset(), dif = tzo >= 0 ? "+" : "-", pad = function (num) { return (num < 10 ? "0" : "") + num; }; return ( this.toFakeIso() + dif + pad(Math.floor(Math.abs(tzo) / 60)) + ":" + pad(Math.abs(tzo) % 60) ); }, }); Object.defineProperty(Date.prototype, "toFakeIso", { value: function () { const date = this; pad = function (num) { return (num < 10 ? "0" : "") + num; }; return ( date.getFullYear() + "-" + pad(date.getMonth() + 1) + "-" + pad(date.getDate()) + "T" + pad(date.getHours()) + ":" + pad(date.getMinutes()) + ":" + pad(date.getSeconds()) ); }, }); Object.defineProperty(Date.prototype, "clone", { /** * @returns Retourne une copie de la date (copie non liée) */ value: function () { return structuredClone(this); }, }); Object.defineProperty(Date.prototype, "format", { value: function (formatString) { let iso = this.toIsoUtcString(); switch (formatString) { case "DD/MM/Y HH:mm": return this.toLocaleString("fr-FR", { day: "2-digit", month: "2-digit", year: "2-digit", hour: "2-digit", minute: "2-digit", hour12: false, timeZone: SCO_TIMEZONE, }); case "DD/MM/YYYY HH:mm": return this.toLocaleString("fr-FR", { day: "2-digit", month: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit", hour12: false, timeZone: SCO_TIMEZONE, }); case "YYYY-MM-DDTHH:mm": // slice : YYYY-MM-DDTHH // slice + 3 : YYYY-MM-DDTHH:mm return iso.slice(0, iso.indexOf(":") + 3); case "YYYY-MM-DD": return iso.slice(0, iso.indexOf("T")); default: return this.toFakeIso(); } }, }); Object.defineProperty(Date.prototype, "add", { /** * Ajoute une valeur spécifiée à un élément de la date. * @param {number} value - La valeur à ajouter. * @param {string} type - Le type de la valeur (year, month, day, hours, minutes, seconds). */ value: function (value, type) { switch (type) { case "years": this.setFullYear(this.getFullYear() + value); break; case "months": this.setMonth(this.getMonth() + value); break; case "days": this.setDate(this.getDate() + value); break; case "hours": this.setHours(this.getHours() + value); break; case "minutes": this.setMinutes(this.getMinutes() + value); break; case "seconds": this.setSeconds(this.getSeconds() + value); break; default: throw new Error( `Invalid type for adding to date | type : ${type} value : ${value}` ); } return this; // Return the modified date }, }); class Duration { /** * Constructeur de la classe Duration. * @param {Date} start - La date de début de la période. * @param {Date} end - La date de fin de la période. */ constructor(start, end) { this.start = start; // Stocke la date de début. this.end = end; // Stocke la date de fin. this.duration = end - start; // Calcule la durée en millisecondes entre les deux dates. } /** * Calcule le nombre d'années entre les deux dates et arrondit le résultat à quatre décimales. * @return {number} Le nombre d'années arrondi à quatre décimales. */ get years() { const startYear = this.start.getFullYear(); // Obtient l'année de la date de début. const endYear = this.end.getFullYear(); // Obtient l'année de la date de fin. // Calcule la différence en années et arrondit à quatre décimales. return parseFloat((endYear - startYear).toFixed(4)); } /** * Calcule le nombre de mois entre les deux dates, en tenant compte des années et des jours, et arrondit le résultat à quatre décimales. * @return {number} Le nombre de mois arrondi à quatre décimales. */ get months() { const years = this.years; // Nombre d'années complètes. // Calcule la différence en mois, en ajoutant la différence en jours divisée par 30 pour une approximation. const months = years * 12 + (this.end.getMonth() - this.start.getMonth()) + (this.end.getDate() - this.start.getDate()) / 30; // Arrondit à quatre décimales. return parseFloat(months.toFixed(4)); } /** * Calcule le nombre de jours entre les deux dates et arrondit le résultat à quatre décimales. * @return {number} Le nombre de jours arrondi à quatre décimales. */ get days() { // Convertit la durée en millisecondes en jours et arrondit à quatre décimales. return parseFloat((this.duration / (24 * 60 * 60 * 1000)).toFixed(4)); } /** * Calcule le nombre d'heures entre les deux dates et arrondit le résultat à quatre décimales. * @return {number} Le nombre d'heures arrondi à quatre décimales. */ get hours() { // Convertit la durée en millisecondes en heures et arrondit à quatre décimales. return parseFloat((this.duration / (60 * 60 * 1000)).toFixed(4)); } /** * Calcule le nombre de minutes entre les deux dates et arrondit le résultat à quatre décimales. * @return {number} Le nombre de minutes arrondi à quatre décimales. */ get minutes() { // Convertit la durée en millisecondes en minutes et arrondit à quatre décimales. return parseFloat((this.duration / (60 * 1000)).toFixed(4)); } /** * Calcule le nombre de secondes entre les deux dates et arrondit le résultat à quatre décimales. * @return {number} Le nombre de secondes arrondi à quatre décimales. */ get seconds() { // Convertit la durée en millisecondes en secondes et arrondit à quatre décimales. return parseFloat((this.duration / 1000).toFixed(4)); } /** * Obtient le nombre de millisecondes entre les deux dates et arrondit le résultat à quatre décimales. * @return {number} Le nombre de millisecondes arrondi à quatre décimales. */ get milliseconds() { // Arrondit la durée totale en millisecondes à quatre décimales. return parseFloat(this.duration.toFixed(4)); } } /** * Fonction qui vérifie si une période est dans un interval * Objet période / interval * { * deb: Date, * fin: Date, * } * @param {object} period * @param {object} interval * @returns {boolean} Vrai si la période est dans l'interval */ function hasTimeConflict(period, interval) { return period.deb.isBefore(interval.fin) && period.fin.isAfter(interval.deb); }