Provides additional date-time classes that complement those in JDK 8



ThreeTen-Extra provides additional date-time classes that complement those in JDK 8.

Not every piece of date/time logic is destined for the JDK. Some concepts are too specialized or too bulky to make it in. This project provides some of those additional classes as a well-tested and reliable jar.


Various documentation is available:


Release 1.6.0 is the current release. This release is considered stable and worthy of the 1.x tag as per SemVer.

ThreeTen-Extra requires Java SE 8 or later and has no dependencies.

Available in the Maven Central repository

Tidelift dependency check


Please use Stack Overflow for general usage questions. GitHub issues and pull requests should be used when you want to help advance the project. Commercial support is available via the Tidelift subscription.

To report a security vulnerability, please use the Tidelift security contact. Tidelift will coordinate the fix and disclosure.

Release process

  • Update version (,, changes.xml)
  • Commit and push
  • Run mvn clean release:clean release:prepare release:perform on Java 11
  • Website will be built and released by GitHub Actions
  • Why doesn't LocalDateTime have plus/minusMilliseconds()?

    Why doesn't LocalDateTime have plus/minusMilliseconds()?

    Out of curiosity, why does LocalDateTime have plus/minus hours, minutes, second and even nanoseconds, but not milliseconds? Is there a technical reason for this? Can it be added?

    Yes, I am familiar with plus(long amountToAdd, TemporalUnit unit) but I'm wondering why all other units have dedicated methods and milliseconds does not.

    opened by cowwoc 15
  • A zoneless time source for java.time

    A zoneless time source for java.time

    Every java.time.Clock also contains a time zone, and it can be freely used to produce zone-dependent values; as in However, we've found that most users really just want zoneless Instants (the zone component usually comes from the user session, not the server).

    Inside of Google we have a TimeSource interface, that looks like this:

    public interface TimeSource {
      static TimeSource system() { ... }
      Instant now();
      default LocalDateTime now(ZoneId zoneId) { ... }
      default LocalDate today(ZoneId zoneId) { ... }
      default Clock asClock(ZoneId zoneId) { ... }

    We strongly recommend its use over java.time.Clock, and its usage outnumbers Clock by 8x at this point.

    We'd like to contribute this to threeten-extra, but a few obstacles:

    1. we now have 30k+ references to our TimeSource, which makes migration very difficult (even for something as simple as a package/class rename).

    2. threeten-extra already has a TimeSource interface in org.threeten.extra.scale. That interface is nearly what we want, minus the UtcInstant and TaiInstant-returning methods. Do you see any path forward for harmonizing these interfaces? What are the stability guarantees for threeten-extra?

    Thanks, -Kurt (on behalf of Google's "GoodTime" team)

    opened by kluever 13
  • Inconsistencies of LocalDateRange

    Inconsistencies of LocalDateRange

    I guess that the main reason for blurring distinction between [*, LocalDate.MAX) and [*, +∞) was (1) inability to construct ranges containing LocalDate.MAX (that's my impression after following #53 discussion). The other reason I see is (2) presence of LocalDateRange.ofClosed which is the only possible way to (at least try to) create [*, LocalDate.MAX].

    Although fix for #53, more or less, resolved problem with (1), it introduced new problems instead. I'll try to show this later.

    As a side note... One may think that using [a, b] instead of [a, b) could be a good solution for (1) and (2) - although not being so convenient to implement, but that's another story. [a, b] would indeed solve (1) and (2), but at the same time it would introduce almost the same problem with toString. How would you stringify [LocalDate.MINLocalDate.MAX]? Would you consider "-999999999-01-01/+1000000000-01-01" legal despite "+1000000000-01-01" being out of domain? On the other hand, using "-999999999-01-01/+999999999-12-31" would make [LocalDate.MINLocalDate.MAX] indistinguishable from [LocalDate.MINLocalDate.MAX). This seems like some kind of vicious circle. Finally, with [a, b] you couldn't represent empty ranges.

    To summarize: with [a, b) and no LocalDateRange.ofClosed, there would be just one problem: (1) inability to construct ranges containing LocalDate.MAX. I believe that making LocalDate.MIN and LocalDate.MAX special, caused more problems than it solved. Some of the resulting quirks are documented, some aren't.

    I'll try to show several things at once using one example.

    LocalDateRange range = LocalDateRange.ofClosed(
        LocalDate.MAX.minusDays(1), LocalDate.MAX.minusDays(1)
    range.isEmpty();                            // -> false (of course)
    range.lengthInDays();                       // -> 1     (so far, so good)
    range.contains(LocalDate.MAX.minusDays(1)); // -> true  (obviously)
    range.contains(LocalDate.MAX);              // -> true  (what???)
    range.isUnboundedEnd();                     // -> true  (it's getting worse...)

    Seems like non-empty range of length 1 contains 2 days, all of that despite being unbounded at the end. On the surface, no LocalDate.MAX involved. Weird.

    As you can see, (3) isEmpty, contains, lengthInDays and isUnboundedStart / isUnboundedEnd are inconsistent with each other.

    Needless to say, problem with non-expressibility hasn't disappeared. There is still no way to represent [LocalDate.MAX.minusDays(1), LocalDate.MAX.minusDays(1)]. Internally, it is indistinguishable from [LocalDate.MAX.minusDays(1), +∞). Everything close to LocalDate.MAX becomes suspicious. This is documented, but consequences are not so obvious and can be surprising.

    There are similar problems with LocalDate.MIN too. For instance, [LocalDate.MIN, LocalDate.MIN) is empty and unbounded at the same time.

    I know it's rather unlikely to happen, but the least I can do is to leave my two cents here. Sticking to always bounded [a, b) would be perfect. It is possible to migrate in almost entirely backward compatible way.

    1. No more infinities. From now on, isUnboundedStart and isUnboundedEnd are returning false unconditionally.
    2. [*, LocalDate.MAX] silently becomes [*, LocalDate.MAX), just as it is now. The only change is that resulting range doesn't contain LocalDate.MAX.

    I agree that everything what I've just described.. those are "just" edge-cases. They should't cause much trouble in real life. And maybe they won't. However, I would argue that if there have to be some quirks in the implementation - and we're stuck with (2) I believe - they should be as "local" and "constrained" as possible (for the lack of better words). It's easier to reason about code when there's only one method referring to edge case (ofClosed), than where there are many (of, getEnd, getEndInclusive, contains).

    Discussion Fixed 
    opened by perceptron8 13
  • Symmetry010 handles ALIGNED_DAY_OF_WEEK_IN_MONTH incorrectly, claims each month starts on a monday

    Symmetry010 handles ALIGNED_DAY_OF_WEEK_IN_MONTH incorrectly, claims each month starts on a monday

    The Symmetry010 date and chronology claim every month starts on a Monday:

  • Week day - every month starts on a Monday. There are no days outside of the week or month.
  • This is false; every quarter (and year) starts on a Monday. I haven't looked to see if anything other than the documentation would need to be adjusted.


    opened by Clockwork-Muse 13
  • Add OffsetDate

    Add OffsetDate

    Resolves #137

    Relevant ThreeTenBP commit:


    • [x] Add
    • [x] Fix OffsetDate compilation
      • Implemented OffsetDate.isSupported(TemporalUnit)
      • Removed custom serialization
    • [x] Add
    • [x] Fix TestOffsetDate compilation
    • [x] Fix TestOffsetDate tests
      • Removed custom serialization testing
    • [x] Align API with those of OffsetDateTime and OffsetTime
      • [x] Rename toString(DateTimeFormatter) to format(DateTimeFormatter)
      • [x] Rename getDate() to toLocalDate()
      • [x] Implement from(int, int, int, ZoneOffset)
      • [x] Implement toEpochSecond(LocalTime)
      • [x] Rename withOffset(ZoneOffset) to withOffsetSameLocal(ZoneOffset)
    • [x] Improve test coverage
    • [x] Miscellaneous
      • [x] Add Joda-Convert annotations
      • [x] assertEquals(true, ...) -> assertTrue(...) etc.
      • [x] Update copyright header
      • [x] Add contributor
    Fixed RFE 
    opened by mkroening 11
  • PeriodFormatter

    PeriodFormatter says that PeriodFormatter is not included in java.time. Can this be added to threeten-extra?

    Fixed RFE 
    opened by cowwoc 11
  • New Chronology for International Fixed Calendar

    New Chronology for International Fixed Calendar

    Hello 3-10 stakeholders

    This changes have been incorporated from the code review:

    • InternationalFixedChronology is now final
    • method names now followed directly by open parenthesis
    • corrected comments referring to Julian or Pax chronologies
    • member item comments not preceded by a blank line anymore
    • deprecated InternationalFixedChronology constructor and commented accordingly
    • grouping of methods aligned, followed the examples of PaxDate and PaxChronology
    • InternationalFixedChronology#eraOf now has return type InternationalFixedChronology
    • Corrected exception messages to better reflect the error
    • the name 'International Fixed' calendar was chosen by Cotsworth, and yes, it was boldly done for global spreading. Perhaps a better name would be KodakFixedChronology / KodakFixedDate, since it was used for 71 years at Eastman Kodak internally. Another choice is CutsworthFixedChronology / CutsworthFixedDate.
    • Corrected comments on the alignment of Fixed calendar with Gregorian calendar
    • Corrected (non-leap) year constant DAYS_IN_YEAR to hold 365 days
    • introduced a factory method which validates a given date first, only invokes the constructor if date is accepted
    • Corrected year-range check in InternationalFixedDate
    • Corrected leap-year check in factory method to call InternationalFixedChronology#isLeapYear(long)
    • Corrected CheckStyle warnings and errors for fixed chronology, era and date
    • Generated new serial version UID for fixed chronology and date
    • Corrected tests affected by code changes above
    • Added missing range checks
    • Re-worked the internal representation of InternationalFixedDate, to distinguish between calendar days and month-less days.
    • Added test cases for leap-day and year-day.
    • Added test cases for dateYearDay
    • Implemented day-of-week and test cases.
    Fixed RFE 
    opened by catull 9
  • Add `Interval` class similar to Joda-Time

    Add `Interval` class similar to Joda-Time

    I might have missed it, but neither Java 8 nor ThreeTen-Extra seem to include the Interval class from Joda time.

    Is it going to be ported to one or the other? If not, what is the rationale for leaving it out?


    Fixed RFE 
    opened by homeworkprod 9
  • Support NRF accounting calendar

    Support NRF accounting calendar

    Hi, I may just be missing something, but I'm trying to use the AccountingChronology to create a calendar that matches the (US) National Retail Federation calendar, a 454 calendar, ending the year on the last Saturday in January:

    I setup my chronology as follows

            AccountingChronology nrfChronology = new AccountingChronologyBuilder()

    Everything seems ok, except the next Federation leap year is 2023, but my chronology has leap years in 2021 and 2026. Is there something I can do to shift the leap year?

    Fixed RFE 
    opened by lwhite1 8
  • Add Interval.containedBy(Start|End) for checking the separate parts of the con…

    Add Interval.containedBy(Start|End) for checking the separate parts of the con…

    …tains check.

    I see my developers often having problems with the closed/open properties of Intervals. In this case there is no built in function to point them to leading the developers to "duplicate" the inclusive/exclusive properties into call sites of getStart()/getEnd().

    The concrete use case they ran into was filtering a list of intervals that preceded or overlapped an instant leading them to duplicating the inclusiveness of start like: list.filter { it.start <= now }.

    I dont think the name is 100% spot on but.. yeah :)

    opened by spand 7
  • Calculation problem

    Calculation problem

    I have a question, when using this library to calculate HijrahDate, sometimes it is a day late. E.g Convert today 2020-1-7 to HijrahDate: 1441-5-12 But the result calculated using this library is: 1441-5-11 What is the reason at this time?

    opened by lsgmkk 7
  • Bump checkstyle from 8.41 to 8.45.1

    Bump checkstyle from 8.41 to 8.45.1

    Bumps checkstyle from 8.41 to 8.45.1.

    Release notes

    Sourced from checkstyle's releases.







    • 005fba5 [maven-release-plugin] prepare release checkstyle-8.45.1
    • 8626ae0 doc: release notes 8.45.1
    • 9553361 config: update to 8.45.1-SNAPSHOT
    • fe1ee0d Issue #10548: Migrate to Inline Config Parser in ArrayTrailingCommaCheckTest
    • f3d1b92 Issue #10559: Update inputs for FinalParametersCheckTest
    • a1338ac Issue #10562: Update inputs for OuterTypeFilenameCheckTest
    • c350a32 Issue #10558: Update inputs for DescendantTokenCheckTest
    • c58a869 Issue #10544: Update inputs for RecordTypeParameterNameCheckTest
    • 8dd7a39 Issue #10543: Update inputs for RecordComponentNameCheckTest
    • 1ecc59d supplemental: Convert from Todo check to better MatchXpath check(#10107)
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.

    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    opened by dependabot[bot] 0
  • Rewrite `Interval.parse(CharSequence)`

    Rewrite `Interval.parse(CharSequence)`

    This is an attempt to make Interval parsing more readable and (hopefully) less error prone. I believe that proposed way of splitting code into methods makes much more sense than before. At least one bug was fixed. At the same time, parsing became a little more flexible.

    The bug was caused by the following:

    long move = end.isBefore(Instant.EPOCH) ? 1000 * 86400 : -1000 * 86400;
    Instant start = end.plusSeconds(move).atOffset(ZoneOffset.UTC).minus(amount).toInstant().minusSeconds(move);
    long move = start.isBefore(Instant.EPOCH) ? 1000 * 86400 : -1000 * 86400;
    Instant end = start.plusSeconds(move).atOffset(ZoneOffset.UTC).plus(amount).toInstant().minusSeconds(move);

    It looks like author's intention was to move instant 1000 days towards Instant.EPOCH. First, it is not exactly 1000 days - it's approximately 1000 days. What's important is that it can (but doesn't have to) move instant into month with different number of days. I decided to use leap year cycle length (which is fixed) to avoid this kind of problems.

    Without this fix, not a single test covered by org.threeten.extra.TestInterval.data_parse_outside_bounds(String, String, String) is going to pass. For instance -1000000000-01-31T00:00:00Z/P1M should be parsed to interval ending at -02-29, not -03-02 and for -1000000000-01-31T00:00:00Z/P2M interval's end should be -03-31 instead of -04-01 .

    There are still some cases that this rewrite doesn't fix. All of them involve duration. Please, see org.threeten.extra.TestInterval.data_parse_crossing_bounds(String, String, String) (intervals starting within date-time bounds, with duration making them end outside of it) and org.threeten.extra.TestInterval.data_parse_crossing_bounds_twice(String, String, String) (intervals starting before OffsetDateTime.MIN and ending after OffsetDateTime.MAX because of duration). Maybe someone will be interested in making these tests pass - for now, they are disabled.

    As I mentioned, parsing became a little more flexible. It is now possible to parse `OffsetDateTime/LocalDateTime` and `LocalDateTime/OffsetDateTime` (previously only `OffsetDateTime/LocalDateTime` was supported). It seems to be valid according to spec, at least if Wiki can be trusted.

    For <start>/<end> expressions, if any elements are missing from the end value, they are assumed to be the same as for the start value including the time zone (

    Edit: I must have misread something. If desired, I can easily revert old behavior.

    Probably related: #80.

    opened by perceptron8 1
  • Three package-info.class files with bytecode version 53 (JDK 9) is added to jar

    Three package-info.class files with bytecode version 53 (JDK 9) is added to jar

    In one of our projects use the extra maven enforcer rule enforceBytecodeVersion to ensure that artifacts we believe to be JDK 8 compliant actually are.

    This fails when running against threeten-extra 1.7.1:

    [INFO] --- maven-enforcer-plugin:3.1.0:enforce (enforce) @ bom-integration-test ---
    [INFO] Adding ignore: module-info
    [INFO] Restricted to JDK 8 yet org.threeten:threeten-extra:jar:1.7.1:compile contains org/threeten/extra/chrono/package-info.class targeted to JDK 9
    [ERROR] Rule 3: org.apache.maven.plugins.enforcer.EnforceBytecodeVersion failed with message:
    Found Banned Dependency: org.threeten:threeten-extra:jar:1.7.1

    We can get around this with exclusions I noticed that the package-info.class files are not in the 1.7.0 jar file, but they are included in 1.7.1 with bytecode version 53. Is this intentional?

    opened by klaraward 1
  • Year Half

    Year Half

    Support concept of Year Half. This is useful for some industries, such as finance, to represent the beginning or trailing ends of a year.

    AFAIK there is no standard representation, but typically <year>-H<1|2> (e.g. 2022-H2) is used and similar to Year Quarter.

    opened by dansiviter 1
  • Implement MISP Time System instant

    Implement MISP Time System instant

    This implements the MISP time system as described in the MISB Motion Imagery Handbook (downloadable from - sorry, direct links frequently broken). The implementation follows the TaiInstant implementation, and makes use of the TAI conversion routines where practical.

    Resolves #194

    The PR includes unit tests for all added code.

    There is a change to the UtcRules implementation that adds an abstract method. That won't be source compatible for anyone implementing their own rules (i.e. its arguably an API break). It is not strictly necessary to do so, and although I think the implementation makes more sense in the SystemUtcRules, I could see a case for not doing it that way. I'll update the PR to avoid that if required.

    opened by bradh 1
  • Added TemporalAdjuster for rounding to nearest part of an hour

    Added TemporalAdjuster for rounding to nearest part of an hour

    Hi there,

    this PR contains four TemporalAdjuster to round time to the nearest part of an hour. Rounding to the nearest part of an hour is often done in payroll systems, scheduling and appointment making.

    • Add public static TemporalAdjuster nearestHalf to Temporals
    • Add public static TemporalAdjuster nearestQuarter to Temporals
    • Add public static TemporalAdjuster nearestTenth to Temporals
    • Add public static TemporalAdjuster nearestTwelfth to Temporals

    The code is repetitive and contains hardcoded numbers. Granted not the most clever approach, but it is straightforward and easy to read and maintain.

    I know this project emphasizes well written JavaDoc. I am not a native speaker. I tried.

    opened by raupachz 9
Supporting projects for JSR-310 dates and times in Java
Meno Hochschild 382 Dec 25, 2022
Joda-Time is the widely used replacement for the Java date and time classes prior to Java SE 8.

Joda-Time Joda-Time provides a quality replacement for the Java date and time classes. The design allows for multiple calendar systems, while still pr 4.9k Dec 27, 2022
Core for open source libraries, included some important Classes for those libs.

OpenSource Core You could also read the CHINESE version of README This is a very useful Java class library. In this update, we have merged the origina

Theodore Hills 10 Nov 16, 2022
Meno Hochschild 382 Dec 25, 2022
Set of support modules for Java 8 datatypes (Optionals, date/time) and features (parameter names)

Overview This is a multi-module umbrella project for Jackson modules needed to support Java 8 features, especially with Jackson 2.x that only requires

FasterXML, LLC 372 Dec 23, 2022
Cron utils for parsing, validations and human readable descriptions as well as date/time interoperability.

cron-utils We define crons. And support them. cron-utils is a Java library to define, parse, validate, migrate crons as well as get human readable des

jmrozanec 965 Dec 30, 2022
Easily regenerate worlds at a specific time & date you want (SpigotMC plugin)

Restore/reset worlds at specific times without kicking players from the server! No need to go through the hassle of resetting your worlds manually anymore. Plenty of features are already included in the free version!

Kihsomray 11 Sep 23, 2022
JSilhouette provides additional shapes for Java applications

JSilhouette JSilhouette provides additional shapes for Java applications. Currently JavaFX is supported. Installing You can get the latest version of

Kordamp 39 Nov 7, 2022
DataFX - is a JavaFX frameworks that provides additional features to create MVC based applications in JavaFX by providing routing and a context for CDI.

What you’ve stumbled upon here is a project that intends to make retrieving, massaging, populating, viewing, and editing data in JavaFX UI controls ea

Guigarage 110 Dec 29, 2022
Time-Based One-Time Password (RFC 6238) and HMAC-Based One-Time Password (RFC 4226) reference implementations and more.

Crypto Time-Based One-Time Password (RFC 6238) and HMAC-Based One-Time Password (RFC 4226) reference implementations and more. Getting Started TOTP ge

Oliver Yasuna 1 May 12, 2022
The Java collections framework provides a set of interfaces and classes to implement various data structures and algorithms.

Homework #14 Table of Contents General Info Technologies Used Project Status Contact General Information Homework contains topics: Sorting an ArrayLis

Mykhailo 1 Feb 12, 2022
KC4Streams - a simple Java library that provides utility classes and standard implementations for most of the Kafka Streams pluggable interfaces

KC4Streams (which stands for Kafka Commons for Streams) is a simple Java library that provides utility classes and standard implementations for most of the Kafka Streams pluggable interfaces.

StreamThoughts 2 Mar 2, 2022
Nginx module for embedding Clojure or Java or Groovy programs, typically those Ring based handlers.

Nginx-Clojure Nginx-Clojure is a Nginx module for embedding Clojure or Java or Groovy programs, typically those Ring based handlers. Core Features The

nginx-clojure 1k Dec 22, 2022
Generate Java types from JSON or JSON Schema and annotates those types for data-binding with Jackson, Gson, etc

jsonschema2pojo jsonschema2pojo generates Java types from JSON Schema (or example JSON) and can annotate those types for data-binding with Jackson 2.x

Joe Littlejohn 5.9k Jan 5, 2023
A small tools to play with JavaFX Color.derive() function - allows to create custom colors and to save those in color palettes.

DeriveColorsFX This is not a serious application. Its a small tool where I just played with the method Color::deriveColor provided by JavaFX. Also its

Oliver Löffler 11 Oct 9, 2022
WordleCompanion - A tool to help you determine those hard-to-guess words while doing your daily Wordle puzzles.

A tool to help you determine those hard-to-guess words while doing your daily Wordle puzzles. How it works Enter the 5-letter word you

Ken Vaczi 1 Jan 22, 2022
The Apache Software Foundation 3k Jan 4, 2023 "Java & React Bootcamp" up to date Lectures and Homeworks.

Java & React Bootcamp ( Lectures Lecture 1 intro Lecture 2 oopIntro homework Lecture 3 oopIntro2 inheritance inheritance2 homework

Karcan Ozbal 237 Dec 29, 2022