Как заставить дату повторяться каждый год в последний день февраля в Java для iCal google-rfc-2445
Мне нужно повторять дату каждый последний день февраля, я использую время Joda, чтобы использовать правило для генерации дат дней, недель, месяцев и т. Д. Для Months работает нормально, но когда идет год, я получаю неправильные результаты.
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;
}
Но я получаю это:
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
и в случае високосного года это:
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
Как я пишу одно правило, чтобы получить последний день февраля каждый год?
4 ответа
Мое решение состоит в том, чтобы считать от последнего дня года до дня до 1 марта. Так что правило будет таким:
"RRULE:FREQ=YEARLY;COUNT=6;INTERVAL=1;BYYEARDAY=-307"
Если вы хотите убедиться, что вы получаете событие на последний день месяца, вы должны использовать BYMONTHDAY=-1
(См. RRULE в RFC), чтобы убедиться, что это произойдет только в феврале BYMONTH=2
который затем дает:
RRULE:FREQ=YEARLY;BYMONTH=2;BYMONTHDAY=-1
Затем, так как вы упоминаете COUNT
свойство, которое вы могли бы также определить UNTIL
который указывает до тех пор, пока вы не хотите, чтобы ваш RRULE
подлежит оценке:
RRULE:FREQ=YEARLY;BYMONTH=2;BYMONTHDAY=-1;UNTIL=20200302T070000Z
НИКОГДА не используйте DateTimes, если вы хотите манипулировать только датами, LocalDate - правильный класс.
Если вы действительно хотите получить последние дни февраля:
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;
}
Вычтите один день с первого марта.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );
DateTime firstOfMarch = new DateTime( "2014-03-01", timeZone ).withTimeAtStartOfDay();
DateTime lastOfFebruary = firstOfMarch.minusDays( 1 ).withTimeAtStartOfDay();
На firstOfMarch
объект, вызов plusYears(1)
продолжать дальше.