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

Help using timezone in events #759

Closed
landoncrabtree opened this issue Sep 5, 2024 · 3 comments
Closed

Help using timezone in events #759

landoncrabtree opened this issue Sep 5, 2024 · 3 comments

Comments

@landoncrabtree
Copy link

Hi,

I'm trying to create a quick sample project to see if this library fits my needs. The documentation is a bit, bare? And so I've been trying to go through issues and the API reference to get timezone working, but I can't get it.

var fs = require('fs');
var ICAL = require('ical.js');
var tzlib = require('timezones-ical-library');

// If test.ics, create blank calendar with America/Chicago timezone
if (!fs.existsSync('test.ics')) {
    const comp = new ICAL.Component(['vcalendar', [], []]);
    const vtimezone = tzlib.tzlib_get_ical_block('America/Chicago')[0].toString();
    const output = comp.toString().replace('END:VCALENDAR', vtimezone + '\nEND:VCALENDAR');
    return fs.writeFileSync('test.ics', output);
}

// Read calendar
const data = fs.readFileSync('test.ics', 'utf8');
const jcalData = ICAL.parse(data);
const comp = new ICAL.Component(jcalData);

// Create new event
const newEvent = new ICAL.Component('vevent');
newEvent.addPropertyWithValue('summary', 'Test Event');
newEvent.addPropertyWithValue('description', 'This is a test event');
newEvent.addPropertyWithValue('location', 'Test Location');

// Create an ICAL.Timezone object
const timezone = new ICAL.Timezone({
    tzid: comp.getFirstSubcomponent('vtimezone').getFirstPropertyValue('tzid'),
    component: comp.getFirstSubcomponent('vtimezone')
});

const startDateTime = new ICAL.Time({
    year: 2024,
    month: 10,
    day: 1,
    hour: 10,
    minute: 0,
    second: 0
}, timezone);

const endDateTime = new ICAL.Time({
    year: 2024,
    month: 10,
    day: 1,
    hour: 11,
    minute: 0,
    second: 0
}, timezone);

newEvent.addPropertyWithValue('dtstart', startDateTime);
newEvent.addPropertyWithValue('dtend', endDateTime);

newEvent.addPropertyWithValue('uid', 'test-uid');
newEvent.addPropertyWithValue('attendee', 'mailto:[email protected]');
newEvent.addPropertyWithValue('organizer', 'mailto:[email protected]');

comp.addSubcomponent(newEvent);

// Write to file
const output = comp.toString();
fs.writeFileSync('test.ics', output);

Basically, I'm using timezones-ical-library to generate the VTIMEZONE component and manually add that to the .ICS. Beyond that, that's where I'm stuck. Whenever I run this, I just get floating point times, ie DTSTART:20241001T100000. I copied the ICAL.Timezone straight from the API docs so that should be working fine, so I'm sure it's something to do with how I'm instantiating the ICAL.Time class?

Example ICS:

BEGIN:VCALENDAR
BEGIN:VTIMEZONE
TZID:America/Chicago
X-LIC-LOCATION:America/Chicago
LAST-MODIFIED:20240205T192834Z
BEGIN:DAYLIGHT
TZNAME:CDT
TZOFFSETFROM:-0600
TZOFFSETTO:-0500
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
BEGIN:STANDARD
TZNAME:CST
TZOFFSETFROM:-0500
TZOFFSETTO:-0600
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
SUMMARY:Test Event
DESCRIPTION:This is a test event
LOCATION:Test Location
DTSTART:20241001T100000
DTEND:20241001T110000
UID:test-uid
ATTENDEE:mailto:[email protected]
ORGANIZER:mailto:[email protected]
END:VEVENT
END:VCALENDAR
@landoncrabtree
Copy link
Author

Solved this very goofy-ly:

var fs = require('fs');
var ICAL = require('ical.js');
var tzlib = require('timezones-ical-library');

function randomUid() {
    return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
}

// If test.ics, create blank calendar with America/Chicago timezone
if (!fs.existsSync('test.ics')) {
    const comp = new ICAL.Component(['vcalendar', [], []]);
    const vtimezone = tzlib.tzlib_get_ical_block('America/Chicago')[0].toString();
    const output = comp.toString().replace('END:VCALENDAR', vtimezone + '\nEND:VCALENDAR');
    return fs.writeFileSync('test.ics', output);
}

// Read calendar
const data = fs.readFileSync('test.ics', 'utf8');
const jcalData = ICAL.parse(data);
const comp = new ICAL.Component(jcalData);

// Create new event
const newEvent = new ICAL.Component('vevent');
newEvent.addPropertyWithValue('uid', randomUid());
newEvent.addPropertyWithValue('summary', 'Test Event');
newEvent.addPropertyWithValue('description', 'This is a test event');
newEvent.addPropertyWithValue('location', 'Test Location');

// // Create an ICAL.Timezone object
// const timezone = new ICAL.Timezone({
//     tzid: comp.getFirstSubcomponent('vtimezone').getFirstPropertyValue('tzid'),
//     component: comp.getFirstSubcomponent('vtimezone')
// });

const startDateTime = new ICAL.Time({
    year: 2024,
    month: 10,
    day: 1,
    hour: 10,
    minute: 0,
    second: 0
});

const endDateTime = new ICAL.Time({
    year: 2024,
    month: 10,
    day: 1,
    hour: 11,
    minute: 0,
    second: 0
});

newEvent.addPropertyWithValue('dtstart', startDateTime);
newEvent.addPropertyWithValue('dtend', endDateTime);
newEvent.addPropertyWithValue('attendee', 'mailto:[email protected]');
newEvent.addPropertyWithValue('organizer', 'mailto:[email protected]');

var newEventString = newEvent.toString();
newEventString = newEventString.replace('DTSTART:', 'DTSTART;TZID=America/Chicago:');
newEventString = newEventString.replace('DTEND:', 'DTEND;TZID=America/Chicago:');

comp.addSubcomponent(ICAL.Component.fromString(newEventString));

// Write to file
const output = comp.toString();
fs.writeFileSync('test.ics', output);

Would love a native solution rather than manually patching the vevent DTSTART/DTEND properties. But was never able to get it working using built-in classes.

@kewisch
Copy link
Owner

kewisch commented Sep 11, 2024

Have you seen the examples in the wiki? I know docs isn't a strong suite here, would love some help in expanding them. I don't actually know off hand if there is a timezones example, but I know the wiki is often missed.

When you use timezones, you should make sure to register the timezones beforehand using ICAL.TimezoneService.register(). Once those are in, timezone calculations should be working better. Further, to set a timezone with the time correctly you need to also set the TZID. addPropertyWithValue is a shortcut for creating a property and setting a value, but it does not automatically update the TZID parameter. So You can create the ICAL.Property, setParameter TZID to Chicago, set the time value, then add that property to the component.

Hope this helps!

@kewisch kewisch added the needinfo More information has been requested label Sep 12, 2024
Copy link

It looks like we haven't heard back on this issue, therefore we are closing this issue. If this problem persists in the latest version of ical.js, please re-open this issue.

@github-actions github-actions bot removed the needinfo More information has been requested label Oct 12, 2024
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