I faced the same issue and I found out that the same issue was reported in the Magento 2 Github repository:
https://github.com/magento/magento2/issues/23157
And this is the Pull Request with the solution:
https://github.com/magento/magento2/pull/31549
It's fixed in Magento 2.4.
So, i made a patch from that Pull Request to apply in previous Magento 2 versions with composer patches:
From: Santiago Valveson <https://www.linkedin.com/in/santiago-valveson/>
Subject: [PATCH] Invalid date when timeOnly defined on datetime UIComponent -
Fixed in the v2.4
---
view/base/web/js/form/element/date.js | 9 +++-
.../js/lib/knockout/bindings/datepicker.js | 47 +++++++++----------
2 files changed, 30 insertions(+), 26 deletions(-)
diff --git a/view/base/web/js/form/element/date.js b/view/base/web/js/form/element/date.js
index 22fcdcb..a5447b2 100644
--- a/view/base/web/js/form/element/date.js
+++ b/view/base/web/js/form/element/date.js
@@ -107,6 +107,13 @@ define([
return this._super().observe(['shiftedValue']);
},
+ /**
+ * @inheritdoc
+ */
+ getPreview: function () {
+ return this.shiftedValue();
+ },
+
/**
* Prepares and sets date/time value that will be displayed
* in the input field.
@@ -120,7 +127,7 @@ define([
if (this.options.showsTime && !this.options.timeOnly) {
shiftedValue = moment.tz(value, 'UTC').tz(this.storeTimeZone);
} else {
- shiftedValue = moment(value, this.outputDateFormat);
+ shiftedValue = moment(value, this.outputDateFormat, true);
}
if (!shiftedValue.isValid()) {
diff --git a/view/base/web/js/lib/knockout/bindings/datepicker.js b/view/base/web/js/lib/knockout/bindings/datepicker.js
index 2fab8c2..ff09835 100644
--- a/view/base/web/js/lib/knockout/bindings/datepicker.js
+++ b/view/base/web/js/lib/knockout/bindings/datepicker.js
@@ -7,11 +7,8 @@ define([
'ko',
'underscore',
'jquery',
- 'mage/translate',
- 'mage/calendar',
- 'moment',
- 'mageUtils'
-], function (ko, _, $, $t, calendar, moment, utils) {
+ 'mage/translate'
+], function (ko, _, $, $t) {
'use strict';
var defaults = {
@@ -46,10 +43,12 @@ define([
observable = config;
}
- $(el).calendar(options);
+ require(['mage/calendar'], function () {
+ $(el).calendar(options);
- ko.utils.registerEventHandler(el, 'change', function () {
- observable(this.value);
+ ko.utils.registerEventHandler(el, 'change', function () {
+ observable(this.value);
+ });
});
},
@@ -62,6 +61,7 @@ define([
*/
update: function (element, valueAccessor) {
var config = valueAccessor(),
+ $element = $(element),
observable,
options = {},
newVal;
@@ -75,26 +75,23 @@ define([
observable = config;
}
- if (_.isEmpty(observable())) {
- if ($(element).datepicker('getDate')) {
- $(element).datepicker('setDate', null);
- $(element).blur();
+ require(['moment', 'mage/utils/misc', 'mage/calendar'], function (moment, utils) {
+ if (_.isEmpty(observable())) {
+ newVal = null;
+ } else {
+ newVal = moment(
+ observable(),
+ utils.convertToMomentFormat(
+ options.dateFormat + (options.showsTime ? ' ' + options.timeFormat : '')
+ )
+ ).toDate();
}
- } else {
- newVal = moment(
- observable(),
- utils.convertToMomentFormat(
- options.dateFormat + (options.showsTime ? ' ' + options.timeFormat : '')
- )
- ).toDate();
- if ($(element).datepicker('getDate') == null ||
- newVal.valueOf() !== $(element).datepicker('getDate').valueOf()
- ) {
- $(element).datepicker('setDate', newVal);
- $(element).blur();
+ if (!options.timeOnly) {
+ $element.datepicker('setDate', newVal);
+ $element.blur();
}
- }
+ });
}
};
});
--
2.21.0
This is the Magento 2 guide to apply composer patches:
https://devdocs.magento.com/guides/v2.3/comp-mgr/patching/composer.html
This is the code to make it work well (taken from the QA done by Magento to approve the Pull Request
):
<field name="start_date">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="dataType" xsi:type="string">string</item>
<item name="label" xsi:type="string" translate="true">Start Time</item>
<item name="formElement" xsi:type="string">date</item>
<item name="source" xsi:type="string">import_profile</item>
<item name="dataScope" xsi:type="string">start_time</item>
<item name="options" xsi:type="array">
<item name="timeOnlyTitle" xsi:type="string">Select Start Time</item>
<item name="showsTime" xsi:type="boolean">true</item>
<item name="timeOnly" xsi:type="boolean">true</item>
<item name="timeFormat" xsi:type="string">HH:mm:ss</item>
<item name="dateFormat" xsi:type="string">yyyy-MM-dd</item>
</item>
</item>
</argument>
</field>
Another solution (better to me) is use the type time input:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/time
And create a new input template (I choose this way because i couldn't receive the time post param of the original date UI field.
in your module:
Vendor/ModuleName/view/adminhtml/web/template/form/element/time_input.html
<input class="admin__control-text" type="time"
data-bind="
event: {change: userChanges},
value: value,
hasFocus: focused,
valueUpdate: valueUpdate,
attr: {
name: inputName,
placeholder: placeholder,
'aria-describedby': noticeId,
id: uid,
disabled: disabled,
}"/>
And then, in your form:
<field name="start_date" formElement="input">
<settings>
<elementTmpl>Vendor_ModuleName/form/element/time_input</elementTmpl>
<dataType>text</dataType>
<dataScope>start_date</dataScope>
<label translate="true">Start Date</label>
<validation>
<rule name="required-entry" xsi:type="boolean">true</rule>
</validation>
</settings>
</field>
And you can standardize the post param in the Save/Validator Controller and the Data Provider with this:
date('H:i', strtotime($this->_request->getParam('opening_time')))
Should looks like this:
Input image
Input image with time select