Skip to content
Mike Angstadt edited this page Aug 23, 2018 · 4 revisions

iCalendar data can be encoded in JSON. This format is called jCal. The jCal specification is defined in RFC 7265.

Note that, unlike the rest of biweekly which requires a 1.5 JVM, you must have a 1.6 JVM or later in order to work with jCards.

Below is an example of a jCal.

["vcalendar",
  [
    ["version", {}, "text", "2.0"],
    ["prodid", {}, "text", "-//Microsoft Corporation//Outlook 14.0 MIMEDIR//EN"]
  ],
  [
    ["vevent",
      [
        ["uid", {}, "text", "d6d88f2e50080b9602da53dac1102762"],
        ["dtstamp", {}, "date-time", "2013-06-01T08:00:00Z"],
        ["summary", {"language":"en-us"}, "text", "Team Meeting"],
        ["dtstart", {}, "date-time", "2013-06-10T12:00:00Z"],
        ["duration", {}, "duration","PT1H"],
        ["rrule", {}, "recur", {"freq":"WEEKLY", "interval":2}]
      ],
      []
    ]
  ]
]

1 Reading JSON-encoded iCalendar data

The JCalReader class handles the parsing of JSON-encoded iCalendar data. The data is read in a streaming fashion, meaning it parses the data as it is read off the wire. This results in a smaller memory footprint than other approaches.

JCalReader automatically takes timezone data into account by parsing date/time values according to their assigned VTIMEZONE definition. See the Timezones page for more information on working with timezones.

1.1 Important methods

readNext()
Parses and returns the next ICalendar object in the data stream. The method returns null when the end of stream has been reached.

getWarnings()
Returns any problems the parser encountered while parsing the ICalendar object that was last returned by readNext(). Examples of things that could cause warnings are: malformed date values or unparseable property values.

close()
As with all I/O operations, it's important to call the close() method when you are done with the JCalReader object in order to properly close the input stream.

Please see the Javadocs for a complete listing of all the methods.

1.2 Example

The example below outputs the start times and summaries of each event in an jCard data stream.

Note that, when outputting the start dates, the DateFormat object is not configured with a timezone. Therefore, the dates will be displayed in the user's local timezone. For example, if a date/time value has a time of 13:00 UTC, and the user's local timezone is 5 hours behind UTC, the time will be displayed as "08:00".

File file = new File("events.json");
JCalReader reader = new JCalReader(file);
try {
  ICalendar ical;
  DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm");
  while ((ical = reader.readNext()) != null) {
    for (VEvent event : ical.getEvents()) {
      DateStart dateStart = event.getDateStart();
      String dateStartStr = (dateStart == null) ? null : df.format(dateStart.getValue());

      Summary summary = event.getSummary();
      String summaryStr = (summary == null) ? null : summary.getValue();

      if (summaryStr != null && dateStartStr != null) {
        System.out.println(dateStartStr + ": " + summaryStr);
        continue;
      }

      if (summaryStr != null){
        System.out.println(summaryStr);
        continue;
      }

      if (dateStartStr != null){
        System.out.println(dateStartStr);
        continue;
      }
    }
  }
} finally {
  reader.close();
}

1.3 A note about unparseable property values

If a property's value cannot be parsed (for example, due to a malformed date value), the property is treated as an experimental property and a warning is logged. The code below demonstrates this:

String json =
"[\"vcalendar\"," +
  "[" +
    "[\"version\", {}, \"text\", \"2.0\"]" +
  "]," +
  "[" +
    "[\"vevent\"," +
      "[" +
        "[\"summary\", {\"language\":\"en-us\"}, \"text\", \"Party at my place.\"]," +
        "[\"dtstart\", {}, \"date-time\", \"Come over whenever, dude.\"]" +
      "]," +
      "[]" +
    "]" +
  "]" +
"]";

JCalReader reader = new JCalReader(json);
ICalendar ical = reader.readNext();

List<String> warnings = reader.getWarnings();
System.out.println("Warnings: " + warnings);

VEvent event = ical.getEvents().get(0);
System.out.println("DTSTART property: " + event.getDateStart());

RawProperty prop = event.getExperimentalProperty("DTSTART");
System.out.println("Experimental property: " + prop.getValue());

reader.close();

The above code produces the following output. The comma character is escaped to simulate how the value would appear in a plain-text iCalendar object.

Warnings: [Line 1 (dtstart property): (1) Property value could not be unmarshalled.  Value: "Come over whenever\, dude."  Reason: (17) Could not parse date-time value.]
DTSTART property: null
Experimental property: Come over whenever\, dude.

2 Writing JSON-encoded iCalendar data

The JCalWriter class handles the creation of JSON-encoded iCalendar data.

By default, JCalWriter automatically formats all date/time values in UTC time, but this can be changed. See the Timezones page for more information on working with timezones.

2.1 Important methods

write()
Writes the contents of an ICalendar object to the data stream.

close()
As with all I/O operations, it's important to call the close() method when you are done with the JCalWriter object in order to properly close the output stream. It's especially important for JCalWriter because it must write the proper closing characters to complete the JSON syntax.

Please see the Javadocs for a complete listing of all the methods.

2.2 Example

The example below writes a list of ICalendar objects to a JSON file.

List<ICalendar> icals = ...
File file = new File("events.json");
JCalWriter writer = new JCalWriter(file);
try {
  for (ICalendar ical : icals) {
    writer.write(ical);
  }
} finally {
  writer.close();
}