What's the difference between Calendar's getActualMinimum and getGreatestMinimum methods?

603 views Asked by At

Since getActualMinimum() and getGreatestMinimum() are going to return the same value for every field what's the exact difference?

3

There are 3 answers

6
Daniel Widdis On BEST ANSWER

The getActualMinimum() method returns the minimum possible value that an attribute could possibly have. For example, Calendar.DAY_OF_MONTH is never less than 1, since no month starts with a day numbered 0 or less.

The getGreatestMinimum() method returns the maximum possible value that getActualMinimum() could ever have. While in most cases these values will always be the same (months nearly always start with 1), the code allows for them to be different in some rare circumstances. Using getGreatestMinimum() is appropriate for data validation scenarios.

One place this can (and does) occur is when there are skipped dates or discontinuities in a calendar. Java's GregorianCalendar, for example implements dates in the Julian calendar before a cutover date, and the Gregorian calendar after that date, and thus has a gap of several days where dates in the calendar simply don't exist.

The Calendar class getGreatestMinimum() method is abstract, so it is required to be implemented by a subclass. The JRE's implementation for GregorianCalendar shows that it could differ on the DAY_OF_MONTH field if the "skipped days" on the cutover month don't include the first of the month:

public int getGreatestMinimum(int field) {
    if (field == DAY_OF_MONTH) {
        BaseCalendar.Date d = getGregorianCutoverDate();
        long mon1 = getFixedDateMonth1(d, gregorianCutoverDate);
        d = getCalendarDate(mon1);
        return Math.max(MIN_VALUES[field], d.getDayOfMonth());
    }
    return MIN_VALUES[field];
}

Using this as a cue, you can use setGregorianChange() to set the cutover date for Julian-to-Gregorian change. By default it is 15 October 1582 (having skipped 10 days from 4 October 1582). Different Locales switched at different times, for example Great Britain switched on 14 September 1752 (the day after 2 September).

By setting this cutover to a date in a month that makes the skipped days overlap the first of the month, we can generate these edge cases.

An actual locale-based discontinuity with a real cutover date is probably Romania, in which the day after 31 March 1919 was 14 April 1919. So in a Romanian locale, the month of April 1919 would only include days from 14 to 30, and getGreatestMin() will return 14.

Since I don't have that locale installed I can change the cutover date to simulate what would happen:

GregorianCalendar cal = new GregorianCalendar();
// Deprecated, but an easy way of showing this example
cal.setGregorianChange(new Date(1911, Calendar.APRIL, 14));
System.out.println("actual min = " + cal.getActualMinimum(cal.DAY_OF_MONTH));
System.out.println("greatest min = " + cal.getGreatestMinimum(cal.DAY_OF_MONTH));

Output:

actual min = 1
greatest min = 14

Another edge case exists if you use Date(Long.MIN_VALUE) as the cutover, giving a "pure Gregorian" calendar with no gaps. But in that case, the "beginning of time" is on the 16th of the month (in the Gregorian calendar), so greatest min in that case is 16.

Other calendar systems may have similar discontinuities and edge cases.

0
Mayank Madhav On

There is no such method as leastminimum . The methods are getActualMaximum(), getActualMinimum(), getLeastMaximum(),getMaximum() and getMinimum()

getLeastMaximum() would return 28, getMaximum() would return 31, getMinimum() would return 1 for input as Calendar.DAY_OF_WEEK

The methods with 'Actual' will return the corresponding least or max values specific to the calendar instance value being used. ( Some calendars have 13 months in a year)

So the Actuals are relative and the other 3 methods are absolute.

I just read through the java doc and the below 2 links to arrive at this conclusion

getActualMaximum()

getActualMinimum()

1
Arvind Kumar Avinash On

I recommend you stop using the outdated and error-prone java.util date-time API. In the modern date-time API, the smallestMaximum refers to the smallest of the maximum values e.g. the maximum number of days for the month ranges from 28 (for Feb) to 31 and therefore the smallestMaximum is 28.

Similar is the case with largestMinimum whose name is self-descriptive. However, unlike the smallestMaximum which holds the smallest value from the range of maximum values, I haven't been able to find the range of minimum values from which the largest value has to be held by the largestMinimum. In other words, the values held by minimum and largestMinimum are same for all the ChronoFields.

With the modern date-time API:

import java.time.temporal.ChronoField;

public class Main {
    public static void main(String[] args) {
        // e.g. Value range for ChronoField.DAY_OF_MONTH
        System.out.println("Stats of ChronoField.DAY_OF_MONTH:");
        System.out.println("Supported value range: " + ChronoField.DAY_OF_MONTH.range());
        System.out.println("Maximum supported value: " + ChronoField.DAY_OF_MONTH.range().getMaximum());
        System.out.println("Minimum supported value: " + ChronoField.DAY_OF_MONTH.range().getMinimum());
        System.out.println("Largest minimum supported value: " + ChronoField.DAY_OF_MONTH.range().getLargestMinimum());
        System.out
                .println("Smallest maximum supported value: " + ChronoField.DAY_OF_MONTH.range().getSmallestMaximum());

        // e.g. Value range for ChronoField.DAY_OF_YEAR
        System.out.println("\nStats of ChronoField.DAY_OF_YEAR:");
        System.out.println("Supported value range: " + ChronoField.DAY_OF_YEAR.range());
        System.out.println("Maximum supported value: " + ChronoField.DAY_OF_YEAR.range().getMaximum());
        System.out.println("Minimum supported value: " + ChronoField.DAY_OF_YEAR.range().getMinimum());
        System.out.println("Largest minimum supported value: " + ChronoField.DAY_OF_YEAR.range().getLargestMinimum());
        System.out.println("Smallest maximum supported value: " + ChronoField.DAY_OF_YEAR.range().getSmallestMaximum());
    }
}

Output:

Stats of ChronoField.DAY_OF_MONTH:
Supported value range: 1 - 28/31
Maximum supported value: 31
Minimum supported value: 1
Largest minimum supported value: 1
Smallest maximum supported value: 28

Stats of ChronoField.DAY_OF_YEAR:
Supported value range: 1 - 365/366
Maximum supported value: 366
Minimum supported value: 1
Largest minimum supported value: 1
Smallest maximum supported value: 365

Check TemporalAccessor#range for more details. Learn more about the modern date-time API from Trail: Date Time.