Search code examples
javatimelimit

Why is Java.Time.Year arbitrarily limited to less than its primitive limits?


The Java 8 doc page for Java.Time.Year states that the minimum and maximum supported years are -999,999,999 and 999,999,999, respectively.

Field Summary

static int MAX_VALUEThe maximum supported year, '+999,999,999'.

static int MIN_VALUEThe minimum supported year, '-999,999,999'.


However, the primitive type variable that stores the year value is an int, which should be capable of storing between -2,147,483,648 and 2,147,483,647.

/**
 * The year being represented.
 */
private final int year;

Why are there these arbitrary limits?


Solution

  • The reason 999,999,999 is used is not linked to any specific issue with parsing implementation within the code.

    It is likely to have been selected as it is the maximum value of any number that consists of between 1 and 9 digits. We cannot store a full set of years to 10 digits with an INT, as 9,999,999,999 (and frankly another 79% of possible 10 digit numbers) cannot be stored in an integer. It is important to note that the formatter itself can support individual numbers up to 64 digits seamlessly, and only uses MIN/MAX for error checking. If the Min/Max were raised to INT_MIN and INT_MAX, it would still function without issues. Values exceeding INT_MAX would properly throw an error and prevent any issues regarding integer overflow, so there is no concern regarding any sort of parse failure.

        ISO_LOCAL_DATE = new DateTimeFormatterBuilder()
                .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
                .appendLiteral('-')
                .appendValue(MONTH_OF_YEAR, 2)
                .appendLiteral('-')
                .appendValue(DAY_OF_MONTH, 2)
                .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
    

    Year is either 4 numbers for traditional ISO, i.e. 0-9999, or has a +/-, i.e. +999999 for Year 999999.

    Of note is that the ISO_LOCAL_DATE Formatter accepts 10-digit years by default, excluding the +/- sign, so a value of +9,876,543,210 is actually properly parsed, but exceeds the acceptable values for MAX_YEAR.

    Text '+9876543210-10-31' could not be parsed: Invalid value for Year (valid values -999999999 - 999999999): 9876543210
    

    Everything in the DateTimeFormatterBuilder supports up to 64 digits, parsing a digit at a time. All these values are parsed safely as BigIntegers, and carefully multiplied by 10 as the index moves towards the right, and upon completion are converted and stored in a parse context consisting of field names and longs, even though fields Months and Days can clearly be stored as INTS. These are later converted back into their associated primitives.

    Practically speaking, DateTimeFormatterBuilder could definitely use 2,147,483,647 as a valid min/max year without breaking.

    Realistically speaking, the description of "Java accepts any year value up to 9 digits" presents a concrete barrier where there is no chance of integer overflow or confusion when of adding two years together, and reduces any potential black box confusion as to why year 2,100,000,000 works but 2,200,000,000 breaks to a halt.