More Enhancements to the Browser Date Parser

More Enhancements to the Browser Date Parser

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 🙂

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 )

Twitter picture

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

Facebook photo

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

Connecting to %s