Adding a Custom Date Parser to jQueryUI’s Date Picker

Adding a Custom Date Parser to jQueryUI’s Date Picker

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

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s