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 () { const date = this; var tzo = -date.getTimezoneOffset(), dif = tzo >= 0 ? "+" : "-", 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()) + dif + pad(Math.floor(Math.abs(tzo) / 60)) + ":" + pad(Math.abs(tzo) % 60) ); }, }); 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) { 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, }); 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, }); case "YYYY-MM-DDTHH:mm": let iso = this.toIsoUtcString(); // slice : YYYY-MM-DDTHH // slice + 3 : YYYY-MM-DDTHH:mm return iso.slice(0, iso.indexOf(":") + 3); default: return this.toIsoUtcString(); } }, }); 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)); } } class ScoDocDateTimePicker extends HTMLElement { constructor() { super(); // Initialisation du shadow DOM pour l'encapsulation du style et du comportement. const shadow = this.attachShadow({ mode: "open" }); // Création de l'input pour la date. const dateInput = document.createElement("input"); dateInput.type = "date"; dateInput.id = "date"; // Création de l'input pour l'heure. const timeInput = document.createElement("input"); timeInput.type = "time"; timeInput.id = "time"; // Ajout des inputs date et heure dans le shadow DOM. shadow.appendChild(dateInput); shadow.appendChild(timeInput); // Ajout de gestionnaires d'événements pour mettre à jour la valeur lorsque les inputs changent. dateInput.addEventListener("change", () => this.updateValue()); timeInput.addEventListener("change", () => this.updateValue()); // Style CSS pour les inputs, ici pour les afficher côte à côte. const style = document.createElement("style"); style.textContent = ` input { display: inline-block; } `; // Ajout du style dans le shadow DOM. shadow.appendChild(style); } // Méthode pour mettre à jour la valeur interne basée sur les inputs de date et d'heure. updateValue() { const dateInput = this.shadowRoot.querySelector("#date"); const timeInput = this.shadowRoot.querySelector("#time"); // Formatage de la valeur en format datetime ISO (YYYY-MM-DDTHH:MM). this._value = `${dateInput.value}T${timeInput.value}`; } // Getter pour obtenir la valeur actuelle. get value() { return this._value; } // Setter pour définir la valeur. Sépare la valeur en date et heure et les définit individuellement. set value(val) { const [date, time] = val.split("T"); this.shadowRoot.querySelector("#date").value = date; this.shadowRoot.querySelector("#time").value = time; this._value = val; } // Getter pour obtenir la valeur en tant qu'objet Date. get valueAsDate() { return new Date(this._value); } // Setter pour définir la valeur à partir d'un objet Date. set valueAsDate(dateVal) { // Formatage de l'objet Date en string et mise à jour de la valeur. this.value = `${dateVal.getFullYear()}-${String( dateVal.getMonth() + 1 ).padStart(2, "0")}-${String(dateVal.getDate()).padStart(2, "0")}T${String( dateVal.getHours() ).padStart(2, "0")}:${String(dateVal.getMinutes()).padStart(2, "0")}`; } } // Définition du nouvel élément personnalisé 'scodoc-datetime'. customElements.define("scodoc-datetime", ScoDocDateTimePicker);