Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding one month to date fails using Joda-Time DateTime in Java

I tried to add full months from a given start date by using java DateTime and method plusMonths().

When my start time is at the beginning of a month, everything works like expected:

DateTime startOfMonth = new DateTime(2013, 1, 1, 00, 00, 00);
    System.out.println(startOfMonth.toString());
    for (int i = 0; i < 12; i++) {
        startOfMonth = startOfMonth.plusMonths(1);
        System.out.println(startOfMonth.toString());
}

The output is the first day of every month like expected and everything is great!

2013-01-01T00:00:00.000+01:00
2013-02-01T00:00:00.000+01:00
2013-03-01T00:00:00.000+01:00
2013-04-01T00:00:00.000+02:00
2013-05-01T00:00:00.000+02:00
2013-06-01T00:00:00.000+02:00
2013-07-01T00:00:00.000+02:00
2013-08-01T00:00:00.000+02:00
2013-09-01T00:00:00.000+02:00
2013-10-01T00:00:00.000+02:00
2013-11-01T00:00:00.000+01:00
2013-12-01T00:00:00.000+01:00
2014-01-01T00:00:00.000+01:00

But when I change my example to the end of a month it doesn't return what I want!

System.out.println("");
DateTime endOfMonth = new DateTime(2012, 12, 31, 23, 59, 59);
System.out.println(endOfMonth.toString());
for (int i = 0; i < 12; i++) {
    endOfMonth = endOfMonth.plusMonths(1);
    System.out.println(endOfMonth.toString());
}

This returns:

2012-12-31T23:59:59.000+01:00
2013-01-31T23:59:59.000+01:00
2013-02-28T23:59:59.000+01:00
2013-03-28T23:59:59.000+01:00
2013-04-28T23:59:59.000+02:00
2013-05-28T23:59:59.000+02:00
2013-06-28T23:59:59.000+02:00
2013-07-28T23:59:59.000+02:00
2013-08-28T23:59:59.000+02:00
2013-09-28T23:59:59.000+02:00
2013-10-28T23:59:59.000+01:00
2013-11-28T23:59:59.000+01:00
2013-12-28T23:59:59.000+01:00

So, why is "2013-02-28T23:59:59.000+01:00" plus one month not "2013-03-31T23:59:59.000+01:00"? Where are these three days?

like image 596
Gatschet Avatar asked Dec 08 '22 11:12

Gatschet


1 Answers

The problem with date operations is that months have different number of days. In January, you have 31 days, February has only 28. If you add "one month" to January 31st, the software can't guess what you want to achieve, so it adds increments the month which gives you February, 31st - which isn't valid. The next step is then to reconcile the date which yields these odd results that you're seeing.

Note: In the original Java Date classes, you'd get 2nd or 3rd of March after adding one month to January which isn't exactly better :-)

The correct way to iterate over the end of month is to iterate over the first day of then month and the subtract one day (or one millisecond):

DateTime startOfMonth = new DateTime(2013, 1, 1, 00, 00, 00);
System.out.println(startOfMonth.toString());
for (int i = 0; i < 12; i++) {
    startOfMonth = startOfMonth.plusMonths(1);
    DateTime endOfMonth = startOfMonth.minusDays(1); // magic here
    System.out.println(startOfMonth + "-" + endOfMonth);
}

If you just need a date range, use an half open range [start,end) where end is always the first of a month.

like image 98
Aaron Digulla Avatar answered Apr 27 '23 08:04

Aaron Digulla