Calendar 的 getActualMinimum 和 getGreatestMinimum 方法有什么区别?
What's the difference between Calendar's getActualMinimum and getGreatestMinimum methods?
因为 getActualMinimum()
和 getGreatestMinimum()
将 return 每个字段的相同值,具体区别是什么?
getActualMinimum()
方法 return 是属性可能具有的最小可能值。例如,Calendar.DAY_OF_MONTH
永远不会小于 1,因为没有月份以编号为 0 或更小的一天开始。
getGreatestMinimum()
方法 return 是 getActualMinimum()
可能拥有的最大可能值。虽然在大多数情况下这些值将始终相同(月份几乎总是以 1 开头),但代码允许它们在极少数情况下不同。使用 getGreatestMinimum()
适用于数据验证方案。
这可能(并且确实)发生的一个地方是日历中有跳过的日期或不连续的日期。 Java 的 GregorianCalendar
,例如在转换日期之前在儒略历中实现日期,在该日期之后实现公历,因此有几天的间隔,而日历中的日期根本就没有不存在。
Calendar
classgetGreatestMinimum()
方法是抽象的,所以需要由子class实现. 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()
设置 Julian-to-Gregorian 更改的转换日期。默认情况下是 1582 年 10 月 15 日(从 1582 年 10 月 4 日起跳过了 10 天)。不同的 Locales 在不同的时间切换,例如英国在 1752 年 9 月 14 日(9 月 2 日之后的一天)切换。
通过将此切换设置为一个月中的某个日期,使跳过的日期与该月的第一天重叠,我们可以生成这些边缘情况。
一个实际的 locale-based 具有实际切换日期的不连续点可能是罗马尼亚,其中 1919 年 3 月 31 日之后的那一天是 1919 年 4 月 14 日。因此在罗马尼亚语言环境中,1919 年 4 月将只包括几天从 14 到 30,getGreatestMin()
将 return 14.
因为我没有安装那个语言环境,所以我可以更改转换日期来模拟会发生什么:
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));
输出:
actual min = 1
greatest min = 14
如果您使用 Date(Long.MIN_VALUE)
作为转换,则存在另一个边缘情况,给出一个没有间隙的“纯公历”日历。但在那种情况下,“时间的开始”是该月的 16 日(在公历中),因此在这种情况下最大的最小值是 16.
其他日历系统可能有类似的不连续性和边缘情况。
没有 leastminimum 这样的方法。这些方法是 getActualMaximum()、getActualMinimum()、getLeastMaximum()、getMaximum() 和 getMinimum()
getLeastMaximum() 会 return 28,getMaximum() 会 return 31,
getMinimum() 将 return 1 作为输入 Calendar.DAY_OF_WEEK
带有 'Actual' 的方法将 return 特定于正在使用的日历实例值的相应最小值或最大值。 (有些日历一年有13个月)
所以 Actuals 是相对的,其他 3 种方法是绝对的。
我刚刚通读了 java 文档和以下 2 个链接以得出这个结论
我建议您停止使用过时的 error-prone java.util
date-time API。在现代 date-time API 中,smallestMaximum
指的是最大值中的最小值,例如该月的最大天数范围从 28
(对于 Feb
)到 31
,因此 smallestMaximum
是 28
。
名字为self-descriptive的largestMinimum
也是如此。但是,与 smallestMaximum
不同,它保存 最大值范围 中的最小值,我无法找到 最小值范围 其中最大值必须由 largestMinimum
持有。换句话说,minimum
和 largestMinimum
持有的值对于所有 ChronoField
都是相同的。
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());
}
}
输出:
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
勾选TemporalAccessor#range
for more details. Learn more about the modern date-time API from Trail: Date Time.
因为 getActualMinimum()
和 getGreatestMinimum()
将 return 每个字段的相同值,具体区别是什么?
getActualMinimum()
方法 return 是属性可能具有的最小可能值。例如,Calendar.DAY_OF_MONTH
永远不会小于 1,因为没有月份以编号为 0 或更小的一天开始。
getGreatestMinimum()
方法 return 是 getActualMinimum()
可能拥有的最大可能值。虽然在大多数情况下这些值将始终相同(月份几乎总是以 1 开头),但代码允许它们在极少数情况下不同。使用 getGreatestMinimum()
适用于数据验证方案。
这可能(并且确实)发生的一个地方是日历中有跳过的日期或不连续的日期。 Java 的 GregorianCalendar
,例如在转换日期之前在儒略历中实现日期,在该日期之后实现公历,因此有几天的间隔,而日历中的日期根本就没有不存在。
Calendar
classgetGreatestMinimum()
方法是抽象的,所以需要由子class实现. 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()
设置 Julian-to-Gregorian 更改的转换日期。默认情况下是 1582 年 10 月 15 日(从 1582 年 10 月 4 日起跳过了 10 天)。不同的 Locales 在不同的时间切换,例如英国在 1752 年 9 月 14 日(9 月 2 日之后的一天)切换。
通过将此切换设置为一个月中的某个日期,使跳过的日期与该月的第一天重叠,我们可以生成这些边缘情况。
一个实际的 locale-based 具有实际切换日期的不连续点可能是罗马尼亚,其中 1919 年 3 月 31 日之后的那一天是 1919 年 4 月 14 日。因此在罗马尼亚语言环境中,1919 年 4 月将只包括几天从 14 到 30,getGreatestMin()
将 return 14.
因为我没有安装那个语言环境,所以我可以更改转换日期来模拟会发生什么:
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));
输出:
actual min = 1
greatest min = 14
如果您使用 Date(Long.MIN_VALUE)
作为转换,则存在另一个边缘情况,给出一个没有间隙的“纯公历”日历。但在那种情况下,“时间的开始”是该月的 16 日(在公历中),因此在这种情况下最大的最小值是 16.
其他日历系统可能有类似的不连续性和边缘情况。
没有 leastminimum 这样的方法。这些方法是 getActualMaximum()、getActualMinimum()、getLeastMaximum()、getMaximum() 和 getMinimum()
getLeastMaximum() 会 return 28,getMaximum() 会 return 31, getMinimum() 将 return 1 作为输入 Calendar.DAY_OF_WEEK
带有 'Actual' 的方法将 return 特定于正在使用的日历实例值的相应最小值或最大值。 (有些日历一年有13个月)
所以 Actuals 是相对的,其他 3 种方法是绝对的。
我刚刚通读了 java 文档和以下 2 个链接以得出这个结论
我建议您停止使用过时的 error-prone java.util
date-time API。在现代 date-time API 中,smallestMaximum
指的是最大值中的最小值,例如该月的最大天数范围从 28
(对于 Feb
)到 31
,因此 smallestMaximum
是 28
。
名字为self-descriptive的largestMinimum
也是如此。但是,与 smallestMaximum
不同,它保存 最大值范围 中的最小值,我无法找到 最小值范围 其中最大值必须由 largestMinimum
持有。换句话说,minimum
和 largestMinimum
持有的值对于所有 ChronoField
都是相同的。
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());
}
}
输出:
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
勾选TemporalAccessor#range
for more details. Learn more about the modern date-time API from Trail: Date Time.