[FIX] web: use right datetime format in daterange field
- First issue The format passed to the daterangepicker locale options could have been wrong as the daterangepicker lib uses moment and we would pass to it the date(time) format expressed with luxon's format tokens. Furthermore, there was no need to pass the format to the daterangepicker library as the DateRangeField component already handles this. - Second issue There was also another issue with the DateRangeField component: When applying the daterangepicker values, the conversion between a moment object to a luxon DateTime object was wrong because of the format used to convert the moment object to a string. - Explanation The format tokens are different between luxon and moment. - After this commit An helper function has been introduced in order to transform a luxon format into a moment format. The DateRangeField component now properly converts a moment object to a luxon's DateTime object when applying the daterangepicker selection. - Additional note Also, the DatePicker component was locally converting the luxon's datetime format and thus has been adapted to use the new helper. closes odoo/odoo#98578 Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
||||
areDateEquals,
|
||||
formatDate,
|
||||
formatDateTime,
|
||||
luxonToMomentFormat,
|
||||
parseDate,
|
||||
parseDateTime,
|
||||
} from "@web/core/l10n/dates";
|
||||
@@ -33,14 +34,6 @@ function luxonDateToMomentDate(date) {
|
||||
return window.moment(String(date));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} format
|
||||
* @returns {string}
|
||||
*/
|
||||
function luxonFormatToMomentFormat(format) {
|
||||
return format.replace(/[dy]/g, (x) => x.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} format
|
||||
* @returns {boolean}
|
||||
@@ -198,7 +191,7 @@ export class DatePicker extends Component {
|
||||
const params = {
|
||||
...commandOrParams,
|
||||
date: this.date || null,
|
||||
format: luxonFormatToMomentFormat(format),
|
||||
format: luxonToMomentFormat(format),
|
||||
locale: commandOrParams.locale || (this.date && this.date.locale),
|
||||
};
|
||||
for (const prop in params) {
|
||||
|
||||
@@ -44,6 +44,14 @@ const normalizeFormatTable = {
|
||||
X: "HH:mm:ss",
|
||||
};
|
||||
|
||||
const luxonToMomentFormatTable = {
|
||||
c: "d",
|
||||
d: "D",
|
||||
o: "DDDD",
|
||||
a: "A",
|
||||
y: "Y",
|
||||
};
|
||||
|
||||
const smartDateUnits = {
|
||||
d: "days",
|
||||
m: "months",
|
||||
@@ -143,6 +151,19 @@ export const strftimeToLuxonFormat = memoize(function strftimeToLuxonFormat(valu
|
||||
return output.join("");
|
||||
});
|
||||
|
||||
/**
|
||||
* Converts a Luxon format to a moment.js format.
|
||||
* NB: this is not a complete conversion, only the supported tokens are converted.
|
||||
*
|
||||
* @param {string} value original format
|
||||
* @returns {string} valid moment.js format
|
||||
*/
|
||||
export const luxonToMomentFormat = memoize(function luxonToMomentFormat(format) {
|
||||
return format.replace(alphaRegex, (match) => {
|
||||
return luxonToMomentFormatTable[match] || match;
|
||||
});
|
||||
});
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Formatting
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { localization } from "@web/core/l10n/localization";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { loadJS } from "@web/core/assets";
|
||||
import { luxonToMomentFormat } from "@web/core/l10n/dates";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { standardFieldProps } from "../standard_field_props";
|
||||
|
||||
@@ -16,6 +17,9 @@ export class DateRangeField extends Component {
|
||||
this.root = useRef("root");
|
||||
this.isPickerShown = false;
|
||||
this.pickerContainer;
|
||||
this.momentFormat = luxonToMomentFormat(
|
||||
this.isDateTime ? localization.dateTimeFormat : localization.dateFormat
|
||||
);
|
||||
|
||||
useExternalListener(window, "scroll", this.onWindowScroll, { capture: true });
|
||||
onWillStart(() => loadJS("/web/static/lib/daterangepicker/daterangepicker.js"));
|
||||
@@ -32,9 +36,6 @@ export class DateRangeField extends Component {
|
||||
locale: {
|
||||
applyLabel: this.env._t("Apply"),
|
||||
cancelLabel: this.env._t("Cancel"),
|
||||
format: this.isDateTime
|
||||
? localization.dateTimeFormat
|
||||
: localization.dateFormat,
|
||||
},
|
||||
startDate: start ? window.moment(start) : window.moment(),
|
||||
endDate: end ? window.moment(end) : window.moment(),
|
||||
@@ -126,10 +127,9 @@ export class DateRangeField extends Component {
|
||||
async onPickerApply(ev, picker) {
|
||||
const start = this.isDateTime ? picker.startDate : picker.startDate.startOf("day");
|
||||
const end = this.isDateTime ? picker.endDate : picker.endDate.startOf("day");
|
||||
const format = this.isDateTime ? localization.dateTimeFormat : localization.dateFormat;
|
||||
const parser = parsers.get(this.props.formatType);
|
||||
const dates = [start, end].map((date) => {
|
||||
return parser(date.format(format.toUpperCase()), {
|
||||
return parser(date.format(this.momentFormat), {
|
||||
timezone: this.isDateTime,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -191,6 +191,27 @@ QUnit.module("Fields", (hooks) => {
|
||||
"30",
|
||||
"active end date minute should be '30' in date range picker"
|
||||
);
|
||||
|
||||
// Select a new range and check that inputs are updated
|
||||
await triggerEvent(datepicker, ".start-date", "mousedown"); // 02/08/2017
|
||||
await triggerEvent(datepicker, ".start-date + .available", "mousedown"); // 02/09/2017
|
||||
await click(datepicker, ".applyBtn");
|
||||
assert.equal(
|
||||
target.querySelector("[name=datetime] input").value,
|
||||
"02/08/2017 15:30:00"
|
||||
);
|
||||
assert.equal(
|
||||
target.querySelector("[name=datetime_end] input").value,
|
||||
"02/09/2017 05:30:00"
|
||||
);
|
||||
|
||||
// Save
|
||||
await click(target, ".o_form_button_save");
|
||||
fields = target.querySelectorAll(".o_field_daterange");
|
||||
|
||||
// Check date after save
|
||||
assert.strictEqual(fields[0].textContent, "02/08/2017 15:30:00");
|
||||
assert.strictEqual(fields[fields.length - 1].textContent, "02/09/2017 05:30:00");
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user