A user submitted a form with the datetime "3/9/202...
# cfml-general
d
A user submitted a form with the datetime "3/9/2025 2:45 am". Our pretty robust date validation blew up, because the change to daylight savings means that that hour doesn't exist, causing isDate( "3/9/2025 2:45 am") to crash ACF 2021. Does anyone have a good way to detect that, other than try/catch?
b
Hey Dave, wow that is one of those perfect storm kind of things. Rarely would that happen, but it obviously can happen. Kinda funny in a sense, but not for your server. Yes the date stamp is invalid, but only to local time, not to GMT time. That is probably where the hangup is. Not knowing your servers or database, that is what needs to be sorted out. Maybe allow the system to collect GMT time, then convert it to local.
d
Not going to change all date handling everywhere in a big app for this. Try/catch does work to avoid that crash, but replacing every use of isDate() with a custom function is a bit much, and it turns out it's more complicated than that on a higher level. For reasons I haven't sussed out, when I do that in our validation code, it ends up not crashing, but also not saving the date or rejecting it as invalid. That shouldn't happen of course. Simplest would be if CF didn't blow up in that situation, just returned false, like every other invalid datetime. I should file a bug, and I will, but it won't get fixed in CF2021 anyway. Bleh.
Really I think, our datetime UI shouldn't have shown that hour, since it doesn't exist.
b
Yes true, that is your issue. It depends on where that time value is coming from. If it follows a time schedule with DST, then it should work... in theory. If not, you might have to create a function that does.
d
I was thinking it could use a try/catch test every hour value for the currently selected date, only show the ones that don't error, relace if you change dates. Pretty awkward workaround for a CF bug, but it may be the best I can do.
t
Lucee does not blow up likes ACF2021. But if you use parseDateTime on it Lucee will silently change the value from 2.45am to 3.45am (well, 2.45am is technically 3.45am when DST starts in that hour) Beside try/catch (which is the easiest way), you could do these hard ways too 😅: • Use RegExp to validate • Change Lucee server timezone to UTC temporarily while doing validation (very bad solution, but it is still a solution) • Change CF server timezone to UTC • Switch to Lucee Regardless what to do there is no simple & quick way to address it
d
We do use RegEx and other techniques to validate dates, but this fall through the cracks, because its valid in ever sense except that the hour got skipped in some locales. The flip side of this is that when we "fall back" in the fall, there will be two instances of the hour between 1 and 2, which could lead to a whole other class of weirdness. Ex: How could this half hour long encounter have negative duration? Yuck.
Does CF Docs do something fancy/weird about error handling? Locally on ACF 2021, this code crashes:
Copy code
<cfset result = isDate("3/9/2025 2:45 am")>
<cfoutput>#result#</cfoutput>
Message: Date value passed to date function createDateTime is unspecified or invalid. Detail: Specify a valid date in createDateTime function. But on CF Docs, it shows Yes, for all offered versions of ACF. Why is that? And just to say it, that answer is wrong, it's NOT valid, that hour was skipped that night in this timezone, as noted above. CF Docs result is the same if I don't set the timezone, which defaults to Etc/UTC, or if I set it to America/New_York, which is my local. One possible reason for the isDate() difference is java versions. Locally, server.system.properties.java.version is 11.0.26, which I think is what's spec'd for CF2021 However, on CF Docs it's 1.8.0_292, which I don't understand, not the spec'd version. No idea if that's responsible for the differing isDate() results. I'd appreciate it if some of you could try running that snippet and let me know what happens, and your versions of ColdFusion and java. Thanks.
j
Tested this on ColdFusion (2023 Release) Version 2023.0.12.330713 Java Version 17.0.12 Windows Server 2022 Standard 21H2 FAILS on "3/9/2025 2:45 am" WORKS on "3/8/2025 2:45 am" and "3/10/2025 2:45 am" Adding it in a try/catch with a substitute date does work
<cfloop index="i" from="8" to="10">
<cftry>
<cfset somedate = "3/#i#/2025 2:45 am">
<cfset result = isDate(somedate)>
<cfoutput><p>#datetimeformat(somedate,"long")# --- #result#</p></cfoutput>
<cfcatch type = "any">
<cfset somedate = now()>
<cfset result = isDate(somedate)>
<cfoutput><p>#datetimeformat(somedate,"long")# --- #result#</p></cfoutput>
</cfcatch>
</cftry>
</cfloop>
Looking at the "long" output, the date/time goes from EST to EDT. Not really sure how to address that, though.
👍 1
m
on cfdocs, isdate() behaves differently if you pass it a string vs if you give it a variable set to that string.
j
OK, minor update to rule that out and not pass in a var and just a string yields same results:
<cfloop index="i" from="8" to="10">
<cftry>
<cfset result = isDate("3/#i#/2025 2:45 am")>
<cfoutput><p>#datetimeformat('3/#i#/2025 2:45 am',"long")# --- #result#</p></cfoutput>
<cfcatch type = "any">
<cfset result = isDate("#now()#")>
<cfoutput><p>#datetimeformat("#now()#","long")# --- #result#</p></cfoutput>
</cfcatch>
</cftry>
</cfloop>
b
Hey Jim, all good, but it doesn't solve the underlying issue. As mentioned, the date is invalid but only for local, not GMT. Best practice is to collect time as GMT, then convert to local. But if you can't, then use a function with a schedule... If date is x, and time between y and z, then do this. Otherwise, I don't think there is a silver bullet here. For example, MySQL gives you the ability to load a time zone table, but with CF, you have to do it yourself. That is one reason we use MySQL for all our time collections, and not CF.
j
Gotcha. It would need some conversion along the way.
d
I still don't understand the isDate() difference between CF Docs and my local, or why CF Docs has the java version it does. Am I missing something obvious?
m
I'd guess he's running java 8 because he also supports versions back to 10
d
Fair guess. Do we think that's the reason why isDate() works there and not on my local?
t
@Dave Merrill cfdocs will throw error for CF2021 & CF2023 as well. How did you test it on cfdocs that it didn't throw error? Maybe share a screenshot?
oh, so @Matt Jones has already pointed out.
on cfdocs, isdate() behaves differently if you pass it a string vs if you give it a variable set to that string.
This is a weird behaviour for CF...
s
Am I being too facile by just saying you should return a message if they don't put it in properly 😂
We have a couple of clients that report bugs of that ilk and we just reply with telling them to input it as dd/mm/(yy)yy
There's also the option to just split the date and time
We've done that in a couple of places too. A field for the date a field for the time and underneath join them with the jvm / createodbctime
Date and time fields are one of the niche instances where I do my best to be strict with the users
Even your allowing them to put am/pm is more generous than me
m
@salted format wasn't the issue at all in this scenario. The problem arose because it was daylight saving time for that timezone which shifted the clock forward an hour making the time not valid to use in any createdatetime type statement with acf. isdate and isvalid date both apply the createdatetime to the string. lucee appears to automatically correct in these cases (moves the value forward an hour), acf doesn't. one of my apps had a break also, same issue slightly different scenario, it has a nightly restart (scheduled, but a schedule i cannot adjust), the users wanted a message warning them/counting down to it, etc.
maintenanceTime = createDateTime( year(now()), month(now()), day(now()), 2, 55, 0 )
works every day of the year except when that time lands during the lost hour as the clock springs forward.
👍 1
s
Interesting
d
@Matt Jones Yes this exactly.
@bdw429s @zackster Can you tell me the logic Lucee uses to not get caught out by this? Maybe it could be applied in ACF code. Side note: I still don't get why CF Docs returns YES for isDate("3/9/2025 2:45 am") on the same CF engine that blows up for me and I think @Matt Jones.
z
there's been a lot of changes with date handling in newer java releases and Lucee 6.2 • one of the main pain points was switching the character between 6:30 AM from a space to a non breaking space in java • Lucee 6.2.1 had a major refactor to how we approach all this • switching to java.time.format.DateTimeFormatter https://luceeserver.atlassian.net/browse/LDEV-5115 • moving to an exceptionless approach when testing formats, we do some testing to see which potential date masks could match • keeping track of which date formats your code is using and trying the first (not AI, just being clever) I created lucee testlab which runs a series of micro benchmarks against different lucee and java versions (see why upgrading to 6.2 is worth it? 🙂 ) https://github.com/lucee/lucee-testlab/actions/runs/13816547334/attempts/1#summary-38652477672
❤️ 4
🚀 4
👍 1
of course we had some problems too with 6.2.0.321, already fixed in the upcoming 6.2.1 https://luceeserver.atlassian.net/browse/LDEV-5278
d
Cool stuff, excellent work, definitely moving things forward. Outside of CF Docs, what does Lucee return for isDate("3/9/2025 2:45 am")? If it doesn't blow up, why? Is it because of the newer java version? Use of java.time.format.DateTimeFormatter instead of createDateTime()?
z
it really depends what adobe are doing in their closed source code! https://trycf.com/gist/7cc5eaf8c4d83329c8226032cde211f2/lucee6?theme=monokai
d
TryCF with ACF 2021 says isDate("3/9/2025 2:45 am") is YES, like CF Docs, but it blows up in real life. (Note again that that's actually wrong, that hour didn't exist, but it didn't crash.) There's something different about how these multi-engine sites handle this. Can you do me a favor and try that on raw Lucee and see what you get? We're all ACF here.
z
what do you mean by raw lucee? there's going to be no difference between trycf and local? the stacktrace from ACF will tell you something about their approach
image.png
b
That date might not have existed in specific time zones but it definitely existed...
d
"there's going to be no difference between trycf and local" -- That's not what I see. TryCF and CF Docs both return YES from that on ACF 2021 and 2023, and don't crash. However, both @Matt Jones and I see it crashing in our local dev environments, and I originally started looking at this when it blew up in production, ACF 2021. I'm interested in how Lucee avoids crashing. I don't want to actually port that approach to ACF code though, because the result is wrong.
z
oh, i'm not american so i just quick read that date an australian, now i see
🤦 1
d
@brettpr You're right that this issue only happens in timezones that switched to daylight savings time at 2am 3/9/2025, which US Eastern Time did. That could be why we're seeing different results than TryCF and CF Docs. However, I tried calling setTimezone("America/New_York") first, not change still no crash on either of those sites, so I don't get it.
z
"there's going to be no difference between trycf and local" for ACF ? I was referring to Lucee
t
@Dave Merrill just to be sure, below WILL blow up in tryCF for ACF 2021 & 2023
Copy code
setTimezone("America/New_York")
test = "3/9/2025 2:45 am"
isDate(test)
But this will NOT blow up in tryCF for ACF 2021 & 2023
Copy code
setTimezone("America/New_York")
isDate("3/9/2025 2:45 am")
So for your local, you got the 1st test above error out in your local? Or the 2nd test above error out in local?
d
I filed this same bug last year. It's listed as Withdrawn, which is BS. That ticket refers to another issue, also "Withdrawn", which says they've updated the docs. What?!? This isn't a documentation issue. I added a comment there about this. Maybe it's that daylight savings time isn't a thing in India, so this bug effectively doesn't exist for the CF team. Really annoying, especially the fake "Withdrawn" status. They really shouldn't do do that, at least own up to it and mark it as Won't Fix, For Some Reason. @Mark Takata (Adobe)
👍 1
m
@priyank_adobe can you please refer to this bug and let me know what the reason was for withdrawal?
❤️ 1
p
Let me check
d
@priyank_adobe Even better, fix the bug!!!