fix full day recurring events east of UTC for RRULE/Luxon confusion, also update windows zones to include old offset based strings (UTC+05:00) US Eastern and Canada

This commit is contained in:
Sam Detweiler
2020-10-28 09:31:05 -05:00
parent 8a1d46deb4
commit a735275864
2 changed files with 196 additions and 52 deletions

View File

@@ -32,6 +32,7 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn
let reloadTimer = null;
let events = [];
let debug = false;
let fetchFailedCallback = function () {};
let eventsReceivedCallback = function () {};
@@ -215,7 +216,7 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn
}
const dates = rule.between(pastLocal, futureLocal, true, limitFunction);
// console.log("title="+event.summary.val+" dates="+JSON.stringify(dates))
if (debug) console.log("title=" + event.summary.val + " dates=" + JSON.stringify(dates));
// The "dates" array contains the set of dates within our desired date range range that are valid
// for the recurrence rule. *However*, it's possible for us to have a specific recurrence that
// had its date changed from outside the range to inside the range. For the time being,
@@ -243,54 +244,25 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn
let curEvent = event;
let showRecurrence = true;
// for full day events, the time might be off from RRULE/Luxon problem
if (isFullDayEvent(event)) {
if (debug) console.log("fullday");
// if the offset is negative, east of GMT where the problem is
if (date.getTimezoneOffset() < 0) {
// get the offset of today when we are processing
// this will be the correction we need to apply
let nowOffset = new Date().getTimezoneOffset();
if (debug) console.log("now offset is " + nowOffset);
// reduce the time by the offset
if (debug) console.log(" recurring date is " + date + " offset is " + date.getTimezoneOffset());
// apply the correction to the date/time to get it UTC relative
date = new Date(date.getTime() - Math.abs(nowOffset) * 60000);
if (debug) console.log("new recurring date is " + date);
}
}
startDate = moment(date);
// console.log("now timezone="+ moment.tz.guess());
// whether we need to adjust for RRULE returning the wrong date, with the right time (forward of URC timezones)
let adjustDays = 0;
// if a timezone was specified
if (!event.start.tz) {
event.start.tz = moment.tz.guess();
}
// console.log("tz="+event.start.tz)
if (event.start.tz) {
// if this is a windows timezone
if (event.start.tz.indexOf(" ") > 0) {
// use the lookup table to get theIANA name as moment and date don't know MS timezones
let tz = getIanaTZFromMS(event.start.tz);
// watch out for unregistered windows timezone names
// if we had a successfule lookup
if (tz) {
// change the timezone to the IANA name
event.start.tz = getIanaTZFromMS(event.start.tz);
// console.log("corrected timezone="+event.start.tz)
}
}
// get the start time in that timezone
let mms = moment.tz(moment(event.start), event.start.tz).utcOffset();
// console.log("ms offset="+mms)
// get the specified date in that timezone
let mm = moment.tz(moment(date), event.start.tz);
let mmo = mm.utcOffset();
// console.log("mm ofset="+ mmo+" hour="+mm.format("H")+" event date="+mm.toDate())
// if the offset is greater than 0, east of london
if (mmo > 0) {
let h = parseInt(mm.format("H"));
// check if the event time is less than the offset
if (h > 0 && h < mmo / 60) {
// if so, rrule created a wrong date (utc day, oops, with utc yesterday adjusted time)
// we need to fix that
adjustDays = 24;
// console.log("adjusting date")
}
if (mmo > mms) {
adjustDays += 1;
// console.log("adjust up 1 hour dst change")
} else if (mmo < mms) {
adjustDays -= 1;
//console.log("adjust down 1 hour dst change")
}
}
}
let adjustDays = getCorrection(event, date);
// For each date that we're checking, it's possible that there is a recurrence override for that one day.
if (curEvent.recurrences !== undefined && curEvent.recurrences[dateKey] !== undefined) {
@@ -380,12 +352,13 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn
//console.log("end same as start")
endDate = endDate.endOf("day");
}
// get correction for date saving and dst change between now and then
let adjustDays = getCorrection(event, startDate.toDate());
// Every thing is good. Add it to the list.
newEvents.push({
title: title,
startDate: startDate.format("x"),
endDate: endDate.format("x"),
startDate: (adjustDays ? startDate.subtract(adjustDays, "hours") : startDate).format("x"),
endDate: (adjustDays ? endDate.subtract(adjustDays, "hours") : endDate).format("x"),
fullDayEvent: fullDayEvent,
class: event.class,
location: location,
@@ -407,6 +380,79 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn
});
};
/*
*
* get the time correction, either dst/std or full day in cases where utc time is day before plus offset
*
*/
const getCorrection = function (event, date) {
let adjustHours = 0;
// if a timezone was specified
if (!event.start.tz) {
if (debug) console.log(" if no tz, guess based on now");
event.start.tz = moment.tz.guess();
}
if (debug) console.log("initial tz=" + event.start.tz);
// if there is a start date specified
if (event.start.tz) {
// if this is a windows timezone
if (event.start.tz.includes(" ")) {
// use the lookup table to get theIANA name as moment and date don't know MS timezones
let tz = getIanaTZFromMS(event.start.tz);
// watch out for unregistered windows timezone names
// if we had a successfule lookup
if (tz) {
// change the timezone to the IANA name
event.start.tz = tz;
// if(debug) console.log("corrected timezone="+event.start.tz)
}
}
if (debug) console.log("corrected tz=" + event.start.tz);
// if there is still an offset, lookup failed, use it
if (event.start.tz.startsWith("(")) {
const regex = /[+|-]\d*:\d*/;
offset = event.start.tz.match(regex).toString();
if (debug) console.log("ical offset=" + offset);
}
// get the start time in that timezone
if (debug) console.log("ttttttt=" + moment(event.start).toDate());
let mms = moment.tz(moment(event.start), event.start.tz).utcOffset();
if (debug) console.log("ms offset=" + mms);
if (debug) console.log("start date =" + moment.tz(moment(event.start), event.start.tz).toDate());
// get the specified date in that timezone
let mm = moment.tz(moment(date), event.start.tz);
if (debug) console.log("mm=" + mm.toDate());
let mmo = mm.utcOffset();
if (debug) console.log("mm ofset=" + mmo + " hour=" + mm.format("H") + " event date=" + mm.toDate());
// if the offset is greater than 0, east of london
if (mmo > 0) {
// big offset
if (debug) console.log("offset");
let h = parseInt(mm.format("H"));
// check if the event time is less than the offset
if (h > 0 && h < Math.abs(mmo) / 60) {
// if so, rrule created a wrong date (utc day, oops, with utc yesterday adjusted time)
// we need to fix that
adjustHours = 24;
// if(debug) console.log("adjusting date")
}
if (mmo > mms) {
adjustHours += 1;
if (debug) console.log("adjust up 1 hour dst change");
} else if (mmo < mms) {
adjustHours -= 1;
if (debug) console.log("adjust down 1 hour dst change");
}
}
}
if (debug) console.log("adjustHours=" + adjustHours);
return adjustHours;
};
/**
*
* lookup iana tz from windows