-
-
Notifications
You must be signed in to change notification settings - Fork 52
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
Corrected timezone handling for recurring events #231
Changes from all commits
602fd51
150d685
8f5e091
c9a85d5
501f6f6
94444b9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -156,9 +156,19 @@ function getTimeZone(value) { | |
// And offset is still present | ||
if (tz && tz.startsWith('(')) { | ||
// Extract just the offset | ||
const regex = /[+|-]\d*:\d*/; | ||
const offsetcomps = tz.match(/([+|-]\d+):?(\d+)/); | ||
if (offsetcomps && offsetcomps[0]) { | ||
if (offsetcomps[3] && offsetcomps[3] !== '00') { | ||
// Unpack sub-hour offsets, even if they cannot be mapped | ||
found = String(offsetcomps[0]); | ||
} else { | ||
// Map full-hour offsets to IANA Etc zones | ||
const intoffset = -1 * Number.parseInt(offsetcomps[1], 10); | ||
found = 'Etc/GMT' + (intoffset < 0 ? '' : '+') + intoffset; | ||
} | ||
} | ||
|
||
tz = null; | ||
found = tz.match(regex); | ||
} | ||
|
||
// Timezone not confirmed yet | ||
|
@@ -251,22 +261,27 @@ const dateParameter = function (name) { | |
const tz1 = getTimeZone(tz); | ||
if (tz1) { | ||
tz = tz1; | ||
// We have a confirmed timezone, don't use offset, may confuse DST/STD time | ||
offset = ''; | ||
// Fix the parameters for later use | ||
parameters[0] = 'TZID=' + tz; | ||
} | ||
} | ||
|
||
// Watch out for offset timezones | ||
// If the conversion above didn't find any matching IANA tz | ||
// And offset is still present | ||
if (tz && tz.startsWith('(')) { | ||
// Extract just the offset | ||
const regex = /[+|-]\d*:\d*/; | ||
offset = tz.match(regex); | ||
const offsetcomps = tz.match(/([+|-]\d+):?(\d+)/); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here, why is this regex change required? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The answer is the same as above. |
||
if (offsetcomps && offsetcomps[0]) { | ||
if (offsetcomps[3] && offsetcomps[3] !== '00') { | ||
offset = String(offsetcomps[0]); | ||
found = offset; | ||
} else { | ||
const intoffset = -1 * Number.parseInt(offsetcomps[1], 10); | ||
found = 'Etc/GMT' + (intoffset < 0 ? '' : '+') + intoffset; | ||
} | ||
} | ||
|
||
tz = null; | ||
found = offset; | ||
} | ||
|
||
// Timezone not confirmed yet | ||
|
@@ -278,7 +293,7 @@ const dateParameter = function (name) { | |
} | ||
|
||
// Timezone confirmed or forced to offset | ||
newDate = found ? moment.tz(value, 'YYYYMMDDTHHmmss' + offset, tz).toDate() : new Date( | ||
newDate = found ? moment.tz(value, 'YYYYMMDDTHHmmss' + offset, found).toDate() : new Date( | ||
Number.parseInt(comps[1], 10), | ||
Number.parseInt(comps[2], 10) - 1, | ||
Number.parseInt(comps[3], 10), | ||
|
@@ -576,7 +591,6 @@ module.exports = { | |
// Recurrence rules are only valid for VEVENT, VTODO, and VJOURNAL. | ||
// More specifically, we need to filter the VCALENDAR type because we might end up with a defined rrule | ||
// due to the subtypes. | ||
|
||
if ((value === 'VEVENT' || value === 'VTODO' || value === 'VJOURNAL') && curr.rrule) { | ||
let rule = curr.rrule.replace('RRULE:', ''); | ||
// Make sure the rrule starts with FREQ= | ||
|
@@ -613,7 +627,9 @@ module.exports = { | |
// If the original date has a TZID, add it | ||
if (curr.start.tz) { | ||
const tz = getTimeZone(curr.start.tz); | ||
rule += `;DTSTART;TZID=${tz}:${curr.start.toISOString().replace(/[-:]/g, '')}`; | ||
const tzoffset = moment.tz(tz).utcOffset() * -60000; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In fact, the minus in |
||
const localISOTime = (new Date(curr.start - tzoffset)).toISOString().slice(0, -1); | ||
rule += `;DTSTART;TZID=${tz}:${localISOTime.replace(/[-:]/g, '')}`; | ||
} else { | ||
rule += `;DTSTART=${curr.start.toISOString().replace(/[-:]/g, '')}`; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
BEGIN:VCALENDAR | ||
BEGIN:VEVENT | ||
TRANSP:OPAQUE | ||
X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY | ||
CREATED:20221004T073016Z | ||
LAST-MODIFIED:20221011T063437Z | ||
DTSTAMP:20221011T063437Z | ||
DTSTART;TZID="(GMT +01:00)":20221004T140000 | ||
DTEND;TZID="(GMT +01:00)":20221004T150000 | ||
SUMMARY:Music School | ||
CLASS:PUBLIC | ||
UID:0000021 | ||
X-MOZ-SNOOZE-TIME:20221004T113000Z | ||
X-MICROSOFT-CDO-OWNER-CRITICAL-CHANGE:20221014T203413Z | ||
X-MICROSOFT-CDO-ATTENDEE-CRITICAL-CHANGE:20221014T203413Z | ||
X-MICROSOFT-CDO-APPT-SEQUENCE:0 | ||
X-MICROSOFT-CDO-OWNERAPPTID:-1 | ||
X-MICROSOFT-CDO-ALLDAYEVENT:FALSE | ||
RRULE:FREQ=WEEKLY;UNTIL=20221201T020000;BYDAY=TU | ||
END:VEVENT | ||
END:VCALENDAR |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
BEGIN:VCALENDAR | ||
VERSION:2.0 | ||
PRODID:Fictitious Recurrence Test Calendar | ||
BEGIN:VEVENT | ||
CREATED:20221018T221500Z | ||
DTSTAMP:20221019T171200Z | ||
UID:000021a | ||
SUMMARY:Party | ||
RRULE:FREQ=YEARLY | ||
DTSTART;TZID=Europe/Berlin:20220714T140000 | ||
DTEND;TZID=Europe/Berlin:20220714T210000 | ||
TRANSP:OPAQUE | ||
SEQUENCE:5 | ||
END:VEVENT | ||
BEGIN:VEVENT | ||
CREATED:20221019T181700Z | ||
DTSTAMP:20221019T191200Z | ||
UID:000021b | ||
SUMMARY:Party next day | ||
RRULE:FREQ=YEARLY | ||
DTSTART;TZID="(GMT +02:00)":20220715T140000 | ||
DTEND;TZID="(GMT +02:00)":20220715T210000 | ||
TRANSP:OPAQUE | ||
SEQUENCE:5 | ||
END:VEVENT | ||
END:VCALENDAR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please explain why exactly you changed that regex and what the added lines following this change try to fix/change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I try to map indications like
(GMT +02:00)
to matching IANA etcetera zones, if available. The advantage of those IANA zone names is that they can be processed by moment-timezone.