Breaking change in CF2021, new date format mask of D may be serious problem for old code
Note: This blog post is from 2020. Some content may be outdated--though not necessarily. Same with links and subsequent comments from myself or others. Corrections are welcome, in the comments. And I may revise the content as necessary.(I've revised this post since its original writing, the week after CF2021 came out. I've tried to help it make better sense for those reading it in the years to follow, as it will affect us in future releases as well.)
It turns out that with the release of CF2021, Adobe introduced a breaking change...if you use any of the CF tags or functions that use date formatting masks. The problem is that while a capital "D" value used in such mask used to simply mean the same as a lower-case "d" ("day of month"), the change in CF2021 is that "D" now means instead "day of YEAR"! That can be a devastating problem that might lurk for days or weeks, corrupting your data.
TLDR; You have two solutions:
- you can choose either find and change the affected code (not easy but using techniques shared below)
- or you can implement a new JVM arg that Adobe offers to revert this behavior back to how things worked before CF2021 (discussed below), which still applies in CF2023 and beyond
If you're affected, you must do one or the other of these things. For more, read on.
The sections below include:
- The new JVM argument, and how to implement it...carefully
- What changed, why is this a problem? (with examples)
- This change affects more than just the dateformat function
- Finding the code, to change it instead
- How were we to know?
The new JVM argument, and how to implement it...carefully
Adobe solved this problem by offering the option to use a new JVM argument to revert this change of behavior:
You can add that (carefully) either of two ways.
Adding it using the CF Admin
One way to implement that change is to use the CF Admin's "java and jvm" page, to edit its "java arguments" field, where you could just add it at the end of what's already there separating it with a space from what's there (do NOT put it on its own new line). If you do that, you will be told you must restart CF for that to take effect. If CF does not start, see the next section.
Adding it to CF's jvm.config file
The other option to add that arg is to instead edit CF's jvm.config file (found in CF's cfusion/bin folder, or [instancename]/bin if you run multiple instances). Before changing it, you would be wise to save a copy of it.
(And note that changes made on that CF Admin page above are actually saved into that file for you. If you make a mistake there and CF won't start, then you will HAVE to edit the jvm.config file to correct your mistake.)
Edit the file and find its java.args line (if it has a # in front of it, that version of the line is a commented-out one). Again, add the new arg above to the end of whatever is on that line--separating it from any other args with a space and being careful NOT to put it on its own new line. Save the file but keep it open.
Then restart CF. Since CF won't start if you make any mistake, review the change you made, or consider using your editor's undo feature, or revert to the file backup I recommended you make.
You should now find that your use of D in date format functions again means "day of month".
When the JVM arg was introduced
FWIW, Adobe first added this via a special hotfix in Dec 2020, as I blogged about then, a week after this original post. That had offered a special hotfix jar which enabled the ability to set that JVM arg.
Then CF2021 Update 1 made the JVM argument option a permanently available one. Again, it's still needed (and still works) in CF2023 and later.
(To be clear, Adobe never did NOT revert the behavior for you: you must use this JVM arg to do it--again even in later CF versions--or you can choose to try the other option of trying to find the code that needs to change, as discussed below.)
What changed, why is this a problem? (with examples)
Let's start with just 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 would 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 again 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.
This change affects more than just the dateformat function
Note also that this issue applies not only to dateformat but several related CFML functions with "date formatting": not only lsdateformat (locale-specific dateformatting) but also any of many functions which TAKE a date mask, such as dateadd, datecompare, dateformat, datediff, dateformat, datepart, datetimeformat, parsedatetime. And there are also tags that accepts a date mask, like cfinput or cfgridcolumn which both have a mask attribute.
So yeah, this is a huge deal for some.
A "live" example you can run
Here's a running example, first at cffiddle.org, where you can change the version to run it either as CF2021, CF2018, or CF2016.
Here also is a link to run the same code at trycf.com.
Finding the code, to change it instead
So, that's the problem. And if you don't want want to rely on that new JVM arg, you might want to instead look for and change the affected code. That's not so easy as it may seem at first.
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, not to mention those multiple functions that are affected. It would be impossible to pick any single normal string to be sure to find ALL such occurrences.
But here's great news: since posting this blog entry, some kind community contributors have come to the rescue (in the comments below) 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!
So with those two solutions covered, let me continue with some of the original content I'd written.
How were we to know?
Sadly, this change 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 (this was eventually corrected, indeed with it pointing to this very post of mine).
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 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.
Conclusion
This was quite a significant change. At least there are the two broad solutions, as well as this explanation of "wha' happened?" Hope that's helpful, for years to come.
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





dateadd, datecompare, dateformat, datediff, dateformat, datepart, datetimeformat, parsedatetime
And I found these tags: cfinput and its mask attribute, cfgridcolumn and its mask attribute
Of course, we can decry people using such UI tags, and it's not clear if their masks are affected by this change, but I'm noting them for the sake of completeness.
And Brad Wood wondered about a regex to help people find such mask use and Scott also started working on one, including to handle the variants above. He will hopefully post here if he comes up with one. Thanks, Scott!
Or if anyone else is up to the challenge, feel free. :-)
More to the point, if you look at the cffiddle.org link, you can actually RUN the code against CF2021 AND CF2018 AND CF2016, and the problem happens ONLY in CF2021.
But I just noticed that somehow the link didn't make it in. I have corrected that, now under the new "Running Example" section near the top.
However, I believe there are some typos in your sample code.
This should be better:
https://cffiddle.org...
But again, the crux of the article--and what's demonstrated in that code, whether changed as you have it or not--was about the D (or DD), and the surprising change in CF2021.
And more important is the matter that in prior releases, the D or DD was treated the same as d, and now no longer is.
But I appreciate that you were trying to help. Make sense now?
When I looked to the output, it made no real sense, because the "description" in front does not match the executed code.
dateformat("11-23-20","MM-DD-YY"): 11-328-2020
dateformat("11-23-20","MM-DD-YY"): 11-328-20
dateformat("11-23-20","MM-DD-YY"): 11-23-20
dateformat("11-23-20","MM-DD-YY"): 11-328-2020
That's why I changed it to :
dateformat("11-23-20","M-D-Y"): 11-328-2020
dateformat("11-23-20","MM-DD-YY"): 11-328-20
dateformat("11-23-20","m-d-y"): 11-23-2020
dateformat("11-23-20","M-D-Y"): 11-328-2020
Where the output matches the description in front.
But, I could be wrong of course.
As Ashish mentioned, to cater to the requirement of those users who would want the behavior of D to be similar to what was there in earlier versions, we will be introducing a new flag. We already have a fix ready and are currently testing it. We are also working on updating the documentation to call out this change.
Thank you for flagging this. As discussed, we've provided a fix, the details of which are documented in the following.
1. https://helpx.adobe.... (also contains the hotfix location and installation details)
2. DateFormat- https://helpx.adobe.... (The history section has been updated)
3. New and changed functions in CF 2021- https://helpx.adobe....
Once again, a ton of thanks for your continuous help and support.
Thanks,
Saurav
A couple of things, though: while I highlighted the issue with D vs d, there would seem to be potential for issues with the other case-sensitive variants (Y vs y and M vs m). I would have thought the fix would have been to control case-sensitivity of masks rather than just about the D alone. Or do you have info from the engineers to suggest that's not an issue?
As for the DateFormat reference page, I see the history indicating this new JVM arg. I don't see it indicating that the D was added. I know some people are saying that this is not NEW in CF2021, but I really thought it was--or else we would have seen this problem sooner. Anyway, can you get someone to clarify WHEN it was added (and if it was removed and added back, perhaps), and get THAT indicated in the history? Same for Y and M.
Finally, you may want to get mention of this added to this doc:
https://helpx.adobe....
5974 lines w/ DateFormat
3648 of those with DD instead of dd.
Soo... thanks for being on top of this :-/
And did you happen to catch the comment from Adobe above, that they had addressed the problem with a new update? While all that code WOULD have failed, it need not if you apply the hotfix and JVM arg change.
I'll update this post to clarify that available fix and point to the Adobe comment, and then I plan to do a blog post also to help make the available resolution standout (and I will point to that here at the top of this post).
the regex pattern I have created is here:
((?<=l?s?(dateformat|datetimeformat)).+[DY]+[^\)]+)
This uses regex lookbehind to check for the existence of a D or Y in the dateformat/datetimeformat/lsdateformat/lsdatetimeformat functions.
should work both in script and tags
https://trycf.com/gi...
While your demonstration of the use of the java regex pattern matcher is interesting, and the 40k test cases compelling, can you help clarify how you'd see people using it to find and address the problem in their code? :-) That was your original intent, right?
It's just that I found issues with the more common ways I'd expect people might try to use it:
- when I used the regex (in your comment) in vsCode or CFBuilder, it matched all the dateformat examples above, whether using the upper or lowercase D (of course, using the setting in the Find to search on a regex). So that's curious.
- when I tried to use it in notepad++, its regex search flat said it was an invalid regex
- and even when I tried it in an refind function, it got "Malformed regular expression" and "Sequence (?<...) not recognized." Here's a gist of that:
https://trycf.com/gi... (which failed in all the CF versions or Lucee)
I tried the last example both to see if the CF regex engine would be different, and in case someone somehow might want to try to do such a scan of their code using CFML but maybe would not be allowed to do the createobject/cfobject to pull in the java regexer.
But of course it would seem the biggest concern is what I experienced in the editors. I tried to do a little digging to see if I could get it to work but I had to give up and wanted to get this comment out for you or others to consider.
Again, I do appreciate that you're wanting to help folks get a regex to help find code that would be troubled by this issue, especially if they can't use the new Adobe-provided JVM arg "fix".
Thanks, and looking forward to any thoughts.
I imagine the reason its failing in vscode and notepad++ would be due to parts of the regex expression not being recognized by their respective regex engine.
the tricky bit is the (?<... portion which is a 'lookbehind'). I can follow up with a compliant regex that would work for vs code, ill try notepad++ as well if it supports a different form of lookbehind. This part is required because otherwise, I can't confirm that the date mask is actually a part of the ColdFusion function dateformat.
Here is the link https://trycf.com/gi...
Here is the regex:
l?s?(dateformat|datetimeformat)(.*?)[''"](.*?)[DY]{1,10}(.*?)[''"]
Pattern Breakdown:
- l?s?(dateformat|datetimeformat) --> find lsdateformat, lsdatetimeformat, dateformat, datetimeformat
- (.*?)[''"] --> lazy search until you find a single or double qoute
- (.*?)[DY]{1,10} --> lazy search until you can find a string containing between 1 - 10 characters of D and or Y
- (.*?)[''"] --> lazy search until you find a single or double qoute
And as you say, if using either editor, we DO have to tick the option to make the find be case-sensitive. That may surprise some, if they figure that the point of the regex is that IT can itself control case-sensitivity in what it's matching. While that's true, the find features in the editors really won't pay attention to the case of what they find and match against (even if the regex has case-specificity) unless we do check that option.
Finally, sorry for the delay in responding to the comments here from a couple of weeks ago.
(date)(.*)\(.*(DD\/).*\)|(date)(.*)(date)(.*)\(.*(DD-).*\)|(date)(.*)\(.*(\/DD).*\)|(date)(.*)\(.*(-DD).*\)|(date)(.*)\(.*(D\/).*\)|(date)(.*)\(.*(D-).*\)|(date)(.*)\(.*(\/D).*\)|(date)(.*)\(.*(-D).*\)
- what editors are you saying yours works in? And did you confirm it works in cfml itself?
- did you create that because for some reason the previous (simpler) one from Scott somehow did not serve you as well? How so?
- finally, it seems worth noting here that the bug fix mentioned above, from Adobe, is now rolled into Update 1 of cf2021, though that does not mean the error no longer happens. Rather, it means merely that we don't have to implement the special fix/jar before adding the jvm arg that reverts cf to the previous way of using D for dateformat.
Looking forward to your thoughts, since you did push on to find and share this alternative regex. Thanks.
I used the regex in sublime, my current favorite editor.
The previous supplied regex definitely works to get any instance of dateformat or datetimeformat. You could also add in parsedatetime, dateadd, datepart if you wanted.
I created this regex to attempt to list any method that contained 'date', which in turn had capital D or DD as part of the mask.
previous regex would include items like DateFormat(defaultEnd,'dd')
after running my regex through a few systems I support, I realized that it was incomplete. The method text should be case insensitive, as some coders like to yell, others do not. This modified version seems to work to get them all.
(?i)date(?-i)(.*)\(.*(DD\/).*\)|(?i)date(?-i)(.*)(?i)date(?-i)(.*)\(.*(DD-).*\)|(?i)date(?-i)(.*)\(.*(\/DD).*\)|(?i)date(?-i)(.*)\(.*(-DD).*\)|(?i)date(?-i)(.*)\(.*(D\/).*\)|(?i)date(?-i)(.*)\(.*(D-).*\)|(?i)date(?-i)(.*)\(.*(\/D).*\)|(?i)date(?-i)(.*)\(.*(-D).*\)
But as I clarify in both places: the "fix" Adobe offered is a JVM arg that one can add which changes the behavior BACK to letting the D mean the same as d. The fix does not ITSELF change the behavior back, but allows one to control it for a CF instance. And before update 1, one also had to get and implement a special hotfix jar file (discussed in my Dec 2020 post), but update 1 now incorporates the fix (and obviates the need of that jar).
That said, even as of Update 1, one still does need to enable that JVM arg to "revert the behavior" to how things worked before CF2021 (treating the D like a d). So this "breaking change" will remain in CF2021 going forward, it seems, unless one adds that special JVM arg.
If one does NOT want to (or cannot for any reason) rely on that jvm arg and prefers instead to find and replace all their occurrences of D in dateformat, some very good news is that previous comments here from Scott Steinbeck and Curtis Fraser offer regex's that could be used in editors/IDEs to find them. Perhaps you, Scott, were referring to them when you said you "replaced all instances of uppercase in my date masks".
I updated both my blog posts to offer a specific mention of and link to those comments, to help others use such a find/replace operation if they prefer that over relying on the new JVM arg. Again, thanks guys!
In earlier versions of Coldfusion the mask "w" would return the number of weeks but now it returns the number of weekdays! If we want weeks we now need to use "ww".
https://helpx.adobe....
So we need to pick through our code for this one. Using "w" won't throw an error but it will give you unexpected results if you're expecting weeks your return will be out by a factor of about 7!
If Adobe wanted to introduce a weekdays mask they surely could have used "ww" for that and left the legacy "w" mask as was - seems rather inconsiderate to me, unless I've missed something.
Hope this helps someone.
Best wishes,
Nick
"Note: The mask w as weekdays is only valid for the 2018 release of ColdFusion. For 2016 and earlier versions of ColdFusion, w returns the number of weeks."
It's kind of surprising to hear that no one seems to have noticed that for 4 years (that I've seen). Then again, most running it probably only switched to it (or later) in the years since, so such changes only become more widely known over time.
And FWIW, I'll confirm that I myself had not come across this change nor had I documented it for my "hidden gems in cf2018" talks back in 2018 and 2019.
So, at least it is documented. But I agree that such a change is significant and seems it should have been avoided. Thanks for sharing it.
l?s?(dateformat|datetimeformat)(.*?)[''"](.*?)[DY]{1,10}(.*?)[''")]
Pattern Breakdown:
- l?s?(dateformat|datetimeformat) --> find lsdateformat, lsdatetimeformat, dateformat, datetimeformat
- (.*?)[''"] --> lazy search until you find a single or double quote
- (.*?)[DY]{1,10} --> lazy search until you can find a string containing between 1 - 10 characters of D and or Y
- (.*?)[''")] --> lazy search until you find a single or double quote or a ending parenthesis