Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Feb 03 15:48

    mangstadt on master

    Update README for 0.6.7 release (compare)

  • Feb 03 15:33

    mangstadt on master

    [maven-release-plugin] prepare … (compare)

  • Feb 03 15:33

    mangstadt on 0.6.7

    (compare)

  • Feb 03 15:33

    mangstadt on master

    [maven-release-plugin] prepare … (compare)

  • Feb 03 15:07

    mangstadt on master

    Add unit test for Issue 121 ht… Add test for seeing if tzurl.or… Put URL-build code in its own m… and 2 more (compare)

  • Jan 06 02:54
    mangstadt closed #122
  • Jan 06 02:54
    mangstadt commented #122
  • Jan 04 22:11
    elmaimbo commented #122
  • Dec 26 2022 16:22
    mangstadt labeled #122
  • Dec 26 2022 16:22
    mangstadt commented #122
  • Dec 26 2022 16:21

    mangstadt on master

    Fix problem with recurrences th… (compare)

  • Dec 21 2022 01:30
    elmaimbo opened #122
  • Nov 06 2022 14:48
    mangstadt closed #115
  • Nov 06 2022 14:48
    mangstadt closed #117
  • Nov 06 2022 14:47
    mangstadt closed #118
  • Oct 22 2022 05:12
    M66B closed #121
  • Oct 22 2022 05:12
    M66B commented #121
  • Oct 21 2022 22:04
    mangstadt commented #121
  • Oct 19 2022 12:50
    M66B opened #121
  • Sep 08 2022 14:37
    mangstadt commented #120
Michael Angstadt
@mangstadt

Hi @dankarp. You can get this information by calling ICalReader.getTimezoneInfo() immediately after the ICalendar object has been parsed.

ICalReader reader = ...
ICalendar ical = reader.readNext();
TimezoneInfo tzinfo = reader.getTimezoneInfo();

DateStart dtstart = ical.getEvents().get(0).getDateStart();
java.util.TimeZone tz = tzinfo.getTimeZone(dtstart);
VTimezone vtimezone = tzinfo.getComponent(dtstart);
boolean floating = tzinfo.isFloating(dtstart);

Please let me know if this helps.

Dan Karp
@dankarp
Got it. I was using Biweekly.parse to parse the stream. I'll try doing it without the convenience methods.
Dan Karp
@dankarp
So the TimezoneInfo object is available during the parse but only the most recent is fetchable after each new ICalendar object is read? Perhaps it should also be persisted in the ICalendar object?
Dan Karp
@dankarp
Regardless, thanks! You have gotten me going!
Michael Angstadt
@mangstadt
@dankarp My reasoning for separating out the timezone information from the ICalendar object is that I thought it would be cleaner to treat the timezone info as part of how an iCalendar is serialized. After all, an iCalendar object can have the same exact same date/time information, but encoded in a variety of different timezones. Please let me know if you encounter any other difficulties!
Dan Karp
@dankarp
Ooh, I don't think that's correct. The recurrence is dependent on the timezone, so there's no way to regenerate the recurrence times without reparsing the original.
Michael Angstadt
@mangstadt
@dankarp Mmm, I didn't think of that. Is this what you need the timezone information for?
Dan Karp
@dankarp
Yep.
I need to take a text/calendar mail attachment and put it into an intermediate format that a calendar application can manage.
Michael Angstadt
@mangstadt
Well, isn't this a sticky situation. xD
Dan Karp
@dankarp
So if I end up with an appointment in Mountain Standard Time, I need to know that the recurrences are not going to shift when the rest of the country goes to daylight savings time.
Michael Angstadt
@mangstadt
And all this time I thought I was being clever.
Right.
Well, a workaround for the time being would be to store the timezone info using ICalReader.getTimezoneInfo() along with the ICalendar info.
Dan Karp
@dankarp
Yep, that's exactly what I'm doing now.
Michael Angstadt
@mangstadt
Any suggestions?
Dan Karp
@dankarp
I am, of course, completely hosed if the timezone doesn't have an Olson name, as I want to get out of the "store the full timezone definition each time" business. But that is my problem, not yours.
Well, the TimezoneInfo map could be persisted on the corresponding ICalendar object.
Michael Angstadt
@mangstadt
Maybe I'll do that. I'll have to think about it.
Dan Karp
@dankarp
No rush, now that I have the ICalReader.getTimezoneInfo() workaround.
Michael Angstadt
@mangstadt
Ok, thanks for the report.
Dan Karp
@dankarp
No problem!
Michael Angstadt
@mangstadt
@dankarp See: mangstadt/biweekly#46
Dan Karp
@dankarp
Thanks!
Dan Karp
@dankarp
I have an old iCalendar REPLY that throws an NPE when parsed.
BEGIN:VCALENDAR
METHOD:REPLY
BEGIN:VEVENT
DTSTAMP:20050317T164626Z
DTSTART:20050318T170000Z
UID:040000008200E00074C5B7101A82E00800000000A0DD17CECD2AC501000000000000000010000000DA4A35FDD8F70E4686F330A21558AF27
ATTENDEE;PARTSTAT=ACCEPTED;CN="Roland Schtroumpf":MAILTO:schtroumpf@example.com
LOCATION:866-555-3378, conf ID = 650-555-0500, passcode = 255455
DTEND:20050318T180000Z
END:VEVENT
END:VCALENDAR
It's malformed (missing a VERSION), but that shouldn't lead to an NPE.
Michael Angstadt
@mangstadt
@dankarp Thanks for the report. See my response in mangstadt/biweekly#48.
Parth
@ParthPadg
Hi @mangstadt - I've started integrating Biweekly into an Android app that I'm working on, and I've gotta say, it's a great library! Thanks so much for making an easy-to-use API!
I have one question though: it looks like the DateIterators that I can generate never actually terminate - even though I have a DTEND section under VEVENT, I still get iterator dates past the year 12,135!
I've tried both(?) ways of generating the DateIterator - either event.getRecurrenceRule().getDateIterator(event.getDateStart(), tzinfo) or event.getDateIterator(event.getDateStart(), tzinfo)
do you have any suggestions, or is there anything obvious that I'm missing?
(I can send over my sample ICal event that I'm using to test out my code, as well as my test code, if you'd like)
Parth
@ParthPadg
FYI - my current workaround is that I created a wrapper Iterator that checks each Date returned, validating that it's before the DTEND specified.
Parth
@ParthPadg
Well, now I feel stupid. I realized that my recurrence rule didn't have an UNTIL specified - so of course the DateIterator will be infinite!
Sorry for the spam - thanks again for the awesome library! :D
(PS - can't wait until timezone info is included inside the ICalendar object! Maybe having a JodaTime plugin, which would allow you to make the DateStart/End objects contain a DateTime, which knows about timezones?)
Michael Angstadt
@mangstadt
@ParthPadg Thanks for the compliments! I'm glad you like biweekly. There's always the potential for migrating to Java 1.8 and using Java's updated date/time API as well.
Parth
@ParthPadg

@mangstadt RE migrating to Java 1.8, what would that mean for Android Lollipop/Marshmallow support? Currently, only Android N supports 1.8 syntax.

One more question - if I wanted to use Biweekly to parse solely an RRULE, do you have any suggestions in regards to using the RecurrenceRuleScribe?
I'm currently initializing the Scribe using whatever compiles, which looks something like this:

RecurrenceRuleScribe scribe = new RecurrenceRuleScribe();
ParseContext pc = new ParseContext();
pc.setVersion(ICalVersion.V2_0);
ICalParameters icp = new ICalParameters();
RecurrenceRule rrule = scribe.parseText("FREQ=WEEKLY;BYDAY=MO,WE,FR", null, icp, pc);

Is there a better way to be doing this?

Michael Angstadt
@mangstadt
@ParthPadg Hmm, good point about Android. It's not just the syntax but the API as well. Only Java 1.8 has the new date/time API.
@ParthPadg Yes, you are initializing the RecurrenceRuleScribe correctly.
Parth
@ParthPadg

@mangstadt hopefully the last question for you!

I'm using RecurrenceRule.getDateIterator(startDate, timezone), and it's exhibiting the very expected behavior of "remembering" the last Date that it spat out. However, if I want to repeatedly check from the "beginning" (like, if the user exits a screen and comes back, and I need to show the first date again, etc.), is there a way to "reset" the DateIterator? I've tried DateIterator.advanceTo(Date), but that ignores the input if input < current.
Am I stuck with just calling RecurrenceRule.getDateIterator(startDate, timezone) every time I need to reset?

Michael Angstadt
@mangstadt
@ParthPadg Yes, you'll just have to call getDateIterator() again. There's no way to "reset" the iterator.
Parth
@ParthPadg

@mangstadt I know I've been asking a lot of questions, and I apologize!

But I think I've found a small bug in the DateIterable created from DateIteratorFactory.createDateIterable(String, Date, TimeZone, boolean).
The bug is: 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 originally wrote it using org.joda.DateTime objects, but someone pointed out that I should use java.util.Date to reduce confounding variables. Let me know if I'm doing anything funky as a result - I don't use java.util.Date much.

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 :) )

Script that repros this issue:

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
Michael Angstadt
@mangstadt
@ParthPadg Thank you for the report. If I recall correctly, other people have noticed this issue as well. Fortunately, biweekly does not call this method.
Does this code work correctly for you?
TimeZone timezone_pdt = TimeZone.getTimeZone("America/Los_Angeles");
TimeZone.setDefault(timezone_pdt);

Calendar c = Calendar.getInstance();
c.clear();
c.set(Calendar.YEAR, 2016);
c.set(Calendar.MONTH, Calendar.AUGUST);
c.set(Calendar.DATE, 17);
c.set(Calendar.HOUR_OF_DAY, 14);
Date start = c.getTime();

Recurrence recur = new Recurrence.Builder(Frequency.WEEKLY).byDay(DayOfWeek.TUESDAY).build();
RecurrenceRule rrule = new RecurrenceRule(recur);

DateIterator it = rrule.getDateIterator(start, timezone_pdt);
int count = 3;
while (--count >= 0) {
    System.out.println(it.next());
}
Parth
@ParthPadg

@mangstadt I believe that does work -- I was using it previously.
The reason why I switched to DateIteratorFactory.getDateIterable() is because it returns a DateIterable, which allows me to create a new Iterator instance upon every call to iterator(). Especially when using enhanced for-each syntax, it's then easy to ensure that we don't cache/reuse an old instance of the DateIterator.

Of course, the other workaround it just to pass the createDateIterable() method a UTC timezone, which is easy enough to do.

Either way, figured I'd send the bug report your way. Thanks for finding another workaround! :)

Michael Angstadt
@mangstadt
@ParthPadg Thanks again for reporting this issue. This issue has been reported previously in mangstadt/biweekly#16. I created a mangstadt/biweekly#51 based on our conversation. Thanks again!
Parth
@ParthPadg
@mangstadt sorry, I was on vacation so I didn't respond sooner. Thanks for creating the issue and for creating such an awesome library! :)
Michael Angstadt
@mangstadt
Thank you, @ParthPadg!
Naftoli Gugenheim
@nafg
Hi, just used Biweekly to write an email attachment in an app, so thanks for the library
Naftoli Gugenheim
@nafg
I was wondering though, why the API is so full of indirection... e.g. DateStart wraps an ICalDate which both wraps and extends java.util.Date, similar for Priority