Comprehensive timezone handling with support for VTIMEZONE components, UTC offset calculations, and timezone conversions. These classes enable proper timezone-aware date and time operations in compliance with RFC 5545.
Timezone representation providing offset calculations and conversion utilities for iCalendar timezone handling.
/**
* Timezone handling
* @param data - Timezone initialization data
*/
class Timezone {
constructor(data?: object);
// Properties
tzid: string; // Timezone identifier
component: Component; // VTIMEZONE component
expandedUntilYear: number; // Year until which timezone is expanded
// Static methods
static convert_time(tt: Time, from_zone: Timezone, to_zone: Timezone): Time;
static fromData(aData: object): Timezone;
static get utcTimezone(): Timezone;
static get localTimezone(): Timezone;
// Instance methods
fromData(aData: object): void;
utcOffset(tt: Time): number;
toString(): string;
}Usage Examples:
import ICAL from "ical.js";
// Get built-in timezones
const utc = ICAL.Timezone.utcTimezone;
const local = ICAL.Timezone.localTimezone;
console.log(utc.tzid); // "UTC"
console.log(local.tzid); // System timezone ID
// Create timezone from VTIMEZONE component
const timezoneData = `BEGIN:VTIMEZONE
TZID:America/New_York
BEGIN:DAYLIGHT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:EDT
DTSTART:20070311T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:EST
DTSTART:20071104T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
END:VTIMEZONE`;
const tzComponent = ICAL.Component.fromString(timezoneData);
const nyTimezone = new ICAL.Timezone(tzComponent);
console.log(nyTimezone.tzid); // "America/New_York"
// Get UTC offset for specific time
const summerTime = ICAL.Time.fromString("20230715T120000");
const winterTime = ICAL.Time.fromString("20231215T120000");
const summerOffset = nyTimezone.utcOffset(summerTime); // -14400 (EDT: -4 hours)
const winterOffset = nyTimezone.utcOffset(winterTime); // -18000 (EST: -5 hours)
console.log(`Summer offset: ${summerOffset / 3600} hours`); // -4
console.log(`Winter offset: ${winterOffset / 3600} hours`); // -5
// Convert time between timezones
const utcTime = ICAL.Time.fromString("20230715T160000Z");
const nyTime = ICAL.Timezone.convert_time(utcTime, utc, nyTimezone);
console.log(`UTC: ${utcTime.toString()}`); // "2023-07-15T16:00:00Z"
console.log(`NY: ${nyTime.toString()}`); // "2023-07-15T12:00:00"
// Convert back to UTC
const backToUtc = ICAL.Timezone.convert_time(nyTime, nyTimezone, utc);
console.log(`Back to UTC: ${backToUtc.toString()}`); // "2023-07-15T16:00:00Z"
// Create timezone from data
const customTz = ICAL.Timezone.fromData({
tzid: "Custom/Example",
// Additional timezone data
});Singleton timezone registry for managing and accessing timezone definitions across the application.
/**
* Timezone registry singleton
*/
const TimezoneService: {
// Properties
readonly count: number; // Number of registered timezones
// Methods
reset(): void;
has(tzid: string): boolean;
get(tzid: string): Timezone | null;
register(timezone: Timezone | Component, name?: string): void;
remove(tzid: string): boolean;
};Usage Examples:
import ICAL from "ical.js";
// Check available timezones
console.log(ICAL.TimezoneService.count); // Number of registered timezones
// Check if timezone exists
const hasNY = ICAL.TimezoneService.has("America/New_York");
console.log(hasNY); // true/false
// Get timezone by ID
const nyTimezone = ICAL.TimezoneService.get("America/New_York");
if (nyTimezone) {
console.log(nyTimezone.tzid); // "America/New_York"
}
// Register new timezone from component
const timezoneComponent = ICAL.Component.fromString(`BEGIN:VTIMEZONE
TZID:Europe/London
BEGIN:DAYLIGHT
TZOFFSETFROM:+0000
TZOFFSETTO:+0100
TZNAME:BST
DTSTART:20070325T010000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0100
TZOFFSETTO:+0000
TZNAME:GMT
DTSTART:20071028T020000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE`);
ICAL.TimezoneService.register(timezoneComponent);
// Verify registration
console.log(ICAL.TimezoneService.has("Europe/London")); // true
console.log(ICAL.TimezoneService.count); // Increased by 1
// Register timezone object with custom name
const customTimezone = new ICAL.Timezone(timezoneComponent);
ICAL.TimezoneService.register(customTimezone, "Custom/London");
// Remove timezone
const removed = ICAL.TimezoneService.remove("Custom/London");
console.log(removed); // true if successfully removed
// Reset to default timezones
ICAL.TimezoneService.reset();
console.log(ICAL.TimezoneService.count); // Back to default count
// Working with calendar components and timezones
const vcalendar = new ICAL.Component("vcalendar");
vcalendar.addSubcomponent(timezoneComponent);
// Register all timezones from a calendar
const allSubcomponents = vcalendar.getAllSubcomponents("vtimezone");
allSubcomponents.forEach(tzComponent => {
ICAL.TimezoneService.register(tzComponent);
});
// Use timezone service with events
const event = new ICAL.Component("vevent");
event.addPropertyWithValue("dtstart", ICAL.Time.fromString("20230715T120000"));
const startProp = event.getFirstProperty("dtstart");
startProp.setParameter("tzid", "Europe/London");
// Get timezone for the event
const eventTimezone = ICAL.TimezoneService.get("Europe/London");
if (eventTimezone) {
const startTime = startProp.getFirstValue();
startTime.zone = eventTimezone;
console.log(`Event starts at ${startTime.toString()} in ${eventTimezone.tzid}`);
}UTC offset representation for handling timezone offsets in hours and minutes.
/**
* UTC offset representation
* @param aData - Offset initialization data
*/
class UtcOffset {
constructor(aData?: object);
// Properties
hours: number; // Offset hours
minutes: number; // Offset minutes
factor: number; // Sign factor (+1 or -1)
// Static methods
static fromString(aString: string): UtcOffset;
static fromSeconds(aSeconds: number): UtcOffset;
// Instance methods
clone(): UtcOffset;
fromData(aData: object): void;
fromSeconds(aSeconds: number): void;
toSeconds(): number;
compare(other: UtcOffset): number;
toICALString(): string;
toString(): string;
}Usage Examples:
import ICAL from "ical.js";
// Create offset from string
const offset1 = ICAL.UtcOffset.fromString("-0500"); // -5 hours
const offset2 = ICAL.UtcOffset.fromString("+0230"); // +2 hours 30 minutes
console.log(offset1.hours); // 5
console.log(offset1.minutes); // 0
console.log(offset1.factor); // -1
console.log(offset2.hours); // 2
console.log(offset2.minutes); // 30
console.log(offset2.factor); // 1
// Create from seconds
const offset3 = ICAL.UtcOffset.fromSeconds(-18000); // -5 hours
console.log(offset3.toICALString()); // "-0500"
// Create from data
const offset4 = new ICAL.UtcOffset({
hours: 3,
minutes: 45,
factor: 1
});
// Convert to seconds
console.log(offset1.toSeconds()); // -18000 (-5 hours)
console.log(offset2.toSeconds()); // 9000 (+2.5 hours)
// Compare offsets
console.log(offset1.compare(offset2)); // -1 (offset1 < offset2)
console.log(offset2.compare(offset1)); // 1 (offset2 > offset1)
// String representations
console.log(offset1.toICALString()); // "-0500"
console.log(offset1.toString()); // "-0500"
console.log(offset2.toICALString()); // "+0230"
console.log(offset2.toString()); // "+0230"
// Clone offset
const offsetCopy = offset1.clone();
console.log(offsetCopy.toICALString()); // "-0500"
// Modify offset
offset4.fromSeconds(7200); // Change to +2 hours
console.log(offset4.toICALString()); // "+0200"
// Working with timezone components
const vtimezone = new ICAL.Component("vtimezone");
vtimezone.addPropertyWithValue("tzid", "Custom/Offset");
const standard = new ICAL.Component("standard");
standard.addPropertyWithValue("tzoffsetfrom", offset2);
standard.addPropertyWithValue("tzoffsetto", offset1);
standard.addPropertyWithValue("dtstart", ICAL.Time.fromString("20231029T020000"));
vtimezone.addSubcomponent(standard);
// Extract offsets from properties
const offsetFromProp = standard.getFirstProperty("tzoffsetfrom");
const offsetToProp = standard.getFirstProperty("tzoffsetto");
console.log(offsetFromProp.getFirstValue().toICALString()); // "+0230"
console.log(offsetToProp.getFirstValue().toICALString()); // "-0500"import ICAL from "ical.js";
// Helper function to update timezones in a calendar
ICAL.helpers.updateTimezones(vcalendar);
// Example: Processing calendar with timezone definitions
const calendarString = `BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example//Example//EN
BEGIN:VTIMEZONE
TZID:America/New_York
BEGIN:STANDARD
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:EST
DTSTART:20071104T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:EDT
DTSTART:20070311T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
UID:event@example.com
DTSTART;TZID=America/New_York:20230715T120000
DTEND;TZID=America/New_York:20230715T130000
SUMMARY:Meeting in NY timezone
END:VEVENT
END:VCALENDAR`;
const calendar = ICAL.Component.fromString(calendarString);
// Update timezones processes VTIMEZONE components
ICAL.helpers.updateTimezones(calendar);
// Now events can use the timezone
const event = calendar.getFirstSubcomponent("vevent");
const startTime = event.getFirstPropertyValue("dtstart");
console.log(startTime.zone.tzid); // "America/New_York"
console.log(startTime.toString()); // Local time in NY timezoneimport ICAL from "ical.js";
// Convert event times to different timezones
function convertEventTimezone(event, targetTimezone) {
const startTime = event.startDate;
const endTime = event.endDate;
const newStart = ICAL.Timezone.convert_time(startTime, startTime.zone, targetTimezone);
const newEnd = ICAL.Timezone.convert_time(endTime, endTime.zone, targetTimezone);
event.startDate = newStart;
event.endDate = newEnd;
return event;
}
// Get timezone offset for display
function getTimezoneDisplay(timezone, time) {
const offset = timezone.utcOffset(time);
const offsetObj = ICAL.UtcOffset.fromSeconds(offset);
return `${timezone.tzid} (UTC${offsetObj.toString()})`;
}
// Check if time is in daylight saving time
function isDST(timezone, time) {
// Compare with standard time offset
const winterTime = new ICAL.Time({
year: time.year,
month: 12, // December
day: 15,
hour: 12
});
const currentOffset = timezone.utcOffset(time);
const winterOffset = timezone.utcOffset(winterTime);
return currentOffset !== winterOffset;
}