0

I need to repeat a date every last day of February, I am using Joda time to use a rule to generate the dates for days, weeks, months, etc. For Months is working fine but when is about years I receive wrong outputs.

private static List<DateTime> calculateRecurrentDates(DateTime startDate, String recurrentRule) {
    List<DateTime> dates = new ArrayList<DateTime>();
    TimeStamp startDate = Timestamp.valueOf("2011-02-28 10:10:10");
    String recurrentRule = "RRULE:FREQ=YEARLY;COUNT=6;INTERVAL=1;";
    String leapYearRule = "RRULE:FREQ=YEARLY;COUNT=6;INTERVAL=1;BYMONTHDAY=28,29;BYSETPOS=-1";

    try {
        DateTimeIterable range = DateTimeIteratorFactory.createDateTimeIterable(recurrentRule, startDate, DateTimeZone.UTC, true);
        for (DateTime date : range) {
           dates.add(date);
        }
    } catch (ParseException e) {
        dates = null;
        logger.error(e.getMessage());
    }
    return dates;
}

But I receive this:

2011-02-28T10:10:10.000Z
2012-02-28T10:10:10.000Z
2013-02-28T10:10:10.000Z
2014-02-28T10:10:10.000Z
2015-02-28T10:10:10.000Z
2016-02-28T10:10:10.000Z

and in the case is in a leap year this:

2012-02-29T10:10:10.000Z
2012-12-29T10:10:10.000Z
2013-12-29T10:10:10.000Z
2014-12-29T10:10:10.000Z
2015-12-29T10:10:10.000Z
2016-12-29T10:10:10.000Z
2017-12-29T10:10:10.000Z

How I write one rule to get the last day of February every year?

TulioPa
  • 177
  • 9

4 Answers4

1

My solution is to count from the last day of the year to the day before March 1st. So the rule will be like this:

"RRULE:FREQ=YEARLY;COUNT=6;INTERVAL=1;BYYEARDAY=-307"
TulioPa
  • 177
  • 9
1

if you want to make sure you are getting an event for last day of a month you should use BYMONTHDAY=-1 (See RRULE in RFC), then to make sure it only occurs on February BYMONTH=2 which then gives:

RRULE:FREQ=YEARLY;BYMONTH=2;BYMONTHDAY=-1

Then since you mention a COUNT property you could also define a UNTIL which specifies until when you want your RRULE to be evaluated:

RRULE:FREQ=YEARLY;BYMONTH=2;BYMONTHDAY=-1;UNTIL=20200302T070000Z
Community
  • 1
  • 1
Auberon Vacher
  • 4,655
  • 1
  • 24
  • 36
0

Subtract one day from the first of March.

DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );
DateTime firstOfMarch = new DateTime( "2014-03-01", timeZone ).withTimeAtStartOfDay();
DateTime lastOfFebruary = firstOfMarch.minusDays( 1 ).withTimeAtStartOfDay();

On the firstOfMarch object, call plusYears(1) to continue onwards.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
0

Don't EVER use DateTimes if you only want to manipulate dates, LocalDate is the right class.

If you really want to get the last days of February:

public static List<LocalDate> getLastDaysOfFebruary(LocalDate start, int n) {
    ArrayList<LocalDate> list = new ArrayList<>();
    LocalDate firstMar = start.withMonthOfYear(3).withDayOfMonth(1);
    if(! firstMar.isAfter(start)) firstMar = firstMar.plusYears(1);
    for(int i=0;i<n;i++) {
        list.add(firstMar.minusDays(1));
        firstMar = firstMar.plusYears(1);
    }
    return list;
}
leonbloy
  • 73,180
  • 20
  • 142
  • 190