英文:
What's the difference between Calendar's getActualMinimum and getGreatestMinimum methods?
问题
由于 getActualMinimum()
和 getGreatestMinimum()
对于每个字段都将返回相同的值,那么确切的区别是什么?
英文:
Since getActualMinimum()
and getGreatestMinimum()
are going to return the same value for every field what's the exact difference?
答案1
得分: 4
getActualMinimum()
方法返回属性可能具有的最小可能值。例如,Calendar.DAY_OF_MONTH
永远不会小于1,因为没有月份以编号为0或更小的日期开始。
getGreatestMinimum()
方法返回getActualMinimum()
可能具有的最大可能值。虽然在大多数情况下,这些值通常是相同的(月份几乎总是从1开始),但代码允许在某些罕见情况下它们不同。在数据验证场景中,使用getGreatestMinimum()
是适当的。
这种情况可以(而且确实会)在日历中存在跳过的日期或不连续性时发生。例如,Java的GregorianCalendar
在切换日期之前实现了儒略历日期,在切换日期之后实现了公历日期,因此在日历中存在几天的间隙,根本没有日期存在。
Calendar
类的getGreatestMinimum()
方法是抽象的,因此子类必须对其进行实现。JRE对GregorianCalendar
的实现显示,如果在切换月份的“跳过的日子”不包括该月的第一天,则DAY_OF_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];
}
使用此作为提示,您可以使用setGregorianChange()
来设置儒略历转公历的切换日期。默认情况下,它是1582年10月15日(从1582年10月4日跳过了10天)。不同的区域在不同的时间切换,例如英国在1752年9月14日切换(在9月2日之后的第二天)。
通过将这个切换设置为一个月中使跳过的天数与该月的第一天重叠的日期,我们可以生成这些边缘案例。
一个真正的基于区域的具有真实切换日期的不连续性可能是罗马尼亚,在那里,1919年3月31日后的一天是1919年4月14日。因此,在罗马尼亚区域中,1919年4月只包括从14日到30日的日期,而getGreatestMin()
将返回14。
由于我没有安装那个区域设置,我可以更改切换日期以模拟会发生的情况:
GregorianCalendar cal = new GregorianCalendar();
// 虽然过时,但是显示这个示例的简单方法
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));
输出:
actual min = 1
greatest min = 14
如果您将Date(Long.MIN_VALUE)
用作切换日期,将得到一个没有间隙的“纯公历”日历。但在这种情况下,“时间的开始”是该月的第16天(在公历日历中),因此在这种情况下,最大值是16。
其他日历系统可能存在类似的不连续性和边缘情况。
英文:
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.
答案2
得分: 2
我建议您停止使用过时且容易出错的java.util
日期时间API。在现代日期时间API中,smallestMaximum
指的是最大值中的最小值,例如月份的最大天数范围从28
(对于2月
)到31
,因此smallestMaximum
是28
。
类似的情况也适用于largestMinimum
,其名称是自说明的。然而,与smallestMaximum
不同的是,largestMinimum
保存的是最小值范围中的最大值,我还没有找到最小值范围,即largestMinimum
必须保存的最大值。换句话说,对于所有的ChronoField
,minimum
和largestMinimum
所保存的值是相同的。
使用现代日期时间API:
import java.time.temporal.ChronoField;
public class Main {
public static void main(String[] args) {
// 例如 ChronoField.DAY_OF_MONTH 的值范围
System.out.println("ChronoField.DAY_OF_MONTH 的统计信息:");
System.out.println("支持的值范围: " + ChronoField.DAY_OF_MONTH.range());
System.out.println("支持的最大值: " + ChronoField.DAY_OF_MONTH.range().getMaximum());
System.out.println("支持的最小值: " + ChronoField.DAY_OF_MONTH.range().getMinimum());
System.out.println("最大最小值范围中的最大值: " + ChronoField.DAY_OF_MONTH.range().getLargestMinimum());
System.out.println("最小最大值范围中的最小值: " + ChronoField.DAY_OF_MONTH.range().getSmallestMaximum());
// 例如 ChronoField.DAY_OF_YEAR 的值范围
System.out.println("\nChronoField.DAY_OF_YEAR 的统计信息:");
System.out.println("支持的值范围: " + ChronoField.DAY_OF_YEAR.range());
System.out.println("支持的最大值: " + ChronoField.DAY_OF_YEAR.range().getMaximum());
System.out.println("支持的最小值: " + ChronoField.DAY_OF_YEAR.range().getMinimum());
System.out.println("最大最小值范围中的最大值: " + ChronoField.DAY_OF_YEAR.range().getLargestMinimum());
System.out.println("最小最大值范围中的最小值: " + ChronoField.DAY_OF_YEAR.range().getSmallestMaximum());
}
}
输出:
ChronoField.DAY_OF_MONTH 的统计信息:
支持的值范围: 1 - 28/31
支持的最大值: 31
支持的最小值: 1
最大最小值范围中的最大值: 1
最小最大值范围中的最小值: 28
ChronoField.DAY_OF_YEAR 的统计信息:
支持的值范围: 1 - 365/366
支持的最大值: 366
支持的最小值: 1
最大最小值范围中的最大值: 1
最小最大值范围中的最小值: 365
有关更多详细信息,请查看TemporalAccessor#range
。从 Trail: Date Time 了解更多有关现代日期时间API的信息。
英文:
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 ChronoField
s.
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.
答案3
得分: 1
没有"leastminimum"方法。方法包括getActualMaximum()、getActualMinimum()、getLeastMaximum()、getMaximum()和getMinimum()。
对于Calendar.DAY_OF_WEEK作为输入:
- getLeastMaximum()将返回28
- getMaximum()将返回31
- getMinimum()将返回1
带有"Actual"的方法将返回与所使用的日历实例值相关的相应最小或最大值(一些日历每年有13个月)。
所以,"Actuals"是相对的,其他三种方法是绝对的。
我刚刚阅读了Java文档以及下面的两个链接,得出了这个结论:
英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论