Search code examples
momentjsicalendarmoment-timezone

Generate ics with dynamic VTIMEZONE using moment js


Trying to create a .ics file which has a VTIMEZONE component, which based on the supplied timezone sets the Standard time and Daylight Savings time dynamically.

Just a sample:

BEGIN:VTIMEZONE
TZID:America/New_York
LAST-MODIFIED:20050809T050000Z
BEGIN:STANDARD
DTSTART:20071104T020000
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:EST
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:20070311T020000
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:EDT
END:DAYLIGHT
END:VTIMEZONE

In my attempt to solve this I created a moment.tz.zone(timezone)Object which based on the documentation of moment https://momentjs.com/timezone/docs/#/zone-object/ I assume holds the necessary data untils(should be TZOFFSETFROM, TZOFFSETTO) and offsets(DTSTART).

Yet I can't find a clear documentation on how to extract these data.

Was wondering if there's anyway that one can extract the DTSTART, TZOFFSETFROM and TZOFFSETTO for Standard time and Daylight in moment-timezone.js


Solution

  • As you already mentioned in the question, you can use the moment.tz.zone(name) method. This will give you a Zone object that contains a list of timestamps in the untils property, then you can apply your logic to get the timestamps you want in the VTIMEZONE (I've used the first timestamps of the untils array in my code sample).

    You can use moment.tz and format() on a timestamp to get DTSTART. You can pass ZZ token to format() to get offset for TZOFFSETFROM and TZOFFSETTO.

    You can use abbrs values to get TZNAME.

    Here a live sample:

    const MAX_OCCUR = 2;
    const getVtimezoneFromMomentZone = (tzName) => {
      const zone = moment.tz.zone(tzName);
      const header = `BEGIN:VTIMEZONE\nTZID:${tzName}`;
      const footer = 'END:VTIMEZONE';
      
      let zTZitems = '';
      for(let i=0; i<MAX_OCCUR && i+1<zone.untils.length; i++){
        const type = i%2 == 0 ? 'STANDARD' : 'DAYLIGHT';
        const momDtStart = moment.tz(zone.untils[i], tzName);
        const momNext = moment.tz(zone.untils[i+1], tzName);
        const item = 
    `BEGIN:${type}
    DTSTART:${momDtStart.format('YYYYMMDDTHHmmss')}
    TZOFFSETFROM:${momDtStart.format('ZZ')}
    TZOFFSETTO:${momNext.format('ZZ')}
    TZNAME:${zone.abbrs[i]}
    END:${type}\n`;
        zTZitems += item;
      }
      const result = `${header}\n${zTZitems}${footer}\n`;
      return result;
    };
    
    console.log(getVtimezoneFromMomentZone('America/New_York'));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.23.0/moment-with-locales.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.23/moment-timezone-with-data-2012-2022.min.js"></script>