Java:最简单的日期相减方法

20

我创建了一个类,其中包含两个需要为日期的字段:start_datedate_passed。我一直在研究如何在Java中以YYYY MM DD格式处理日期,以便进行简单的日期减法并能够“构造”日期,例如未来的日期。

以下是我想要实现的示例...

library.circulate_book("Chemistry", **start date here**) //actual date or random date
library.pass_book("Chemistry", **Date Passed here**) //random date such as 5 days after start date
int days_had = Date_Passed - start_date

到目前为止,我已经找到了很多使用日历和日期类来格式化日期的方法,但是由于大多数日期最终都会成为字符串,所以尚未找到看起来适用的方法。如果有任何建议/小例子,将不胜感激!同时,任何示例链接也将非常棒!

6个回答

33

简述

通过添加/减去若干天数来移动日期。

LocalDate.now(
    ZoneId.of( "Pacific/Auckland" ) 
)
.minusDays( 5 )

计算两个日期之间经过的天数、月数和年数。
ChronoUnit.DAYS.between( start , stop )

解析

首先,您必须将字符串输入解析为日期时间对象。然后使用这些对象进行业务逻辑处理。

不要再把日期时间值看作字符串,那会让您发疯的。我们在代码中使用日期时间对象;我们使用该日期时间对象的字符串表示形式与用户或其他应用程序交换数据。

在Java 8及更高版本中,请使用java.time框架。请参见教程

如果您只需要日期而不需要时分秒,则可以使用LocalDate类。

那个奇怪的双冒号语法是方法引用,一种指定其他代码应调用哪个方法的方式。

String input = "2015 01 02";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "yyyy MM dd" );
LocalDate localDate = formatter.parse ( input , LocalDate :: from );

当前日期

确定今天的日期需要考虑时区。对于任何给定的时刻,日期因时区而异。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalDate todayTunis = LocalDate.now( z ) ;

如果您想获取JVM当前的默认时区,请调用ZoneId.systemDefault

日期相减

这个问题在StackOveflow.com上已经被多次讨论。例如,如何使用Java日历从日期中减去X天?。有关详细信息,请参见其他答案,例如我写的这篇文章我写的这篇文章。提示: "elapsed" 是一个关键词。

使用ChronoUnit.DAYS枚举来计算经过的天数。

LocalDate weekLater = localDate.plusDays ( 7 );
long daysElapsed = java.time.temporal.ChronoUnit.DAYS.between( todayTunis , weekLater ) ;

将数据输出到控制台。

System.out.println ( "localDate: " + localDate + " to " + weekLater + " in days: " + daysElapsed );

本地日期:2015年01月02日至2015年01月09日,天数:7


非常好的回答,我正在查看LocalDate方法,也许我读错了,但是是否有一种方法可以仅返回本地日期,例如今天的“2015 04 11”? - Bob
now()能否从程序后面的日期中减去,例如LocalDate localDate = formatter.parse(input, LocalDate::from); - Bob
@user38254 你似乎仍然混淆了日期时间值和它们的字符串表示。要获取"今天",只需调用LocalDate today = LocalDate.now(ZoneId.of("America/Montreal"));。时区在确定日期方面至关重要(好好想一想!)。对于一个字符串,使用与上述相同的格式化程序:String output = today.format(formatter);。在此主题上搜索其他StackOveflow页面。 - Basil Bourque
这个答案的问题在于 .getDays 方法不能获取两个日期之间的绝对天数,它只会获取相对于月份/年份的天数。而 ChronoUnit 方法则没有这个缺点。 - Logister
@Logister 您是正确的,我的代码有缺陷。现在已经更正了。感谢您的指出。 - Basil Bourque

19

在Java 8中实现最佳方式不是Basil Bourque错误的答案,而是以下方法:

String startDate = "2016 01 02";
String passedDate = "2016 02 29";

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
LocalDate date1 = LocalDate.parse(startDate, formatter);
LocalDate date2 = LocalDate.parse(passedDate, formatter);

long elapsedDays = ChronoUnit.DAYS.between(date1, date2);
System.out.println(elapsedDays); // 58 (correct)
建议使用java.time.Duration.toDays()而非java.time.Period.getDays(),因为后者在经过一个月以上的时间后会出错。整个Period是P1M27D,所以代码实际上只查询了部分流逝的天数(还有一个已经流逝的月份)。
System.out.println(Period.between(date1, date2).getDays()); // 27 (WRONG!!!)

使用java.util.DateGregorianCalendar等类来找到一个令人满意的解决方案很困难。您可以使用Tacktheritrix的答案,但必须注意java.util.Date的子日部分可能导致计算出的经过天数不同,而且由于忽略了夏令时转换(在世界上许多地区时钟会向前或向后跳动一小时),因此不可靠。

附注:至少8个外部库也提供了好的解决方案。但我认为,除非你还没有使用Java-8,否则你简单的用例不足以证明嵌入额外的库。任何其他方法来计算两个日期之间经过的天数都不比在Java-8中容易 - 只是类似。既然您已接受了Basil Bourque的与Java-8相关的答案,我假设您确实正在使用Java-8,因此不再解释如何使用其他库解决您的问题。


1
Java 8 中的日期时间更改本应使生活变得轻松,但有时候找到这些东西确实感觉很难 :) - Mike
@Mike 日期和时间处理本质上是困难的。任何声称它不是困难的库,很可能会给您带来错误。 - Ole V.V.

3

Joda有一个daysBetween方法,可能会起到作用。 - Mark Sholund
Joda是什么,我该如何获取它? - Bob
不,实际上在我们学校的系统中被阻止了,真是运气不好啊。 - Bob
1
为了让这个回答变得真实可信,而不是仅有链接的回答,请展示如何使用Java 8日期API和/或Joda Time来实现。 - Erwin Bolwidt
我曾经考虑过这个问题,但是网络上已经有成千上万的例子都已经完全合格了,为什么还要再创建一个呢... - Emerson Cod
@EmersonCod "为什么要再创建一个"……因为StackOverflow.com旨在成为编程问题答案的权威来源。你的回答应该是Google/Bing在这个主题上提供的最佳结果。就像维基百科一样,但更加专注。如果你发现相同类型的问题,请标记为重复。 - Basil Bourque

1
这是一个使用Calendar的答案:
Calendar cal = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();

cal2.setTime(cal.getTime());
cal2.add(Calendar.DAY_OF_YEAR, 5);
System.out.println((cal2.getTimeInMillis() - cal.getTimeInMillis()) / (1000d * 60 * 60 * 24));

1
    LocalDate startDate = LocalDate.of(2009, 9, 1);
    LocalDate today = LocalDate.now();
    Period p = Period.between(startDate, today);
    System.out.println("Years " + p.getYears());
    System.out.println("Months " + p.getMonths());
    System.out.println("Days " + p.getDays());

0

如果你被困在旧版的Java中,你可以使用SimpleDateFormat。

    //For substraction
    long differenceInMillis = date1.getTime() - date2.getTime();

    //Date Format
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy MM dd");
    String dateAsString = dateFormat.format(date1); //To get a text representation
    Date dateParsed = dateFormat.parse(dateAsString); //To get it back as date

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接