MyFaces Trinidad
  1. MyFaces Trinidad
  2. TRINIDAD-61

tr:validateDateTimeRange validation fails on last day of valid range

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 1.0.5-core, 1.2.5-core
    • Component/s: Components
    • Labels:
      None

      Description

      When used without an given converter (tr:convertDateTime), a tr:validateDateTimeRange's javaScript-validation fails (when used with facelets? not tested.) if the last day of the valid date-range was choosen in the tr:inputDate. (see screenshot). Debugging the javaScript shows that the select date was converted into for example "20.09.2007 01:00:00" (depending on timeZone) and is checked against "20.09.2007 00:00:00". So the choosen date is bigger then the max date and the validation fails.
      Using a ValueBinding and setting the maxdate to "20.09.2007 23:59:59" does not solve the problem since the time component seems to be cut of from maxDate for javaScript validation.
      A <tr:convertDateTime pattern="dd.MM.yyyy"/> is a workaround.

      1. screenshot-1.jpg
        23 kB
        Thorsten Guenther
      2. trin11_61.diff
        4 kB
        Yee-Wah Lee
      3. trin12_61.diff
        4 kB
        Yee-Wah Lee
      4. trin11_61_add.diff
        3 kB
        Yee-Wah Lee
      5. trin12_61_add.diff
        2 kB
        Yee-Wah Lee
      6. trin11_61_add_2.diff
        2 kB
        Yee-Wah Lee
      7. trin12_61_add_2.diff
        2 kB
        Yee-Wah Lee

        Activity

        Hide
        Thorsten Guenther added a comment - - edited

        tr:convertDateTime is not a workaround. Perhaps JavaScript was off due to debugging as I tried it at first. Sorry for confusion. I turned off client validation all to gether for now.

        Show
        Thorsten Guenther added a comment - - edited tr:convertDateTime is not a workaround. Perhaps JavaScript was off due to debugging as I tried it at first. Sorry for confusion. I turned off client validation all to gether for now.
        Hide
        Matthias Weßendorf added a comment -

        not related to Facelets, that issue will occur is JSP world as well.

        Show
        Matthias Weßendorf added a comment - not related to Facelets, that issue will occur is JSP world as well.
        Hide
        Yee-Wah Lee added a comment -

        I can repro the issue (without Facelets, convertDateTime or InputDate), using the online demo:
        http://www.irian.at/trinidad-demo/faces/convertValidate/clientConvert.jspx

        <tr:inputText value="#

        {clientValidation.date}

        ">
        <tr:validateDateTimeRange minimum="2007-01-01"
        maximum="2007-12-31"/>
        </tr:inputText>

        1. Look for the input with "examples of values that will fail validation: any date which is not in 2007".
        2. Enter 12/31/2007 and press Submit.
        3. The client validator returns error "Enter a date on or between 12/31/2006
        and 12/30/2007."

        I believe the problem is the following code in DateFormat.js
        TrDateTimeConverter.prototype._simpleDateParseImpl = function(..)

        { var parsedTime = new Date(0); }
        • new Date(0) corresponds to the Date (milliseconds) constructor, returning a date with 0 milliseconds since 1 January 1970 00:00:00 UTC, which is converted with timezone offset locally. E.g. in my timezone the Date is Dec 31 1969 16:00:00 PDT
        • The code then goes to parse the submittedValue for MM/DD/YYYY and sets those on parsedTime. So, calling setFullYear(),setMonth(),setDate() gives parsedTime a value of Dec 31 2007 16:00:00 PDT
        • As you notice, the hours, minutes, seconds components are still present. This value is then used in comparison against the maxValue from the server which was generated using 0 as default values for the hh:mm:ss, i.e. Dec 31 2007 00:00:00 PDT.
        Show
        Yee-Wah Lee added a comment - I can repro the issue (without Facelets, convertDateTime or InputDate), using the online demo: http://www.irian.at/trinidad-demo/faces/convertValidate/clientConvert.jspx <tr:inputText value="# {clientValidation.date} "> <tr:validateDateTimeRange minimum="2007-01-01" maximum="2007-12-31"/> </tr:inputText> 1. Look for the input with "examples of values that will fail validation: any date which is not in 2007". 2. Enter 12/31/2007 and press Submit. 3. The client validator returns error "Enter a date on or between 12/31/2006 and 12/30/2007." I believe the problem is the following code in DateFormat.js TrDateTimeConverter.prototype._simpleDateParseImpl = function(..) { var parsedTime = new Date(0); } new Date(0) corresponds to the Date (milliseconds) constructor, returning a date with 0 milliseconds since 1 January 1970 00:00:00 UTC, which is converted with timezone offset locally. E.g. in my timezone the Date is Dec 31 1969 16:00:00 PDT The code then goes to parse the submittedValue for MM/DD/YYYY and sets those on parsedTime. So, calling setFullYear(),setMonth(),setDate() gives parsedTime a value of Dec 31 2007 16:00:00 PDT As you notice, the hours, minutes, seconds components are still present. This value is then used in comparison against the maxValue from the server which was generated using 0 as default values for the hh:mm:ss, i.e. Dec 31 2007 00:00:00 PDT.
        Hide
        Yee-Wah Lee added a comment -

        This will be partially resolved by fix for JIRA Trinidad-748:
        https://issues.apache.org/jira/browse/TRINIDAD-748

        That fix uses the converter for both the value and the min/max values, so they all carry the same timezone offset and predefaulted values for h/m/s/ms.

        However, the problem still remains on the server. The default value for the maxDate's h/m/s/ms is zero. However, there is code that copies over the h/m/s/ms from the existing value to the newly converted value (to avoid data loss when the converter shows only date). Thus, comparisons with the maxDate generally fail because the existing values are non-zero. The code that does this is: DateTimeConverter.java#_fillTimePortion()

        Show
        Yee-Wah Lee added a comment - This will be partially resolved by fix for JIRA Trinidad-748: https://issues.apache.org/jira/browse/TRINIDAD-748 That fix uses the converter for both the value and the min/max values, so they all carry the same timezone offset and predefaulted values for h/m/s/ms. However, the problem still remains on the server. The default value for the maxDate's h/m/s/ms is zero. However, there is code that copies over the h/m/s/ms from the existing value to the newly converted value (to avoid data loss when the converter shows only date). Thus, comparisons with the maxDate generally fail because the existing values are non-zero. The code that does this is: DateTimeConverter.java#_fillTimePortion()
        Hide
        Yee-Wah Lee added a comment -

        Plugin-changes also required. This file contains changes to Trinidad 1.1 for:

        • Adding the new metadata property to chooseDate.xml and ValidateDateTimeRange.xml
        • New method in UIXComponentTag and TagUtils which sets the DateProperty with maximum time components.
        Show
        Yee-Wah Lee added a comment - Plugin-changes also required. This file contains changes to Trinidad 1.1 for: Adding the new metadata property to chooseDate.xml and ValidateDateTimeRange.xml New method in UIXComponentTag and TagUtils which sets the DateProperty with maximum time components.
        Hide
        Yee-Wah Lee added a comment -

        Plugin-changes also required. This file contains the Trinidad 1.2 changes for:

        • Adding metadata property to chooseDate.xml and validateDateTimeRange.xml which indicates to maximize the time components
        • New method in UIXComponentELTag and TagUtils which sets the Date with max time
        Show
        Yee-Wah Lee added a comment - Plugin-changes also required. This file contains the Trinidad 1.2 changes for: Adding metadata property to chooseDate.xml and validateDateTimeRange.xml which indicates to maximize the time components New method in UIXComponentELTag and TagUtils which sets the Date with max time
        Hide
        Yee-Wah Lee added a comment -

        Plugins-patch is available on private branch:
        http://svn.apache.org/repos/asf/myfaces/trinidad-maven/branches/matzew_test_drive/

        Which also contains the plugins-refactoring, hence I have not uploaded my original patch (based on unrefactored code).

        Show
        Yee-Wah Lee added a comment - Plugins-patch is available on private branch: http://svn.apache.org/repos/asf/myfaces/trinidad-maven/branches/matzew_test_drive/ Which also contains the plugins-refactoring, hence I have not uploaded my original patch (based on unrefactored code).
        Hide
        Matthias Weßendorf added a comment -

        Thanks to Yee-Wah, for her fix!!!

        Show
        Matthias Weßendorf added a comment - Thanks to Yee-Wah, for her fix!!!
        Hide
        Yee-Wah Lee added a comment -

        Sorry, my patch didn't include code to set the Application timezone (from the config file) onto the date parser. This would be an issue if the server JDK and the Application timezone were different.

        Show
        Yee-Wah Lee added a comment - Sorry, my patch didn't include code to set the Application timezone (from the config file) onto the date parser. This would be an issue if the server JDK and the Application timezone were different.
        Hide
        Yee-Wah Lee added a comment -

        Addendum to Trinidad-61 for JSF 1.1 trunk:

        • Sets the RequestContext on the DateFormat to ensure min/maxValue is parsed with Application timezone.
        Show
        Yee-Wah Lee added a comment - Addendum to Trinidad-61 for JSF 1.1 trunk: Sets the RequestContext on the DateFormat to ensure min/maxValue is parsed with Application timezone.
        Hide
        Yee-Wah Lee added a comment -

        Addendum to Trinidad-61 for JSF 1.2 trunk:

        • Sets the RequestContext on the DateFormat to ensure min/maxValue is parsed with Application timezone.
        Show
        Yee-Wah Lee added a comment - Addendum to Trinidad-61 for JSF 1.2 trunk: Sets the RequestContext on the DateFormat to ensure min/maxValue is parsed with Application timezone.
        Hide
        Yee-Wah Lee added a comment -

        I have found a case where the above changes are not adequate. On the clientConvert demo:
        http://www.irian.at/trinidad-demo/faces/convertValidate/clientConvert.jspx
        <tr:inputText value="#

        {clientValidation.date}

        ">
        <tr:validateDateTimeRange minimum="2007-01-01"
        maximum="2007-12-31"/>
        </tr:inputText>

        Suppose the server is running in America/Los_Angeles (UTC -8) , but has timezone-id set to "Europe/Stockholm" (UTC+1). When running the demo above, type the value "12/31/2007" and submit - it fails, returning with the error message 'Date should be between 1/1/2007 and 12/31/2007'.

        Debugging notes:
        1. In TagUtils.java, the validator has its value set as "12/31/2007". It uses a simple date format, with timezone set to Europe/Stockholm, to parse it to get 12/31/2007 00:00 (UTC+1) = 12/30/2007 15:00 (UTC-8) . It adds the time maximize logic after the date has been parsed, so in this case it adds 8h 59 min to get 12/30/2007 23:59 (UTC -8) which is equivalent to 12/31/2007 8:59 (UTC +1).

        2. When user submits "12/31/2007", the converter does String <-> Date conversion. In the Trinidad DateTimeConverter#getAsObject(), it does the following.
        _getParsedDate:

        • Creates a SimpleDateFormat with timezone (Europe/Stockholm) and the type/pattern specified.
        • Uses the SimpleDateFormat to parse the string "12/31/2007" - it gets 12/31/2007 00:00 (UTC + 1)

        The next step is to ensure that time components aren't lost from the value just because the converter doesn't display time (data loss). So:
        _fillTimePortion:

        • Gets the previous value and creates a Calendar object with timezone Europe/Stockholm based on the time. Suppose the previous value was **** 22:43 (UTC+1) (The date doesn't really matter, it is going to copy the time components in the next step).
        • Copies the time components over to the new time. So,
          Parsed Time = 12/31/2007 00:00 (UTC + 1)
          Added Time components = 22 h 43 s
          Return value = 12/31/2007 22:43 (UTC + 1)

        3. Then, when the validator does the comparison, it throws a validation error because it finds value > maximum
        Value: 12/31/2007 22:43 (UTC + 1)
        Maximum: 12/31/2007 11:00 (UTC + 1)

        The clientConvert.jspx example prepopulates the value with the current date-time, so this bug may not be occur when the current time is less than ((difference between timezone param and server timezone offset) - 1), or if everything is running in the same timezone. It demonstrates a bug with the time maximize logic, which should maximize the time before parsing, otherwise it may add less than the range required to make validation pass.

        Show
        Yee-Wah Lee added a comment - I have found a case where the above changes are not adequate. On the clientConvert demo: http://www.irian.at/trinidad-demo/faces/convertValidate/clientConvert.jspx <tr:inputText value="# {clientValidation.date} "> <tr:validateDateTimeRange minimum="2007-01-01" maximum="2007-12-31"/> </tr:inputText> Suppose the server is running in America/Los_Angeles (UTC -8) , but has timezone-id set to "Europe/Stockholm" (UTC+1). When running the demo above, type the value "12/31/2007" and submit - it fails, returning with the error message 'Date should be between 1/1/2007 and 12/31/2007'. Debugging notes: 1. In TagUtils.java, the validator has its value set as "12/31/2007". It uses a simple date format, with timezone set to Europe/Stockholm, to parse it to get 12/31/2007 00:00 (UTC+1) = 12/30/2007 15:00 (UTC-8) . It adds the time maximize logic after the date has been parsed, so in this case it adds 8h 59 min to get 12/30/2007 23:59 (UTC -8) which is equivalent to 12/31/2007 8:59 (UTC +1). 2. When user submits "12/31/2007", the converter does String <-> Date conversion. In the Trinidad DateTimeConverter#getAsObject(), it does the following. _getParsedDate: Creates a SimpleDateFormat with timezone (Europe/Stockholm) and the type/pattern specified. Uses the SimpleDateFormat to parse the string "12/31/2007" - it gets 12/31/2007 00:00 (UTC + 1) The next step is to ensure that time components aren't lost from the value just because the converter doesn't display time (data loss). So: _fillTimePortion: Gets the previous value and creates a Calendar object with timezone Europe/Stockholm based on the time. Suppose the previous value was **** 22:43 (UTC+1) (The date doesn't really matter, it is going to copy the time components in the next step). Copies the time components over to the new time. So, Parsed Time = 12/31/2007 00:00 (UTC + 1) Added Time components = 22 h 43 s Return value = 12/31/2007 22:43 (UTC + 1) 3. Then, when the validator does the comparison, it throws a validation error because it finds value > maximum Value: 12/31/2007 22:43 (UTC + 1) Maximum: 12/31/2007 11:00 (UTC + 1) The clientConvert.jspx example prepopulates the value with the current date-time, so this bug may not be occur when the current time is less than ((difference between timezone param and server timezone offset) - 1), or if everything is running in the same timezone. It demonstrates a bug with the time maximize logic, which should maximize the time before parsing, otherwise it may add less than the range required to make validation pass.
        Hide
        Yee-Wah Lee added a comment -

        Additional fix for trunk which properly sets the timezone first, then maximizes the time components on the parsed date.

        Show
        Yee-Wah Lee added a comment - Additional fix for trunk which properly sets the timezone first, then maximizes the time components on the parsed date.
        Hide
        Yee-Wah Lee added a comment -

        Additional fix for JSF 1.2 (1.2.6.1 branch) which properly sets the timezone first, then maximizes the time components on the parsed date.

        Show
        Yee-Wah Lee added a comment - Additional fix for JSF 1.2 (1.2.6.1 branch) which properly sets the timezone first, then maximizes the time components on the parsed date.

          People

          • Assignee:
            Matthias Weßendorf
            Reporter:
            Thorsten Guenther
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development