Today we are going to add a custom Date parsing routine to the JQueryUI Date Picker so it automagically parses dates in a variety of formats.
Back in August of 2020, I wrote an article showing you how to incorporate the JQueryUI Date Picker into your WebDev applications. If you have read that article be sure to read it first, as this article will just cover extending the functionality.
I ended that article with a suggestion that it should be possible to write your own date parsing function and integrate that with the Data Picker to have a WEBDEV date control that would be better than sliced garlic cheese bread.
Well no one took up the mantle, or if they did they didn’t share the results with me. Today we had a client that really needed their date controls to feature the parsing logic, so now we have it!
First the Date Parsing Logic, it has to be browser based code, and we could like it to be able to accept dates in almost any format you could dream up, and return the date in standard YYYYMMDD format. It needs to support both Day/Month/Year and Month/Day/Year formats, and it needs to intelligently convert 2 digit years to 4 digits
Here is a trace log from my testing procedure, as you can see that is a lot of formats it handled. The function has two flags. DayFirst tells the logic to expect the date with the day first. You can see there are separate testing sections for each. The other flag is NoFutureDate, which tells the logic to assume the date is always in the past, for example, birth date fields. This affects the rollover logic for two digit years, notice 01/16/24 returns 2024 with this option off, but 1924 with it on. The rollover logic without the NoFutureDate flag assumes anything within 20 years into the future is a future date, otherwise it is a past date.
This function is actually quite long by WEBDEV standards at 133 lines but it is doing quite a bit in those 133 lines. I won’t go into detail on the logic as it isn’t the point of this article but hopefully, you can follow it, if you have any questions just let me know
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 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
Fortunately using the function is much more straightforward, in the exit with changes browser event of the edit control we have attached to the date picker we place this code
tmpHold is string = edtDemoDateDisplay edtDemoDateDisplay = DateToString(edtDemoDate,"MM/DD/YYYY") IF tmpHold <> edtDemoDateDisplay THEN // They keyed in the date instead of using the date picker //edtDemoDate = ParseDate(tmpHold,True,false) // No future dates - handles 2 digit year rollovers as being in the past - i.e. 010124 will be 1924 not 2024 - Good for Birthdays edtDemoDate = ParseDate(tmpHold,False,False) // with future dates - handles 2 digit year rollovers as being in the future if within 20 years - i.e. 010124 will be 2024 not 1924, but 010154 will be 1954 edtDemoDateDisplay = DateToString(edtDemoDate,"MM/DD/YYYY") END
tmpHold saves what is in the edit control
Next, we format the value in our hiddle control that is populated via the Date Pickers altField option. This value is in YYYYMMDDD so WEBDEV can handle it as a date variable
If they selected a date from the calendar then tmpHold and edtDemoDate will have the same value and we are done, if not, then we use the ParseDate function to populate our hidden control based on what the user typed into edtDemoDateDisplay. Note there are two sample calls, depending on if this field is likely to have future dates or not.
And now we have date control that is attractive and allows the user to select a date from a very functional calendar, or key the date in almost any imaginable format.
I have a sample page showing this control published at demo.wxperts.com if you would like to see it in action.
You can also download our wxDemov27 program from Dropbox which contains this demo page and code.
One thought on “Adding a Custom Date Parser to jQueryUI’s Date Picker”