In this post, I discuss the problem, as well as two solutions you can choose between: a) finding and changing the incompatible code, or (new since Dec 2020) b) implementing a new JVM arg that Adobe offered to revert this behavior back to how things worked before CF2021. You must do one or the other of these things, if you are affected by this issue. The update does not REVERT the behavior.
Updates since the original Nov 2020 post here
[Update 2, Mar 2021: Adobe now offers the JVM argument (discussed below) as of CF2021 Update 1. As such, if you are on update 1 or above, you need not obtain the special fix jar file discussed below, but you do STILL have to implement the JVM arg--or change your code. The update does NOT alone revert the behavior.]
[Update 1, Dec 2020: the week after I posted this, Adobe created an optional fix for this. See my Dec 2020 post, where they have offered both a special hotfix jar (now included in update 1 and above) and a jvm argument that you can use, if you want to revert CF2021 to treating the "D" datemask format as it had in prior releases. Read on for an explanation of the problem, to appreciate the available solution. In time I'll do a separate post with more on the update.]
TLDR; a simple demo of the problem
Consider this fragment, which could exist in similar form in millions of CFML templates:
See anything wrong? Probably not. It will indeed "work fine" in CF2018 and before, producing 11-24-2020, as most would expect.
But that same code in CF2021 will produces instead 11-329-2020, which virtually no one would expect! Because D now means "day in year". It's a Java-standard datemask, but until now CF didn't complain if you used D. It treated it like d.
And the disaster is that you may have old code that's worked like this for years, but now in CF2021 that code will produce these WRONG RESULTS, which is bad enough if it's just a date shown on a page; but it's catastrophic if that date is then used in code to make decisions, to perform calculations, to store in databases, to pass to other systems, and so on.
And of course it applies if you use 2 D's, as in MM/DD/YYYY, or any variation like DD-MM-YY, and so on. It also applies to lsdateformat, and any functions or tags that take a date mask, such as dateadd, datecompare, dateformat, datediff, dateformat, datepart, datetimeformat, parsedatetime.
So yeah, this seems a huge deal!
What changed, why is this a problem, and what can you or Adobe do? what about Lucee?
What's changed is that a new dateformat mask of D was added (to mean "day in year"). Of course, the lower-case d mask has long existed and meant of course "day in month", as in dateformat(now),"m/d/yyyy".
The problem is that it turns out CF was loose in its enforcement of this casing before, so you got the same "day in the month" with a "d" OR a "D", such as M/D/YYYY. Until CF2021, that is. So what now?
For more, read on where I discuss what you can do, what Adobe might want to consider, and how the same "loose casing" of masks happens in Lucee as well (but Lucee has no D for "day in year", so does not have the "same" problem, yet). I also explain how this D for "day in year" is indeed a Java-standard mask value.
Here's a running example, first at cffiddle.org, where you can change the version to run it either as CF2021, CF2018, or CF2016.
And as an update, since first posting this, I had offered a link at the bottom to run the same code at trycf.com, to see it running on Lucee. But as I had noted then, that site didn't offer CF2021, but I have learned later today that it's being added.
How were we to know?
Again, this was not mentioned in the 500-page beta release notes, nor was it on the what's new page, both of which I discussed in my blog post on, "The many new and improved features in CF2021".
I only found this issue yesterday myself while working with a client, helping him find and understand what was going on, and how things were unexpectedly different.
And while the new mask value of D is indeed documented in the CFML Dateformat reference, it's NOT (currently) indicated there as being something new. I did a comparison with old versions of the docs to discern that it was indeed new. (There's also a new M and Y value, but I have not been able to tell how they differ in their results from the older m and y.)
The Java standard dateformat also supports "D" vs "d"
FWIW, I will note also that the use of the D for "day in year" is not something Adobe just "created out of thin air". It's been in the Java dateformat for years, both per the Java 5 docs (2004 timeframe).
Again, the problem is not so much Adobe supporting such a "standard" dateformat mask--it's that until now, CF ignored the case and so folks have current apps that use "D" but mean (and found that CF acted as if they meant) merely "d". A HUGE difference (which perhaps Java never suffered if back in earlier versions they had not blithely allowed a "D" where only "d" was defined, if there was such a time).
What can you do?
So, that's the problem. Now you know. But what can you do at this point? And what might Adobe want to consider?
First, if you are concerned with or have been hit by this problem, please register a vote here, the ticket I encouraged my client to create, which he did today: https://tracker.adobe.com/#/view/CF-4210921 [Update: again, this is no longer needed. Adobe did solve this.]
Second, you could certainly TRY to search your codebase to find such formatting masks, so as to change any "D" references to "d" instead. [Update: see the next subsection, with some regex's to use in editors to find such masks.]
There are of course ways to use either editors or command line tools or search tools to search for any string in code (my favorite, for Windows, is File Locator Lite), and they can all be told to do a case-sensitive search.
But a challenge here is that there are so many mask variants you may have, such as M-D-Y, MM-DD-YY, MM/DD/YY, DD/MM/YY, and so on. It will be hard to pick a single string to be sure to find ALL such occurrences.
And you can't even try to limit it to references to dateformat, as you may also use dateformat, or still other CFML functions that use formatting masks, such as these (added after the original post): dateadd, datecompare, dateformat, datediff, dateformat, datepart, datetimeformat, and parsedatetime. See the comment to the post, below. And there are also tags that accepts a date mask, like cfinput or cfgridcolumn which both have a mask attribute.
Bottom line: I think it's going to be TOUGH for us to easily find, let alone rectify, any and all occurrences of such use of a capital D in a date mask.
But forewarned is forearmed. Go forth and at least try.
Update: Some regex's to more easily find occurrences of this D in dateformat expressions
Since posting this blog entry, some kind community contributors have come to the rescue with regular expressions that you could use in any of various editors, to find and replace these troublesome dateformat usages. In particular, see comments below, first from Scott Steinbeck and then from Curtis Fraser, as well as the couple of comments before and after each that relate to the use of such regex's in different IDEs/editors. Thanks, guys!
What might Adobe want to consider?
Now, what might Adobe want to do about this?
Of course, it's probably too late to expect Adobe to change this behavior, such as to pick a NEW mask value to refer to "day in year"...but then since CF2021 is so new, perhaps they could.
Or perhaps they could add a switch (in the admin, app-level, or an jvm arg) to allow turning OFF this new D mask, while perhaps also adding a new one. That way those who want to keep the "new" behavior can, but those who don't want to have so many compatibility issues (which may well be major business impacts) can choose to "keep the old way" for some period of time. (And yes, I realize a problem there is that many use such a crutch to then "do nothing"...but it's not like this is some security vulnerability if the "old way" was allowed to remain in perpetuity.)
[Update: Again, in December 2020 they did just that, adding a JVM arg (though you needed to obtain and implement a special fix jar as well). Then in Mar 2021 they incorporated that "fix" into CF2021 Update 1. You do still need to implement the JVM arg if you want to revert the behavior to allow D to act like d. For more, see my Dec 2020 post when the special fix was first released.]
What about Lucee?
For those who may wonder, I'll note that Lucee works the same as CF did BEFORE 2021--it DOES allow and treat "D" the same as "d". And according to the Lucee docs for dateformat, it has no current mask for "day in year".
I'll note also that it too makes no mention of how case is ignored (and none of the masks are capitalized). So whether we can say "Lucee handles things better" seems an open question, but at least they can learn from this debacle and should NOT implement support for a "D", given how they also were loose in allowing a "D" to be left to mean the same as "d".
Finally, if it may interest anyone, here is a gist to run against Lucee the same code from the cffiddle above, using trycf.com.
So, quite a pickle.
What do you think of all this?
For more content like this from Charlie Arehart:
Need more help with problems?
- Signup to get his blog posts by email:
- Follow his blog RSS feed
- View the rest of his blog posts
- View his blog posts on the Adobe CF portal
- If you may prefer direct help, rather than digging around here/elsewhere or via comments, he can help via his online consulting services
- See that page for more on how he can help a) over the web, safely and securely, b) usually very quickly, c) teaching you along the way, and d) with satisfaction guaranteed