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 🙂