{"id":13596297,"url":"https://github.com/adamgibbons/ics","last_synced_at":"2026-04-01T21:57:15.558Z","repository":{"id":22403276,"uuid":"25740487","full_name":"adamgibbons/ics","owner":"adamgibbons","description":"iCalendar (ics) file generator for node.js","archived":false,"fork":false,"pushed_at":"2025-02-25T05:53:24.000Z","size":1262,"stargazers_count":756,"open_issues_count":31,"forks_count":155,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-04-23T20:53:55.585Z","etag":null,"topics":["alarm","calendar","calendar-events","hacktoberfest","ical","icalendar","ics","ics-ical","javascript","vcalendar","vevent"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adamgibbons.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-10-25T17:51:22.000Z","updated_at":"2025-04-23T19:20:26.000Z","dependencies_parsed_at":"2024-06-18T12:11:56.368Z","dependency_job_id":"88aa9238-14f3-4c70-be2d-6411a9852497","html_url":"https://github.com/adamgibbons/ics","commit_stats":{"total_commits":498,"total_committers":76,"mean_commits":6.552631578947368,"dds":0.2991967871485943,"last_synced_commit":"0638524ee48271330779990767e2fe25f3192c22"},"previous_names":[],"tags_count":53,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamgibbons%2Fics","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamgibbons%2Fics/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamgibbons%2Fics/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamgibbons%2Fics/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adamgibbons","download_url":"https://codeload.github.com/adamgibbons/ics/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250514767,"owners_count":21443208,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alarm","calendar","calendar-events","hacktoberfest","ical","icalendar","ics","ics-ical","javascript","vcalendar","vevent"],"created_at":"2024-08-01T16:02:16.457Z","updated_at":"2026-04-01T21:57:15.552Z","avatar_url":"https://github.com/adamgibbons.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"ics\n==================\n\nThe [iCalendar](http://tools.ietf.org/html/rfc5545) generator\n\n[![npm version](https://badge.fury.io/js/ics.svg)](http://badge.fury.io/js/ics)\n[![CI](https://github.com/adamgibbons/ics/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/adamgibbons/ics/actions/workflows/build.yml)\n[![Downloads](https://img.shields.io/npm/dm/ics.svg)](http://npm-stat.com/charts.html?package=ics)\n\n## Install\n\n`npm install -S ics`\n\n## Example Usage\n\n#### In node / CommonJS\n\n1) Create an iCalendar event:\n\n```javascript\nconst ics = require('ics')\n// or, in ESM: import * as ics from 'ics'\n\nconst event = {\n  start: [2018, 5, 30, 6, 30],\n  duration: { hours: 6, minutes: 30 },\n  title: 'Bolder Boulder',\n  description: 'Annual 10-kilometer run in Boulder, Colorado',\n  location: 'Folsom Field, University of Colorado (finish line)',\n  url: 'http://www.bolderboulder.com/',\n  geo: { lat: 40.0095, lon: 105.2669 },\n  categories: ['10k races', 'Memorial Day Weekend', 'Boulder CO'],\n  status: 'CONFIRMED',\n  busyStatus: 'BUSY',\n  organizer: { name: 'Admin', email: 'Race@BolderBOULDER.com' },\n  attendees: [\n    { name: 'Adam Gibbons', email: 'adam@example.com', rsvp: true, partstat: 'ACCEPTED', role: 'REQ-PARTICIPANT' },\n    { name: 'Brittany Seaton', email: 'brittany@example2.org', dir: 'https://linkedin.com/in/brittanyseaton', role: 'OPT-PARTICIPANT' }\n  ]\n}\n\nics.createEvent(event, (error, value) =\u003e {\n  if (error) {\n    console.log(error)\n    return\n  }\n\n  console.log(value)\n})\n// BEGIN:VCALENDAR\n// VERSION:2.0\n// CALSCALE:GREGORIAN\n// PRODID:adamgibbons/ics\n// METHOD:PUBLISH\n// X-PUBLISHED-TTL:PT1H\n// BEGIN:VEVENT\n// UID:S8h0Vj7mTB74p9vt5pQzJ\n// SUMMARY:Bolder Boulder\n// DTSTAMP:20181017T204900Z\n// DTSTART:20180530T043000Z\n// DESCRIPTION:Annual 10-kilometer run in Boulder\\, Colorado\n// X-MICROSOFT-CDO-BUSYSTATUS:BUSY\n// URL:http://www.bolderboulder.com/\n// GEO:40.0095;105.2669\n// LOCATION:Folsom Field, University of Colorado (finish line)\n// STATUS:CONFIRMED\n// CATEGORIES:10k races,Memorial Day Weekend,Boulder CO\n// ORGANIZER;CN=Admin:mailto:Race@BolderBOULDER.com\n// ATTENDEE;RSVP=TRUE;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Adam Gibbons:mailto:adam@example.com\n// ATTENDEE;RSVP=FALSE;ROLE=OPT-PARTICIPANT;DIR=https://linkedin.com/in/brittanyseaton;CN=Brittany\n//   Seaton:mailto:brittany@example2.org\n// DURATION:PT6H30M\n// END:VEVENT\n// END:VCALENDAR\n```\n\n2) Write an iCalendar file:\n```javascript\nconst { writeFileSync } = require('fs')\nconst ics = require('ics')\n\nics.createEvent({\n  title: 'Dinner',\n  description: 'Nightly thing I do',\n  busyStatus: 'FREE',\n  start: [2018, 1, 15, 6, 30],\n  duration: { minutes: 50 }\n}, (error, value) =\u003e {\n  if (error) {\n    console.log(error)\n  }\n\n  writeFileSync(`${__dirname}/event.ics`, value)\n\n/*\nYou cannot use fs in Frontend libraries like React so you rather import a module to save files to the browser as follow [  import { saveAs } from 'file-saver'; // For saving the file in the browser]\nconst blob = new Blob([value], { type: 'text/calendar' });\n        saveAs(blob, `${title}.ics`);\n\n*/\n})\n```\n\n3) Create multiple iCalendar events:\n```javascript\nconst ics = require('./dist')\n\nconst { error, value } = ics.createEvents([\n  {\n    title: 'Lunch',\n    start: [2018, 1, 15, 12, 15],\n    duration: { minutes: 45 }\n  },\n  {\n    title: 'Dinner',\n    start: [2018, 1, 15, 12, 15],\n    duration: { hours: 1, minutes: 30 }\n  }\n])\n\nif (error) {\n  console.log(error)\n  return\n}\n\nconsole.log(value)\n// BEGIN:VCALENDAR\n// VERSION:2.0\n// CALSCALE:GREGORIAN\n// PRODID:adamgibbons/ics\n// METHOD:PUBLISH\n// X-PUBLISHED-TTL:PT1H\n// BEGIN:VEVENT\n// UID:pP83XzQPo5RlvjDCMIINs\n// SUMMARY:Lunch\n// DTSTAMP:20230917T142209Z\n// DTSTART:20180115T121500Z\n// DURATION:PT45M\n// END:VEVENT\n// BEGIN:VEVENT\n// UID:gy5vfUVv6wjyBeNkkFmBX\n// SUMMARY:Dinner\n// DTSTAMP:20230917T142209Z\n// DTSTART:20180115T121500Z\n// DURATION:PT1H30M\n// END:VEVENT\n// END:VCALENDAR\n```\n\n3b) Create multiple events asynchronously (large batches):\n\n`createEventsAsync` returns a `Promise` that resolves to `{ error, value }` (there is no callback form). While building the calendar it yields to the event loop periodically, which helps keep huge event lists from blocking Node or the browser for too long.\n\n```javascript\nconst { createEventsAsync } = require('ics')\n\nasync function run () {\n  const { error, value } = await createEventsAsync([\n    {\n      title: 'Lunch',\n      start: [2018, 1, 15, 12, 15],\n      duration: { minutes: 45 }\n    },\n    {\n      title: 'Dinner',\n      start: [2018, 1, 15, 12, 15],\n      duration: { hours: 1, minutes: 30 }\n    }\n  ])\n\n  if (error) {\n    console.log(error)\n    return\n  }\n\n  console.log(value)\n}\n\nrun()\n```\n\nAn empty event list and optional calendar header work the same as with `createEvents`:\n\n```javascript\ncreateEventsAsync([], { calName: 'My calendar' }).then(({ error, value }) =\u003e {\n  if (error) console.log(error)\n  else console.log(value)\n})\n```\n\n4) Create iCalendar events with Audio (Mac):\n```javascript\nlet ics = require(\"ics\")\nlet moment = require(\"moment\")\nlet events = []\nlet alarms = []\n\nlet start = moment().format('YYYY-M-D-H-m').split(\"-\").map((a) =\u003e parseInt(a))\nlet end = moment().add({'hours':2, \"minutes\":30}).format(\"YYYY-M-D-H-m\").split(\"-\").map((a) =\u003e parseInt(a))\n\nalarms.push({\n  action: 'audio',\n  description: 'Reminder',\n  trigger: {hours:2,minutes:30,before:true},\n  repeat: 2,\n  attachType:'VALUE=URI',\n  attach: 'Glass'\n})\n\nlet event = {\n  productId:\"myCalendarId\",\n  uid: \"123\"+\"@ics.com\",\n  startOutputType:\"local\",\n  start: start,\n  end: end,\n  title: \"test here\",\n  alarms: alarms\n}\nevents.push(event)\nconsole.log(ics.createEvents(events).value)\n\n// BEGIN:VCALENDAR\n// VERSION:2.0\n// CALSCALE:GREGORIAN\n// PRODID:myCalendarId\n// METHOD:PUBLISH\n// X-PUBLISHED-TTL:PT1H\n// BEGIN:VEVENT\n// UID:123@ics.com\n// SUMMARY:test here\n// DTSTAMP:20230917T142621Z\n// DTSTART:20230917T152600\n// DTEND:20230917T175600\n// BEGIN:VALARM\n// ACTION:AUDIO\n// REPEAT:2\n// DESCRIPTION:Reminder\n// ATTACH;VALUE=URI:Glass\n// TRIGGER:-PT2H30M\\nEND:VALARM\n// END:VEVENT\n// END:VCALENDAR\n```\n\n#### Using ESModules \u0026 in the browser\n\n```javascript\nimport { createEvent} from 'ics';\n\nconst event = {\n  ...\n}\n\nasync function handleDownload() {\n  const filename = 'ExampleEvent.ics'\n  const file = await new Promise((resolve, reject) =\u003e {\n    createEvent(event, (error, value) =\u003e {\n      if (error) {\n        reject(error)\n      }\n\n      resolve(new File([value], filename, { type: 'text/calendar' }))\n    })\n  })\n  const url = URL.createObjectURL(file);\n\n  // trying to assign the file URL to a window could cause cross-site\n  // issues so this is a workaround using HTML5\n  const anchor = document.createElement('a');\n  anchor.href = url;\n  anchor.download = filename;\n\n  document.body.appendChild(anchor);\n  anchor.click();\n  document.body.removeChild(anchor);\n\n  URL.revokeObjectURL(url);\n}\n```\n\n## API\n\n### `createEvent(attributes[, callback])`\n\nGenerates an iCal-compliant VCALENDAR string with one VEVENT.\nIf a callback is not provided, returns an object having the form `{ error, value }`,\nwhere `value` contains an iCal-compliant string if there are no errors.\nIf a callback is provided, returns a Node-style callback.\n\n#### `attributes`\n\nObject literal containing event information.\nOnly the `start` property is required.\n\nNote all date/time fields can be the array form, or a number representing the unix timestamp in milliseconds (e.g. `getTime()` on a `Date`).\n\nThe following properties are accepted:\n\n| Property      | Description   | Example  |\n| ------------- | ------------- | ----------\n| start         | **Required**. Date and time at which the event begins. | `[2000, 1, 5, 10, 0]` (January 5, 2000) or a `number`\n| startInputType | Type of the date/time data in `start`:\u003cbr\u003e`local` (default): passed data is in local time.\u003cbr\u003e`utc`: passed data is UTC |\n| startOutputType | Format of the start date/time in the output:\u003cbr\u003e`utc` (default): the start date will be sent in UTC format.\u003cbr\u003e`local`: the start date will be sent as \"floating\" (form #1 in [RFC 5545](https://tools.ietf.org/html/rfc5545#section-3.3.5)) |\n| end           | Time at which event ends. *Either* `end` or `duration` is required, but *not* both. | `[2000, 1, 5, 13, 5]` (January 5, 2000 at 1pm) or a `number`\n| endInputType | Type of the date/time data in `end`:\u003cbr\u003e`local`: passed data is in local time.\u003cbr\u003e`utc`: passed data is UTC.\u003cbr\u003eThe default is the value of `startInputType` |\n| endOutputType | Format of the start date/time in the output:\u003cbr\u003e`utc`: the start date will be sent in UTC format.\u003cbr\u003e`local`: the start date will be sent as \"floating\" (form #1 in [RFC 5545](https://tools.ietf.org/html/rfc5545#section-3.3.5)).\u003cbr\u003eThe default is the value of `startOutputType` |\n| duration      | How long the event lasts. Object literal having form `{ weeks, days, hours, minutes, seconds }` *Either* `end` or `duration` is required, but *not* both. | `{ hours: 1, minutes: 45 }` (1 hour and 45 minutes)\n| title         | Title of event. | `'Code review'`\n| description   | Description of event. | `'A constructive roasting of those seeking to merge into master branch'`\n| location      | Intended venue | `Mountain Sun Pub and Brewery`\n| geo   | Geographic coordinates (lat/lon) | `{ lat: 38.9072, lon: 77.0369 }`\n| url           | URL associated with event | `'http://www.mountainsunpub.com/'`\n| status        | Three statuses are allowed: `TENTATIVE`, `CONFIRMED`, `CANCELLED` | `CONFIRMED`\n| organizer     | Person organizing the event | `{ name: 'Adam Gibbons', email: 'adam@example.com', dir: 'https://linkedin.com/in/adamgibbons', sentBy: 'test@example.com' }`\n| attendees     | Persons invited to the event | `[{ name: 'Mo', email: 'mo@foo.com', rsvp: true }, { name: 'Bo', email: 'bo@bar.biz', dir: 'https://twitter.com/bo1234', partstat: 'ACCEPTED', role: 'REQ-PARTICIPANT' }]`\n| categories    | Categories associated with the event | `['hacknight', 'stout month']`\n| alarms        | Alerts that can be set to trigger before, during, or after the event. The following `attach` properties work on Mac OS: Basso, Blow, Bottle, Frog, Funk, Glass, Hero, Morse, Ping, Pop, Purr, Sousumi, Submarine, Tink | `{ action: 'display', description: 'Reminder', trigger: [2000, 1, 4, 18, 30] }` OR `{ action: 'display', description: 'Reminder', trigger: { hours: 2, minutes: 30, before: true } }` OR `{ action: 'display', description: 'Reminder', trigger: { hours: 2, minutes: 30, before: false }` OR `{ action: 'audio', description: 'Reminder', trigger: { hours: 2, minutes: 30, before: true }, repeat: 2, attachType: 'VALUE=URI', attach: 'Glass' }`\n| productId     | Product which created ics, `PRODID` field | `'adamgibbons/ics'`\n| uid           | Universal unique id for event, produced by default with `nanoid`.  **Warning:** This value must be **globally unique**.  It is recommended that it follow the [RFC 822 addr-spec](https://www.w3.org/Protocols/rfc822/) (i.e. `localpart@domain`).  Including the `@domain` half is a good way to ensure uniqueness. | `'LZfXLFzPPR4NNrgjlWDxn'`\n| method        | This property defines the iCalendar object method associated with the calendar object. When used in a MIME message entity, the value of this property MUST be the same as the Content-Type \"method\" parameter value.  If either the \"METHOD\" property or the Content-Type \"method\" parameter is specified, then the other MUST also be specified. | `PUBLISH`\n| recurrenceRule        | A recurrence rule, commonly referred to as an RRULE, defines the repeat pattern or rule for to-dos, journal entries and events. If specified, RRULE can be used to compute the recurrence set (the complete set of recurrence instances in a calendar component). You can use a generator like this [one](https://www.textmagic.com/free-tools/rrule-generator). | `FREQ=DAILY`\n| recurrenceId  | Date-time used with recurring events to identify a specific instance being updated/cancelled; serialized as `RECURRENCE-ID`. Provide a date-time in local time. | `[2000, 1, 5, 10, 0]` or a `number`\n| exclusionDates | Array of date-time exceptions for recurring events, to-dos, journal entries, or time zone definitions. | `[[2000, 1, 5, 10, 0], [2000, 2, 5, 10, 0]]` OR `[1694941727477, 1694945327477]`\n| sequence      | For sending an update for an event (with the same uid), defines the revision sequence number. | `2`\n| busyStatus    | Used to specify busy status for Microsoft applications, like Outlook. See [Microsoft spec](https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxcical/cd68eae7-ed65-4dd3-8ea7-ad585c76c736). | `'BUSY'` OR `'FREE'` OR `'TENTATIVE`' OR `'OOF'`\n| transp        | Used to specify event transparency (does event consume actual time of an individual). Used by Google Calendar to determine if event should change attendees availability to 'Busy' or not. | `'TRANSPARENT'` OR `'OPAQUE'`\n| classification    | This property defines the access classification for a calendar component. See [iCalender spec](https://icalendar.org/iCalendar-RFC-5545/3-8-1-3-classification.html). | `'PUBLIC'` OR `'PRIVATE'` OR `'CONFIDENTIAL`' OR any non-standard string\n| created | Date-time representing event's creation date. Provide a date-time in local time | `[2000, 1, 5, 10, 0]` or a `number`\n| lastModified | Date-time representing date when event was last modified. Provide a date-time in local time | [2000, 1, 5, 10, 0] or a `number`\n| calName       |  Specifies the _calendar_ (not event) name. Used by Apple iCal and Microsoft Outlook; see [Open Specification](https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxcical/1da58449-b97e-46bd-b018-a1ce576f3e6d) | `'Example Calendar'` |\n| htmlContent       | Used to include HTML markup in an event's description. Standard DESCRIPTION tag should contain non-HTML version. | `\u003c!DOCTYPE html\u003e\u003chtml\u003e\u003cbody\u003e\u003cp\u003eThis is\u003cbr\u003etest\u003cbr\u003ehtml code.\u003c/p\u003e\u003c/body\u003e\u003c/html\u003e` |\n\nTo create an **all-day** event, pass only three values (`year`, `month`, and `date`) to the `start` and `end` properties.\nThe date of the `end` property should be the day *after* your all-day event.\nFor example, in order to create an all-day event occuring on October 15, 2018:\n```javascript\nconst eventAttributes = {\n  start: [2018, 10, 15],\n  end: [2018, 10, 16],\n  /* rest of attributes */\n}\n```\n\n#### `callback`\n\nOptional.\nNode-style callback.\n\n```javascript\nfunction (err, value) {\n  if (err) {\n    // if iCal generation fails, err is an object containing the reason\n    // if iCal generation succeeds, err is null\n  }\n\n  console.log(value) // iCal-compliant text string\n}\n```\n\n### `createEvents(events[, headerParams, callback])`\n\nGenerates an iCal-compliant VCALENDAR string with multiple VEVENTS.\n\n`headerParams` may be omitted, and in this case they will be read from the first event.\n\nIf a callback is not provided, returns an object having the form `{ error, value }`, where value is an iCal-compliant text string\nif `error` is `null`.\n\nIf a callback is provided, returns a Node-style callback.\n\n#### `events`\n\nArray of `attributes` objects (as described in `createEvent`).\n\n#### `callback`\n\nOptional.\nNode-style callback.\n\n```javascript\nfunction (err, value) {\n  if (err) {\n    // if iCal generation fails, err is an object containing the reason\n    // if iCal generation succeeds, err is null\n  }\n\n  console.log(value) // iCal-compliant text string\n}\n```\n\n### `createEventsAsync(events[, headerAttributes])`\n\nAsync variant of `createEvents`. Resolves to an object `{ error, value }` where `value` is an iCal-compliant string when `error` is `null`. There is no callback overload.\n\n`events` is an array of the same `attributes` objects as in `createEvent`. The optional `headerAttributes` object is merged with the first event when `events` is non-empty, or used alone to build the calendar header when `events` is empty (same behavior as `createEvents`).\n\nWhile iterating events, the implementation yields to the event loop at intervals so very large batches are less likely to freeze the process. It also builds the output in parts and joins once at the end to reduce string concatenation overhead.\n\n## Develop\n\nRun mocha tests and watch for changes:\n```\nnpm start\n```\n\nRun tests once and exit:\n```\nnpm test\n```\n\nBuild the project, compiling all ES6 files within the `src` directory into vanilla JavaScript in the `dist` directory.\n```\nnpm run build\n```\n\n## References\n\n- [RFC 5545: Internet Calendaring and Scheduling Core Object Specification (iCalendar)](http://tools.ietf.org/html/rfc5545)\n- [iCalendar Validator](http://icalendar.org/validator.html#results)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadamgibbons%2Fics","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadamgibbons%2Fics","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadamgibbons%2Fics/lists"}