Giter Site home page Giter Site logo

biweekly's People

Contributors

dependabot[bot] avatar dinomite avatar hypfvieh avatar lf- avatar mangstadt avatar scottschmitz avatar toby-cisco avatar zeeshanasghar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

biweekly's Issues

Bug in "DateIteratorFactory#createDateIterable"

From @ParthPadg:

I think I've found a small bug in the DateIterable created from DateIteratorFactory.createDateIterable(String, Date, TimeZone, boolean).

If I create a DateIterable with a Date (e.g., July 17, 2016 @ 14:00) and timezone=PDT, the DateIterable doesn't entirely respect the timezone I input--it spits out a Date with UTC time (e.g., July 19, 2016 @ 21:00). The workaround is to initialize the DateIterable with UTC time, but it isn't readily apparent that that's what a user should do.

I've written a small script that reproduces this issue (see below). I suspect that one of the issues is in DateIteratorFactory#dateToDateValue(Date, boolean), but it might be deeper in the iterator generator code. (I also realize that this is code ported from Google's RFC2445 lib, so feel free to tell me that this isn't your problem anymore )

TimeZone timezone_pdt = TimeZone.getTimeZone("America/Los_Angeles");
Date startDate = new Date(2016, 7, 17, 14, 0, 0);

DateIterable workaroundIterable = DateIteratorFactory.createDateIterable("RRULE:FREQ=WEEKLY;BYDAY=TU", startDate, DateTimeZone.UTC.toTimeZone(), true);
DateIterable PDTInitializedIterable = DateIteratorFactory.createDateIterable("RRULE:FREQ=WEEKLY;BYDAY=TU", startDate, timezone_pdt, true);

int count = 3;

SimpleDateFormat sdf_pdt = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz");
sdf_pdt.setTimeZone(timezone_pdt);

SimpleDateFormat sdf_default = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz");

for (DateIterator pdtIter = PDTInitializedIterable.iterator(), workaroundIter = workaroundIterable.iterator(); pdtIter.hasNext() && workaroundIter.hasNext();) {
    Date pdtNext = pdtIter.next();
    Date utcNext = workaroundIter.next();
    System.out.println("Next PDT-initialized-iterable time: \t" + sdf_pdt.format(pdtNext)); // should be "14:00:00 PDT", but is "...21:00:00 PDT"
    System.out.println("Next workaround-created time: \t\t" + sdf_default.format(utcNext));
    System.out.println();

    if (--count == 0)
        break;
}

Output:

Next PDT-initialized-iterable time:     Thu Aug 17 21:00:00 PDT
Next workaround-created time:         Thu Aug 17 14:00:00 PDT

Next PDT-initialized-iterable time:     Tue Aug 22 21:00:00 PDT
Next workaround-created time:         Tue Aug 22 14:00:00 PDT

Next PDT-initialized-iterable time:     Tue Aug 29 21:00:00 PDT
Next workaround-created time:         Tue Aug 29 14:00:00 PDT

Original gitter conversation: https://gitter.im/mangstadt/biweekly?at=578eb63bac85f2507ad30fb1

Date value from iterator during Daylight Savings Gap Hour

Mike,

I would like to get your comments on a problem I am seeing regarding the Date returned from a DateIterator when the event occurs during the Daylight Savings Time (DST) "gap" hour (at least for the Pacific Time Zone) of 02:00 to 02:59. I have written a test shown below that illustrates the problem.

Specifically, for the occurrence on the day DST begins, the Date returned has the time as 01:30 when I believe it should be 03:30. Is my understanding of how the "gap" hour is handled incorrect or is my use of the library incorrect? Or Both? Also listed below is a test that uses Java 8's ZonedDate time for the same set of dates and in it the occurrence that would fall on the "gap" hour is advanced to 03:30.

Thank you in advance for any feedback.

       /**
     *  Output:
     *      Sun Mar 06 02:30:00 PST 2016
     *      Sun Mar 13 01:30:00 PST 2016 <-- Should be 03:30?
     *      Sun Mar 20 02:30:00 PDT 2016
     * @throws ParseException
     */
    @Test
    public void daylightSavingsGapHour() throws ParseException {
        final TimeZone pacificTimeZone = TimeZone.getTimeZone("America/Los_Angeles");

        // Start date: March 6, 2016 at 02:30 - one week before DST begins
        RecurrenceIterator recurrenceIterator = RecurrenceIteratorFactory.createRecurrenceIterator(
                "RRULE:FREQ=WEEKLY;INTERVAL=1;COUNT=3", new DateTimeValueImpl(2016, 3, 6, 2, 30, 0), pacificTimeZone, true);

        DateIterator dateIterator = DateIteratorFactory.createDateIterator(recurrenceIterator);
        while (dateIterator.hasNext()) {
            Date next = dateIterator.next();
            System.out.println(next);
        }
    }

Here is an example of date-time stamps I think should be given using Java 8's ZonedDateTime:

    /**
     *  Output:
     *      2016-03-06T02:30-08:00[America/Los_Angeles]
     *      2016-03-13T03:30-07:00[America/Los_Angeles] <--- Time is at 03:30 and in DST (e.g. -07:00 offset)
     *      2016-03-20T02:30-07:00[America/Los_Angeles]
     */
    @Test
    public void gapHourUsingJavaTimePackage() {
        // Time is March 6, 2016 at 02:30 (One week before DST begins)
        final ZonedDateTime start = ZonedDateTime.of(2016, 3, 6, 2, 30, 0, 0, ZoneId.of("America/Los_Angeles"));
        System.out.println(start);

        // Add One week
        ZonedDateTime march13th2016 = start.plusWeeks(1);
        System.out.println(march13th2016);

        // Add two weeks
        ZonedDateTime march20th2016 = start.plusWeeks(2);
        System.out.println(march20th2016);
    }

VTimezone

Hello,

I think I'm having a problem with timezones in an iCalendar example I'm using.

I created a recurring event on outlook and exported to iCalendar format for testing. It uses my timezone. The resulting iCalendar data is in here http://pastebin.com/ABXCD18s

So, it contains two VTIMEZONE objects, and the VEVENT references them like:
DTSTART;TZID="Unnamed Time Zone 1":20160805T150000
DTEND;TZID="E. South America Standard Time":20160805T153000

This is supposed to be America/Sao_Paolo timezone which is -3:00 GMT. So I try to verify the final value I'm getting like (using joda time):

    assertEquals(new DateTime(Instant.parse("20160805T150000", DateTimeFormat.forPattern("yyyyMMdd'T'HHmmss"))).toDateTime().plusHours(3).getMillis(), event.getDateStart().getValue().getTime());

    assertEquals(new DateTime(Instant.parse("20160805T153000", DateTimeFormat.forPattern("yyyyMMdd'T'HHmmss"))).toDateTime().plusHours(3).getMillis(), event.getDateEnd().getValue().getTime());

If I use direct GMT values the test works. What I'm I missing to make sure the time is taking into consideration the vtimezone?

ICalendar to Android Intent

Hello,

I'm starting to use the biweekly library, and I want to use the parsed iCalendar data to create an intent that will prompt the user to add the event to its calendar app.

Is there any easy way to do that?
I'm having to get each value and fill the intent specific parameter.

I'm stuck on the RRULE. I think I need to pass a single RAW String to the RRULE android field, like: "FREQ=WEEKLY;COUNT=9;BYDAY=WE,FR"

When I parse the event I can't find a way to get this raw parameter string that was included in the icalendar data. How can I do that without the need to reconstruct the string using each separated parameter value?

Recurrence iterators for all-day events include a time component

The attached iCalendar file contains an all-day event (the DTSTART is a "date" as opposed to a "date/time"). When outputting its dates generated by a recurrence iterator, the dates have a time component. But they should not have time components because it is an all-day event.

Code:

ICalReader reader = new ICalReader(new File("[email protected]"));
ICalendar ical = reader.readNext();
VEvent event = ical.getEvents().get(1);

System.out.println("Start: " + event.getDateStart().getValue());
DateIterator iterator = event.getDateIterator(TimeZone.getDefault());

int count = 0;
while (iterator.hasNext()) {
    if (++count == 10) break;
    final Date date = iterator.next();
    System.out.println(date);
}

Output:

Start: Mon Jun 06 00:00:00 EDT 2016
Sun Jun 05 20:00:00 EDT 2016
Sun Jun 19 20:00:00 EDT 2016
Sun Jul 03 20:00:00 EDT 2016
Sun Jul 17 20:00:00 EDT 2016
Sun Jul 31 20:00:00 EDT 2016
Sun Aug 14 20:00:00 EDT 2016
Sun Aug 28 20:00:00 EDT 2016
Sun Sep 11 20:00:00 EDT 2016
Sun Sep 25 20:00:00 EDT 2016

Test_obalqpctbh1c4f66r683opue5g@group.calendar.google.com.ics.txt

DateIterator.advanceTo fails to advance under certain conditions

In the course of using the advanceTo method on a DateIterator I have come across an issue that exists in release 0.4.6 whereby the advanceTo method on an DateIterator fails to actually advance.

This unit test below illustrates the problem. In the unit test, a Recurrence is created with a DAILY frequency, a start time of 2016-07-01 00:01:00, and a time zone of America/Los_Angeles. After fetching the iterator it is advanced to 2016-07-01 06:59:00 then next is called on the iterator. The first occurrence, which is the start time, should be skipped but it is not.

@Test
    public void advanceIterator() {

        // Use time zone with negative offset
        TimeZone pacificTimeZone = TimeZone.getTimeZone("America/Los_Angeles");
        Date startTime = date("2016-07-01 00:01:00", pacificTimeZone);
        Date advanceTo = date("2016-07-01 06:59:00", pacificTimeZone); // advance iterator to the time that is 1-minute less than the time zone offset.

        // Note: date-time used for advancement must first be converted to UTC first.
        Recurrence recur = new Recurrence.Builder(Recurrence.Frequency.DAILY).count(4).build();
        RecurrenceProperty recurrenceProperty = new RecurrenceProperty(recur);
        DateIterator it = recurrenceProperty.getDateIterator(startTime, pacificTimeZone);
        it.advanceTo(new Date(advanceTo.getTime())); //

        //@formatter:off
        // First occurrence is skipped. The last three occurrences should be returned.
        List<Date> expected = Arrays.asList(
                date("2016-07-02 00:01:00", pacificTimeZone),
                date("2016-07-03 00:01:00", pacificTimeZone),
                date("2016-07-04 00:01:00", pacificTimeZone)
        );
        //@formatter:on

        List<Date> actual = new ArrayList<Date>();
        while (it.hasNext()) {
            actual.add(it.next());
        }

        assertEquals(expected, actual);
    }

The root cause of the problem appears to be method convert in TimeUtils.java: https://github.com/mangstadt/biweekly/blob/master/src/main/java/biweekly/util/com/google/ical/util/TimeUtils.java#L88-89

When converting from UTC within method convert, line 89 where method addSeconds is called, is not necessary. The UTC time passed into the method has already been adjusted to the time zone passed into convert by line 88. Because addSeconds is called, the DateTimeValue returned in line 88 is further adjusted by the offset of the time zone in use. For the unit test above, the DateTimeValue returned by line 88 is 2016-07-01 06:59:00. The call to addSeconds causes -25,200 seconds (e.g. -7 hours) to be added which adjusts the value (back) further to 2016-06-30 23:59:00. Note this is actually prior to the start time. Because the iterator is now behind the the start-time, the first call to next causes the occurrence at the start-time to be returned.

It should be noted that this problem arose due to PR #39, which I submitted. That PR resolved an issue related to the DST gap hour but apparently created the issue reported here. The problem described by this issue does not exist in releases prior to 0.4.6, though the issue resolved by PR #39 would exist.

I am working on a fix for this issue and associated unit tests. A PR will be submitted for your review today or tomorrow.

mvn package fails due to testrun

I can't build JAR-Package because the testrun fails:

Results :

Failed tests:
  Google2445UtilsTest.getDateIterator:124->assertIteratorEquals:132 expected:<Sun Mar 27 20:00:00 CEST 2016> but was:<Sun Mar 27 15:00:00 CEST 2016>

Tests run: 1036, Failures: 1, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8.862s
[INFO] Finished at: Tue Aug 23 10:33:13 CEST 2016
[INFO] Final Memory: 32M/457M
[INFO] ------------------------------------------------------------------------

Make VTimezone Serializable

I'm trying to use ICalWriter on a production host that has no access to internet. When I call icalWriter.getTimezoneInfo().setDefaultTimeZone(tz);, it indirectly uses TzUrlDotOrgGenerator, which need access to the internet and thus blocks my code.

One way I thought of fixing this is to obtain the VTimezone instance on a host with internet access, serialize it, and then de-serialize it on the "real" app code. The main problem is that VTimezone is not serializable :(

java.time support

Are you planning to provide a support of java.time (LocalDateTime, Datetime etc) for usage of Date, DateTime classes?

Not necessarely for internal working, but as parameters for methods?

Iterator for Union of RecurrenceRule, RecurrenceDates, and ExceptionDates

I'm curious if it is possible to combine a biweekly.property.RecurrenceRule, a biweekly.property.RecurrenceDates, and an biweekly.property.ExceptionDate and then obtain a DateIterator (or some variant of it) of their union? The application I am working on will need to account for RDates and ExDates when computing occurrences of an event from a recurrence rule. The getDateIterator method on biweekly.property.RecurrenceRule does not appear to handle RecurrenceDates and ExceptionDates.

The static join method in com.google.ical.iter.RecurrenceIteratorFactory would appear to do what I need. Just curious if there is some analogous functionality in the biweekly package.

Performance issue parsing iCalendar files with VTIMEZONE components

spring.ics.txt

Parsing the above iCalendar file takes a very long time. Removing the VTIMEZONE component from the file speeds the parse time up significantly, so the issue appears to be with how biweekly is handling this component.

The bottleneck seems to be that, in order to convert the necessary date/time property values to the given timezone, it wants to calculate the daylight savings time switch-over dates for every year since 1600 (this is the start date defined in the VTIMEZONE component). And it repeats this process from scratch for every date/time property that's using the timezone.

The code in question is located in the ICalTimeZone.getObservanceBoundary(int, int, int, int, int, int) method. In two places, a RecurrenceIterator object is created and iterated over until the right date is found. Caching the values that this iterator generates may help with performance. It is unclear whether the RecurrenceIterator.advanceTo() method will help, as this may cause the iterator to skip over the value that it's looking for (in at least one case).

Workaround:

A workaround is to use Olson timezone IDs. This forces biweekly to use Java's integrated timezone definitions, which greatly speeds up the parsing process. To do this, simply prepend every TZID parameter value with a "/", like so:

DTSTART;TZID="/Europe/Istanbul":20160628T110000

If you have no control over how the .ics files are created, this could be accomplished with some simple "find and replace" code on the .ics file contents.

RRULE.UNTIL requires UTC time

When events are published with local timezone info, some clients (Outlook, Google Calendar) do not interpret "until" time of recurring events correctly. Turns out that rfc5545 specification of UNTIL requires: "If specified as a DATE-TIME value, then it MUST be specified in a UTC time format." (see http://tools.ietf.org/html/rfc5545#section-3.3.10 for all the complex details).
I fixed rendering of "until" in RecurrencePropertyScribe to always use UTC, see attached patch. Clients are interpreting my use cases properly now.
Please review and decide whether this fix is generally useful.

Thanks
Peter

Reported by: pmenhart

Original Ticket: biweekly/tickets/10

Cannot selectively ignore parse warnings

I want to be able to parse ICalendar's that use global ID's for timezones rather than a VTIMEZONE component. Whenever I try to parse an ICalendar that is formatted this way, I get this warning: (37): No VTIMEZONE component exists. ID will be treated as an Olsen timezone ID instead. Which is fine. Except that the ParseWarnings object just stores a list of error messages as Strings with no mapping to the error code, so I have to do something like this to ignore the warning:

reader.getWarnings().forEach(warning -> {
          if (!warning.startsWith("(37)")) {
            errorResponse.addMessage(warning);
          }
        });

I don't think this is a good way to do this at all, especially because I have seen parse warnings that start with the line number rather than the error code.

Feature Request: Streaming components

It would be nice to have a reader or a visitor to stream components (VEVENT, etc.) as they're encountered instead of reading all of them into memory. This would allow for reading larger calendars without the memory concerns.

NPE when parsing REPLY without VERSION

The following slightly-malformed REPLY:

BEGIN:VCALENDAR
METHOD:REPLY
BEGIN:VEVENT
DTSTAMP:20050317T164626Z
DTSTART:20050318T170000Z
UID:040000008200E00074C5B7101A82E00800000000A0DD17CECD2AC501000000000000000010000000DA4A35FDD8F70E4686F330A21558AF27
ATTENDEE;PARTSTAT=ACCEPTED;CN="Roland Schtroumpf":MAILTO:[email protected]
LOCATION:866-555-3378, conf ID = 650-555-0500, passcode = 255455
DTEND:20050318T180000Z
END:VEVENT
END:VCALENDAR

Causes the following NPE:

Caused by: java.lang.NullPointerException: null
    at biweekly.io.scribe.property.AttendeeScribe._defaultDataType(AttendeeScribe.java:51) ~[biweekly-0.4.6.jar:na]
    at biweekly.io.scribe.property.ICalPropertyScribe.defaultDataType(ICalPropertyScribe.java:171) ~[biweekly-0.4.6.jar:na]
    at biweekly.io.text.ICalReader._readNext(ICalReader.java:301) ~[biweekly-0.4.6.jar:na]
    at biweekly.io.StreamReader.readNext(StreamReader.java:150) ~[biweekly-0.4.6.jar:na]

Java 8 LocalDate and DateTime compatibility

There could be added LocalDateIteratorFactory and DateTimeIteratorFactory as java.time support. In google-rfc-2445 there are already implemented similar iterators for jodatime compatibility.

biweekly should output all day event DTSTART/DTEND fields as DATE type values

The spec defines DTSTART and DTEND as being able to be either a DATE-TIME or a DATE value type. biweekly always outputs whole day events with a date with a time of midnight (sans timezone). While this techincally the same timespan as an all day event, most calendar apps, including Google and Yahoo calendars treat this as a time-bounded event. And if there is ambiguity about the timezone of the calendar because it's ommitted, then all day events often end with their times up being offset by the timezone inferred by the calendar system that is subscribed to an ical feed.

To avoid this, biweekly should output dates from all date events using DATE values and not DATE-TIME values.

The spec says (http://tools.ietf.org/html/rfc5545#section-3.8.2.4):

Value Type: The default value type is DATE-TIME. The time value MUST be one of the forms defined for the DATE-TIME value type. The value type can be set to a DATE value type.

But biweekly is parsing DTSTART and DTEND dates that are just DATEs as DATE-TIMEs and setting the time to T000000. For example, reading in an ICS with

DTSTART;VALUE=DATE:20141005

results in an entry which biweekly will output as:

DTSTART:20141005T000000

The behavor ICalPropertyScribe$DateWriter.write() should be to prefix the value with "VALUE=DATE:" and omit the time and timezone portion when the hasTime is false.

Reported by: evaneaston

Original Ticket: biweekly/tickets/7

Provide a way to cancel an existing events

I have been searching through the documentation and don't see any way to create an ics file that cancels an existing event. I have just started using this library and it is fantastic. Just wanted to add event cancellations to the wish list :).

Timezone issue in com.google.ical.compat.javautil.DateIteratorFactory

The method:

  public static DateIterator createDateIterator(
      String rdata, Date start, TimeZone tzid, boolean strict)
      throws ParseException {
    return new RecurrenceIteratorWrapper(
        RecurrenceIteratorFactory.createRecurrenceIterator(
            rdata, dateToDateValue(start, true),
            tzid, strict));
  }

claims it will use the timezone to interpret the start parameter, but it does not actually do that. The GregorianCalendar that is created in dateToDateValue is hard-coded to UTC, and thus the start parameter is not properly handled if the tzid is not UTC.

The following unit test shows the issue:

    @Test
    public void testTimeZoneHandling() throws Exception {
        TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
        Calendar calendar = Calendar.getInstance(timeZone, Locale.US);
        calendar.clear();
        calendar.set(2015, Calendar.JANUARY, 1, 0, 0, 0);
        Date start = calendar.getTime();
        DateIterator dateIterator = DateIteratorFactory.createDateIterator("RRULE:FREQ=DAILY;INTERVAL=1", start, timeZone, true);
        Date next = dateIterator.next();
        assertEquals(start, next);
    }

I believe that the RecurrenceIteratorWrapper and the RecurrenceIterableWrapper need to store the timezone, and use it when converting between internal date formats and java.util.Dates. The only method I'm not sure about is public static DateIterator createDateIterator(RecurrenceIterator rit), which would then require a timezone parameter, although adding one does not work properly.

As a work-around, I'm explicitly using createDateIterator(createRecurrenceIterator(rrule, start, timeZone, true)) and manually building the DateValue using the correct time zone for the start date.

Note: This unit test can be used to verify that public static DateIterator createDateIterator(RecurrenceIterator rit) continues to work correctly, with any changes that are made.

    @Test
    public void testTimeZones_viaRecurrenceIterator() throws Exception {
        TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
        RecurrenceIterator recurrenceIterator = RecurrenceIteratorFactory.createRecurrenceIterator("RRULE:FREQ=DAILY;INTERVAL=1", new DateTimeValueImpl(2015, 1, 1, 0, 0, 1), timeZone, true);
        DateIterator dateIterator = DateIteratorFactory.createDateIterator(recurrenceIterator);
        Date next = dateIterator.next();

        Calendar calendar = Calendar.getInstance(timeZone, Locale.US);
        calendar.clear();
        calendar.set(2015, Calendar.JANUARY, 1, 0, 0, 1);
        Date start = calendar.getTime();
        assertEquals(start, next);
    }

Multiple CATEGORY properties within a calendar component

According to spec "more than one category can be specified as a COMMA-separated list of categories" (p. 81) which implies that it should appear only once within an event.
However the method "VEvent.addCategories(String... categories)" adds a new CATEGORIES property every time it is invoked. The same applies to other components where the CATEGORIES property is allowed: VTodo, VJournal.
In my point of view adding new categories should append them to the CATEGORIES property if one exists.

Reported by: bjgumble

Original Ticket: biweekly/tickets/5

Working with outputstream

Consider the following code :

ICalendar ical = getCalendar();
File file = new File("target/test-simpleCalendarToOutputStream.ics");
FileOutputStream fileOutputStream = new FileOutputStream(file);
ical.write(fileOutputStream);

Nothing is written into the file.

When you dive into biweekly source code, you'll find :

public void go(OutputStream out) throws IOException {
    go(new ICalWriter(out));
}

Writer needs to be flush at one point.

FYI, you don't have any problem with file directly (not through output stream), because the writer is properly close (and flush before that automatically) :

public void go(File file, boolean append) throws IOException {
    ICalWriter icalWriter = new ICalWriter(file, append);
    try {
        go(icalWriter);
    } finally {
        IOUtils.closeQuietly(icalWriter);
    }
}

The go(OutputStream out) should manage the writer with a proper closing.

Reported by: rgonord

Original Ticket: biweekly/tickets/4

Error parsing duration value that begins with "+"

From @dankarp via gitter:

When a VALARM has a TRIGGER that goes off at the start of the event, biweekly's VAlarm.getTrigger() returns null. This seems like a really bad idea.

BEGIN:VALARM
ACTION:DISPLAY
DESCRIPTION:REMINDER
TRIGGER;RELATED=START:+PT00H00M00S
END:VALARM

VAlarm.getTrigger() returns null because an error occurs when the property's duration value is parsed. The parser incorrectly thinks the "+" at the beginning of the duration string is invalid.

license clarification

Hi

I really like this lib and would like to use it in a project. However, when dealing with enterprise orgs and/or OSS redistribution, the license is a cruical factor.
From what I understand, you use a custom "this is my license" license. Did you consider switching this to a more standard way? I really don't care if its apache, gnu or whatever, but it would be helpful to argue "pro" biweekly if it would be a known one.

Concerns?

Jan

Value-less parameters cause exception to be thrown

If a parameter is value-less, then a NullPointerException is thrown when attempting to insert the parameter into the multimap.

Example:

::text
ATTACH;FMTTYPE:application/postscript:ftp://xyzCorp.com/pub/
```~~

Stack trace:

```~~
:::text
Exception in thread "main" java.lang.NullPointerException
at biweekly.parameter.ICalParameters.sanitizeKey(ICalParameters.java:591)
at biweekly.parameter.ICalParameters.sanitizeKey(ICalParameters.java:42)
at biweekly.util.ListMultimap.get(ListMultimap.java:112)
at biweekly.util.ListMultimap.put(ListMultimap.java:81)
at biweekly.io.text.ICalRawReader.parseLine(ICalRawReader.java:125)
at biweekly.io.text.ICalRawReader.start(ICalRawReader.java:70)
at biweekly.io.text.ICalReader.readNext(ICalReader.java:172)
at biweekly.Biweekly$ParserChainText.first(Biweekly.java:447)
at biweekly.Biweekly$ParserChainTextString.first(Biweekly.java:570)
at Tests.TestBiWeeklyParsing.parse(TestBiWeeklyParsing.java:92)
at Tests.TestBiWeeklyParsing.main(TestBiWeeklyParsing.java:52)
```~~

See: https://sourceforge.net/p/biweekly/discussion/help-and-support/thread/e5efcfc4/

Reported by: mangstadt

Original Ticket: [biweekly/tickets/1](https://sourceforge.net/p/biweekly/tickets/1)

Boolean allDay

Hi,

I am using biweekly to add events on Outlook, it works fine but i can't find any boolean "all day event". Without this boolean, i can't set the related checkbox in outlook even if my dateStart and dateEnd are ok.

Waiting to hear from you,
Yours sincerely

Disable Zulu time when timezones specified

I have multiple VTIMEZONE objects specified in my calendar, all of which are being used by VEVENTS. I do not want to specify a timezone for the calendar as a whole, but rather on individual events.

Perhaps I am mistaken, but it seems as though specifying a timezone property on a VEvent object should cause it to be serialized without a Zulu time. An example, using Scala but should work same in Java:

val timezoneIds = List("America/Seattle")

// Create some timezones
val timezones: List[VTimezone] = buildTimezones(timezoneIds)

// Create a DateStart
val dtStart = new DateStart(startTime)
val dtEnd = new DateEnd(endTime)

// Create timezone params and add to start and end
val params = new ICalParameters()
params.setTimezoneId(timezoneIds(0)) // Example, use the first timezone
dtStart.setParameters(params)
dtEnd.setParameters(params)

// Add the start and end to an event
val event = new VEvent()
event.setProperty(dtStart)
event.setProperty(dtEnd)

val calendar = new iCalendar()

calendar.addEvent(event)


val writer = new ICalWriter(buffer, ICalVersion.V2_0)

// Add the timezone
writer.getTimezoneInfo.assign(timezones(0), TimeZone.getTimeZone(timezoneIds(0))

// Write to a string
val buffer = new ByteArrayOutputStream()
val written = f(writer)
written.flush()
written.close()
val calString = new String(buffer.toByteArray)

// calStrig now contains a VTimezone object, and VEvent object in the format
// DTSTART;TZID=America/Seattle:20160505T150000Z

There is mention in the "Working with Timezones" page about using icalWriter.getTimezoneInfo().setDefaultTimeZone(tz); to set timezones for the calendar as a whole. I do not need to specify a global timezone as all events have a timezone specified, however if that is the best solution I could specify a bunk timezone to prevent the Zulu time specification.

Hope this makes sense, happy to provide more clarification

How to get string representation of Recurrence?

Hi, thanks for this library.

I am creating recurrence as following:

Recurrence recurrence = new Recurrence.Builder(Frequency.DAILY).build();

Question: how to get string representation of Recurrence?

Parse errors (or lack thereof)

When I try to run the readme reader code but put in leading spacing on the string literal, rather than an error as I expected, I simply get an empty collection.

I'm not sure if parse is supposed to be able to handle arbitrary streams, but it seems desirable that it throws an error if it gets a malformed stream. Thoughts?

TimezoneInfo cannot be completely decoupled from iCalendar object

Currently, when biweekly parses an iCalendar object, the object's timezone information is stored separately from the parsed ICalendar object. The idea behind this was that, because a date/time value can be formatted in any number of timezones, the timezone that a date is formatted in is more of a serialization matter, and should be separated from the "raw" iCalendar data.

For example, if a DTSTART property is formatted in the "America/New_York" timezone (as opposed to UTC time), then the property's date value is parsed according to that timezone and saved to the ICalendar object as a Java Date object (which does not retain the timezone that the date was parsed under). The fact that the property was originally formatted in "America/New_York" time is stored in a separate TimezoneInfo object, obtained by calling ICalReader.getTimezoneInfo() immediately after parsing the ICalendar object.

However, this becomes a problem with recurrence rules. They require a timezone in order to properly compute the date/value values they cover. Therefore, it is vitally important that the timezone in the original iCalendar file be preserved and be treated as part of the "raw" iCalendar data.

A possible fix for this problem would be to store the TimezoneInfo object inside the ICalendar object. This way, the TimezoneInfo object is more securely "attached" to its ICalendar object.

DaySaveTime issue

Hi mangstadt
I used the biweekly(version 0.6.0) to generate executed times. But if the date value equals
' Sun Nov 06 01:46:46 PST 2016' or ' Sun Nov 06 01:46:46 PDT 2016'
the result is same. I am not sure that is correct.
If there is no problem, pls ignore this issue.

The code:
` final TimeZone pacificTimeZone = TimeZone.getTimeZone("America/Los_Angeles");

Recurrence.Builder builder = new Recurrence.Builder(Frequency.DAILY);
builder.count(5);
builder.interval(1);
RecurrenceIterator recurrenceIterator = RecurrenceIteratorFactory.createRecurrenceIterator(builder.build(), date, pacificTimeZone);
DateIterator dateIterator = DateIteratorFactory.createDateIterator(recurrenceIterator);
while (dateIterator.hasNext()) {
System.out.println(dateIterator.next());
}`

date = 'Sun Nov 06 01:46:46 PDT 2016'
Output
Sun Nov 06 01:46:46 PST 2016
Mon Nov 07 01:46:46 PST 2016
Tue Nov 08 01:46:46 PST 2016
Wed Nov 09 01:46:46 PST 2016
Thu Nov 10 01:46:46 PST 2016

date = 'Sun Nov 06 01:46:46 PST 2016'
Output
Sun Nov 06 01:46:46 PST 2016
Mon Nov 07 01:46:46 PST 2016
Tue Nov 08 01:46:46 PST 2016
Wed Nov 09 01:46:46 PST 2016
Thu Nov 10 01:46:46 PST 2016

mybatis example

Not sure if this is the right channel. If not, please indicate which channel to use.

Any example on how to use biweekly with mybatis? Working on an application where biweekly VEvent need to be store in a database.

Thanks.

Bug in ICalDate(Date, DateTimeComponents, boolean)

From thread: https://sourceforge.net/p/biweekly/discussion/help-and-support/thread/0540a0b1/?limit=25#e251

This constructor uses the Calendar class to remove the time components from the specified date. The Calendar object returned from Calendar.getInstance defaults to using the default timezone for the device (machine). This causes the resulting date to be offset by the default timezone’s offset from UTC. As an example:

I want to create an all day event with a start date of 9/24/2015 and end date of 9/25/2015. I pass in a date object for 9/24/2015 00:00:00, and 9/25/2015 00:00:00 (obviously UTC, since all Dates are UTC). My timezone is CDT (UTC-5:00). What happens is, the Calendar object has a time of 9/23/2015 19:00:00, because it’s in CDT time, and I end up with a date of 9/23/2015 with the time components removed.
This should be a simple matter of adding the line: c.setTimeZone(TimeZone.getTimeZone("UTC”));

Reported by: mangstadt

Original Ticket: biweekly/tickets/13

Attendee/Organizer emails not discovered with upper case MAILTO

Outlook.com produces ics files with MAILTO URIs:

ATTENDEE;CUTYPE=INDIVIDUAL;CN=John Doe;ROLE=REQ-PARTICIPAN
 T;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:MAILTO:[email protected]
ORGANIZER;CN=John Smith:MAILTO:[email protected]

The biweekly API returns null for the email on the attendee/organizer. If you lower-case the URI, it works as expected:

ATTENDEE;CUTYPE=INDIVIDUAL;CN=John Doe;ROLE=REQ-PARTICIPAN
 T;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:mailto:[email protected]
ORGANIZER;CN=John Smith:mailto:[email protected]

Is case sensitivity required? The specs I've seen usually document them as upper case. In practice, most clients seem to use lower case (except outlook.com).

Test Case (groovy):

@Test
void testOutlookCalendar() {
    def ical = Biweekly.parse(new FileInputStream("test-outlook.ics")).first()
    assertEquals("[email protected]", ical.events.first().attendees.first().email)
    assertEquals("[email protected]", ical.events.first().organizer.email)
}

See attached file: test-outlook.ics.zip

EnumProperty could be Enums

I'm curious why EnumProperty classes like Method aren't Java enums.

It would seem to make it much easier to parse them.

Even not being enums, one can't even do:

switch(method.getValue()) {
case Method.PUBLISH:
}

because Method.PUBLISH is private.

Daylight savings start time data loss

It appears that some data loss can occur when parsing daylight savings start times. For example:

:::java
//daylight savings start time for Paris, France:
//March 31, 2013 at 02:00
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Paris"));
DateFormat df = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
Date date = df.parse("20130331T020000");
System.out.println(df.format(date));
//expected: "20130331T020000"
//actual: "20130331T030000"
```~~

In the example above, "20130331T020000" should be printed, but "20130331T030000" is printed instead.

It looks like the data loss occurs when the default timezone of the local computer is the same as the timezone being parsed.

iCalendar example:

```~~
:::text
BEGIN:VCALENDAR
BEGIN:VTIMEZONE
TZID:Europe/Paris
BEGIN:DAYLIGHT
DTSTART:20130331T020000
...
END:DAYLIGHT
END:VTIMEZONE
END:VCALENDAR
```~~

If the local computer's timezone is "Europe/Paris", then it will appear as if the `DTSTART` property in the example above is set to "20130331T030000".  However, its true value is "20130331T020000".

Discussion: https://sourceforge.net/p/biweekly/discussion/help-and-support/thread/cb55fc2a/

**Workaround:**

Use the attached marshaller and property classes to get the raw string value of all DTSTART properties:

```~~
:::java
String str = 
"BEGIN:VCALENDAR\r\n" +
"BEGIN:VTIMEZONE\r\n" +
"BEGIN:DAYLIGHT\r\n" +
"DTSTART:20130331T020000\r\n" +
"END:DAYLIGHT\r\n" +
"END:VTIMEZONE\r\n" +
"END:VCALENDAR\r\n";

ICalendar ical = Biweekly.parse(str).register(new DateStartRawMarshaller()).first();
DateStartRaw prop = ical.getTimezones().get(0).getDaylightSavingsTime().get(0).getProperty(DateStartRaw.class);
System.out.println(prop.getValueRaw());
```~~

Reported by: mangstadt

Original Ticket: [biweekly/tickets/3](https://sourceforge.net/p/biweekly/tickets/3)

google-rfc2445 confict

We are currently using the 'original' google-rfc2445 jar and its jodatime compatibility package. As biweekly uses its own copy of google-rfc2445 without that package (presumably to avoid a dependency), we have to face a conflict.
A possible solution would be to rename biweekly's package to something like biweekly.com.google.ical.

How convert Android event recurrence params into Biweekly objects?

Hi @mangstadt, I am new in your library and I'd like to sorry in advance if the question is trivial. I want to select android events and convert them into VEvent for future processing. I am stuck with converting from string and setting following fields:

CalendarContract.Events.RRULE (String),
CalendarContract.Events.RDATE (String), 
CalendarContract.Events.EXDATE (String), 
CalendarContract.Events.EXRULE (String)

I need probably these methods from your library

setRecurrenceRule();
addRecurrenceDates();
addExceptionRule();
addExceptionDates();

but I haven't found how to parse their parameters from string. How can I do that with your library?

Thanks for your library and I highly appreciate your help.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.