日期不相等

huangapple go评论145阅读模式
英文:

Calendar dates are not equal

问题

我有关于Java Calendar日期的问题。
基本上,我有一个假期列表,想要检查一个日期是否属于该列表。对于Calendar类如何创建和格式化其日期仍然感到困惑。

请查看以下代码示例:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class CompareCalendarDates {
    public static void main(String args[]) {
        Date date1 = null;
        try {
            date1 = new SimpleDateFormat("yyyy-MM-dd").parse("2019-12-25");
        } catch (ParseException e) {
            date1 = null;
        }

        Calendar calendar1 = Calendar.getInstance();
        calendar1.clear();
        calendar1.setTime(date1);

        Calendar calendar2 = Calendar.getInstance();
        calendar2.clear();
        calendar2.setLenient(false); // 不自动转换无效日期。
        calendar2.set(2019, 11, 25, 0, 0, 0);
        calendar2.getTimeInMillis();

        boolean isEqual = calendar1.equals(calendar2);
        System.out.println("两个日期是否相等:" + isEqual);
    }
}

我使用Calendar类的不同方法创建了两个日期。在我看来,这两个日期应该是相等的,但事实并非如此。
我漏掉了什么?setTime()set 方法之间有什么区别?

英文:

I am having problem with java Calendar dates.
Bassically I have a list of holidays and want to check if a date belong
to the list. Still confused about how the Calendar class
is creating and formating its dates.

Please see the folowing code sample:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class CompareCalendarDates {
public static void main(String args[]) {
    Date date1 = null;
    try {
        date1=  new SimpleDateFormat("yyyy-MM-dd").parse("2019-12-25");
    } catch (ParseException e) {
        date1 = null;
    }

    Calendar calendar1 = Calendar.getInstance();
    calendar1.clear();
    calendar1.setTime(date1);

    Calendar calendar2 = Calendar.getInstance();
    calendar2.clear();
    calendar2.setLenient(false); // Don't automatically convert invalid date.
    calendar2.set(2019, 11, 25, 0, 0, 0);
    calendar2.getTimeInMillis();

    boolean isEqual = calendar1.equals(calendar2);
    System.out.println ("Are to dates equal: " + isEqual);
}
}

I'm creating in 2 dates using different methods from Calendar class.
In my opinion the dates should be equal but there are not.
What am I missing? What is the difference between the methods
setTime () and set ?

答案1

得分: 1

LocalDate
.parse("2019-12-25") 
.isEqual(
    LocalDate.of(2019, Month.DECEMBER, 25)
)

>true

Details

永远不要使用 Date/Calendar。只使用 java.time 类。

LocalDate::isEqual

对于仅包含日期而没有时间和时区信息的值,请使用 LocalDate

LocalDate ld = LocalDate.parse("2019-12-25");

LocalDate other = LocalDate.of(2019, 11, 25);

使用 isEqualisBeforeisAfter 进行比较。

boolean sameDates = ld.isEqual(other);

这个问题已经在Stack Overflow上多次讨论过。要了解更多信息,请搜索。

十二月与十一月

与那些旧类不同,java.time 类使用合理的编号。月份从1到12分别表示一月到十二月。

因此,请注意你的两个输入不同,一个是十二月,一个是十一月。

为了清晰起见,您可以使用 Month 枚举而不是整数。枚举的另一个好处是确保有效的值。

LocalDate other = LocalDate.of(2019, Month.NOVEMBER, 25);

<details>
<summary>英文:</summary>

# tl;dr

```java
LocalDate
.parse( &quot;2019-12-25&quot; ) 
.isEqual(
    LocalDate.of( 2019 , Month.DECEMBER , 25 )
)

>true

Details

Never use Date/Calendar. Use only java.time classes.

LocalDate::isEqual

For a date-only value without time-of-day and without time zone, use LocalDate.

LocalDate ld = LocalDate.parse( &quot;2019-12-25&quot; ) ;

LocalDate other = LocalDate.of( 2019, 11, 25 ) ;

Compare using isEqual, isBefore, isAfter.

boolean sameDates = ld.isEqual( other ) ;

This has been addressed many many times already on Stack Overflow. So I am keeping this Answer brief. Search to learn more.

December versus November

Unlike those legacy classes, the java.time classes use sane numbering. Months are counted 1-12 for January-December.

So notice that your pair of inputs differ, one for December, and one for November.

For clarity, you can use Month enum rather than an integer. Another benefit of enums is to ensure valid values.

LocalDate other = LocalDate.of( 2019 , Month.NOVEMBER , 25 ) ;

答案2

得分: 1

你应该使用:

boolean isEqual = calendar1.getTime().equals(calendar2.getTime());

而不是:

boolean isEqual = calendar1.equals(calendar2);

因为Calendar类中的equals()方法如下所示:

public boolean equals(Object obj) {
    return obj instanceof Date && getTime() == ((Date) obj).getTime();
}

所以它检查这两个日历中的日期是否是相同的对象,在你的情况下它们不是相同的对象,它们只是具有相同的值。

英文:

You should use

boolean isEqual = calendar1.getTime().equals(calendar2.getTime());

Instead of

 boolean isEqual = calendar1.equals(calendar2);

because the equals() method in Calendar class looks like these:

public boolean equals(Object obj) {
    return obj instanceof Date &amp;&amp; getTime() == ((Date) obj).getTime();
}

So it checks if the dates in these two calendars are the same objects, and in your case they are not the same objects, they jut have the same value.

答案3

得分: 1

java.time

如果您从无法升级到java.time(现代Java日期和时间API)的旧API中获取了一个Calendar对象,您现在想知道它是否表示与某个字符串相同的日期,只需将它们都转换为LocalDate,然后使用isEqual方法进行比较:

String date1Str = "2019-12-25";
Calendar calendar2 = new GregorianCalendar(2019, Calendar.DECEMBER, 25);

LocalDate date1 = LocalDate.parse(date1Str);
LocalDate date2 = ((GregorianCalendar) calendar2).toZonedDateTime().toLocalDate();

boolean isEqual = date1.isEqual(date2);
System.out.println("Are to dates equal: " + isEqual);

输出:

Are to dates equal: true

LocalDate是没有时分秒、时区和其他旧式Calendar对象的属性的日期。因此,比较两个LocalDate将给您预期的结果。

代码中出了什么问题?

虽然您的两个Calendar对象确实表示相同的时间点和相同的日历日期(这不是同一件事情),但存在一些差异,例如:

  1. calendar1的所有字段都已设置,而calendar2具有一些未计算的字段,包括时代、年份周、上午/下午、毫秒和时区偏移等。
  2. calendar1是宽松模式,calendar2不是。

我认为这些差异足以使这些对象不被认为是相等的。我没有检查确切的标准文档。您可能出于好奇心而查看文档,但我建议您不需要这样做,因为您不需要比较两个Calendar对象是否相等。

回答您的问题,似乎setTime()会设置所有字段,而set明显只设置了一些字段。我惊讶地发现getTimeInMillis()没有计算其余部分,但它确实没有这样做。

链接

Oracle教程:日期时间 解释了如何使用java.time。

英文:

java.time

If you have got a Calendar object from a legacy API that you cannot afford to upgrade to java.time, the modern Java date and time API, just now, and you want to know whether it denotes the same date as some string, convert both to LocalDate and compare using the isEqual method:

	String date1Str = &quot;2019-12-25&quot;;
	Calendar calendar2 = new GregorianCalendar(2019, Calendar.DECEMBER, 25);
	
	LocalDate date1 = LocalDate.parse(date1Str);
	LocalDate date2 = ((GregorianCalendar) calendar2).toZonedDateTime().toLocalDate();
	
	boolean isEqual = date1.isEqual(date2);
    System.out.println (&quot;Are to dates equal: &quot; + isEqual);

Output:

> Are to dates equal: true

A LocalDate is a date without time of day, time zone, and all the other things that an old-fashioned Calendar object carries with it. So comparing two LocalDate will give you the result that you had expected.

What went wrong in your code?

While your two Calendar objects do denote the same point in time and also the same calendar date (which is not the same thing to ask), there are some differences, for example:

  1. calendar1 has got all its fields set while calendar2 has got some uncomputed fields including for example era, week of year, AM/PM, millisecond of second and zone offset.
  2. calendar1 is lenient, calendar2 is not.

I believe that this is more than enough that the objects are not considered equal. I haven’t checked the documentation for the exact criteria. You may do that out of curiosity, but I suggest that you don’t need to because you are not going to need to compare two Calendar objects for equality.

To answer your question, it seems that setTime() sets all fields while set obviuosly only sets some. I was surprised to see that getTimeInMillis() didn’t calculate the rest, but it doesn’t.

Oracle tutorial: Date Time explaining how to use java.time.

huangapple
  • 本文由 发表于 2020年7月30日 00:06:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/63157800.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定