Appendix: Feature comparison

Table Of Contents

General design
Miscellaneous metrics (estimated)
Value types (overview)
Calendar date features
Wall time features
Moment/Instant-features
Clocks
Timezones
Formatting and parsing
Internationalization
Interval handling
Non-ISO calendar systems
Java compatibility
Android compatibility
Code examples

General design
Feature java.util.Date/Calendar Joda-Time v2.9.6 Java-8 (JSR-310) Time4J v3.x/4.x Date4J
Immutability of value types no yes (some mutable types exist) yes yes yes
Compile-time type-safety based on generics no no no yes no
Modular structure no no no yes no
Fluent programming style (method chaining) no yes yes yes no
Nominal precision milliseconds milliseconds nanoseconds nanoseconds nanoseconds
Magic numbers versus enums magic numbers magic numbers enums enums enums
Rejects null parameters by NPE yes no (indicating default) yes yes no (later NPE?)
Prevents implicit defaults for locale and zone no no no yes yes
Standard way how to create value types constructor constructor static factory method static factory method constructor
Extension mechanism for value types inheritance strategy pattern (limited) strategy pattern strategy pattern no
Low-level interfaces no yes yes yes no
Generic manipulation interface - {property-concept} TemporalAdjuster ChronoOperator<T> -
Field-based operators/adjusters no {property-concept} no yes no
Separated concepts for fields and units no yes yes yes no
Preferred field-access (example for int-value) get(Calendar.DAY_OF_YEAR) getDayOfYear() getDayOfYear() get(PlainDate.DAY_OF_YEAR) getDayOfYear()
low-level type of field/element-value int int long V (generic) Integer

Miscellaneous metrics (estimated)
Feature java.util.Date/Calendar Joda-Time v2.8.1 Java-8 (JSR-310) Time4J v3.2 Date4J
Count of public classes in main package 6 59 18 33 3
Total count of public classes 14 145 69 174 3
Size of jar-file in kByte (part of JDK) 608 497 (threeten-bp) core: 402
i18n: 255
olson: 77
misc: 56
range: 74
35
Method count in class files (part of JDK) 3873 2498 (threeten-bp) core: 2410
i18n: 657
olson: 278
misc: 196
range: 352
206

Value types (overview)
Feature java.util.Date/Calendar Joda-Time v2.9.6 Java-8 (JSR-310) Time4J v3.25/4.21 Date4J
ISO-types representing points in time java.util.Date
java.util.Calendar
java.util.GregorianCalendar
XMLGregorianCalendar
DateTime
MutableDateTime
Instant
LocalDate
LocalTime
LocalDateTime
DateMidnight (deprecated)
YearMonthDay (deprecated)
TimeOfDay (deprecated)

YearMonth
MonthDay
ZonedDateTime
Instant
LocalDate
LocalTime
LocalDateTime
OffsetDateTime
OffsetTime
Year
YearMonth
MonthDay
Moment
PlainDate
PlainTime
PlainTimestamp
ZonalDateTime
CalendarYear
CalendarQuarter
CalendarMonth
CalendarWeek
AnnualDate
DateTime
Duration types (without start or end) javax.xml.datatype.Duration Duration
Period
MutablePeriod
Years
Months
Weeks
Days
Hours
Minutes
Seconds
Duration
Period
Duration<IsoUnit>
Duration<CalendarUnit>
Duration<ClockUnit>
MachineTime<TimeUnit>
MachineTime<SI>
-
Interval types (anchored on timeline) - Interval
MutableInterval
- MomentInterval
DateInterval
ClockInterval
TimestampInterval
SimpleInterval
-

Calendar date features
Feature java.util.Date/Calendar Joda-Time v2.9.6 Java-8 (JSR-310) Time4J v3.25/4.21 Date4J
Dedicated value type for calendar date - org.joda.time.LocalDate java.time.LocalDate net.time4j.PlainDate -
Replacement value type for calendar date java.util.GregorianCalendar not an issue not an issue not an issue hirondelle.date4j.DateTime
Count of supported fields/elements 10 12 25 29 6
Count of built-in manipulations
(estimated)
~21 ~130 ~56 ~180 ~8
Proleptic gregorian calendar rules no yes yes yes yes
ISO week model yes yes yes yes no
Localized week model yes no yes yes no
Support for julian/epoch days - DateTimeUtils JulianFields EpochDays getModifiedJulianDayNumber()
Historic centuries no yes no yes no
Support for gregorian/julian cutover GregorianCalendar GJChronology - ChronoHistory -
Easter calculation - - - Eastern- or Western-style -
Support for historic anomalies - - - Swedish calendar
Triennal julian leap years
New Year rules
Year definition (after/before New Year)
Byzantine era
Spanish era
A.U.C.
Roman numerals
-
Date difference in calendar days no yes yes yes yes
Date difference
in years, months, days
no yes yes yes no
Date difference
in arbitrary multiple calendar units
no yes1) no yes no
Prevents mixed signs in date difference - no2) no2) yes not an issue
Alternative day overflow strategy
when adding months
no no no yes yes

1) Joda-Time offers the customizable class PeriodType for controlling which units to be used.
2) Mixed signs like in P1M-30D are avoided per default but can be enforced by user construction. Discussion of algorithm and implications see Time4J-API.

Wall time features
Feature java.util.Date/Calendar Joda-Time v2.9.6 Java-8 (JSR-310) Time4J v3.25/4.21 Date4J
Dedicated value type for wall time - org.joda.time.LocalTime java.time.LocalTime net.time4j.PlainTime -
Replacement value type for wall time java.util.GregorianCalendar not an issue not an issue not an issue hirondelle.date4j.DateTime
Count of supported fields/elements 6 11 15 21 4
Count of built-in manipulations
(estimated)
~26 ~110 ~38 ~180 ~12
Time difference
in single clock unit
no yes yes yes no1)
Time difference
in arbitrary multiple clock units
no yes no2) yes no
Support for dayperiods
(morning, evening etc.)
no no no yes no
Support for 24:00 no no no yes no
Support for decimal hours/minutes no no no yes no
Support for collecting day cycles no no no yes no
Support for convenient truncation no yes yes yes yes
Other rounding features available no yes no yes no

1) Only seconds are supported.
2) java.time.Duration consists of seconds and nanos only. All other units like the pair [hours+minutes] require user-defined workarounds.

Moment/Instant-features
Feature java.util.Date/Calendar Joda-Time v2.9.6 Java-8 (JSR-310) Time4J v3.33/4.28 Date4J
Dedicated value type for moment/instant - org.joda.time.Instant java.time.Instant net.time4j.Moment -
Replacement value type for moment/instant java.util.GregorianCalendar org.joda.time.DateTime java.time.ZonedDateTime
java.time.OffsetDateTime
net.time4j.ZonalDateTime -1)
Field queries via built-in timezone yes (GregorianCalendar) yes (DateTime) yes (ZonedDateTime) yes (ZonalDateTime) no
Field manipulations via built-in timezone yes (GregorianCalendar) yes (DateTime) yes (ZonedDateTime) no no
Field queries via timezone parameter no no no yes (Moment) 2) no
Field manipulations via timezone parameter no no no yes (Moment) 3) DateTime.changeTimeZone()
Translation to decimal elapsed seconds no no no yes no
Support for Julian days (as decimal value) no yes no yes 4) no
Time difference as machine time no yes (Duration) yes (Duration) yes (MachineTime) no
Support for UTC leap seconds no no no yes no
Multiple time scales no no no 5) yes 6) no

1) hirondelle.date4j.DateTime is not a global timestamp. A timezone-dependent conversion to/from elapsed milliseconds since UNIX epoch is offered.
2) Most elements (fields) implement ZonalElement which defines parameterized queries for any timezone.
3) Many element interfaces define various operators of type ElementOperator which define further zonal parameterized operators.
4) Offered by the class net.time4j.calendar.astro.JulianDay in the calendar-module.
5) The Java time scale was defined as UTC-SLS, but cannot be implemented this way due to lack of built-in leap-second-table. Hence the real behaviour is just like in POSIX.
6) POSIX, UTC, GPS, TAI, TT, UT

Clocks
Feature java.util.Date/Calendar Joda-Time v2.9.6 Java-8 (JSR-310) Time4J v3.25/4.21 Date4J
Injectable clock abstraction - DateTimeUtils.MillisProvider java.time.Clock net.time4j.base.TimeSource -
Type of clock abstraction - interface abstract class interface -
Timezone-related clock available no no yes (java.time.Clock) yes (ZonalClock) no
Built-in fixed clock no no 1) yes yes 2) no
Adjustable by fixed offset/duration no no 1) yes yes 2) no
Pulsed clock (ticks in truncated mode) no no 1) yes yes 2) no
Monotonic clock no no no yes no
HTTP-clock (default port 80) no no no yes no
DAYTIME-clock (default port 13) no no no yes no
SNTP-clock (default port 123) no no no yes no

1) Users have to implement their own MillisProvider-interface. Easy for fixed clocks, less easy for other clock variants.
2) Time4J does not try to unify all clock variants in one class but use the delegate pattern with different clock implementations.

Timezones
Feature java.util.Date/Calendar Joda-Time v2.9.6 Java-8 (JSR-310) Time4J v3.25/4.21 Date4J
Independent timezone repository yes yes yes yes no
Facade for any time zone provider no yes yes yes no
Support for IANA-TZDB yes yes yes yes no
How to update TZDB-repository? TZ-Updater-Tool extra zone compiler TZ-Updater-Tool extra zone compiler -
Support for MS-Windows zones no no no yes 1) no
Support for military zones no no no yes no
Simultaneous access to alternative timezone data no no no 2) yes 3) no
Queries for offset (raw + dst) yes yes yes yes no
Queries for gaps/overlaps no gaps gaps/overlaps gaps/overlaps no
Access to timezone history no limited 4) yes yes no
Dump of timezone history no no no yes no
Default transition strategy for invalid local time push forward abort push forward push forward -
Alternative transition strategies 5) no no limited 6) yes no
Geographical timezone offset (in decimal seconds) no no no yes no
Enums for standard timezone identifiers no no no yes no

1) Support for conversion from Windows identifiers to standard TZDB identifiers only, the reverse way is not supported.
2) JSR-310 (java.time) requires the user to supply a special implementation of ZoneRulesProvider and to register it. This provider might use tzids with different group-prefixes. However, there is no built-in alternative so this option remains abstract.
3) Time4J is able to refer to timezones based on java.util.TimeZone and simultaneously to other within independent TZDB-repo. This is done just via prefixing of tzid.
4) Support is given by the navigation method DateTimeZone.nextTransition(instant).
5) This affects the conversion from local timestamps to global timestamps (instants).
6) The class ZonedDateTime offers two special methods withEarlierOffsetAtOverlap() and withLaterOffsetAtOverlap().

Formatting and parsing
Feature java.util.Date/Calendar Joda-Time v2.9.6 Java-8 (JSR-310) Time4J v3.33/4.28 Date4J
Main entry point of format engine SimpleDateFormat DateTimeFormatter DateTimeFormatter ChronoFormatter DateTime
Builder-based format engine no yes yes yes no
Facade for alternative format engines no no no yes no
Supported target types java.util.Date DateTime
LocalDate
LocalTime
LocalDateTime
millis since Unix epoch
ReadWritableInstant
MutableDateTime
TemporalAccessor 1) T extends ChronoEntity<T>
ZonalDateTime
other types via Converter
DateTime
Pattern-based formats yes yes yes yes yes 2)
Multiple format patterns no no no yes 3) no
Parser for multiple formats no no no yes 4) no
Parser for multiple types no yes 5) yes 6) no no
Support for java.util.Formatter yes no yes yes (v4.x only) no
Print to some kind of Appendable yes (StringBuffer) yes (Appendable) yes (Appendable) yes (Appendable) no
Print with field/element-positions yes 7) no no yes no
Predefined format attributes 6 4 6 21 1
Custom format attributes no no no yes no
Sectional format attributes no no no yes no
Support for time scales no no no yes no
Optional sections no yes (with multiple parsers) yes ([] for parsing) yes (for print+parse) no
Adjacent digit parsing yes yes yes 8) yes no
Informative parser errors with position info yes yes yes yes no
Custom chrono printers or parsers no yes no yes no
Parse with default field values no no 9) yes yes no
Parse with custom text resources no no 10) yes yes no
Support for alternative era names no no no yes no
Support for ordinal numbers no no no yes no
Support for padding min-count of pattern symbols min-count of pattern symbols
min/max-args in builder-methods
min-count of pattern symbols
min/max-args in builder-methods
padNext()
min-count of pattern symbols
min/max-args in builder-methods
padNext()
padPrevious()
pad-char-attribute
no
Support for ISO-duration-format (print+parse) no yes no yes no
Custom parseable duration format no yes (PeriodFormatterBuilder) no yes (Duration.Formatter) no
Support for relative times ("5 days ago") no no no yes no
Support for ("yesterday/today/tomorrow)") no no no yes no
Localized representations of duration no 14 languages no 86 languages no
Short or narrow unit names (i18n) no no no yes no
Support for plural rules in time units no yes (via regular expressions) no yes (no user-action required) no

1) JSR-310-formatters do not parse finished results but an intermediate result which can then be evaluated in static from()-methods of real target types.
2) Date4J has only very limited parsing capabilities and cannot understand arbitrary pattern-based formats during parsing.
3) CLDR, CLDR_24, CLDR_DATE, DYNAMIC, SIMPLE_DATE_FORMAT, THREETEN (v4.x)
4) either via MultiFormatParser or via or-operator "|" in patterns
5) using methods like parseDateTime(), parseLocalDate() etc.
6) by help of parseBest(), forces the user to apply instanceOf-patterns
7) Based on AttributedCharacterIterator-API.
8) Fractional seconds (before Java-9) and localized fields (i.e. week-of-year - before Java-9) do not take part into the protocol of adjacent digit parsing.
9) As exception: Default years are supported, however.
10) As exception: Custom timezone names are supported, however.

Internationalization
Feature java.util.Date/Calendar Joda-Time v2.9.6 Java-8 (JSR-310) Time4J v3.33/4.28 Date4J
Independent i18n-resources {part of Java} no {part of Java} 1) yes no
Count of supported languages ~46 {delegate to Java} ~46 ~86
(plus Java-resources as fallback)
{delegate to Java}
Localized week definitions yes no yes yes no
Standalone forms for months etc. available yes no yes yes no
Parsing localized timezone names yes no yes yes no
Localized date/time-patterns yes {delegate to Java} yes yes no

1) The backport threetenbp has no own i18n-resources.

Interval handling
Feature java.util.Date/Calendar Joda-Time v2.9.6 Java-8 (JSR-310) Time4J v3.28/4.24 Date4J
Moment/Instant-intervals no yes no yes no
Calendar date intervals no no no yes no
Clock time intervals no no no yes no
Plain timestamp intervals no no no yes no
Queries for duration no yes no yes no
Support for after/before/start/end-queries no yes no yes no
Support for gap-queries no yes no yes no
Support for intersect/overlap-queries no yes no yes no
Support for abut/meet-queries no yes no yes no
Support for Allen's interval algebra no no no yes no
Standard ISO-8601-format 1) no yes no yes no
Parsing general ISO-8601-formats 2) no no no yes no
Custom interval pattern formats no no no yes no
Support for open/closed-boundaries no no 3) no yes no
Support for infinite boundaries no no no yes no
Interval search tree no no no yes no
Algebra of single intervals no gap/overlap no collapse/move/toCanonical no
Algebra of interval collections no no no plus/minus/union/intersect/xor
withBlocks/withComplement/withGaps
withIntersection/withSplits/withTimeWindow
no
Streaming (only on Java-8) no no no yes no
Day partitions no no no yes no
Interface for holidays no no no yes (only v4.x) no
Recurrent intervals (ISO) no no no yes no

1) Defined as: yyyy-MM-dd'T'HH:mm:ss.SSSXXX/yyyy-MM-dd'T'HH:mm:ss.SSSXXX
2) Example: yyyy-DDD'T'HH:mmXXX/'T'HH:mm (higher-order-elements and offset left out on end component)
3) Only half-open intervals are supported.

Non-ISO calendar systems
java.util.Date/Calendar Joda-Time v2.9.6 Java-8 (JSR-310) Time4J v3.33/4.28 Date4J
ThaiBuddhist (only valid after 1940)
Japanese (since Meji era)
Gregorian/Julian-Cutover
Proleptic Julian
Islamic (4 leap year patterns - no i18n)
ThaiBuddhist (only valid after 1940)
Coptic (no i18n)
Ethiopic (no i18n)
Umalqura (Saudi-Arabia)
ThaiBuddhist (only valid after 1940)
Japanese (since Meji era)
Minguo (Taiwan)
Islamic (8 leap year patterns + ICU4J-data)
Umalqura (Saudi-Arabia)
Diyanet (Turkey)
Persian (3000 years)
Japanese (since midage)
ThaiBuddhist (+ Rattanakosin era)
Minguo (Taiwan)
Indian national (Saka)
Coptic
Ethiopic (incl. time and tabots)
French revolutionary
Proleptic Julian
-

Java compatibility
Feature java.util.Date/Calendar Joda-Time v2.9.6 Java-8 (JSR-310) Time4J v4.x Date4J
Support for elapsed millis since UNIX epoch yes yes yes yes yes
Conversion to/from java.time (Java-8) yes no {not an issue} yes no
Conversion to/from java.util.Date {not an issue} yes yes 1) yes no
Conversion to/from
java.sql.Date/Time/Timestamp
{part of Java 6} via other libraries like
Hibernate, Jadira-Usertype etc.
built into sql classes bridge class JDBCAdapter only as String
Support for JPA yes (built-in) @Convert-annotation 2) @Convert-annotation 2) @Convert-annotation 2) @Convert-annotation 2)
Conversion to/from XMLGregorianCalendar {part of Java 6} no no yes no

1) Support for the conversion between old Java and JSR-310 was intentionally restricted to the old-Java-side where such conversion methods exist.
2) The converter mechanism requires at least JPA 2.1.

Android compatibility
Feature java.util.Date/Calendar Joda-Time-Android v2.9.3 ThreeTenABP v1.0.5 Time4A v3.19-2016d Date4J
Management of app resources {part of Android-API} assets in AAR-library assets in AAR-library assets in AAR-library {not relevant}
APK-method-count (theoretical upper bound) {part of Android-API} 4756 2831 6243 {not relevant < 10?}
APK-method-count (with Proguard 1)) {part of Android-API} ~1400 ~1100 ~2800 {not relevant < 10?}
Independent timezone data {part of Android-API} yes yes yes no
Access to Android timezone data with own API {part of Android-API} no 2) no 2) yes 3) no 2)
Tracking system-tz-updates {part of Android-API} yes yes yes no
Independent i18n-resources {part of Android-API} no no 4) yes no
Real-time access of system clock {part of Android-API} no no yes 5) no
Sensible for user preference of 12/24-hour-format {part of Android-API} no no yes no
Prefetch resources in the background no no no yes no

1) The real APK-method-count depends on the use-case. Given numbers refer to the typical use-case of formatting the current local time.
2) Users have to directly use java.util.TimeZone which has a very different API.
3) Time4J either offers SystemClock.inPlatformView() or prefixing of timezone identifiers (with "java.util.TimeZone~").
4) Threeten-BP is not a perfect backport of JSR-310 since latter one refers to resources only available on Java-8, for example the umalqura-variant of the islamic calendar defined in JSR-310 is not supported on Android.
5) The monotonic clock of Time4A automatically chooses elapsedRealtime().

Code examples
API/library Today in default timezone and minutes ISO-week-date [2015-W52-5] What is next Wednesday at 17:45 in Paris?
java.util.Date/Calendar GregorianCalendar gcal =
  new GregorianCalendar();
int year = gcal.get(Calendar.YEAR);
int month = gcal.get(Calendar.MONTH)+1;
int day = gcal.get(Calendar.DAY_OF_MONTH);
int hour = gcal.get(Calendar.HOUR_OF_DAY);
gcal.set(year,month-1,day,hour,0,0);
gcal.set(Calendar.MILLISECOND,0);
GregorianCalendar gcal =
  new GregorianCalendar(2000,1,1);
gcal.setWeekDate(2015,52,5);
{complex workaround}1)
Joda-Time v2.9.1 LocalDateTime now = LocalDateTime.now();
now = now.minuteOfHour().roundFloorCopy();
LocalDate d=
  new LocalDate();
d = d.weekyear().setCopy(2015);
d = d.weekOfWeekyear().setCopy(52);
d = d.withDayOfWeek(5);
{complex workaround}1)
Java-8 (JSR-310) import static java.time.temporal.ChronoUnit.*;
LocalDateTime now = LocalDateTime.now();
now = now.truncatedTo(MINUTES);
import static java.time.temporal.IsoFields.*;
import static java.time.DayOfWeek.*;
LocalDate d = LocalDate.of(2000,1,1);
d = d.with(WEEK_BASED_YEAR,2015);
d = d.with(WEEK_OF_WEEK_BASED_YEAR,52);
d = d.with(FRIDAY);
import static java.time.temporal.TemporalAdjusters.*;
import static java.time.DayOfWeek.*;
LocalDate d =
  LocalDate.now().with(next(WEDNESDAY));
LocalDateTime ldt = ldt.atTime(17, 45);
ZonedDateTime zdt =
  ldt.atZone(ZoneId.of("Europe/Paris"));
LocalDateTime result = zdt.toLocalDateTime();
Time4J v3.11/4.8 import static net.time4j.PlainTime.*;
import static net.time4j.ClockUnit.*;
PlainTimestamp now =
  SystemClock.inLocalView().now();
now = now.with(PRECISION,MINUTES);
import static net.time4j.Weekday.*;
PlainDate d= PlainDate.of(2015,52,FRIDAY);
import static net.time4j.PlainDate.*;
import static net.time4j.Weekday.*;
PlainDate d = SystemClock.inLocalView().today();
d = d.with(DAY_OF_WEEK.setToNext(WEDNESDAY));
PlainTimestamp tsp = d.atTime(17, 45);
Moment m = tsp.inStdTimezone();
tsp = m.toZonalTimestamp(EUROPE.PARIS);
Date4J DateTime today =
  DateTime.now(TimeZone.getDefault());
today = today.truncate(DateTime.Unit.MINUTE);
{complex workaround}2) {complex workaround}1)

1) No built-in solution for changing to next Wednesday
2) No support for ISO-weekdates