Create ICS Calendar File in Java/Spring Boot

An ICS file is an iCalendar file having .ics extension. An ICS file contains plain text with calendar event details such as starting and ending time of events, event description, etc.

In this example, we will use iCal4j to create an ICS file in Java. iCal4j is a Java library used to read and write iCalendar data streams. The iCalendar standard provides a common data format for storing information about calendar specific events data. The iCalendar standard supports many calendaring tools, such as Outlook, Lotus Notes, Apple's iCal, and Google Calendar.

Gradle Dependency


implementation group: 'org.mnode.ical4j', name: 'ical4j', version: '4.0.0-alpha8'

Maven Dependency



Find the latest version of iCal4j library in the iCal4j Maven Repository .

Here is a snippet of Java code for creating .ics file:


/* Event start and end time in milliseconds */
Long startDateTimeInMillis = 1615956275000L;
Long endDateTimeInMillis = 1615959875000L;

java.util.Calendar calendarStartTime = new GregorianCalendar();
calendarStartTime.setTimeInMillis(startDateTimeInMillis);

// Time zone info
TimeZone tz = calendarStartTime.getTimeZone();
ZoneId zid = tz.toZoneId();


/* Generate unique identifier */
UidGenerator ug = new RandomUidGenerator();
Uid uid = ug.generateUid();

/* Create the event */
String eventSummary = "Happy New Year";
LocalDateTime start = LocalDateTime.ofInstant(calendarStartTime.toInstant(), zid);
LocalDateTime end = LocalDateTime.ofInstant(Instant.ofEpochMilli(endDateTimeInMillis), zid);
VEvent event = new VEvent(start, end, eventSummary);
event.getProperties().add(uid);

/* Create calendar */
Calendar calendar = new Calendar();
calendar.getProperties().add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN"));
calendar.getProperties().add(Version.VERSION_2_0);
calendar.getProperties().add(CalScale.GREGORIAN);

/* Add event to calendar */
calendar.getComponents().add(event);

/* Create a file */
String filePath = "mymeeting.ics";
FileOutputStream fout = null;
try {

    fout = new FileOutputStream(filePath);
    CalendarOutputter outputter = new CalendarOutputter();
    outputter.output(calendar, fout);

} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (ValidationException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (fout != null) {
        try {
            fout.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Output
mymeeting.ics

    BEGIN:VCALENDAR
    PRODID:-//Ben Fortuna//iCal4j 1.0//EN
    VERSION:2.0
    CALSCALE:GREGORIAN
    BEGIN:VEVENT
    DTSTAMP:20210317T061623Z
    DTSTART:20210317T102935
    DTEND:20210317T112935
    SUMMARY:Happy New Year
    UID:261bcd89-30ca-4b12-b7c3-45ad90f76e09
    END:VEVENT
    END:VCALENDAR

Generating ICS File via Spring Boot REST API

Here is an example of a Spring Boot REST controller with an API to generate and download ICS File:


import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import net.fortuna.ical4j.model.Calendar;
import net.fortuna.ical4j.model.component.VEvent;
import net.fortuna.ical4j.model.property.CalScale;
import net.fortuna.ical4j.model.property.ProdId;
import net.fortuna.ical4j.model.property.Uid;
import net.fortuna.ical4j.model.property.Version;
import net.fortuna.ical4j.util.RandomUidGenerator;
import net.fortuna.ical4j.util.UidGenerator;

@RestController
@RequestMapping(path = "/rest/api")
public class CalenderController {

    @GetMapping(path = "/generate-calendar")
    public ResponseEntity generateCalenderFile() {

        /* Event start and end time in milliseconds */
        Long startDateTimeInMillis = 1615956275000L;
        Long endDateTimeInMillis = 1615959875000L;

        java.util.Calendar calendarStartTime = new GregorianCalendar();
        calendarStartTime.setTimeInMillis(startDateTimeInMillis);

        // Time zone info
        TimeZone tz = calendarStartTime.getTimeZone();
        ZoneId zid = tz.toZoneId();


        /* Generate unique identifier */
        UidGenerator ug = new RandomUidGenerator();
        Uid uid = ug.generateUid();

        /* Create the event */
        String eventSummary = "Happy New Year";
        LocalDateTime start = LocalDateTime.ofInstant(calendarStartTime.toInstant(), zid);
        LocalDateTime end = LocalDateTime.ofInstant(Instant.
            ofEpochMilli(endDateTimeInMillis), zid);
        VEvent event = new VEvent(start, end, eventSummary);
        event.getProperties().add(uid);

        /* Create calendar */
        Calendar calendar = new Calendar();
        calendar.getProperties().add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN"));
        calendar.getProperties().add(Version.VERSION_2_0);
        calendar.getProperties().add(CalScale.GREGORIAN);

        /* Add event to calendar */
        calendar.getComponents().add(event);


        byte[] calendarByte = calendar.toString().getBytes();
        Resource resource = new ByteArrayResource(calendarByte);

        HttpHeaders header = new HttpHeaders();
        header.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=mycalendar.ics");
        header.add("Cache-Control", "no-cache, no-store, must-revalidate");
        header.add("Pragma", "no-cache");
        header.add("Expires", "0");

        return ResponseEntity.ok().headers(header).contentType(MediaType.
            APPLICATION_OCTET_STREAM)
                .body(resource);
    }

}