gpt4 book ai didi

java - 2个日历实例之间的差异给出不一致的答案

转载 作者:行者123 更新时间:2023-11-29 04:15:37 25 4
gpt4 key购买 nike

我正在使用jdk 1.7,并使用Calendar类来计算2个日期之间的差。我正在使用下面的代码,但结果不一致。意思是有时是正确的,但有时是一天之久,没有任何规律可言。

public class Test {

public static void main(String ar[]) {

System.out.println(calculateDays());
}

private static long calculateDays() {
long days_past_due;
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal1.set(2013, 12, 1);
cal2.set(2013, 12, 30);
days_past_due = getDifference(cal1, cal2, TimeUnit.DAYS);
return days_past_due;
}

public static long getDifference(Calendar b, Calendar a, TimeUnit units)
{

return units.convert(b.getTimeInMillis() - a.getTimeInMillis(), TimeUnit.MILLISECONDS);
}


例子:

Example 1: cal1.set(2013, 12, 1);
cal2.set(2013, 12, 1);
Answer returned: 0 (Correct)
Example 2: cal1.set(2013, 12, 1);
al2.set(2013, 12, 2);
Answer returned: -1 (Correct)
Example 3: cal1.set(2013, 11, 30);
cal2.set(2013, 12, 1);
Answer returned: -2 (Incorrect)
Example 4: cal1.set(2013, 8, 31);
cal2.set(2013, 8, 31);
Answer returned: 0 (Correct)
Example 5: cal1.set(2013, 8, 31);
cal2.set(2013, 9, 1);
Answer returned: 0 (Incorrect)
Example 6: cal1.set(2013, 6, 30);
cal2.set(2013, 6, 30);
Answer returned: 0 (Correct)
Example 7: cal1.set(2013, 6, 30);
cal2.set(2013, 7, 1);
Answer returned: -2 (Incorrect)


我在这里做错了什么?

最佳答案

tl; dr

您应该使用理性计数的LocalDate而不是麻烦的Calendar类。

ChronoUnit.DAYS.between(
LocalDate.of( 2013 , 11 , 30 ) ,
LocalDate.of( 2013 , 12 , 1 )
)


参见此 code run live at IdeOne.com


  1个


疯狂计数

您似乎没有意识到可怕的 Calendar类中使用的疯狂计数:从1月到12月的0-11个月。

所以 cal1.set(2013, 11, 30)cal2.set(2013, 12, 1)的意思是10月30日至11月1日,实际上是两天,占10月31日。您显然误认为这是11月30日至12月1日,但没有。

这是 index-counting, zero-based。不幸的是,索引计数经常在某些程序员中经常出现,他们不恰当地使用原始数组或系统编程或老式C风格编程中的内存跳转的意义。在使用现代语言的常见商业应用程序中,序数计数通常更有意义。例如,将1月视为第一个月(第1个月),将12月视为第十二个月(第12个月)。

java.time

幸运的是,我们现在有了java.time类。没有理由让您使用可怕的混乱,它们是传统的日期时间类,例如 DateCalendarSimpleDateFormat

对于Java 7的使用,请参阅下面底部的项目符号中链接的ThreeTen-Backport项目。

LocalDate

LocalDate类表示没有日期和时区的仅日期值。

时区对于确定日期至关重要。在任何给定时刻,日期都会在全球范围内变化。例如,在 Paris France中午夜之后的几分钟是新的一天,而在 Montréal Québec中仍是“昨天”。

如果未指定时区,则JVM隐式应用其当前的默认时区。该默认值可能在运行时(!)期间为 change at any moment,因此您的结果可能会有所不同。最好将 desired/expected time zone明确指定为参数。

continent/region的格式指定 proper time zone name,例如 America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用3-4个字母的缩写,例如 ESTIST,因为它们不是真实的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
LocalDate today = LocalDate.now( z ) ;


如果要使用JVM的当前默认时区,请提出要求并作为参数传递。如果省略,则会隐式应用JVM的当前默认值。最好明确一点,因为在运行时的任何时候都可以通过JVM中任何应用程序的任何线程中的任何代码来更改默认值。

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.


或指定一个日期。您可以用数字设置月份,一月至十二月的理智编号为1-12。

LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ;  // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.


或者,最好使用预定义的 Month枚举对象,一年中的每个月使用一个。提示:在整个代码库中使用这些 Month对象,而不仅仅是一个整数,可以使您的代码更具自记录性,确保有效值并提供 type-safety

LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;


ChronoUnit.DAYS

要计算经过的天数,请使用 ChronoUnit枚举。

long days = ChronoUnit.DAYS.between( start , stop ) ;




关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧 legacy日期时间类,例如 java.util.DateCalendarSimpleDateFormat

现在位于 Joda-Time中的 maintenance mode项目建议迁移到 java.time类。

要了解更多信息,请参见 Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为 JSR 310

您可以直接与数据库交换java.time对象。使用与 JDBC driver或更高版本兼容的 JDBC 4.2。不需要字符串,不需要 java.sql.*类。

在哪里获取java.time类?


Java SE 8Java SE 9Java SE 10Java SE 11和更高版本-具有捆绑实现的标准Java API的一部分。


Java 9添加了一些次要功能和修复。

Java SE 6Java SE 7


大多数java.time功能都被反向移植到 ThreeTen-Backport中的Java 6和7。

Android


更高版本的Android捆绑了java.time类的实现。
对于早期的Android(<26), ThreeTenABP项目改编为 ThreeTen-Backport(如上所述)。请参见 How to use ThreeTenABP…



ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如 IntervalYearWeekYearQuartermore

关于java - 2个日历实例之间的差异给出不一致的答案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52546512/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com