Opened 5 years ago

Last modified 2 years ago

#18339 new defect

Dijit/form/DateTextBox validation wrong on dates 01/01/1992, ... 01/01/2014

Reported by: geaden Owned by:
Priority: high Milestone: 1.14
Component: Dijit - Form Version: 1.10.2
Keywords: Cc:
Blocked By: Blocking:

Description

After entering date like 01/01/1992 DateTextBox? widget wrongly validates date as incorrect.

The behavior easily reproduced here:

http://dojotoolkit.org/reference-guide/1.10/dijit/form/DateTextBox.html

(just run first example and enter "wrong" date)

It seems every 12 years validation fails.

On clients timezone is GMT+3.

Attachments (1)

dijit_form_DateTextBox — The Dojo Toolkit - Reference Guide - Google Chrome 2014-10-27 13.56.48.png (9.8 KB) - added by geaden 5 years ago.
Wron date validation on 01.01.1992

Download all attachments as: .zip

Change History (9)

comment:1 Changed 5 years ago by geaden

A little amendment: validation fails every 11 years, 1992, 2003, 2014, etc.

comment:2 Changed 5 years ago by dylan

Milestone: tbd1.11
Priority: undecidedhigh

comment:3 Changed 5 years ago by geaden

Hello. The problem is related to Javascript itself (or even maybe to ES5 standard). According to dijit/form/ValidationTextBox.js (https://github.com/dojo/dijit/blob/master/form/ValidationTextBox.js#L111) method validator is invoked to check whether input value is correct. Inside validator called method this.parse(value, constraints) where this.parse for DateTimeBox? is dojo/date/locale.js(https://github.com/dojo/dojo/blob/master/date/locale.js#L294) After debugging it turned out the following condition

if(!valid ||                                                           
		(monthToken && dateObject.getMonth() > result[1]) ||                  
		(dateToken && dateObject.getDate() > result[2])){                     
		return null;                                                          
	}  

is always true for dates 01/01/1992, 01/01/2003, 01/01/2014, etc. In particular dateObject.getMonth() > result[1] is true and dateObject. getDate() > result[2] is true. I created sandbox method that behaves similiarly and run it in FireFox? javascript console.

Here is a sample code:

                                                                        
function isValid(dateObject, dateArray) {                               
    return !(dateObject.getMonth() > dateArray[1] || dateObject.        
getDate() > dateArray[2]);                                              
                                                                        
}                                                                       
                                                                        
var year = 1970;                                                        
                                                                        
while(year < 2100) {                                                    
  var dateArray = [year, 0, 1];                                         
  var dateObject = new Date(dateArray[0], dateArray[1], dateArray[2]);  
  if (!isValid(dateObject, dateArray)) {                                
     console.log('01/01/' + year + ' invalid; ' + dateObject);          
  }                                                                     
  year++;                                                               
                                                                        
} 

The output is: 01/01/1975 invalid; Tue Dec 31 1974 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/1986 invalid; Tue Dec 31 1985 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/1992 invalid; Tue Dec 31 1991 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/1997 invalid; Tue Dec 31 1996 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/2003 invalid; Tue Dec 31 2002 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/2014 invalid; Tue Dec 31 2013 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/2020 invalid; Tue Dec 31 2019 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/2025 invalid; Tue Dec 31 2024 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/2031 invalid; Tue Dec 31 2030 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/2042 invalid; Tue Dec 31 2041 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/2048 invalid; Tue Dec 31 2047 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/2053 invalid; Tue Dec 31 2052 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/2059 invalid; Tue Dec 31 2058 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/2070 invalid; Tue Dec 31 2069 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/2076 invalid; Tue Dec 31 2075 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/2081 invalid; Tue Dec 31 2080 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/2087 invalid; Tue Dec 31 2086 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) 01/01/2098 invalid; Tue Dec 31 2097 23:00:00 GMT+0300 (Russia TZ 2 Standard Time) This is a list of dates that are wrongly validated by DateTimeBox? widget. It turned out that it's impossible to get the beginning of the year exactly at midnight for these years. For other years we have something like: Thu Jan 01 2015 00:00:00 GMT+0300 (Russia TZ 2 Standard Time)

The problem is not reproducible in Chrome anymore, but in Firefox and IE is still present.

Last edited 5 years ago by geaden (previous) (diff)

comment:4 Changed 4 years ago by bill

Hmm, I'm not sure how to fix it.

comment:5 Changed 4 years ago by geaden

Please note that this issue was also found here https://code.google.com/p/chromium/issues/detail?id=417640 and here https://bugzilla.mozilla.org/show_bug.cgi?id=1079720#c15.

We resolved this issue by patching locale.parse. But it seems it's not reproduceble anymore (I suppose new fix from Microsoft resolved it, but I confused to say which one)

this.adjustDate = function(/* Date */ dateObj) {
  // ---- #18339 issue with previous date
    // Prevent date to go back due to daytime saving
    // Otherwise locale parse fails and we have validation error.
    // Adjust date according to provided value and current time zone
    //console.log('date to adjust=', dateObj);
    if (dateObj === null || dateObj === undefined) {
      return dateObj;
    }
    var adjDate = new Date(dateObj.getTime() + Math.abs(dateObj.getTimezoneOffset() * 60 * 1000));
    // Check if date is broken
    // If not return provided date
    if (adjDate.getMonth() >= dateObj.getMonth() &&
        adjDate.getDate() >= dateObj.getDate()) {
      //console.log('Date not adjusted ', dateObj);
        dateObj.setHours(12, 0, 0);
        return dateObj;
    }
    // We can't have midnight on provided date to keep the right date
    // So set to the middle of date    
    adjDate.setHours(12, 0, 0);
    //console.log('Date adjusted', adjDate);
    return adjDate;

}

var self = this;

locale.parse = function(value, options) {
    // summary:
    //      Convert a properly formatted string to a primitive Date object,
    //      using locale-specific settings.
    //
    // description:
    //      Create a Date object from a string using a known localized pattern.
    //      By default, this method parses looking for both date and time in the string.
    //      Formatting patterns are chosen appropriate to the locale.  Different
    //      formatting lengths may be chosen, with "full" used by default.
    //      Custom patterns may be used or registered with translations using
    //      the dojo/da

comment:6 Changed 4 years ago by dylan

Milestone: 1.111.12

Ok, after massive triage, ended up with about 80 tickets for 1.11 and 400 or so for 1.12. That's a bit unrealistic, so first I changed all 1.12 to 1.13 (with the plan to move some forward to the new 1.12. Now, I'm moving some of the 1.11 tickets that are less likely to get done this month without help to 1.11. Feel free to help out in January if you want to see this ticket land in 1.11.

comment:7 Changed 3 years ago by dylan

Milestone: 1.121.13

Ticket planning... move current 1.12 tickets out to 1.13 that likely won't get fixed in 1.12.

comment:8 Changed 2 years ago by dylan

Milestone: 1.131.14
Note: See TracTickets for help on using tickets.