Last Week I wrote about a custom date parser procedure that could be used along with jQueryUI’s DatePicker, and I said it could handle pretty much any date format you could throw at it. Well turns out it couldn’t … but now it can!
If none of this is making any sense to you be sure to read Adding a Custom Date Parser to jQueryUI’s Date Picker and WEBDEV Date Entry got you down? Try jQuery UI DatePicker instead first!
Shortly after the code made contact with the enemy, I mean the users started using it, a new request came in. They want to be able to just key in the day and it assume the rest of the date. So a few tweaks to the ParseDate function and one change to the setDatePickerDefaults and we now have a few more formats it can handle.
Here is the trace window for those formats
So if you pass in 1 or 2 digits it is going to assume that you are passing in a day. Next depending on whether the NoFutureDate flag is on or not it will assume any day less than today is either earlier this month or next month. For example, today is January 20th, so when I pass 5 with NoFutureDate = false, it returns 20230205, it assumed next month. However with NoFutureDate = true it returns 20230105.
As a bonus, it now also accepts a letter t (for today) and will return today’s date.
Here is the updated ParseDate Function. Lines 51-90 is where the new magic happens
PROCEDURE ParseDate(LOCAL inDate is string ,LOCAL NofutureDate is boolean=False,DayFirst is boolean = False) IF inDate = "" THEN RESULT "" END inDate = NoSpace(inDate) tmpdate is Date IF DateValid(inDate) THEN // Passed in YYYYMMDD format so just format it tmpdate = inDate ELSE FirstPart is string SecondPart is string ThirdPart is string arrMonth is array of 12 strings tmpdate = "19990101" FOR x = 1 TO 12 arrMonth[x] = Replace(DateToString(tmpdate,"MMM"),".","") tmpdate..Month++ END IF Position(inDate,"/") > 0 OR Position(inDate,".") > 0 OR Position(inDate,"-") > 0 OR Position(inDate," ") > 0 THEN // If there is a separator parse into 3 fields FirstPart = ExtractString(inDate,1,["/",".","-"," "]) SecondPart = ExtractString(inDate,2,["/",".","-"," "]) ThirdPart = ExtractString(inDate,3,["/",".","-"," "]) // Need to figure out if they entered month abbreviation, and convert to # tmpMonth is string IF DayFirst THEN tmpMonth = SecondPart ELSE tmpMonth = FirstPart END IF Length(tmpMonth) > 2 THEN tmpMonthNo is int = ArraySeek(arrMonth,asLinearFirst+tccIgnoreCase,tmpMonth) IF tmpMonthNo > 0 THEN tmpMonth = NumToString(tmpMonthNo,"02d") END IF DayFirst THEN SecondPart = tmpMonth ELSE FirstPart = tmpMonth END END ELSE // No separator parse into 3 fields based on length SWITCH Length(inDate) CASE 1,2 tmpdate = Today() IF Upper(inDate) = "T" THEN IF DayFirst THEN FirstPart = tmpdate..Day SecondPart = CurrentMonth() ELSE FirstPart = CurrentMonth() SecondPart = tmpdate..Day END ThirdPart = CurrentYear() ELSE IF DayFirst THEN FirstPart = inDate SecondPart = CurrentMonth() ELSE FirstPart = CurrentMonth() SecondPart = inDate END ThirdPart = CurrentYear() END IF NOT NofutureDate THEN IF DayFirst THEN IF Val(FirstPart) < tmpdate.Day THEN SecondPart = Val(SecondPart) + 1 IF SecondPart > 12 THEN SecondPart = 1 ThirdPart = Val(ThirdPart) + 1 END END ELSE IF Val(SecondPart) < tmpdate.Day THEN FirstPart = Val(FirstPart) + 1 IF FirstPart > 12 THEN FirstPart = 1 ThirdPart = Val(ThirdPart) + 1 END END END END CASE 4 // No Year - Assume current FirstPart = inDate[[1 TO 2]] SecondPart = inDate[[3 TO 4]] ThirdPart = CurrentYear() CASE 6 // 2 digit year FirstPart = inDate[[1 TO 2]] SecondPart = inDate[[3 TO 4]] ThirdPart = inDate[[5 TO 6]] CASE 8 // 4 digit year FirstPart = inDate[[1 TO 2]] SecondPart = inDate[[3 TO 4]] ThirdPart = inDate[[5 TO 8]] END END IF ThirdPart = EOT THEN ThirdPart = "" END // Build Date - Assume current year for now tmpdate = Today() //tmpdate..Year = CurrentYear() IF DayFirst THEN IF SecondPart > 0 AND SecondPart < 13 THEN tmpdate..Month = SecondPart ELSE RESULT "" END IF FirstPart > 0 AND FirstPart < 32 THEN tmpdate..Day = FirstPart ELSE RESULT "" END ELSE IF FirstPart > 0 AND FirstPart < 13 THEN tmpdate..Month = FirstPart ELSE RESULT "" END IF SecondPart > 0 AND SecondPart < 32 THEN tmpdate..Day = SecondPart ELSE RESULT "" END END // Now we need to figure out the century for the year SWITCH Length(ThirdPart) CASE 2 tmpYear is string = CurrentYear() tmpCentry is string = Left(tmpYear,2) tmpYear = Right(tmpYear,2) IF Val(ThirdPart) > Val(tmpYear) + 20 THEN // if more than 20 years in future assume its a past date ThirdPart = NumToString(Val(tmpCentry)-1,"02d") + ThirdPart ELSE ThirdPart = NumToString(Val(tmpCentry),"02d") + ThirdPart END tmpdate..Year = ThirdPart IF NofutureDate AND tmpdate > Today() THEN // if NofutureDate (DOB) assume its a past date tmpdate..Year -= 100 ELSE ThirdPart = NumToString(Val(tmpCentry),"02d") + ThirdPart END CASE 4 tmpdate..Year = ThirdPart CASE 0 tmpdate..Year = CurrentYear() OTHER CASE RESULT "" END END // Return results IF DateValid(tmpdate) THEN RESULT tmpdate ELSE RESULT "" END
One other tweak that has to be made if you want to support the t = today option, is to tell jQueryUI to not restrict the input to just characters allowed by the current format. You do that by adding the following line to the setDatePickerDefaults procedure
dpobj.constrainInput = False
I have published an update of the demo project to http://demo.wxperts.com/ and you can also download an updated version of the project from dropbox here
Now let’s see how long this version survives contact with the enemy 🙂