CALCDATE and Leap Year, 29 February. Be aware!

mgn
Member Posts: 39
This post is no question. It is just something I want to share, so you know how to use the DateExpression in the CALCDATE function:
You might think that the DateExpression
Well, most of the time, but not always!
This week one of my customers reported a bug to me. When creating (monthly) Service Invoices NAV was skipping some Service Contracts. The customer thought it had something to do with the Leap Year, because it happened 4 years ago as well. And because they didn’t fix it back then, but created a workaround, it happened again and I ran into something that resulted in this topic. Note, this bug was due too some (very old) customizations, the standard NAV Service module does not have this bug!
The behavior of how the DateExpression is used by the CALCDATE function is described on MSDN ‘The date expression can be any length. The string is interpreted from left to right with one subexpression at a time. The following rules describe the valid syntax of date expressions’. And it has been noticed a long time ago already by Paul Baxter and perhaps some other blogs I haven't found. But you might not be aware of the consequences when building the DateExpression. At least It wasn’t the first thing that popped up in my mind when confronted with the customer’s bug. So, I spent some time creating examples and thought it my be worth sharing.
Some examples. All date formats in the examples below are in European format, ie. DD-MM-YYYY.
Today is January 1st. So the result of the following functions will be the same:
But what if the Date is 29, 30 or 31-1-2015, of course February does not have 30 or 31 days. So, it should give the last day in February. And for 2016 this the 29th.
step 1. 31-01-2015+ 1M = 28-02-2015
step 2. 28-02-2015 + 1Y = 28-02-2016
I created a codeunit with some examples. It is giving the following result.

As said, nothing new. But just be aware of this behavior. Happy 2016 leap year!
NewDate := CALCDATE(DateExpression [, Date])
You might think that the DateExpression
<1Y+1M>will give the same result as
<1M+1Y>, right?
Well, most of the time, but not always!
This week one of my customers reported a bug to me. When creating (monthly) Service Invoices NAV was skipping some Service Contracts. The customer thought it had something to do with the Leap Year, because it happened 4 years ago as well. And because they didn’t fix it back then, but created a workaround, it happened again and I ran into something that resulted in this topic. Note, this bug was due too some (very old) customizations, the standard NAV Service module does not have this bug!
The behavior of how the DateExpression is used by the CALCDATE function is described on MSDN ‘The date expression can be any length. The string is interpreted from left to right with one subexpression at a time. The following rules describe the valid syntax of date expressions’. And it has been noticed a long time ago already by Paul Baxter and perhaps some other blogs I haven't found. But you might not be aware of the consequences when building the DateExpression. At least It wasn’t the first thing that popped up in my mind when confronted with the customer’s bug. So, I spent some time creating examples and thought it my be worth sharing.
Some examples. All date formats in the examples below are in European format, ie. DD-MM-YYYY.
Today is January 1st. So the result of the following functions will be the same:
CALCDATE(<1Y+1M>,01-01-2016) = 01-02-2017
CALCDATE(<1M+1Y>,01-01-2016) = 01-02-2017
But what if the Date is 29, 30 or 31-1-2015, of course February does not have 30 or 31 days. So, it should give the last day in February. And for 2016 this the 29th.
CALCDATE(<1Y+1M>,31-01-2016) = 29-02-2016
CALCDATE(<1M+1Y>,31-01-2016) = 28-02-2016NAV will calculate <1M+1Y> as follows:
step 1. 31-01-2015+ 1M = 28-02-2015
step 2. 28-02-2015 + 1Y = 28-02-2016
I created a codeunit with some examples. It is giving the following result.

As said, nothing new. But just be aware of this behavior. Happy 2016 leap year!
1
Answers
-
It's working as expected. What's unusual about this behavior?Confessions of a Dynamics NAV Consultant = my blog
AP Commerce, Inc. = where I work
Getting Started with Dynamics NAV 2013 Application Development = my book
Implementing Microsoft Dynamics NAV - 3rd Edition = my 2nd book0 -
Please note: This post is relevant only regarding the order of terms in the dateformula. The formulae given above do not return the last day of the month in other cases too, as one easily might be tempted to believe.
(e.g. CALCDATE(<1M+1Y>,30-06-2016) = 30-07-2017) not 31st
In order to get the last day of the month add the term +CM
With this in mind, you scarcely will find any real world application where change in order of terms leads to an unexpectantly deviating result, such as the one given above (for a non-programmer's mind, that is). And obviously for some terms, the order matters a lot.0 -
Vaprog,
Thanks for adding the calculation rules about the last day of the month. I wasn't clear about that in my post.
0
Categories
- All Categories
- 73 General
- 73 Announcements
- 66.6K Microsoft Dynamics NAV
- 18.7K NAV Three Tier
- 38.4K NAV/Navision Classic Client
- 3.6K Navision Attain
- 2.4K Navision Financials
- 116 Navision DOS
- 851 Navision e-Commerce
- 1K NAV Tips & Tricks
- 772 NAV Dutch speaking only
- 617 NAV Courses, Exams & Certification
- 2K Microsoft Dynamics-Other
- 1.5K Dynamics AX
- 320 Dynamics CRM
- 111 Dynamics GP
- 10 Dynamics SL
- 1.5K Other
- 990 SQL General
- 383 SQL Performance
- 34 SQL Tips & Tricks
- 35 Design Patterns (General & Best Practices)
- 1 Architectural Patterns
- 10 Design Patterns
- 5 Implementation Patterns
- 53 3rd Party Products, Services & Events
- 1.6K General
- 1.1K General Chat
- 1.6K Website
- 83 Testing
- 1.2K Download section
- 23 How Tos section
- 252 Feedback
- 12 NAV TechDays 2013 Sessions
- 13 NAV TechDays 2012 Sessions