{"id":21,"date":"2021-03-09T10:00:49","date_gmt":"2021-03-09T00:00:49","guid":{"rendered":"http:\/\/localhost:8000\/?p=21"},"modified":"2021-03-09T10:00:49","modified_gmt":"2021-03-09T00:00:49","slug":"intro-to-ical4j","status":"publish","type":"post","link":"http:\/\/www.cheerfulprogramming.com\/?p=21","title":{"rendered":"Intro To iCal4J"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>Ben Fortuna\\&#8217;s iCal4J library is a well-established Java implementation<br \/>\nof the RFC 5545 international standard for calendar events. In this<br \/>\narticle I will show you how to use iCal4J to create a iCalendar event in<br \/>\nJava and export it to a .ics file, and how to read in a .ics file and<br \/>\nextract the useful information out of it. ICalendar files can be<br \/>\nimported into the popular calendar applications including Microsoft<br \/>\nOutlook\u2122 and Google Calendar\u2122.<\/p>\n<h2>Set up your iCal4J Properties File<\/h2>\n<p>Put the file in your Java resources directory and call it<br \/>\nical4j.properties. Add the following key-value pairs:<\/p>\n<pre><code class=\"\" data-line=\"\">net.fortuna.ical4j.timezone.cache.impl=net.fortuna.ical4j.util.MapTimeZoneCache<\/code><\/pre>\n<h2>Generating a .ics File<\/h2>\n<p>Note: iCal4J has several classes which have the same name as date and<br \/>\ntime classes in the Java standard library, such as Calendar, Date,<br \/>\nTimeZone, and Duration. For clarity, where I reference Java standard<br \/>\nlibrary date and time classes, in order to distinguish them from iCal4J<br \/>\nI have used fully-qualified class names, eg java.time.Duration.<\/p>\n<p>First we will create an empty iCalendar, and then we will start to add<br \/>\ndifferent types of events to it.<\/p>\n<pre><code class=\"\" data-line=\"\">\/\/Create an iCal4J Calendar\nCalendar c = new Calendar();\n\/\/&quot;EN&quot; is the language.\nc.getProperties().add(new ProdId(&quot;-\/\/Company Name\/\/Product name and version\/\/EN&quot;));\nc.getProperties().add(Version.VERSION_2_0);\nc.getProperties().add(CalScale.GREGORIAN);\n\n\/\/Add an event to the calendar\nc.getComponents().add(\/* next you will create an event to add here *\/ null );\nString icsExport = c.toString();<\/code><\/pre>\n<p>If you take a look at the contents of the icsExport String in your<br \/>\ndebugger (or print it to the console) you will see an iCalendar file.<br \/>\nYou may find it to be more readable if you copy it into a text editor.<\/p>\n<p>Now we will create a simple, single event (non-recurring) which starts<br \/>\non 5<sup>th<\/sup> March 2021 at midday Australian Eastern Daylight Savings Time,<br \/>\nand lasts for one hour.<\/p>\n<pre><code class=\"\" data-line=\"\">private VEvent oneHourSingleEvent() {\n    \/\/Create a new calendar event that starts on 5th March 2021 at midday Australian Eastern Daylight Savings Time and goes for 1 hour.\n    VEvent vEvent = new VEvent();\n    PropertyList&lt;Property&gt; eventProps = vEvent.getProperties();\n    java.time.ZonedDateTime now = java.time.ZonedDateTime.now();\n\n    \/\/Create a unique ID for the event\n    String uidTimestamp = java.time.format.DateTimeFormatter\n                            .ofPattern(&quot;uuuuMMdd&#039;T&#039;hhmmssXX&quot;)\n                            .format(now);\n    \/\/In the real world this could be a number from a generated sequence:\n    String uidSequence = &quot;\/&quot; + (int) Math.ceil(Math.random() * 1000);\n    String uidDomain = &quot;@your.domain.com&quot;;\n    eventProps.add(new Uid(uidTimestamp + uidSequence + uidDomain));\n\n    \/\/Add a start datetime and a duration\n    TimeZoneRegistry tzReg = TimeZoneRegistryFactory.getInstance().createRegistry();\n    TimeZone timezone = tzReg.getTimeZone(&quot;Australia\/Sydney&quot;);\n    try {\n        eventProps.add(new DtStart(new DateTime(&quot;20210305T120000&quot;, timezone)));\n    } catch (ParseException e) {\n        e.printStackTrace();\n    }\n    eventProps.add(new Duration(java.time.Duration.ofHours(1)));\n\n    \/\/Add title and description\n    eventProps.add(new Summary(&quot;The title of the event&quot;));\n    eventProps.add(new Description(&quot;Some longer description of the event.&quot;));\n    return vEvent;\n}<\/code><\/pre>\n<p>Next, add this event to the calendar, run it and view the result.<\/p>\n<pre><code class=\"\" data-line=\"\">    c.getComponents().add(oneHourSingleEvent());<\/code><\/pre>\n<p>It should look something like the iCalendar below. Note that each line<br \/>\nterminates with a carriage return and a new line character, \\r\\n. If<br \/>\nyou copy+paste the example below for use as a test, make sure to include<br \/>\nthe correct line terminators or it may be invalid!<\/p>\n<pre><code class=\"\" data-line=\"\">BEGIN:VCALENDAR\nPRODID:-\/\/Your Company Name\/\/Your product name and version\/\/EN\nVERSION:2.0\nCALSCALE:GREGORIAN\nBEGIN:VEVENT\nDTSTAMP:20210305T061107Z\nUID:20210305T051107+1100\/633@your.domain.com\nDTSTART;TZID=Australia\/Sydney:20210305T120000\nDURATION:PT1H\nSUMMARY:The title of the event\nDESCRIPTION:Some longer description of the event.\nEND:VEVENT\nEND:VCALENDAR<\/code><\/pre>\n<p>Try saving the event in a text file with a .ics extension, and importing<br \/>\nit into your favourite calendar application.<\/p>\n<h2>Parsing a .ics file<\/h2>\n<p>Parsing a .ics file is very simple. The CalendarBuilder takes any object<br \/>\nwhich implements Reader, which could be a FileReader or, as in the<br \/>\nexample below, a StringReader. You can use the code that you\\&#8217;ve already<br \/>\nwritten so far in this tutorial to inject a valid serialised iCalendar<br \/>\nstring, so you don\\&#8217;t need to worry about getting the line terminators<br \/>\nright (remember \\r\\n!). The example parses the calendar, validates it,<br \/>\nand pulls out the useful attributes that we had added earlier, so that<br \/>\nyou have an idea of how it works.<\/p>\n<pre><code class=\"\" data-line=\"\">public Calendar importCalendar(String calendarSerialized) throws Exception {\n    Calendar c = new CalendarBuilder().build(new StringReader(calendarSerialized));\n    c.validate();\n    VEvent event = (VEvent) c.getComponent(Component.VEVENT);\n    DtStamp dtStamp = event.getDateStamp();\n    Uid uid = event.getUid();\n    DtStart startDate = event.getStartDate();\n    String tz = startDate.getTimeZone().getVTimeZone().getTimeZoneId().getValue();\n    PropertyList props = event.getProperties();\n    Duration d1 = props.getProperty(Property.DURATION);\/\/Any property can be retrieved this way.\n    Duration d2 = event.getDuration();\/\/d2 is the same as d1.\n    Summary summary = event.getSummary();\n    Description description = event.getDescription();\n    return c;\n}<\/code><\/pre>\n<h2>Conclusion<\/h2>\n<p>There you have it! These examples should be enough to get you started<br \/>\nwith the iCal4J library and give you and understanding of how it handles<br \/>\niCalendars. If you need more examples, clone the project\\&#8217;s Git<br \/>\nrepository and take a look at the test cases, which are a rich source of<br \/>\nknowledge.<\/p>\n<h2>Further Reading<\/h2>\n<p>iCal4J: <a href=\"https:\/\/github.com\/ical4j\/ical4j\">https:\/\/github.com\/ical4j\/ical4j<\/a><\/p>\n<p>Java: <a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/11\/docs\/api\/index.html\">https:\/\/docs.oracle.com\/en\/java\/javase\/11\/docs\/api\/index.html<\/a><\/p>\n<h2>Acknowledgements<\/h2>\n<p>The author acknowledges the traditional custodians of the Daruk and the<br \/>\nEora People and pays respect to the Elders past and present.<\/p>\n<p>Oracle\u00ae and Java\u00ae are registered trademarks of Oracle and\/or its<br \/>\naffiliates.<\/p>\n<p>Other names may be trademarks of their respective owners.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Ben Fortuna\\&#8217;s iCal4J library is a well-established Java implementation of the RFC 5545 international standard for calendar events. In this article I will show you how to use iCal4J to create a iCalendar event in Java and export it to a .ics file, and how to read in a .ics file and extract the [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":22,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[10],"class_list":["post-21","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-java","tag-ical4j"],"_links":{"self":[{"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=\/wp\/v2\/posts\/21","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=21"}],"version-history":[{"count":0,"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=\/wp\/v2\/posts\/21\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=\/wp\/v2\/media\/22"}],"wp:attachment":[{"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=21"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=21"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=21"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}