DEV Community

Cover image for What day is one month after 31st January? What day is one month before 31st March? I checked it with various RDBs.
kakisoft
kakisoft

Posted on

What day is one month after 31st January? What day is one month before 31st March? I checked it with various RDBs.

On 31/1, when you read this message like this, can you immediately think of what day it is?

"It will expire one month after the registration date."

Also, what about the following message on 31/3?

"One month's notice will be given."

I looked into this, but I couldn't find any legal provisions or international rules.

So, I decided to research it with various RDBs.

I tried with:

  • MySQL
  • PostgreSQL
  • SQL Server
  • Oracle

In all RDBs result were the same.

Result

Contents Result
1 month after 28/1 28/2
1 month after 29/1 28/2
1 month after 30/1 28/2
1 month after 31/1 28/2
1 month before 28/3 28/2
1 month before 29/3 28/2
1 month before 30/3 28/2
1 month before 31/3 28/2
1 month after 28/1(leap year) 28/2
1 month after 29/1(leap year) 29/2
1 month after 30/1(leap year) 29/2
1 month after 31/1(leap year) 29/2
1 month before 28/3(leap year) 28/2
1 month before 29/3(leap year) 29/2
1 month before 30/3(leap year) 29/2
1 month before 31/3(leap year) 29/2

SQL statement

MySQL

ver:5.7

SELECT
    DATE_ADD(CAST('2018/01/28' AS DATE), INTERVAL 1 MONTH) AS "1 month after 28/1"
   ,DATE_ADD(CAST('2018/01/29' AS DATE), INTERVAL 1 MONTH) AS "1 month after 29/1"
   ,DATE_ADD(CAST('2018/01/30' AS DATE), INTERVAL 1 MONTH) AS "1 month after 30/1"
   ,DATE_ADD(CAST('2018/01/31' AS DATE), INTERVAL 1 MONTH) AS "1 month after 31/1"

   ,DATE_ADD(CAST('2018/03/28' AS DATE), INTERVAL -1 MONTH) AS "1 month before 28/3"
   ,DATE_ADD(CAST('2018/03/29' AS DATE), INTERVAL -1 MONTH) AS "1 month before 29/3"
   ,DATE_ADD(CAST('2018/03/30' AS DATE), INTERVAL -1 MONTH) AS "1 month before 30/3"
   ,DATE_ADD(CAST('2018/03/31' AS DATE), INTERVAL -1 MONTH) AS "1 month before 31/3"

   ,DATE_ADD(CAST('2020/01/28' AS DATE), INTERVAL 1 MONTH) AS "1 month after 28/1(leap year)"
   ,DATE_ADD(CAST('2020/01/29' AS DATE), INTERVAL 1 MONTH) AS "1 month after 29/1(leap year)"
   ,DATE_ADD(CAST('2020/01/30' AS DATE), INTERVAL 1 MONTH) AS "1 month after 30/1(leap year)"
   ,DATE_ADD(CAST('2020/01/31' AS DATE), INTERVAL 1 MONTH) AS "1 month after 31/1(leap year)"

   ,DATE_ADD(CAST('2020/03/28' AS DATE), INTERVAL -1 MONTH) AS "1 month before 28/3(leap year)"
   ,DATE_ADD(CAST('2020/03/29' AS DATE), INTERVAL -1 MONTH) AS "1 month before 29/3(leap year)"
   ,DATE_ADD(CAST('2020/03/30' AS DATE), INTERVAL -1 MONTH) AS "1 month before 30/3(leap year)"
   ,DATE_ADD(CAST('2020/03/31' AS DATE), INTERVAL -1 MONTH) AS "1 month before 31/3(leap year)"
Enter fullscreen mode Exit fullscreen mode

PostgreSQL

ver:9.6

SELECT
    CAST('2018/01/28' AS DATE) + interval '1 months' AS "1 month after 28/1"
   ,CAST('2018/01/29' AS DATE) + interval '1 months' AS "1 month after 29/1"
   ,CAST('2018/01/30' AS DATE) + interval '1 months' AS "1 month after 30/1"
   ,CAST('2018/01/31' AS DATE) + interval '1 months' AS "1 month after 31/1"

   ,CAST('2018/03/28' AS DATE) + interval '-1 months' AS "1 month before 28/3"
   ,CAST('2018/03/29' AS DATE) + interval '-1 months' AS "1 month before 29/3"
   ,CAST('2018/03/30' AS DATE) + interval '-1 months' AS "1 month before 30/3"
   ,CAST('2018/03/31' AS DATE) + interval '-1 months' AS "1 month before 31/3"

   ,CAST('2020/01/28' AS DATE) + interval '1 months' AS "1 month after 28/1(leap year)"
   ,CAST('2020/01/29' AS DATE) + interval '1 months' AS "1 month after 29/1(leap year)"
   ,CAST('2020/01/30' AS DATE) + interval '1 months' AS "1 month after 30/1(leap year)"
   ,CAST('2020/01/31' AS DATE) + interval '1 months' AS "1 month after 31/1(leap year)"

   ,CAST('2020/03/28' AS DATE) + interval '-1 months' AS "1 month before 28/3(leap year)"
   ,CAST('2020/03/29' AS DATE) + interval '-1 months' AS "1 month before 29/3(leap year)"
   ,CAST('2020/03/30' AS DATE) + interval '-1 months' AS "1 month before 30/3(leap year)"
   ,CAST('2020/03/31' AS DATE) + interval '-1 months' AS "1 month before 31/3(leap year)"
Enter fullscreen mode Exit fullscreen mode

SQL Server

ver:14.0

SELECT
    DATEADD(MONTH, 1, CAST('2018/01/28' AS DATE)) AS "1 month after 28/1"
   ,DATEADD(MONTH, 1, CAST('2018/01/29' AS DATE)) AS "1 month after 29/1"
   ,DATEADD(MONTH, 1, CAST('2018/01/30' AS DATE)) AS "1 month after 30/1"
   ,DATEADD(MONTH, 1, CAST('2018/01/31' AS DATE)) AS "1 month after 31/1"

   ,DATEADD(MONTH, -1, CAST('2018/03/28' AS DATE)) AS "1 month before 28/3"
   ,DATEADD(MONTH, -1, CAST('2018/03/29' AS DATE)) AS "1 month before 29/3"
   ,DATEADD(MONTH, -1, CAST('2018/03/30' AS DATE)) AS "1 month before 30/3"
   ,DATEADD(MONTH, -1, CAST('2018/03/31' AS DATE)) AS "1 month before 31/3"

   ,DATEADD(MONTH, 1, CAST('2020/01/28' AS DATE)) AS "1 month after 28/1(leap year)"
   ,DATEADD(MONTH, 1, CAST('2020/01/29' AS DATE)) AS "1 month after 29/1(leap year)"
   ,DATEADD(MONTH, 1, CAST('2020/01/30' AS DATE)) AS "1 month after 30/1(leap year)"
   ,DATEADD(MONTH, 1, CAST('2020/01/31' AS DATE)) AS "1 month after 31/1(leap year)"

   ,DATEADD(MONTH, -1, CAST('2020/03/28' AS DATE)) AS "1 month before 28/3(leap year)"
   ,DATEADD(MONTH, -1, CAST('2020/03/29' AS DATE)) AS "1 month before 29/3(leap year)"
   ,DATEADD(MONTH, -1, CAST('2020/03/30' AS DATE)) AS "1 month before 30/3(leap year)"
   ,DATEADD(MONTH, -1, CAST('2020/03/31' AS DATE)) AS "1 month before 31/3(leap year)"
Enter fullscreen mode Exit fullscreen mode

Oracle

ver:11g

SELECT
    ADD_MONTHS(TO_DATE('2018/01/28'), 1) AS "1 month after 28/1"
   ,ADD_MONTHS(TO_DATE('2018/01/29'), 1) AS "1 month after 29/1"
   ,ADD_MONTHS(TO_DATE('2018/01/30'), 1) AS "1 month after 30/1"
   ,ADD_MONTHS(TO_DATE('2018/01/31'), 1) AS "1 month after 31/1"

   ,ADD_MONTHS(TO_DATE('2018/03/31'), -1) AS "1 month before 28/3"
   ,ADD_MONTHS(TO_DATE('2018/03/31'), -1) AS "1 month before 29/3"
   ,ADD_MONTHS(TO_DATE('2018/03/31'), -1) AS "1 month before 30/3"
   ,ADD_MONTHS(TO_DATE('2018/03/31'), -1) AS "1 month before 31/3"

   ,ADD_MONTHS(TO_DATE('2020/01/28'), 1) AS "1 month after 28/1(leap year)"
   ,ADD_MONTHS(TO_DATE('2020/01/29'), 1) AS "1 month after 29/1(leap year)"
   ,ADD_MONTHS(TO_DATE('2020/01/30'), 1) AS "1 month after 30/1(leap year)"
   ,ADD_MONTHS(TO_DATE('2020/01/31'), 1) AS "1 month after 31/1(leap year)"

   ,ADD_MONTHS(TO_DATE('2020/03/31'), -1) AS "1 month before 28/3(leap year)"
   ,ADD_MONTHS(TO_DATE('2020/03/31'), -1) AS "1 month before 29/3(leap year)"
   ,ADD_MONTHS(TO_DATE('2020/03/31'), -1) AS "1 month before 30/3(leap year)"
   ,ADD_MONTHS(TO_DATE('2020/03/31'), -1) AS "1 month before 31/3(leap year)"
FROM
    DUAL
Enter fullscreen mode Exit fullscreen mode

Extra

If you want to notify the expiration date, it may be better to use days instead of month, such as "The data retention period is 90 days".

Top comments (5)

Collapse
 
geraldew profile image
geraldew

One of the tests to consider for this kind of thing is the example person born on the 29th February. Thus the question is: what day is 12 months later and what day is 4 times 12 months later? The latter should come out as the 29th again.

As you might expect, this means that fully checking calendar functions requires a disturbing kind of thoroughness.

As I'm currently on leave, I can't chip in with Teradata equivalents to your tests.

Also, Teradata provide a built in generated calendar that makes thorough checking of these things easier.

In my work I've dealt with dates since before the 2000 century mark so I've had to check my understanding on both sides of that.

Collapse
 
kakisoft profile image
kakisoft

Thank you for comment!

I would love to know the test result of Teradata.

If you test it, please let me know!

Collapse
 
geraldew profile image
geraldew

I managed to find a spare moment to construct the Teradata equivalent, run it, and send myself the results.

I've used the Add_Months function as that's what most Teradata users would probably do. It's likely that one of the Interval methods would have worked, as Teradata supports most of the SQL standard, but I thought this was a more interesting thing to share.

 -- Teradata ver 16.20.53.24 

SELECT 
    ADD_MONTHS( CAST('2018/01/28' AS DATE), 1 ) AS "1 month after 28/1" 
   ,ADD_MONTHS( CAST('2018/01/29' AS DATE), 1 ) AS "1 month after 29/1" 
   ,ADD_MONTHS( CAST('2018/01/30' AS DATE), 1 ) AS "1 month after 30/1" 
   ,ADD_MONTHS( CAST('2018/01/31' AS DATE), 1 ) AS "1 month after 31/1" 
   ,ADD_MONTHS( CAST('2018/03/28' AS DATE), -1) AS "1 month before 28/3" 
   ,ADD_MONTHS( CAST('2018/03/29' AS DATE), -1) AS "1 month before 29/3" 
   ,ADD_MONTHS( CAST('2018/03/30' AS DATE), -1) AS "1 month before 30/3" 
   ,ADD_MONTHS( CAST('2018/03/31' AS DATE), -1) AS "1 month before 31/3" 
   ,ADD_MONTHS( CAST('2020/01/28' AS DATE), 1 ) AS "1 month after 28/1(leap year)" 
   ,ADD_MONTHS( CAST('2020/01/29' AS DATE), 1 ) AS "1 month after 29/1(leap year)" 
   ,ADD_MONTHS( CAST('2020/01/30' AS DATE), 1 ) AS "1 month after 30/1(leap year)" 
   ,ADD_MONTHS( CAST('2020/01/31' AS DATE), 1 ) AS "1 month after 31/1(leap year)" 
   ,ADD_MONTHS( CAST('2020/03/28' AS DATE), -1) AS "1 month before 28/3(leap year)" 
   ,ADD_MONTHS( CAST('2020/03/29' AS DATE), -1) AS "1 month before 29/3(leap year)" 
   ,ADD_MONTHS( CAST('2020/03/30' AS DATE), -1) AS "1 month before 30/3(leap year)" 
   ,ADD_MONTHS( CAST('2020/03/31' AS DATE), -1) AS "1 month before 31/3(leap year)" 
; 
Enter fullscreen mode Exit fullscreen mode

And here's what that generated.

Contents Result
1 month after 28/1 28/02/2018
1 month after 29/1 28/02/2018
1 month after 30/1 28/02/2018
1 month after 31/1 28/02/2018
1 month before 28/3 28/02/2018
1 month before 29/3 28/02/2018
1 month before 30/3 28/02/2018
1 month before 31/3 28/02/2018
1 month after 28/1(leap year) 28/02/2020
1 month after 29/1(leap year) 29/02/2020
1 month after 30/1(leap year) 29/02/2020
1 month after 31/1(leap year) 29/02/2020
1 month before 28/3(leap year) 28/02/2020
1 month before 29/3(leap year) 29/02/2020
1 month before 30/3(leap year) 29/02/2020
1 month before 31/3(leap year) 29/02/2020

 

Thread Thread
 
kakisoft profile image
kakisoft

@geraldew
I really appreciate your kindness and you talking time for this research!
It helps me to understand more!

Thread Thread
 
geraldew profile image
geraldew

FYI - I've now written a new article that was prompted by this one. It seemed a bit too long to put here as a response, but in it I've given a link to here. It is also quite Teradata specific.