From 504b4a71788f0f477f7b89da3e5c3a53ed1fd4e0 Mon Sep 17 00:00:00 2001 From: "Pierre Pulinckx (pipu)" Date: Wed, 12 Jul 2023 12:16:01 +0000 Subject: [PATCH] [REF] *:Replace moment usages with luxon luxon and moment are both used in the solution, but these two libraries facilitate the manipulation of dates. It was decided to replace all uses of moment with luxon so we can then remove moment.js from the code and lighten the assets. task-3391739 closes odoo/odoo#127406 Signed-off-by: Mathieu Duckerts-Antoine (dam) --- .../static/tests/activity_widget_tests.js | 8 +- addons/mail/static/src/js/utils.js | 9 -- .../static/tests/core/message_model_tests.js | 7 +- .../mock_server/models/mail_activity.js | 5 +- .../web/activity/activity_widget_tests.js | 11 ++- .../static/src/js/tours/mass_mailing_tour.js | 4 +- .../static/src/app/debug/debug_widget.js | 6 +- .../errors/popups/error_traceback_popup.js | 4 +- addons/portal/static/src/js/portal_sidebar.js | 10 ++- .../pos_adyen/static/src/js/payment_adyen.js | 3 +- .../global_filters_model_test.js | 8 +- .../test_mail/static/tests/activity_tests.js | 12 +-- .../src/legacy/js/fields/field_utils.js | 9 +- .../tests/legacy/helpers/mock_server.js | 85 ++++++++++--------- .../tests/legacy/helpers/test_utils_tests.js | 4 +- .../static/tests/legacy/mockserver_tests.js | 2 +- .../static/src/js/event_track_timer.js | 7 +- addons/website_slides/static/src/js/slides.js | 5 +- 18 files changed, 110 insertions(+), 89 deletions(-) diff --git a/addons/calendar/static/tests/activity_widget_tests.js b/addons/calendar/static/tests/activity_widget_tests.js index 13d31d781fa..d48ca054cf5 100644 --- a/addons/calendar/static/tests/activity_widget_tests.js +++ b/addons/calendar/static/tests/activity_widget_tests.js @@ -4,6 +4,9 @@ import { click, start, startServer } from "@mail/../tests/helpers/test_utils"; import { patchWithCleanup } from "@web/../tests/helpers/utils"; import { ListController } from "@web/views/list/list_controller"; +import { serializeDate } from "@web/core/l10n/dates"; + +const { DateTime } = luxon; QUnit.module("activity widget"); @@ -14,17 +17,18 @@ QUnit.test("list activity widget: reschedule button in dropdown", async (assert) icon: "fa-calendar", name: "Meeting", }); + const tomorrow = serializeDate(DateTime.now().plus({days:1})); const attendeeId = pyEnv["calendar.attendee"].create({ partner_id: resPartnerId }); const meetingId = pyEnv["calendar.event"].create({ res_model: "calendar.event", name: "meeting1", - start: moment().add(1, "day").format("YYYY-MM-DD"), // tomorrow + start: tomorrow, attendee_ids: [attendeeId], }); const activityId_1 = pyEnv["mail.activity"].create({ name: "OXP", activity_type_id: activityTypeId, - date_deadline: moment().add(1, "day").format("YYYY-MM-DD"), // tomorrow + date_deadline: tomorrow, state: "planned", can_write: true, res_id: resPartnerId, diff --git a/addons/mail/static/src/js/utils.js b/addons/mail/static/src/js/utils.js index 372caeff770..8d5af8e1638 100644 --- a/addons/mail/static/src/js/utils.js +++ b/addons/mail/static/src/js/utils.js @@ -1,6 +1,5 @@ /* @odoo-module */ -import { _t } from "@web/core/l10n/translation"; import { escape } from "@web/core/utils/strings"; /** @@ -213,13 +212,6 @@ function getTextToHTML(text) { .replace(/[\n\r]/g, "
"); } -function timeFromNow(date) { - if (moment().diff(date, "seconds") < 45) { - return _t("now"); - } - return date.fromNow(); -} - export { addLink, escapeAndCompactTextContent, @@ -230,5 +222,4 @@ export { parseAndTransform, parseEmail, stripHTML, - timeFromNow, }; diff --git a/addons/mail/static/tests/core/message_model_tests.js b/addons/mail/static/tests/core/message_model_tests.js index 462f190d669..1ddb6d9a39b 100644 --- a/addons/mail/static/tests/core/message_model_tests.js +++ b/addons/mail/static/tests/core/message_model_tests.js @@ -1,8 +1,7 @@ /* @odoo-module */ import { start } from "@mail/../tests/helpers/test_utils"; - -import { str_to_datetime } from "web.time"; +import { serializeDateTime, deserializeDateTime } from "@web/core/l10n/dates"; QUnit.module("message model test", {}); @@ -25,7 +24,7 @@ QUnit.test("Message model properties", async (assert) => { ], author: { id: 5, displayName: "Demo" }, body: "

Test

", - date: moment(str_to_datetime("2019-05-05 10:00:00")), + date: deserializeDateTime("2019-05-05 10:00:00"), id: 4000, needaction_partner_ids: [3], starred_partner_ids: [3], @@ -37,7 +36,7 @@ QUnit.test("Message model properties", async (assert) => { assert.ok(message.isNeedaction); assert.strictEqual(message.body, "

Test

"); assert.strictEqual( - moment(message.date).utc().format("YYYY-MM-DD hh:mm:ss"), + serializeDateTime(message.date), "2019-05-05 10:00:00" ); assert.strictEqual(message.id, 4000); diff --git a/addons/mail/static/tests/helpers/mock_server/models/mail_activity.js b/addons/mail/static/tests/helpers/mock_server/models/mail_activity.js index e06279422bf..901526c04ba 100644 --- a/addons/mail/static/tests/helpers/mock_server/models/mail_activity.js +++ b/addons/mail/static/tests/helpers/mock_server/models/mail_activity.js @@ -3,6 +3,9 @@ import { sortBy } from "@web/core/utils/arrays"; import { patch } from "@web/core/utils/patch"; import { MockServer } from "@web/../tests/helpers/mock_server"; +import { serializeDate } from "@web/core/l10n/dates"; + +const { DateTime} = luxon; patch(MockServer.prototype, "mail/models/mail_activity", { async _performRPC(route, args) { @@ -144,7 +147,7 @@ patch(MockServer.prototype, "mail/models/mail_activity", { group.date_deadline = minDate; resIdToDeadline[group.res_id] = minDate; let state; - if (group.date_deadline === moment().format("YYYY-MM-DD")) { + if (group.date_deadline === serializeDate(DateTime.now())) { state = "today"; } else if (moment(group.date_deadline) > moment()) { state = "planned"; diff --git a/addons/mail/static/tests/web/activity/activity_widget_tests.js b/addons/mail/static/tests/web/activity/activity_widget_tests.js index 34364a0f7d6..34534e07df4 100644 --- a/addons/mail/static/tests/web/activity/activity_widget_tests.js +++ b/addons/mail/static/tests/web/activity/activity_widget_tests.js @@ -5,6 +5,9 @@ import { ROUTES_TO_IGNORE } from "@mail/../tests/helpers/webclient_setup"; import { ListController } from "@web/views/list/list_controller"; import { patchWithCleanup } from "@web/../tests/helpers/utils"; +import { serializeDate } from "@web/core/l10n/dates"; + +const { DateTime } = luxon; QUnit.module("activity widget"); @@ -148,7 +151,7 @@ QUnit.test("list activity widget: open dropdown", async (assert) => { const [activityId_1, activityId_2] = pyEnv["mail.activity"].create([ { display_name: "Call with Al", - date_deadline: moment().format("YYYY-MM-DD"), // now + date_deadline: serializeDate(DateTime.now()), // now can_write: true, state: "today", user_id: pyEnv.currentUserId, @@ -157,7 +160,7 @@ QUnit.test("list activity widget: open dropdown", async (assert) => { }, { display_name: "Meet FP", - date_deadline: moment().add(1, "day").format("YYYY-MM-DD"), // tomorrow + date_deadline: serializeDate(DateTime.now().plus({days:1})), // tomorrow can_write: true, state: "planned", user_id: pyEnv.currentUserId, @@ -237,7 +240,7 @@ QUnit.test("list activity exception widget with activity", async (assert) => { const [activityId_1, activityId_2] = pyEnv["mail.activity"].create([ { display_name: "An activity", - date_deadline: moment().format("YYYY-MM-DD"), // now + date_deadline: serializeDate(DateTime.now()), // now can_write: true, state: "today", user_id: pyEnv.currentUserId, @@ -246,7 +249,7 @@ QUnit.test("list activity exception widget with activity", async (assert) => { }, { display_name: "An exception activity", - date_deadline: moment().format("YYYY-MM-DD"), // now + date_deadline: serializeDate(DateTime.now()), // now can_write: true, state: "today", user_id: pyEnv.currentUserId, diff --git a/addons/mass_mailing/static/src/js/tours/mass_mailing_tour.js b/addons/mass_mailing/static/src/js/tours/mass_mailing_tour.js index 069128c13ad..d3a0076ac1d 100644 --- a/addons/mass_mailing/static/src/js/tours/mass_mailing_tour.js +++ b/addons/mass_mailing/static/src/js/tours/mass_mailing_tour.js @@ -5,7 +5,7 @@ import {_t} from "web.core"; import "web.legacy_tranlations_loaded"; import {Markup} from "web.utils"; - var now = moment(); + const { DateTime } = luxon; registry.category("web_tour.tours").add('mass_mailing_tour', { url: '/web', @@ -30,7 +30,7 @@ trigger: 'input[name="subject"]', content: Markup(_t('Pick the email subject.')), position: 'bottom', - run: 'text ' + now.format("MMMM") + " Newsletter", + run: 'text ' + DateTime.now().toFormat("LLLL") + " Newsletter", }, { trigger: 'div[name="contact_list_ids"] > .o_input_dropdown > input[type="text"]', run: 'click', diff --git a/addons/point_of_sale/static/src/app/debug/debug_widget.js b/addons/point_of_sale/static/src/app/debug/debug_widget.js index 71198540364..5f6c1b9eb07 100644 --- a/addons/point_of_sale/static/src/app/debug/debug_widget.js +++ b/addons/point_of_sale/static/src/app/debug/debug_widget.js @@ -9,6 +9,8 @@ import { useBus, useService } from "@web/core/utils/hooks"; import { useEffect, useRef, useState, Component } from "@odoo/owl"; import { usePos } from "@point_of_sale/app/store/pos_hook"; +import { serializeDateTime } from "@web/core/l10n/dates"; +const { DateTime } = luxon; export class DebugWidget extends Component { static components = { Transition }; @@ -130,7 +132,7 @@ export class DebugWidget extends Component { } } get paidOrdersFilename() { - return `${this.env._t("paid orders")} ${moment().format("YYYY-MM-DD-HH-mm-ss")}.json`; + return `${this.env._t("paid orders")} ${serializeDateTime(DateTime.now()).replace(/:|\s/gi, "-")}.json`; } get paidOrdersURL() { var URL = window.URL || window.webkitURL; @@ -146,7 +148,7 @@ export class DebugWidget extends Component { } } get unpaidOrdersFilename() { - return `${this.env._t("unpaid orders")} ${moment().format("YYYY-MM-DD-HH-mm-ss")}.json`; + return `${this.env._t("unpaid orders")} ${serializeDateTime(DateTime.now()).replace(/:|\s/gi, "-")}.json`; } get unpaidOrdersURL() { var URL = window.URL || window.webkitURL; diff --git a/addons/point_of_sale/static/src/app/errors/popups/error_traceback_popup.js b/addons/point_of_sale/static/src/app/errors/popups/error_traceback_popup.js index 206c51200f3..bc33159a584 100644 --- a/addons/point_of_sale/static/src/app/errors/popups/error_traceback_popup.js +++ b/addons/point_of_sale/static/src/app/errors/popups/error_traceback_popup.js @@ -3,6 +3,8 @@ import { ErrorPopup } from "@point_of_sale/app/errors/popups/error_popup"; import { _lt } from "@web/core/l10n/translation"; import { usePos } from "@point_of_sale/app/store/pos_hook"; +import { serializeDateTime } from "@web/core/l10n/dates"; +const { DateTime } = luxon; // formerly ErrorTracebackPopupWidget export class ErrorTracebackPopup extends ErrorPopup { @@ -27,7 +29,7 @@ export class ErrorTracebackPopup extends ErrorPopup { return URL.createObjectURL(blob); } get tracebackFilename() { - return `${this.env._t("error")} ${moment().format("YYYY-MM-DD-HH-mm-ss")}.txt`; + return `${this.env._t("error")} ${serializeDateTime(DateTime.now()).replace(/:|\s/gi, "-")}.txt`; } emailTraceback() { const address = this.pos.company.email; diff --git a/addons/portal/static/src/js/portal_sidebar.js b/addons/portal/static/src/js/portal_sidebar.js index 72f0d0fad4e..e23ff167997 100644 --- a/addons/portal/static/src/js/portal_sidebar.js +++ b/addons/portal/static/src/js/portal_sidebar.js @@ -2,9 +2,11 @@ import core from "web.core"; import publicWidget from "web.public.widget"; -import time from "web.time"; import session from "web.session"; import { sprintf } from "@web/core/utils/strings"; +import { deserializeDateTime } from "@web/core/l10n/dates"; + +const { DateTime } = luxon; var _t = core._t; @@ -30,9 +32,9 @@ var PortalSidebar = publicWidget.Widget.extend({ _setDelayLabel: function () { var $sidebarTimeago = this.$el.find('.o_portal_sidebar_timeago').toArray(); $sidebarTimeago.forEach((el) => { - var dateTime = moment(time.auto_str_to_date($(el).attr('datetime'))), - today = moment().startOf('day'), - diff = dateTime.diff(today, 'days', true), + var dateTime = deserializeDateTime($(el).attr('datetime')), + today = DateTime.now().startOf('day'), + diff = dateTime.diff(today).as("days"), displayStr; session.is_bound.then(function (){ diff --git a/addons/pos_adyen/static/src/js/payment_adyen.js b/addons/pos_adyen/static/src/js/payment_adyen.js index 5b7c0cddd80..aaf97b82792 100644 --- a/addons/pos_adyen/static/src/js/payment_adyen.js +++ b/addons/pos_adyen/static/src/js/payment_adyen.js @@ -4,6 +4,7 @@ import { _t } from "@web/core/l10n/translation"; import { PaymentInterface } from "@point_of_sale/app/payment/payment_interface"; import { ErrorPopup } from "@point_of_sale/app/errors/popups/error_popup"; import { sprintf } from "@web/core/utils/strings"; +const { DateTime } = luxon; export class PaymentAdyen extends PaymentInterface { send_payment_request(cid) { @@ -96,7 +97,7 @@ export class PaymentAdyen extends PaymentInterface { SaleData: { SaleTransactionID: { TransactionID: order.uid, - TimeStamp: moment().format(), // iso format: '2018-01-10T11:30:15+00:00' + TimeStamp: DateTime.now().toFormat("yyyy-MM-dd'T'HH:mm:ssZZ"), // iso format: '2018-01-10T11:30:15+00:00' }, }, PaymentTransaction: { diff --git a/addons/spreadsheet/static/tests/global_filters/global_filters_model_test.js b/addons/spreadsheet/static/tests/global_filters/global_filters_model_test.js index 8a54f1b07ae..31c00832de7 100644 --- a/addons/spreadsheet/static/tests/global_filters/global_filters_model_test.js +++ b/addons/spreadsheet/static/tests/global_filters/global_filters_model_test.js @@ -31,6 +31,8 @@ import { } from "@spreadsheet/../tests/utils/date_domain"; import GlobalFiltersUIPlugin from "@spreadsheet/global_filters/plugins/global_filters_ui_plugin"; import { migrate } from "@spreadsheet/o_spreadsheet/migration"; +const { DateTime } = luxon; + /** * @typedef {import("@spreadsheet/global_filters/plugins/global_filters_core_plugin").GlobalFilter} GlobalFilter @@ -604,7 +606,7 @@ QUnit.module("spreadsheet > Global filters model", {}, () => { }, }); await nextTick(); - assert.equal(getCellValue(model, "A10"), `Q1/${moment().year()}`); + assert.equal(getCellValue(model, "A10"), `Q1/${DateTime.now().year}`); await setGlobalFilterValue(model, { id: filter.id, rangeType: "year", @@ -613,7 +615,7 @@ QUnit.module("spreadsheet > Global filters model", {}, () => { }, }); await nextTick(); - assert.equal(getCellValue(model, "A10"), `${moment().year()}`); + assert.equal(getCellValue(model, "A10"), `${DateTime.now().year}`); await setGlobalFilterValue(model, { id: filter.id, rangeType: "year", @@ -623,7 +625,7 @@ QUnit.module("spreadsheet > Global filters model", {}, () => { }, }); await nextTick(); - assert.equal(getCellValue(model, "A10"), `01/${moment().year()}`); + assert.equal(getCellValue(model, "A10"), `01/${DateTime.now().year}`); await setGlobalFilterValue(model, { id: filter.id, rangeType: "year", diff --git a/addons/test_mail/static/tests/activity_tests.js b/addons/test_mail/static/tests/activity_tests.js index d23617fe972..01b8f34d0ad 100644 --- a/addons/test_mail/static/tests/activity_tests.js +++ b/addons/test_mail/static/tests/activity_tests.js @@ -3,6 +3,7 @@ import { ActivityModel } from "@mail/views/web/activity/activity_model"; import { ActivityRenderer } from "@mail/views/web/activity/activity_renderer"; import { start, startServer } from "@mail/../tests/helpers/test_utils"; +import { serializeDate } from "@web/core/l10n/dates"; import testUtils from "web.test_utils"; @@ -16,6 +17,7 @@ import { import { doAction } from "@web/../tests/webclient/helpers"; import { session } from "@web/session"; import { toggleSearchBarMenu } from "@web/../tests/search/helpers"; +const { DateTime } = luxon; let serverData; let pyEnv; @@ -41,7 +43,7 @@ QUnit.module("test_mail", {}, function () { const mailActivityIds = pyEnv["mail.activity"].create([ { display_name: "An activity", - date_deadline: moment().add(3, "days").format("YYYY-MM-DD"), // now + date_deadline: serializeDate(DateTime.now().plus({days:3})), can_write: true, state: "planned", activity_type_id: mailActivityTypeIds[0], @@ -50,7 +52,7 @@ QUnit.module("test_mail", {}, function () { }, { display_name: "An activity", - date_deadline: moment().format("YYYY-MM-DD"), // now + date_deadline: serializeDate(DateTime.now()), can_write: true, state: "today", activity_type_id: mailActivityTypeIds[0], @@ -60,7 +62,7 @@ QUnit.module("test_mail", {}, function () { { res_model: "mail.test.activity", display_name: "An activity", - date_deadline: moment().subtract(2, "days").format("YYYY-MM-DD"), // now + date_deadline: serializeDate(DateTime.now().minus({days:2})), can_write: true, state: "overdue", activity_type_id: mailActivityTypeIds[1], @@ -220,7 +222,7 @@ QUnit.module("test_mail", {}, function () { for (let i = 0; i < 81; i++) { activityToCreate.push({ display_name: "An activity " + i, - date_deadline: moment().add(3, "days").format("YYYY-MM-DD"), + date_deadline: serializeDate(DateTime.now().plus({days:3})), can_write: true, state: "planned", activity_type_id: mailActivityTypeIds[0], @@ -822,7 +824,7 @@ QUnit.module("test_mail", {}, function () { pyEnv["mail.activity"].create([ { display_name: "An activity", - date_deadline: moment().add(3, "days").format("YYYY-MM-DD"), // now + date_deadline: serializeDate(DateTime.now().plus({days:3})), can_write: true, state: "planned", activity_type_id: mailActivityTypeIds[2], diff --git a/addons/web/static/src/legacy/js/fields/field_utils.js b/addons/web/static/src/legacy/js/fields/field_utils.js index 32ce9b2f131..0cf152b6b2a 100644 --- a/addons/web/static/src/legacy/js/fields/field_utils.js +++ b/addons/web/static/src/legacy/js/fields/field_utils.js @@ -20,6 +20,7 @@ import dom from "web.dom"; import session from "web.session"; import time from "web.time"; import utils from "web.utils"; +const { DateTime } = luxon; var _t = core._t; @@ -443,7 +444,7 @@ function formatJson(value, field, options) { * "-4y" will return now + 4 years * * @param {string} value - * @returns {Moment|false} Moment date object + * @returns {DateTime|false} luxon DateTime */ function parseSmartDateInput(value) { const units = { @@ -455,13 +456,13 @@ function parseSmartDateInput(value) { const re = new RegExp(`^([+-])(\\d+)([${Object.keys(units).join('')}]?)$`); const match = re.exec(value); if (match) { - let date = moment(); + let date = DateTime.now() const offset = parseInt(match[2], 10); const unit = units[match[3] || 'd']; if (match[1] === '+') { - date.add(offset, unit); + date.plus({[unit]: offset}); } else { - date.subtract(offset, unit); + date.minus({[unit]: offset}); } return date; } diff --git a/addons/web/static/tests/legacy/helpers/mock_server.js b/addons/web/static/tests/legacy/helpers/mock_server.js index 93fb6ce52d4..f413f100af5 100644 --- a/addons/web/static/tests/legacy/helpers/mock_server.js +++ b/addons/web/static/tests/legacy/helpers/mock_server.js @@ -5,6 +5,13 @@ import { pick } from "@web/core/utils/objects"; import Class from "web.Class"; import Domain from "web.Domain"; import pyUtils from "web.py_utils"; +import { + parseDateTime, + serializeDate, + serializeDateTime, + deserializeDate, + deserializeDateTime +} from "@web/core/l10n/dates"; var MockServer = Class.extend({ /** @@ -62,8 +69,6 @@ var MockServer = Class.extend({ } this.debug = options.debug; - this.currentDate = options.currentDate || moment().format("YYYY-MM-DD"); - this.actions = options.actions || []; this.archs = options.archs || {}; }, @@ -1475,30 +1480,32 @@ var MockServer = Class.extend({ const [fieldName, aggregateFunction = "month"] = groupByField.split(':'); const { type } = fields[fieldName]; if (type === "date") { - if (aggregateFunction === 'day') { - return moment(val).format('YYYY-MM-DD'); - } else if (aggregateFunction === 'week') { - return moment(val).format('[W]WW GGGG'); - } else if (aggregateFunction === 'quarter') { - return moment(val).format('[Q]Q YYYY'); - } else if (aggregateFunction === 'year') { - return moment(val).format('Y'); + const date = deserializeDate(val); + if (aggregateFunction === "day") { + return date.toFormat("yyyy-MM-dd"); + } else if (aggregateFunction === "week") { + return `W${date.toFormat("WW kkkk")}`; + } else if (aggregateFunction === "quarter") { + return `Q${date.toFormat("q yyyy")}`; + } else if (aggregateFunction === "year") { + return date.toFormat("yyyy"); } else { - return moment(val).format('MMMM YYYY'); + return date.toFormat("MMMM yyyy"); } } else if (type === "datetime") { + const date = deserializeDateTime(val); if (aggregateFunction === 'hour') { - return moment(val).format('HH[:00] DD MMM'); - } else if (aggregateFunction === 'day') { - return moment(val).format('YYYY-MM-DD'); - } else if (aggregateFunction === 'week') { - return moment(val).format('[W]WW GGGG'); - } else if (aggregateFunction === 'quarter') { - return moment(val).format('[Q]Q YYYY'); - } else if (aggregateFunction === 'year') { - return moment(val).format('Y'); + return date.toFormat("HH:00 dd MMM yyyy"); + } else if (aggregateFunction === "day") { + return date.toFormat("yyyy-MM-dd"); + } else if (aggregateFunction === "week") { + return `W${date.toFormat("WW kkkk")}`; + } else if (aggregateFunction === "quarter") { + return `Q${date.toFormat("q yyyy")}`; + } else if (aggregateFunction === "year") { + return date.toFormat("yyyy"); } else { - return moment(val).format('MMMM YYYY'); + return date.toFormat("MMMM yyyy"); } } else if (Array.isArray(val)) { if (val.length === 0) { @@ -1578,43 +1585,43 @@ var MockServer = Class.extend({ let startDate, endDate; switch (dateRange) { case "hour": { - startDate = moment(value, "HH[:00] DD MMM"); - endDate = startDate.clone().add(1, "hours"); + startDate = parseDateTime(value, { format: "HH:00 dd MMM yyyy" }); + group[gbField] = startDate.toFormat("HH:00 dd MMM"); + endDate = startDate.plus({ hours: 1 }); + // Remove the year from the result value of the group. It was needed + // to compute the startDate and endDate. break; } case "day": { - startDate = moment(value, "YYYY-MM-DD"); - endDate = startDate.clone().add(1, "days"); + startDate = parseDateTime(value, { format: "yyyy-MM-dd" }); + endDate = startDate.plus({ days: 1 }); break; } case "week": { - startDate = moment(value, "[W]WW GGGG"); - endDate = startDate.clone().add(1, "weeks"); + startDate = parseDateTime(value, { format: "WW kkkk" }); + endDate = startDate.plus({ weeks: 1 }); break; } case "quarter": { - startDate = moment(value, "[Q]Q YYYY"); - endDate = startDate.clone().add(1, "quarters"); + startDate = parseDateTime(value, { format: "q yyyy" }); + endDate = startDate.plus({ quarters: 1 }); break; } case "year": { - startDate = moment(value, "Y"); - endDate = startDate.clone().add(1, "years"); + startDate = parseDateTime(value, { format: "y" }); + endDate = startDate.plus({ years: 1 }); break; } case "month": default: { - startDate = moment(value, "MMMM YYYY"); - endDate = startDate.clone().add(1, "months"); + startDate = parseDateTime(value, { format: "MMMM yyyy" }); + endDate = startDate.plus({ months: 1 }); break; } } - const from = type === "date" - ? startDate.format("YYYY-MM-DD") - : startDate.format("YYYY-MM-DD HH:mm:ss"); - const to = type === "date" - ? endDate.format("YYYY-MM-DD") - : endDate.format("YYYY-MM-DD HH:mm:ss"); + const serialize = type === "date" ? serializeDate : serializeDateTime; + const from = serialize(startDate); + const to = serialize(endDate); // NOTE THAT the range and the domain computed here are not really accurate // due to a the timezone not really taken into account. // FYI, the non legacy version of the mock server handles this correctly. diff --git a/addons/web/static/tests/legacy/helpers/test_utils_tests.js b/addons/web/static/tests/legacy/helpers/test_utils_tests.js index 7f1a5b9c8cb..f96dbcdf903 100644 --- a/addons/web/static/tests/legacy/helpers/test_utils_tests.js +++ b/addons/web/static/tests/legacy/helpers/test_utils_tests.js @@ -1,6 +1,7 @@ /** @odoo-module **/ import testUtils from "web.test_utils"; +const { DateTime } = luxon; QUnit.module('web', {}, function () { QUnit.module('testUtils', {}, function () { @@ -25,8 +26,7 @@ QUnit.test('new moment', function (assert) { assert.expect(1); const unpatchDate = testUtils.mock.patchDate(2018, 9, 23, 14, 50, 0); - const m = moment(); - assert.strictEqual(m.format('YYYY-MM-DD HH:mm'), '2018-10-23 14:50'); + assert.strictEqual(DateTime.now().toFormat("yyyy-MM-dd HH:mm"), '2018-10-23 14:50'); unpatchDate(); }); diff --git a/addons/web/static/tests/legacy/mockserver_tests.js b/addons/web/static/tests/legacy/mockserver_tests.js index 4f2a06be9ec..3effb82de48 100644 --- a/addons/web/static/tests/legacy/mockserver_tests.js +++ b/addons/web/static/tests/legacy/mockserver_tests.js @@ -299,7 +299,7 @@ QUnit.module("Legacy MockServer", { }); assert.deepEqual( result.map((x) => x["datetime:hour"]), - ["12:00 14 Dec", "12:00 26 Oct", "12:00 15 Dec", "12:00 11 Apr", "12:00 30 Dec"] + ["13:00 14 Dec", "13:00 26 Oct", "13:00 15 Dec", "13:00 11 Apr", "13:00 30 Dec"] ); assert.deepEqual( result.map((x) => x.datetime_count), diff --git a/addons/website_event_track/static/src/js/event_track_timer.js b/addons/website_event_track/static/src/js/event_track_timer.js index 58feb7005cd..59be3812177 100644 --- a/addons/website_event_track/static/src/js/event_track_timer.js +++ b/addons/website_event_track/static/src/js/event_track_timer.js @@ -2,6 +2,7 @@ import publicWidget from "web.public.widget"; +const { DateTime } = luxon; /* * Simple implementation of a timer widget that uses a "time to live" configuration @@ -22,8 +23,8 @@ publicWidget.registry.websiteEventTrackTimer = publicWidget.Widget.extend({ start: function () { return this._super.apply(this, arguments).then(() => { let timeToLive = this.$el.data('time-to-live'); - let deadline = moment().add(timeToLive, 'seconds'); - let remainingMs = deadline.diff(moment()); + let deadline = DateTime.now().plus({seconds : timeToLive}); + let remainingMs = deadline.diff(DateTime.now()).as("milliseconds"); if (remainingMs > 0) { this._updateTimerDisplay(remainingMs); this.$el.removeClass('d-none'); @@ -57,7 +58,7 @@ publicWidget.registry.websiteEventTrackTimer = publicWidget.Widget.extend({ * Otherwise, the component will be destroyed. */ _refreshTimer: function () { - let remainingMs = this.deadline.diff(moment()); + let remainingMs = this.deadline.diff(DateTime.now()).as("milliseconds"); if (remainingMs > 0) { this._updateTimerDisplay(remainingMs); } else { diff --git a/addons/website_slides/static/src/js/slides.js b/addons/website_slides/static/src/js/slides.js index 792aa8ab77f..f2a605dae33 100644 --- a/addons/website_slides/static/src/js/slides.js +++ b/addons/website_slides/static/src/js/slides.js @@ -2,6 +2,7 @@ import publicWidget from 'web.public.widget'; import time from 'web.time'; +const { DateTime } = luxon; publicWidget.registry.websiteSlides = publicWidget.Widget.extend({ selector: '#wrapwrap', @@ -20,9 +21,9 @@ publicWidget.registry.websiteSlides = publicWidget.Widget.extend({ // then return fix formate string else timeago var displayStr = ''; if (datetimeObj && new Date().getTime() - datetimeObj.getTime() > 7 * 24 * 60 * 60 * 1000) { - displayStr = moment(datetimeObj).format('ll'); + displayStr = DateTime.fromJSDate(datetimeObj).toFormat('DD'); } else { - displayStr = moment(datetimeObj).fromNow(); + displayStr = DateTime.fromJSDate(datetimeObj).toRelative(); } $(el).text(displayStr); });