Wednesday 29 January 2014

Enhancement suggestion for parseDateTime()

G'day:
A quick one. parseDateTime() is used for taking a string and trying to convert it into a date object (as reflected by the date represented by the string).  It does a pretty shocking job of it, as demonstrated by the following code:



// parseDateTime.cfm
isoDates = [
    "1997",
    "1997-07",
    "1997-07-16",
    "1997-07-16T19:20+01:00",
    "1997-07-16T19:20:30+01:00",
    "1997-07-16T19:20:30.45+01:00"
];
for (isoDate in isoDates){
    try {
        d = parseDateTime(isoDate);
        writeOutput("isoDate: #isoDate# => #dateTimeFormat(d, 'yyyy-mm-dd HH:nn:ss.lll')#<br>");
    } catch (any e){
        writeOutput("#e.type#: #e.message# #e.detail#<br>");
    }
}

Those are all valid ISO dates ("Date and Time Formats", see "formats"), so anything that parses a string containing a date(/time) should accept them.

This is how well ColdFusion deals with these:

Expression: 1997 is an invalid date or time string.
isoDate: 1997-07 => 1997-07-01 00:00:00.000
isoDate: 1997-07-16 => 1997-07-16 00:00:00.000
Expression: 1997-07-16T19:20+01:00 is an invalid date or time string.
Expression: 1997-07-16T19:20:30+01:00 is an invalid date or time string.
Expression: 1997-07-16T19:20:30.45+01:00 is an invalid date or time string.

Not a great hit rate.

Railo does better:

isoDate: 1997 => 1905-06-19 00:00:00.000 
isoDate: 1997-07 => 1997-07-01 00:00:00.000
isoDate: 1997-07-16 => 1997-07-16 00:00:00.000
isoDate: 1997-07-16T19:20+01:00 => 1997-07-16 19:20:00.000
isoDate: 1997-07-16T19:20:30+01:00 => 1997-07-16 19:20:30.000
isoDate: 1997-07-16T19:20:30.45+01:00 => 1997-07-16 19:20:30.045


It seems to be seeing "1997" as a number of days, which does not make sense in this context.

Now I know parseDateTime() is documented as working like this:
Parses a date/time string according to the English (U.S.) locale conventions.
But a function which parses date strings should at a minimum accept ISO-formatted date strings.

Anyway, we are where we are with the current state of affairs. However I think we can improve this.

parseDateTime() could be enhanced to take a mask string, so that it can understand any format, provided it can be given a guide as to which parts represent which in the string.  eg:

d = parseDateTime("1997-07-16T19:20:30+01:00", "yyyy-mm-ddTHH:nn:ssX");
d = parseDateTime("2000AD", "yyyyG"); // sic

(format mask codes taken from "java.text.SimpleDateFormat")

What do you think?

At the very least I'll make sure there's a bug raised for the bits in red (ColdFusion: 3700851; Railo: RAILO-2881), above.

Adam Tuttle...

... guilt tripped me into raising the E/R for the format masking thing right now. So it's done.

--
Adam