Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TimeZones Break between Months #130

Open
bstock21 opened this issue Mar 6, 2024 · 3 comments
Open

TimeZones Break between Months #130

bstock21 opened this issue Mar 6, 2024 · 3 comments

Comments

@bstock21
Copy link

bstock21 commented Mar 6, 2024

I've encountered a situation where advancing hourly with DateIterator does not respect the rules for iterating.

Below I have sudo code which consists of an hourly Recurrence Rule and a date of Jan 31 at 18:00 CST. Which should iterate to Jan 31 at 19:00 CST but instead iterates to Feb 1 at 00:00 CST. Probably has something to do with the difference in time between UTC and current time zone CT.
Please see my sudo code and advise.

// Happening with version 0.6.8

// Params

long after = 1706745600001; // 2024-01-31T18:00:00.001-0600
TimeZone timezone = TimeZone.getTimeZone("America/Chicago");
VEvent event = new VEvent();
event.setDateStart("Mon Jan 01 00:00:00 CST 2024")
event.setRecurrenceRule("[""rrule"", {}, ""recur"", {""freq"": ""HOURLY""}]]") // everything else is 0 or null


biweekly.component.VEvent
  biweekly.property.Uid [ parameters={} | value=c20b6b14-5ebb-47be-a167-eaa4cbc338b3 ]
  biweekly.property.DateTimeStamp [ parameters={} | value=Wed Mar 06 08:39:01 CST 2024 ]
  biweekly.property.DateStart [ parameters={} | value=Mon Jan 01 00:00:00 CST 2024 ]
  biweekly.property.RecurrenceRule [ parameters={} | value=biweekly.util.Recurrence@697f8f09 ]



// Code

DateIterator it = event.getDateIterator(timezone);
it.advanceTo(new Date(after)); // after = 2024-01-31T18:00:00.001-0600
while (it.hasNext()) {
	Date next = it.next(); // next == Thu Feb 01 00:00:00 CST 2024
}   
@mangstadt
Copy link
Owner

mangstadt commented Mar 9, 2024

biweekly.util.com.google.ical.compat.javautil.DateIteratorFactory, line 100:
This is the advanceTo implementation that is called.

biweekly.util.com.google.ical.compat.javautil.DateIteratorFactory, line 159:
In this method, the Date object is converted to a DateValue object, which represents the Date object in UTC time. Then, it checks to see if the DateValue object's time component is midnight. In this case, the time component is midnight because 18:00 CST is 00:00 UTC. If it is midnight, then it treats it as a date value instead of a datetime value. This is what causes the problem. If this if statement is removed, the DateIterator works as expected.

mangstadt added a commit that referenced this issue Mar 9, 2024
@bstock21
Copy link
Author

That change is causing some issues with the createDateIterableUntimed test. When itterator.next() is called it's ignoring the Time Zone and just going to the next date.

image

@bstock21
Copy link
Author

bstock21 commented Aug 7, 2024

For anyone who finds this. Originally, I tried to work around this by just offsetting the time by 1 minute so it would never be midnight UTC. I encountered further issues though. Ultimately I just wrote a small iterator that suited my purposes.

`import biweekly.util.Frequency;

import java.util.Calendar;
import java.util.Date;

// This custom DateIterator exists because the date iterator from BiWeekly library is broken.
public class CustomDateIterator {
    private final Calendar calendar;
    private final Frequency intervalType;

    public CustomDateIterator(Date startDate, Frequency intervalType) {
        this.calendar = Calendar.getInstance();
        this.calendar.setTime(startDate);
        this.intervalType = intervalType;
    }

    public Date next() {
        addInterval();
        Date currentDate = calendar.getTime();
        return currentDate;
    }
    private void addInterval() {
        switch (intervalType) {
        case HOURLY:
            calendar.add(Calendar.HOUR, 1);
            break;
        case DAILY:
            calendar.add(Calendar.DAY_OF_YEAR, 1);
            break;
        case WEEKLY:
            calendar.add(Calendar.WEEK_OF_YEAR, 1);
            break;
        case MONTHLY:
            calendar.add(Calendar.MONTH, 1);
            break;
        }
    }

    public void reset(Date startDate) {
        calendar.setTime(startDate);
    }
}`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants