Skip to content

Commit f47e152

Browse files
committed
Write better comments
1 parent 8ecdf05 commit f47e152

File tree

1 file changed

+27
-6
lines changed

1 file changed

+27
-6
lines changed

docs/cookbook/icalendarTimeZones.mjs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,30 @@
22
import * as Temporal from '../../polyfill/lib/temporal.mjs';
33
import ICAL from 'ical.js';
44

5-
// The time zone can either be a named IANA time zone (in which case everything
6-
// works just like Temporal.ZonedDateTime) or an iCalendar rule-based time zone
5+
// Example of a wrapper class for Temporal.ZonedDateTime that implements custom
6+
// time zones.
7+
// The use case is based on Thunderbird's use of the ical.js library to parse
8+
// iCalendar data. iCalendar uses VTIMEZONE components which define UTC offset
9+
// transitions inside the data format. VTIMEZONE can include a TZID field, which
10+
// may or may not be an IANA time zone ID. If it's an IANA time zone ID,
11+
// Thunderbird uses the environment's TZDB definition and ignores the rest of
12+
// the VTIMEZONE (in which case everything works just like
13+
// Temporal.ZonedDateTime, as we delegate to the this.#impl object). However,
14+
// Microsoft Exchange often generates TZID strings that aren't IANA IDs, and
15+
// then Thunderbird falls back to the iCalendar VTIMEZONE definition (in which
16+
// case we use ical.js to perform the time zone calculations.)
17+
718
class ZonedDateTime {
19+
// #impl: The internal Temporal.ZonedDateTime object. If the VTIMEZONE is an
20+
// IANA time zone, its timeZoneId is the VTIMEZONE's TZID, and we delegate all
21+
// the operations to it. If not, its timeZoneId is UTC.
822
#impl;
9-
#timeZone;
10-
#isIANA;
23+
#timeZone; // The ICAL.Timezone instance.
24+
#isIANA; // Convenience flag indicating whether we can delegate to #impl.
1125

1226
// These properties allow the object to be used as a PlainDateTime property
13-
// bag if the time zone isn't IANA
27+
// bag if the time zone isn't IANA. For example, as a relativeTo parameter in
28+
// Duration methods.
1429
era;
1530
eraYear;
1631
year;
@@ -84,7 +99,7 @@ class ZonedDateTime {
8499
},
85100
timeZone
86101
);
87-
const epochSeconds = icalTime.toUnixTime(); // apply disambiguation parameter?
102+
const epochSeconds = icalTime.toUnixTime(); // TODO: apply disambiguation parameter?
88103
const epochNanoseconds =
89104
BigInt(epochSeconds) * 1000000000n + BigInt(pdt.millisecond * 1e6 + pdt.microsecond * 1e3 + pdt.nanosecond);
90105
return new ZonedDateTime(epochNanoseconds, timeZone, pdt.calendarId);
@@ -98,6 +113,8 @@ class ZonedDateTime {
98113
if (this.#isIANA) {
99114
return this.#impl.toPlainDateTime();
100115
}
116+
// this.#impl with a non-IANA time zone uses UTC internally, so we can just
117+
// calculate the plain date-time in UTC and add the UTC offset.
101118
return this.#impl.toPlainDateTime().add({ nanoseconds: this.offsetNanoseconds });
102119
}
103120

@@ -167,6 +184,8 @@ class ZonedDateTime {
167184
this.#isIANA ||
168185
(duration.years === 0 && duration.months === 0 && duration.weeks === 0 && duration.days === 0)
169186
) {
187+
// Adding non-calendar units is independent of time zone, so in that case
188+
// we can delegate to this.#impl even in the case of a non-IANA time zone
170189
const temporalZDT = this.#impl.add(duration, options);
171190
return new ZonedDateTime(temporalZDT.epochNanoseconds, this.#timeZone, this.#impl.calendarId);
172191
}
@@ -202,6 +221,8 @@ class ZonedDateTime {
202221
if (largestUnit === 'year' || largestUnit === 'month' || largestUnit === 'week' || largestUnit === 'day') {
203222
throw new Error('not implemented');
204223
}
224+
// Non-calendar largestUnit is independent of time zone, so we can delegate
225+
// to this.#impl even in the case of a non-IANA time zone
205226
return this.#impl.until(other.#impl, options);
206227
}
207228

0 commit comments

Comments
 (0)