How to parse calendar file dates with JavaScript?
Asked Answered
L

4

6

We need to use JavaScript on the browser to read and parse calendar files (.ics) (also called iCal formats). I wrote a custom function to read these values and then use the JavaScript Date() function to make a data object.

Is any easier and better way to do this? Please look at my function (below), your comments would be welcome.

A typical date value from an .ics file looks like this:

DTSTART:20110914T184000Z

Need to break it apart at the colon, so:

var strData = 'DTSTART:20110914T184000Z'
var x = strData.indexOf(":");
var strVal = strData.slice(x + 1 );

next, call a function that returns a date object:

var dateObj = calenDate(strVal);

//resulting dateObj value: Fri Oct 14 2011 18:40:00 GMT-0400 (Eastern Daylight Time)

Here is the function that parses the date.

function calenDate(icalStr)  {
    // icalStr = '20110914T184000Z'             
    var strYear = icalStr.substr(0,4);
    var strMonth = icalStr.substr(4,2);
    var strDay = icalStr.substr(6,2);
    var strHour = icalStr.substr(9,2);
    var strMin = icalStr.substr(11,2);
    var strSec = icalStr.substr(13,2);

    var oDate =  new Date(strYear,strMonth, strDay, strHour, strMin, strSec)

return oDate;
}

I think something is wrong since it is getting the month wrong.

Luxembourg answered 28/12, 2011 at 15:44 Comment(0)
C
8

For some odd reason the month parameter is zero-based (reference).

Change this line in your function.

var strMonth = icalStr.substr(4,2);

to this:

var strMonth = parseInt(icalStr.substr(4,2),10)-1;

See working demo on jsFiddle: http://jsfiddle.net/cTkTQ/

Carduaceous answered 28/12, 2011 at 15:51 Comment(2)
The months are zero-based? Thanks for pointing that out! I didn't see it in the RFC 5545.Luxembourg
Sorry for commenting this zombie comment, but I just want to point out that it's not months in iCal (RFC 5545) that is zero-based, but javascript Date months.Subfamily
P
2

A somewhat more robust way of parsing the dates would be:

    var parser = XRegExp("^ (?<prefix> [^:;]+       )    # DTSTART/DTEND/DTSTAMP \n\
                            ((:|;TZID=(?<tz>[^:]+):))    # timezone \n\
                            (?<year>   [0-9]{4}     )    # year    \n\
                            (?<month>  [0-9]{2}     )    # month   \n\
                            (?<day>    [0-9]{2}     ) T  # day     \n\
                            (?<hour>   [0-9]{2}     )    # hour    \n\
                            (?<minute> [0-9]{2}     )    # minute  \n\
                            (?<second> [0-9]{2}     )    # second  \n\
                            (?<utc>     Z?          )    # utc", "x");

     parts = parser.exec (d);

     var od = new Date (parseInt (parts.year, 10),
                        parseInt (parts.month, 10) - 1,
                        parseInt (parts.day, 10),
                        parseInt (parts.hour, 10),
                        parseInt (parts.minute, 10),
                        parseInt (parts.second, 10));

This requires you to add an additional (tiny) dependency, XRegExp, which might be a bit overkill depending on your further needs, but it allows for a clean, easy to read regexp parsing of the date format in .ics files. This also takes into account the time zone identifier, if the date is not UTC. I leave it to you to add proper handling of time zones as well as the use of the prefix part.

The short answer (as noted by jessegavin) however, is that the month-parameter of the constructor expects a number between 0-11 (refer Mozilla Developer Network for more information). However, parseInt() tries to parse leading zeros as radix 8 (octal), so you should make sure to add radix 10 too, that would be the second parameter to parseInt(string [, radix]).

Patricio answered 28/12, 2011 at 17:17 Comment(1)
Nice, didn't need to make all those variables, just goes straight into the Date constructorLuxembourg
N
2

This is a new package (with tests) that seems to work well: ical-date-parser

Usage

import iCalDateParser from 'ical-date-parser';

iCalDateParser('20140422T233000Z');
Nogging answered 18/6, 2016 at 13:33 Comment(0)
R
0

Сomplete solution:

function parseICalDate(date) {
    const year = date.substr(0, 4);
    const month = parseInt(date.substr(4, 2), 10) - 1;
    const day = date.substr(6, 2);
    const hour = date.substr(9, 2);
    const minute = date.substr(11, 2);
    const second = date.substr(13, 2);
    return new Date(Date.UTC(year, month, day, hour, minute, second));
}
Remedial answered 13/8, 2023 at 15:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.