peterbraden / ical.js Goto Github PK
View Code? Open in Web Editor NEWical for javascript
License: Apache License 2.0
ical for javascript
License: Apache License 2.0
I found that this module will not parse events that contain DTSTART or DTEND values that look like this:
DTSTART;TZID=America/Los_Angeles:20140505T183000
The events simply don't show up in the output.
Hitting these errors when trying to run the basic example
node-ical.js?38f9:34 Uncaught TypeError: Cannot read property 'fromString' of undefined
at Object.ical.objectHandlers.END (node-ical.js?38f9:34)
at Object.handleObject (ical.js?0ad9:253)
at Object.parseICS (ical.js?0ad9:294)
at Request.eval [as _callback] (node-ical.js?38f9:11)
at Request.self.callback (request.js?4b05:199)
at Request.EventEmitter.emit (events.js?faa1:84)
at Request.eval (request.js?4b05:1036)
at Request.EventEmitter.emit (events.js?faa1:96)
at exports.IncomingMessage.eval (request.js?4b05:963)
at exports.IncomingMessage.EventEmitter.emit (events.js?faa1:96)
Any interest in adding support for parsing recurring events (RRULE)?
BEGIN:VEVENT
DTSTART;VALUE=DATE:20101209
DTEND;VALUE=DATE:20101210
RRULE:FREQ=WEEKLY;INTERVAL=2
DTSTAMP:20120210T221052Z
UID:E5A18065-536C-4F08-9457-B160D24B71E2
CREATED:20101129T155045Z
DESCRIPTION:
LAST-MODIFIED:20110103T020931Z
LOCATION:
SEQUENCE:6
STATUS:CONFIRMED
SUMMARY:Take donkey to the groomer
TRANSP:OPAQUE
END:VEVENT
When accessing the rrule of an event, the dtstart of the rrule is not set, so I had to do this:
ev.rrule.origOptions.dtstart = ev.start;
ev.rrule = ev.rrule.clone();
Only then could I safely use the rrule
recurDate = ev.rrule.between(currentDate, dateTo);
I don't know git, so the following code adds support for these two fields.
var geoParam = function(name){
return function(val, params, curr){
storeParam(val, params, curr)
var parts = val.split(';');
curr[name] = {lat:Number(parts[0]), lng:Number(parts[1])};
return curr
}
}
, 'TRANSP' : storeParam('transparency')
, 'GEO' : geoParam('geo')
Got the following line from an Outlook event:
DTSTART;TZID="(UTC+02:00) Jerusalem":20160803T180000
Here we have a colon inside a quoted string. The way parseICS
split's it, we get a key-value pair of: ['DTSTART;TZID="(UTC+02' , '00) Jerusalem":20160803T180000)']
To fix this, you need to replace:
var kv = l.split(":");
with:
kv = l.match(/([^:"]+|"[^"]*")+/g) || [];
/home/users/tuhoojabotti/node_modules/ical/ical.js:95
curr[name].tz = p.TZID
^
TypeError: Cannot set property 'tz' of undefined
at Object.DTEND (/home/users/tuhoojabotti/node_modules/ical/ical.js:95:21)
at Object.handleObject (/home/users/tuhoojabotti/node_modules/ical/ical.js:141:40)
at Object.parseICS (/home/users/tuhoojabotti/node_modules/ical/ical.js:175:19)
With this input: http://www.assembly.org/summer11/program/schedule/assembly-summer-2011-all.ics
There is always an extra event. E.g.
var ical = require('ical'); ical.fromURL('http://sg.hackandtell.org/ics/', {}, function(err, data) { console.log(data); } ); { ' 1389076210723542885': { type: 'VEVENT', params: [], uid: ' 1389076210723542885', summary: ' Hack and Tell', location: ' Hackerspace.SG, 344B King George\'s Avenue', description: ' Show and tell for hackers. Five minute demos, each followed by five minutes of questions.', start: ' 20140128T200000', end: ' 20140128T220000' }, '28482.87234082818': {} }
'28482.87234082818' came from nowhere...
I am getting 403: Forbidden For Airbnb iCal. Please help.
line 1446 in rrule.js causes the parser to die if attr is empty. Seems like it should gracefully skip over that.
The following Meetup.com start and end dates are ignored by the current dateParam parser:
DTSTART:19700101T000000
DTSTART;TZID=America/Phoenix:20111109T190000
DTEND;TZID=America/Phoenix:20111109T210000
Full VCALENDAR:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Meetup//RemoteApi//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-ORIGINAL-URL:http://www.meetup.com/events/ical/8333638/dfdba2e469216075
3404f737feace78d526ff0ce/going
X-WR-CALNAME:My Meetups
X-MS-OLK-FORCEINSPECTOROPEN:TRUE
BEGIN:VTIMEZONE
TZID:America/Phoenix
TZURL:http://tzurl.org/zoneinfo-outlook/America/Phoenix
X-LIC-LOCATION:America/Phoenix
BEGIN:STANDARD
TZOFFSETFROM:-0700
TZOFFSETTO:-0700
TZNAME:MST
DTSTART:19700101T000000
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTAMP:20111106T155927Z
DTSTART;TZID=America/Phoenix:20111109T190000
DTEND;TZID=America/Phoenix:20111109T210000
STATUS:CONFIRMED
SUMMARY:Phoenix Drupal User Group Monthly Meetup
DESCRIPTION:Phoenix Drupal User Group\nWednesday\, November 9 at 7:00 PM\
n\nCustomizing node display with template pages in Drupal 6\n\n Jon Shee
han and Matthew Berry of the Office of Knowledge Enterprise Development
(OKED) Knowledge...\n\nDetails: http://www.meetup.com/Phoenix-Drupal-Use
r-Group/events/33627272/
CLASS:PUBLIC
CREATED:20100630T083023Z
GEO:33.56;-111.90
LOCATION:Open Source Project Tempe (1415 E University Dr. #103A\, Tempe\,
AZ 85281)
URL:http://www.meetup.com/Phoenix-Drupal-User-Group/events/33627272/
LAST-MODIFIED:20111102T213309Z
UID:[email protected]
END:VEVENT
END:VCALENDAR
Currently, the require()
's for "request" and "fs" are at the top of the ical.js
.
var request = require('request')
, fs = require('fs')
It would be better if these could be moved to the fromURL
and parseFile
functions directly.
Reason is, I can use ical.js
in the browser, using a CommonJS environment, just fine. Only the require()
's for those two modules aren't needed, and I don't happen to have those modules for the browser anyway. For now, I'm stubbing those modules out with dummy modules; I'd obviously prefer to not have to do that.
I can't use the start and end date objects. I'm not familiar with JS Date object but I don't think I may be able to do anything with objects like these :
{ Mon, 31 Oct 2016 23:00:00 GMT tz: undefined }
{ Fri, 04 Nov 2016 23:00:00 GMT tz: '"Europe/Brussels"' }
I'm I wrong or is this an issue to fix?
Thanks :)
Method fromURL does return an error if the HTTP status code >= 400. An empty result object is returned instead.
I'll come up with a suggested fix (PR) shortly.
The format of the ical file is different to google. Both I think are valid.
You're dates are 8 digits and googles are: "20110324T103000Z". Do you know what specifies the format type? I can get your code working with google ical, but wanted you opinion on how to handle both types of format.... take care, mario
http://gmailblog.blogspot.sg/2013/12/download-copy-of-your-gmail-and-google.html
One such full archive is here: http://s.natalian.org/2014-01-06/hsg-event-archive.ics
ical.js seems to get confused by the alarms that Google Calendar inserts:
I have this event in my ical (probably from thunderbird/lightning I guess). I can't get it in the result array (I get the Alarm alone though in the result)
CREATED:20130620T151401Z
LAST-MODIFIED:20130620T151457Z
DTSTAMP:20130620T151457Z
UID:a2030358-b713-4d9a-b04a-bb4d436c7379
SUMMARY:...
DTSTART;TZID=Europe/Paris:20130626T190000
DTEND;VALUE=DATE-TIME;TZID=Europe/Paris:20130626T220000
LOCATION:...
DESCRIPTION: ...
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;VALUE=DURATION:-P1D
DESCRIPTION:Description par défaut Mozilla
END:VALARM
END:VEVENT
Through using [email protected]
, we have a medium to highly serious issue of a Remote Memory Exposure bug in request
and an ReDOS (Regular Expressions Denial of Service) issue through one of request
's dependencies, [email protected]
. We can solve this by changing the version of request
from 2.40.0 to >= 2.68.0.
I get an error that the length is not defined when parsing this ical
http://www.fcassen.nl/Modules/UitslagenEnStanden/Front/ICal.ashx?id=160
I fixed it by adding the check on the curr.start object:
https://github.com/heskja/MMM-CalendarWeek/blob/master/vendor/ical.js/node-ical.js#L31
if (rule.indexOf('DTSTART') === -1 && curr.start) {
With the URL:
https://calendar.google.com/calendar/ical/kingstonassoc%40gmail.com/public/basic.ics
And the following code:
function updateCalendar() {
ical.fromURL(eventsFeed, {}, function (err, data) {
for (let k in data) {
if (data.hasOwnProperty(k)) {
var ev = data[k];
if (data[k].type == 'VEVENT') {
if (dateNow < ev.start) {
let tts = `On <say-as interpret-as="date" format="ymd">${ev.start.toISOString().slice(0,10)}</say-as> at ${ev.start.toLocaleTimeString('en-GB')}: ${ev.summary}. ${ev.description}`;
console.log(tts);
}
}
}
}
});
}
I get this output:
On <say-as interpret-as="date" format="ymd">2018-10-13</say-as> at 1:00:00 PM: KAB Autumn Social. Save the Date - More details will follow
On <say-as interpret-as="date" format="ymd">2018-09-06</say-as> at 12:00:00 AM: Eye Contact Trip to Coast. For more information contact Anne Bleckwen
On <say-as interpret-as="date" format="ymd">2018-08-08</say-as> at 12:30:00 PM: Lawn Bowls Friendly - Metro Blind Bowls. Pick Up from Kingston Police station 12.30pm
On <say-as interpret-as="date" format="ymd">2018-09-15</say-as> at 9:00:00 AM: Surbiton Farmers Market.
Which is clearly in the wrong order, but for some reason, Google has the dates in random order in the ical output. I've temporarily worked around it with the following code:
function updateCalendar() {
ical.fromURL(eventsFeed, {}, function (err, data) {
var ttsorted = [];
for (let k in data) {
if (data.hasOwnProperty(k)) {
var ev = data[k];
if (data[k].type == 'VEVENT') {
if (dateNow < ev.start) {
let tts = `On <say-as interpret-as="date" format="ymd">${ev.start.toISOString().slice(0,10)}</say-as> at ${ev.start.toLocaleTimeString('en-GB')}: ${ev.summary}. ${ev.description}`;
ttsorted.push(tts);
}
}
}
}
console.log(ttsorted.sort());
});
}
which gives me this.
'On <say-as interpret-as="date" format="ymd">2018-08-08</say-as> at 12:30:00 PM: Lawn Bowls Friendly - Metro Blind Bowls. Pick Up from Kingston Police station 12.30pm',
'On <say-as interpret-as="date" format="ymd">2018-09-06</say-as> at 12:00:00 AM: Eye Contact Trip to Coast. For more information contact Anne Bleckwen',
'On <say-as interpret-as="date" format="ymd">2018-09-15</say-as> at 9:00:00 AM: Surbiton Farmers Market. ',
'On <say-as interpret-as="date" format="ymd">2018-10-13</say-as> at 1:00:00 PM: KAB Autumn Social. Save the Date - More details will follow'
It works, but it would be nice to have a built-in "sort-by-date"
Can new version of this module be released to take advantage of the recent fixes to update request
version?
Hi
Found a problem with different formats of EXDATA in ics files.
Some calendars return it like this:
EXDATE;TZID=South Africa Standard Time:20170403T060000,20170410T060000,20170417T060000,20170501T060000
others return it like:
EXDATE;TZID=South Africa Standard Time:20170403T060000
EXDATE;TZID=South Africa Standard Time:20170410T060000
EXDATE;TZID=South Africa Standard Time:20170417T060000
EXDATE;TZID=South Africa Standard Time:20170501T060000
The last method is working fine, but the first method, is causing a toISOstring error.
Hi Peter,
Please update the NPM package from version 0.2.0 to a higher version so that we can take advantage of the bug fixes that has been merged to this repository.
We would really appreciate it.
Cheers,
Chern Jie
Pleas upgrade the dependency request
to a version >= 2.54.0. Since this version it honors the env variable NO_PROXY
, so we can disable the proxy for testing purposes, like tests with nock
.
Thanks a lot for this project!
I just came across RRule and was about to start integrating it, but then realized that you're already using it. I think that's great, but would have loved to know about it beforehand.
I recommend adding it to the README/documentation.
Since DTSTART and DTEND are converted to JS Date objects, it's impossible to tell if the given event was created as an All-Day event (meaning no time was specified) or an event that was 24 hours long.
For this demo calendar:
https://calendar.google.com/calendar/ical/ssjqjrg27h9mqqctfnr5kscmrk%40group.calendar.google.com/public/basic.ics
For calendar readers, the output looks like this:
But from this project, and its various forks, all I get is this:
On 2018-10-09, Event repeating monthly on 2nd tuesday at 10am
On 2018-10-10, Event repeating weekly on a Wednesday at 11am
On 2018-10-11, Single event on 11th October
Code is as below - a few extras as I'm not interested in dates in the past, and it's nice to have things in upcoming date order, rather than random
const ical = require('ical');
var dateNow = new Date();
const url = "https://calendar.google.com/calendar/ical/ssjqjrg27h9mqqctfnr5kscmrk%40group.calendar.google.com/public/basic.ics";
ical.fromURL(url, {}, function (err, data) {
var ttsorted = [];
for (const k in data) {
const ev = data[k];
const eventStart = new Date(ev.start);
if (data.hasOwnProperty(k)) {
if (eventStart.getTime() >= dateNow.getTime()) {
const tts = `On ${ev.start.toISOString().slice(0,10)}, ${ev.summary} `;
ttsorted.push(tts);
}
}
}
ttsorted.sort();
for (const events of ttsorted) {
console.log(events);
}
});
e.g. UNTIL is completely disregarded.
On line 23 of node-ical.js:
curr['rrule'] = rrule.fromString(line.replace("RRULE:", ""));
A sample string is FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
Since the start date is never passed along to the RRule library, it returns events in the past that shouldn't exist.
I want to process iCal entries containing Timesheet entries - and was thinking of writing back to each entry to indicate that it has been processsed.
Thanks, Martin.
I'm trying to use ical into an Ionic app but the developpement environnement is en local server and the request origin is http://localhost:8100
So when I call fromURL I get the following error message:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8100' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled
But even with a call like that
ical.fromURL('http://url/cal.ics', {mode: 'no-cors'}, function (err, data) {})
THis doesn't work because the option is not recognize ...
Hi,
I am currently storing an ical file in aws s3 bucket. I download the file and convert to string.
I then call ical parse method which returns an object. How do i traverse on this object to inspect the entries?
Sample code:
var putObjectPromise = s3.getObject(getParams).promise();
putObjectPromise.then(
(data) => {
var objectData = data.Body.toString('utf-8'); // Use the encoding necessary
var cal = ical.parseICS(objectData);
console.log(`calendar is ${cal.toString()}`);
}
Is it like:
for (var k in cal) {
if (data.hasOwnProperty(k)) {
var ev = data[k]
// Pick out the data relevant to us and create an object to hold it.
var eventData = {
summary: removeTags(ev.summary)
}
// add the newly created object to an array for use later.
eventList.push(eventData);
console.log(`event data is ${eventData.summary}`);
}
}
Thanks,
Shane.
Hi
Quick question
Is ical.js able to open files from Microsoft Office sitting on a hard drive on Windows?
Thanks
Hello,
Firstly, thank you for this package, it's really helpful. Could you help me and explain, is it possible to receive information about excluded events? For example, I added into my Google calendar series of events which repeated every week. And in case if delete more than one event from series, I will not get this information in response, only last excluded will be shown.
Actual result
"exdate": {
"params": [
"VALUE=DATE"
],
"val": "20160421"
},
But I expected something like this
"exdate": [
{
"params": [
"VALUE=DATE"
],
"val": "20160526"
},
{
"params": [
"VALUE=DATE"
],
"val": "20160512"
},
{
"params": [
"VALUE=DATE"
],
"val": "20160421"
}
],
So, is it an issue? Or Am I doing something wrong?
Thank you in advance.
Hi,
the license of ical.js seems not to be mentioned anywhere.
Did I miss it or isn't there any stated?
Whichever it is, thank you for ical.js.
Greetings, Thomas
I have found that if you set your event in calendar to have "reminder" option enabled, it turns "event" into "alarm", which then adds time/time-zone to the start date param and in this case start/end dates are not being parsed correctly.
in rfc 2445 (https://www.ietf.org/rfc/rfc2445.txt) paragraph 4.1.2 (Multiple Values) is written:
The general rule for encoding multi-valued items is to simply
create a new content line for each value, including the property
name.
but it is not possible to parse multi-valued items in multiple lines, because the function storeParam() (ical.js) writes each line as key/value and a second line with the same property name overwrites the first one.
is there a possibility to change this behavior?
Currently, there is no library that handles both parsing and writing of icals.
Fortunately this library follows almost identically the format required for https://github.com/sebbo2002/ical-generator
The only significant difference being ical-generator expects RRule option properties to be camelCased while in ical they are flat cased, which is interesting because within RRule, origOptions is camelCased.
The purpose of this is not to try to coerce this library, which does a great job btw, into following patterns of another library arbitrarily, but in the hopes that by following standard javascript casing styles we can bring further consistency across related libraries so they may be easily used together.
What do you think? I'd be more than willing to submit the PR myself
The following character sequences need to be un-escaped, for all text fields: \\
, \;
, and \,
.
RFC 2445 section 4.3.11:
text = *(TSAFE-CHAR / ":" / DQUOTE / ESCAPED-CHAR)
; Folded according to description above
ESCAPED-CHAR = "\\" / "\;" / "\," / "\N" / "\n")
; \\ encodes \, \N or \n encodes newline
; \; encodes ;, \, encodes ,
Sample LOCATION field from a VEVENT:
LOCATION:223 TWIN DOLPHIN DR\, Redwood City\, CA\, 94065-1514
Currently the parser seems to add half-baked or empty items to the out-data. These show up as soon as it runs into a BEGIN:
object but it doesn't taking the possible context (or "stack" I think it's referred to as in the code) into consideration. There are a number of different things that can have DTSTART
/DTEND
.
I am not sure about the indented scope of this module: was it ever meant to encapsulate other objects than VEVENT
s?
This ticket might very well be related or duplicating both #28 and #29 -please correct me if I'm mistaken-
I'm sure this is a server setting that I'm missing, but I am parsing the same feed (with the same code) on two servers and the time stamps are coming out different. Both servers are synced to ntp. Other than that I don't know where to look. Any ideas? Thanks!
The following calendar will only return the VALARM event:
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:eb9e1bd2-ceba-499f-be77-f02773954c72
SUMMARY:Event with an alarm
DESCRIPTION:This is an event with an alarm.
ORGANIZER="mailto:[email protected]"
DTSTART;TZID="America/Los_Angeles":20130418T110000
DTEND;TZID="America/Los_Angeles":20130418T120000
STATUS:CONFIRMED
CLASS:PUBLIC
TRANSP:OPAQUE
LAST-MODIFIED:20130418T175632Z
DTSTAMP:20130418T175632Z
SEQUENCE:3
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;RELATED=START:-PT5M
DESCRIPTION:Reminder
END:VALARM
END:VEVENT
END:VCALENDAR
The basic RRULE command is implemented, but not the companion RECURRENCE-ID or EXDATE commands:
https://nylas.com/blog/rrules/
If you have an ics file that looks like this:
BEGIN:VEVENT
UID:0000001
RRULE:FREQ=DAILY;COUNT=5
SUMMARY:Treasure Hunting
DTSTART;TZID=America/Los_Angeles:20150706T120000
DTEND;TZID=America/Los_Angeles:20150706T130000
END:VEVENT
BEGIN:VEVENT
UID:0000001
SUMMARY:Treasure Hunting
LOCATION:The other island
DTSTART;TZID=America/Los_Angeles:20150707T120000
DTEND;TZID=America/Los_Angeles:20150707T130000
RECURRENCE-ID;TZID=America/Los_Angeles:20150707T120000
END:VEVENT
Right now, ical.js will silently replace the recurring event with the single instance. This happens where the code does this:
if (curr.uid)
par[curr.uid] = curr
This should probably look something more like this:
if (curr.uid)
{
if (par[curr.uid] === undefined)
{
par[curr.uid] = curr
}
else
{
// TODO: Add support for RECURRENCE-ID
}
}
Neither the old behaviour or this one is correct, but if you added error-handling code at the TODO area, you could warn users when the calendar is being parsed incorrectly.
In a VEVENT, an all-day event is represented with a start and end date, without time information:
DTSTART;VALUE=DATE:20111108
DTEND;VALUE=DATE:20111111
These values are placed into a javascript Date object, and then adjusted from GMT into the server timezone (GMT-0700 in my case). This gives me a start and end date of 7 hours before midnight. And since the date is no longer midnight, I lose the ability to discover whether it's an all-day event.
I use a time tracking program that writes calendar events as I track time.
It would be useful if I could watch that calendar from node, and everytime an ical entry was made, trigger a sequence of other processing.
So I'm looking for some sort of callback on changes.
I'm using hook.io for another part of the project, so that would be a handy coincidence for me.
Thanks, M.
After hours of fiddling, I realized that the published version of ical.js is very out of date on npm. Support for the recurrences
property is not there, for instance.
Please consider republishing to npm. Thanks!
If fs is a dependency, shouldn't it be required by this modules packages.json?
Hi guys
I had some serious issue with TZID datetimes (as used by apple icalendar) when the server was in a different timezone vs the browser
unfortunately ical doesn't handle it correctly
this is my current workaround:
curr[name] = require('moment-timezone').tz(val.toString(), (parseParams(params).TZID || '')).tz("UTC").toDate()
hope this will help others in my same situation
Skipped dates of a recurring appointment .. aren't skipped.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.