ical4j reads and writes iCalendar streams as a Java object model
A Java library for parsing and building iCalendar data models
At a glance
- What is it?
- ical4j is a BSD-3-Clause Java library for parsing and building iCalendar data models, aimed at Java services that must read or write calendar feeds. It covers the parsing and object model, not transport, scheduling, or storage.
- Who is it for?
- Java teams that already own the transport and the database should adopt ical4j rather than hand rolling an iCalendar parser, since it keeps the dependency list to three required jars and ships a maintained release line. Teams that need invitation delivery, scheduling conflict detection, or a hosted calendar service will find no such features here, because ical4j stops at the parse and build step.
- Can I use it commercially?
- Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A Java object model for iCalendar text, not a calendar server
iCal4j exists because iCalendar files are hard to handle with plain string operations. The format is defined in RFC2445, and a single VEVENT can carry parameters, folded lines, date-time values in several time zone forms, and recurrence rules that other producers write in slightly different ways. The library turns that text into a typed object model and lets your code write the model back out.
The audience is narrow on purpose: Java developers building services that read a calendar feed, generate one, or exchange calendar payloads with other systems. The project describes itself as a library for reading and writing iCalendar data streams, and points readers to the examples on its official website and to the API documentation for usage patterns.
What the library does not do is visible in the scope of the referenced specifications. The README lists RFC5546 for iTIP and RFC6047 for iMIP, but those appear as interop protocol references, not as transport features the library implements. Nothing in the usage sections describes sending invitations, accepting them, or storing them. iCal4j is the parse and build half of a calendar system, and any service around it is yours to write.
That narrow scope is a virtue for evaluation. You can read the whole feature surface in an afternoon and decide whether the object model matches the shape of the calendar data your application already stores.
The 4.x line moved dates to the java.time API
The most visible change in iCal4j 4.x is the move away from the library's own date classes and onto the standard Java date and time API. The README keeps a comparison table so that developers arriving from 3.x can map old calls onto new ones without guessing.
A DTSTART that carries a date value is now built with LocalDate, and one that carries a date-time value uses ZoneDateTime. Parsing a string goes through TemporalAdapter rather than the constructors of org.mnode.ical4j.model.Date and org.mnode.ical4j.model.DateTime. The one-to-one mapping is close enough that a port from the old API is mostly a search and replace, which is a good sign for a library that has existed long enough to have two API generations in the wild.
The version floor moved with it. Version 4.x requires Java 11 or later, 3.x requires Java 8, and 2.x requires Java 7. An organisation still on an older runtime is not cut off, but it is pinned to the 3.x branch and to the older date classes, and the compatibility hints section of the README is where the differences in behaviour between generations are recorded.
Two separate ways of expressing a time zone make this worth reading closely. One is to construct the value with a zone id, the other is to construct a plain value and attach a time zone afterwards. The two are not guaranteed to produce identical output, and choosing one consistently is your job, not the library's.
Three required dependencies and a conditional fourth
The dependency list is deliberately short, and the README explains why each entry is there. slf4j-api is the logging facade used by every class that needs to log. commons-lang3 supplies the custom equals and hashcode implementations that the value types rely on. commons-collections4 is used inside the net.fortuna.ical4j.validate.Validator implementations to cut down on repetition in the validity checks.
The optional entry with a real consequence is javax.cache.cache-api. It exists to support caching of time zone definitions, and the README states the condition plainly: when the cache API is not on the classpath you must set a value for the net.fortuna.ical4j.timezone.cache.impl configuration. Miss that and you have a timezone lookup path with no backing store, which surfaces as behaviour that differs between a developer laptop and a deployed service.
Two more optional entries change the shape of the API rather than the runtime. groovy-all enables library enhancements including iCalendar object construction through the net.fortuna.ical4j.model.ContentBuilder DSL, and the README states plainly that it is optional for all non-Groovy features of iCal4j. bndlib is not a runtime requirement at all: it is used only to generate version information in the javadoc API documentation.
commons-codec sits in the same optional group and provides encoding and decoding of binary data in text form, which is what net.fortuna.ical4j.model.Attach relies on. If your feed carries attachments, this is the dependency you add.
Getting the artifact and running the build from a checkout
Release artifacts are published to Maven Central under the org.mnode.ical4j group, and the README links that repository as the place to download releases. The install sections for Maven and Gradle are present as headings, and the project keeps its own build scripts in the repository: build.gradle, settings.gradle, gradle.properties and a Gradle wrapper checked in at the root.
If you would rather work from a checkout than pull a published artifact, the Makefile wraps the wrapper. These are the targets you would run:
./gradlew build
./gradlew testThe Makefile also exposes an install target that calls publishToMavenLocal, and a publish target that calls publishToMavenCentral, which is how an artifact reaches the repository the README points you at.
./gradlew publishToMavenLocal
./gradlew publishToMavenCentralOne more target is worth knowing because it is not obvious from its name. The zoneinfo target pulls a container image and syncs timezone data into src/main/resources/zoneinfo and src/main/resources/zoneinfo-global:
docker pull benfortuna/tzurlThat target needs Docker and network access, so it belongs to a release preparation step rather than to an everyday developer loop.
The parser implementation is a configuration key, and the README cuts off there
The Configuration section of the README is short, and what it shows is a single key binding a parser implementation to a class name:
net.fortuna.ical4j.parser=net.fortuna.ical4j.dThe value is truncated in the file as published, so the full class name cannot be read from it, and the section ends at that line rather than continuing into a longer set of keys. Treat the configuration surface as something you confirm against the API documentation and the source rather than as a list you can rely on being complete. The separate mention of net.fortuna.ical4j.timezone.cache.impl elsewhere in the README shows that more configuration keys exist than this section shows.
Compatibility hints are grouped under Configuration as well. These are the notes that matter when you receive files from other producers, because iCalendar implementations differ on edge cases and the library's behaviour on those cases can change between releases.
If you rely on a particular parser implementation or on a particular compatibility behaviour, pin the library version rather than tracking the default branch. The default branch is develop, which is where in-progress work lands.
Where the library stops and what it refuses to do
The honest limitations come from the same place as the strengths: this is a parser and an object model, and it does not attempt to be a calendar service.
First, there is no delivery. The specification list includes iTIP and iMIP, the interop protocols for scheduling messages, but the README describes no sending, receiving, or acknowledgement behaviour, and the usage examples contain no network code. If your requirement is an invitation that reaches a colleague's inbox, ical4j gives you the payload and nothing else.
Second, there is no scheduling intelligence. Conflict detection, free and busy negotiation, and recurrence expansion across attendee availability are not described anywhere in the usage sections. Recurrence is part of the parsed model because the format defines it, but the library does not advertise an availability engine, and RFC7953 for calendar availability appears as a reference only.
Third, validation is a component rather than a policy. The Validator implementations live in net.fortuna.ical4j.validate and lean on commons-collections4 closures to avoid repeating the same checks. Whether a feed must pass those checks before you accept it is a decision your application has to make explicitly.
Fourth, the optional dependency situation has sharp edges. Time zone definition caching behaves differently depending on whether javax.cache.cache-api is present, and the Attach model behaves differently depending on whether commons-codec is present. Two services with different classpaths can produce different output from the same code.
Releases, licence and the cost of staying on a version
The repository is not archived, and the last push was on 2026-10-18, so work is still landing. The release line moves in numbered steps: ical4j-4.2.5 on 2026-04-03, ical4j-4.3.0 on 2026-06-27, and ical4j-4.4.0 on 2026-10-02. The project publishes detailed change notes, with the CHANGELOG linked from the README and release notes hosted alongside the API documentation.
The licence is BSD-3-Clause, which permits commercial use and redistribution with the notice requirements the licence text sets out. That is a permissive choice for a library you intend to embed in a service, though the specific obligations should be read in LICENSE.txt rather than assumed.
Upgrade cost is where the tooling gives a real signal. The Makefile carries a listApiChanges target that runs revapi and an approveApiChanges target that accepts breaking changes with a justification, so API breakage is a tracked, deliberate event rather than an accident. Two candidate upgrade paths exist for you. Staying inside 4.x means picking up fixes without moving off the java.time based API. Crossing a major boundary, such as moving from 3.x to 4.x, means rewriting the date handling shown in the comparison table, and rechecking any behaviour you relied on through compatibility hints.
Because a breaking change is recorded in the changelog and in revapi output, reading those before you bump a version is a cheap way to avoid a surprise in your own build.
Editorial conclusion
Java teams that already own the transport and the database should adopt ical4j rather than hand rolling an iCalendar parser, since it keeps the dependency list to three required jars and ships a maintained release line. Teams that need invitation delivery, scheduling conflict detection, or a hosted calendar service will find no such features here, because ical4j stops at the parse and build step. Before adopting, verify the date and time API that matches your runtime, decide whether to set net.fortuna.ical4j.timezone.cache.impl, and read the CHANGELOG for the release you intend to pin.
Frequently asked questions
Which Java version does ical4j 4.x require?
Version 4.x requires Java 11 or later. If you are still on an older runtime, version 3.x runs on Java 8 and version 2.x on Java 7, but the older lines keep the previous date API.
How do I add ical4j to a Maven or Gradle project?
Release artifacts are published to Maven Central under the org.mnode.ical4j group, and the README links that repository as the download location. The dependency set is slf4j-api, commons-lang3 and commons-collections4 as required entries, with javax.cache.cache-api, commons-codec, groovy-all and bndlib listed as optional.
What happens if I do not add the cache API dependency?
javax.cache.cache-api is optional and supports caching of timezone definitions. The README states that when it is not included you must set a value for the net.fortuna.ical4j.timezone.cache.impl configuration.
Does ical4j handle sending calendar invitations over the network?
No. The library reads and writes iCalendar data streams and provides the object model. RFC5546 for iTIP and RFC6047 for iMIP appear in the specification list as references, and no transport, delivery or acknowledgement behaviour is described in the usage sections.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ical4j-ical4j)