5

I'm writing some code to get each months name between a start and an end date. This works fine for most months - except February into march, and november - december.

Heres the code :

Date startDate = Date.parse('5/30/2019');
Date endDate = startDate.addYears(1);

Integer durationInMonths = StartDate.MonthsBetween(EndDate);

for (Integer i = 0; i <= durationInMonths; i++) {
    DateTime m = DateTime.newInstance( StartDate.Year(), StartDate.Month(), 1);

    m = m.addMonths(i); 

    System.debug(i);
    System.debug(m.Day() + ' / ' + m.Month() + ' / ' + String.valueOf(m.year()));                
}

Here you can see the crazy output (DD/MM/YY) - at one point (1/11/19 -> 30/11/19) the date picks up some days instead of months and then the whole thing falls apart. The scary part is that I didn't notice until now due to the output being put into a set and only using (MM/YY).

enter image description here

2
  • 3
    If you notice, blunder happen when Daylight savings is enabled or disabled in march and November. Jun 10, 2019 at 16:26
  • 1
    Try to change your DateTime into a Date and this likely goes away. Jun 10, 2019 at 16:29

2 Answers 2

3

Not an answer, but a clue, it seems it has to do something related to timezone and summer time. Same code in my BST org gives a different response.

Date startDate = Date.parse('30/05/2019');
Date endDate = startDate.addYears(1);

Integer durationInMonths = StartDate.MonthsBetween(EndDate);

for (Integer i = 0; i <= durationInMonths; i++) {
    DateTime m = DateTime.newInstance( StartDate.Year(), StartDate.Month(), 1);

    m = m.addMonths(i);

    System.debug(i);
    System.debug(m.Day() + ' / ' + m.Month() + ' / ' + String.valueOf(m.year()));
}

Debug :

17:17:14.14 (16267512)|USER_DEBUG|[11]|DEBUG|0
17:17:14.14 (16351252)|USER_DEBUG|[12]|DEBUG|1 / 5 / 2019
17:17:14.14 (16404681)|USER_DEBUG|[11]|DEBUG|1
17:17:14.14 (16434289)|USER_DEBUG|[12]|DEBUG|31 / 5 / 2019
17:17:14.14 (16453217)|USER_DEBUG|[11]|DEBUG|2
17:17:14.14 (16480510)|USER_DEBUG|[12]|DEBUG|1 / 7 / 2019
17:17:14.14 (16498216)|USER_DEBUG|[11]|DEBUG|3
17:17:14.14 (16524565)|USER_DEBUG|[12]|DEBUG|31 / 7 / 2019
17:17:14.14 (16542405)|USER_DEBUG|[11]|DEBUG|4
17:17:14.14 (16568781)|USER_DEBUG|[12]|DEBUG|31 / 8 / 2019
17:17:14.14 (16592710)|USER_DEBUG|[11]|DEBUG|5
17:17:14.14 (16619134)|USER_DEBUG|[12]|DEBUG|1 / 10 / 2019
17:17:14.14 (16636368)|USER_DEBUG|[11]|DEBUG|6
17:17:14.14 (16663050)|USER_DEBUG|[12]|DEBUG|30 / 10 / 2019
17:17:14.14 (16680525)|USER_DEBUG|[11]|DEBUG|7
17:17:14.14 (16706633)|USER_DEBUG|[12]|DEBUG|30 / 11 / 2019
17:17:14.14 (16723573)|USER_DEBUG|[11]|DEBUG|8
17:17:14.14 (16750065)|USER_DEBUG|[12]|DEBUG|30 / 12 / 2019
17:17:14.14 (16767156)|USER_DEBUG|[11]|DEBUG|9
17:17:14.14 (16793676)|USER_DEBUG|[12]|DEBUG|30 / 1 / 2020
17:17:14.14 (16810795)|USER_DEBUG|[11]|DEBUG|10
17:17:14.14 (16837147)|USER_DEBUG|[12]|DEBUG|29 / 2 / 2020
17:17:14.14 (16854164)|USER_DEBUG|[11]|DEBUG|11
17:17:14.14 (16880438)|USER_DEBUG|[12]|DEBUG|31 / 3 / 2020
17:17:14.14 (16897409)|USER_DEBUG|[11]|DEBUG|12
17:17:14.14 (16923463)|USER_DEBUG|[12]|DEBUG|1 / 5 / 2020

EDIT:

When you do

Date startDate = Date.parse('30/05/2019');

System.debug(startDate); //Prints 2019-05-30 00:00:00

Which is SummerTime/DaylightSaving 1 hour ahead. So Actual DateTime is 2019-05-29 23:00:00

Am not sure if there can be more than 1 hour in DST, so on safe side I have added 2 hours as offset and it gives me correct response.

Datetime startDate = Datetime.newInstance(2019,05,30 , 2, 0, 0);


for(Integer i =0 ;i < 12;i++){
    startDate = startDate.addMonths(1);
    System.debug(startDate);
}

Debug :

17:47:17.14 (15747813)|USER_DEBUG|[6]|DEBUG|2019-06-30 01:00:00
17:47:17.14 (15781585)|USER_DEBUG|[6]|DEBUG|2019-07-30 01:00:00
17:47:17.14 (15793019)|USER_DEBUG|[6]|DEBUG|2019-08-30 01:00:00
17:47:17.14 (15804331)|USER_DEBUG|[6]|DEBUG|2019-09-30 01:00:00
17:47:17.14 (15817668)|USER_DEBUG|[6]|DEBUG|2019-10-30 01:00:00
17:47:17.14 (15827719)|USER_DEBUG|[6]|DEBUG|2019-11-30 01:00:00
17:47:17.14 (15837722)|USER_DEBUG|[6]|DEBUG|2019-12-30 01:00:00
17:47:17.14 (15848084)|USER_DEBUG|[6]|DEBUG|2020-01-30 01:00:00
17:47:17.14 (15862108)|USER_DEBUG|[6]|DEBUG|2020-02-29 01:00:00
17:47:17.14 (15874963)|USER_DEBUG|[6]|DEBUG|2020-03-29 01:00:00
17:47:17.14 (15884811)|USER_DEBUG|[6]|DEBUG|2020-04-29 01:00:00
17:47:17.14 (15894518)|USER_DEBUG|[6]|DEBUG|2020-05-29 01:00:00
2
  • 1
    I think you're onto something.... because the OP's dates come back to normal in April (DST ends in March in America) and yours come back to normal in May (DST ends in April in Europe). I think what is happening is that the system is subtracting/adding the extra hour and displaying the time accordingly. Bizarre Jun 10, 2019 at 16:28
  • Thats definitely whats going on - makes for some very confusing output! Jun 10, 2019 at 17:00
2

Easy solution that I want to post here - don't use addMonths. It looks like it just adds 30 days to the date, which isn't a valid solution in the slightest and produces problems like above. My mistake was assuming that addMonths wouldn't modify the day part of the date, which it totally will!

Instead, just modify the month given to the constructor.

Date startDate = Date.parse('5/30/2019');
Date endDate = startDate.addYears(1);

Integer durationInMonths = StartDate.MonthsBetween(EndDate);

for (Integer i = 0; i <= durationInMonths; i++) {
    DateTime m = DateTime.newInstance( StartDate.Year(), StartDate.Month() + i, 1);

    System.debug(i);
    System.debug(m.Day() + ' / ' + m.Month() + ' / ' + String.valueOf(m.year()));                
}

This will output a date with the first day and the given month.

enter image description here


Other solution (@Sebastian Kessel) - just use a Date instead of DateTime:

Date startDate = Date.parse('5/30/2019');
Date endDate = startDate.addYears(1);

Integer durationInMonths = StartDate.MonthsBetween(EndDate);

for (Integer i = 0; i <= durationInMonths; i++) {
    Date m = Date.newInstance( StartDate.Year(), StartDate.Month(), 1);

    m = m.addMonths(i);               
}
1
  • Having done my own (minimal) testing, I can say that adding months does NOT add 30 days but does, instead, increment (or decrement) the month and/or year parts of the Datetime. Splitting the computation into Date part (and Time part) is sensible.
    – Phil W
    Aug 3, 2021 at 11:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .