Фильтрация однодневных событий с помощью ical4j, проблемы с датами начала и окончания

Я работаю с экспортом из календаря Zimbra и хочу создать список всех событий, происходящих каждый день. Упрощенный календарь выглядит так.

BEGIN:VCALENDAR
X-WR-CALNAME:Test-Parking
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Europe/Berlin
BEGIN:STANDARD
DTSTART:19710101T030000
TZOFFSETTO:+0100
TZOFFSETFROM:+0200
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=10;BYDAY=-1SU
TZNAME:CET
END:STANDARD
END:VTIMEZONE

BEGIN:VEVENT
RRULE:FREQ=DAILY;COUNT=3;INTERVAL=1
SUMMARY:Day Event 3 Times
DTSTART;VALUE=DATE:20120911
DTEND;VALUE=DATE:20120912
END:VEVENT

BEGIN:VEVENT
SUMMARY:4 hours event
DTSTART;TZID="Europe/Berlin":20120911T090000
DTEND;TZID="Europe/Berlin":20120911T130000
END:VEVENT
END:VCALENDAR

Теперь я написал несколько строк кода для фильтрации событий:

public class CalendarTester {

    private Calendar calendar;
    private TimeZoneRegistry registry;

    public static void main(String[] args) throws Exception {
        CalendarTester tester = new CalendarTester();
        tester.run();
    }

    private void run() throws IOException, ParserException, URISyntaxException,
            ParseException {
        readCalendar();
        TimeZone tz = registry.getTimeZone("Europe/Berlin");
        SimpleDateFormat formatter = new SimpleDateFormat();
        GregorianCalendar cal = new GregorianCalendar(2012,
                GregorianCalendar.SEPTEMBER, 10);
        cal.set(GregorianCalendar.HOUR_OF_DAY, 0);
        cal.set(GregorianCalendar.MINUTE, 0);
        cal.set(GregorianCalendar.SECOND, 0);
        cal.setTimeZone(tz);

        for (int i = 0; i < 5; i++) {
            Period p = new Period(new DateTime(cal.getTime()), new Dur(1, 0, 0,
                    0));
            p.setTimeZone(tz);
            Rule[] rules = new Rule[1];
            rules[0] = new PeriodRule(p);
            Filter f = new Filter(rules, Filter.MATCH_ALL);

            System.out.println("_____________");
            System.out.println(formatter.format(cal.getTime()));
            for (Object event : f.filter(calendar
                    .getComponents(Component.VEVENT))) {
                printEvent((VEvent) event, formatter);
            }
            cal.add(GregorianCalendar.DAY_OF_YEAR, 1);
        }
    }

    private void printEvent(VEvent event, SimpleDateFormat formatter) {
        System.out.println("Start: "
                + formatter.format(event.getStartDate().getDate()) + " End: "
                + formatter.format(event.getEndDate().getDate()) + " Summary: "
                + event.getSummary().getValue());
    }

    private void readCalendar() throws FileNotFoundException, IOException,
            ParserException {
        FileInputStream fin = new FileInputStream(
                "files/Recuring_Calendar_Entry_From_To.ics");

        CalendarBuilder builder = new CalendarBuilder();
        calendar = builder.build(fin);
        registry = builder.getRegistry();
    }

}

Теперь я правильно получаю простое событие, но 3 раза происходит однодневное событие 4 раза из-за неправильного времени начала и окончания.

_____________
10.09.12 01:00
_____________
11.09.12 01:00
Start: 11.09.12 02:00 End: 12.09.12 02:00 Summary: Day Event 3 Times
Start: 11.09.12 10:00 End: 11.09.12 14:00 Summary: 4 hours event
_____________
12.09.12 01:00
Start: 11.09.12 02:00 End: 12.09.12 02:00 Summary: Day Event 3 Times
_____________
13.09.12 01:00
Start: 11.09.12 02:00 End: 12.09.12 02:00 Summary: Day Event 3 Times
_____________
14.09.12 01:00
Start: 11.09.12 02:00 End: 12.09.12 02:00 Summary: Day Event 3 Times

Итак, если у кого-то есть идея, что мне нужно изменить при импорте или в фильтре, чтобы я получал все события в одном и том же часовом поясе.

Танки для любых предложений, Сай


Я сделал несколько тестов, чтобы понять, что происходит. Стартом были Тесты фильтров в:

test/net/fortuna/ical4j/filter/PeriodRuleTest.java

Если я создам новое событие на весь день, как показано там, все в порядке. Если я добавлю recure roule, функциональность будет нарушена.

Recur recur = new Recur("FREQ=DAILY;COUNT=3;INTERVAL=1");
event.getProperties().add(new RRule(recur));

Теперь Событие соответствует дате начала и последующим 3 дням, как показано в примере выше. Если я установлю COUNT=1 в правиле, событие теперь будет совпадать 2 раза. Может я не понимаю повторяющееся правило? Если я взгляну на веб-календарь (Zimbra), куда я экспортировал эти события, все будет так, как я и ожидал.

Здесь вы можете увидеть мой тестовый класс


person surffan    schedule 11.09.2012    source источник


Ответы (1)


Я заметил пару вещей:

Во-первых, ваше событие «Day Event 3 Times» не использует часовой пояс Europe/Berlin для своих дат, поэтому событие фактически находится в «плавающем времени». Это может не иметь значения, если ваш местный часовой пояс — Европа/Берлин.

Во-вторых, одно и то же событие охватывает период с 11 сентября по 12 сентября. Таким образом, с правилом повторения вы получите три экземпляра события:

  • 11 сентября - 12 сентября
  • 12 сентября - 13 сентября
  • 13 сентября - 14 сентября

Я не слишком внимательно смотрел, что делает код, но это может объяснить, почему вы получаете совпадения 14 сентября.

person fortuna    schedule 12.09.2012
comment
Спасибо за ваши уведомления. Я также просмотрел тесты ссылка Здесь создается однодневное событие с датой начала и окончания без часового пояса. Я немного поэкспериментировал и обнаружил, что он работает с одноразовым событием без повторяющегося правила. Если я добавлю повторяющуюся roule даже с COUNT = 1, запись теперь будет соответствовать двум дням, дате начала и окончания. - person surffan; 25.09.2012