考虑日期时的小时差异

时间:2017-09-05 20:39:22

标签: java datetime date-difference java-date

我需要从DB中提取日期字段并将其存储在VO中。如何比较两个日期的小时差异。

例如:
我们说date1 = 01-SEP-17 10:00:00date2 = 05-SEP-17 12:00:00。我需要比较两个日期并执行一些操作,如:

if(hours>10){
//do something
}
if(hours<10){
//do something else
}  

我只能将小时数(date2-date1)之间的差异计算为2但是在计算小时数之间的差异时如何考虑日期?

我现在的代码:

Date dateA = someVO.getDate();  
long date = System.currentTimeMillis();  
SimpleDateFormat df = new SimpleDateFormat("dd-MM-YY HH:mm:ss"); 
Date date1 = new Date(date); 
Date date2 = df.parse(dateA.toString());  
long date1Hours = date1.getHours();
long date2Hours = date2.getHours();  

long dateDiff = date1Hours-date2Hours;  
if(dateDiff>10){  
//something
}  
else if(dateDiff<10){  
//something else
}  

3 个答案:

答案 0 :(得分:3)

使用Java 8中添加的新Java-Time API非常容易:

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
                        .parseCaseInsensitive()
                        .appendPattern("dd-MMM-yy HH:mm:ss")
                        .toFormatter(Locale.US);
LocalDateTime date1 = LocalDateTime.parse("01-SEP-17 10:00:00", fmt);
LocalDateTime date2 = LocalDateTime.parse("05-SEP-17 12:00:00", fmt);
long hours = ChronoUnit.HOURS.between(date1, date2);
System.out.println(hours);

输出

98

答案 1 :(得分:2)

首先,您需要更改SimpleDateFormat中使用的模式,并使用java.util.Locale指定月份名称是英语(否则它使用系统默认语言环境,并且不保证永远是英语)。

然后,您获得每个Date的对应millis值,计算它们之间的差异并使用java.util.concurrent.TimeUnit将其转换为小时数:

SimpleDateFormat df = new SimpleDateFormat("dd-MMM-yy HH:mm:ss", Locale.ENGLISH);
Date date1 = df.parse("01-SEP-17 10:00:00");
Date date2 = df.parse("05-SEP-17 12:00:00");

// get the difference in hours
long dateDiff = TimeUnit.MILLISECONDS.toHours(date2.getTime() - date1.getTime());

dateDiff将为98

如果您想与当前日期进行比较,只需使用new Date()

夏令时发布

这种方法存在一个问题。虽然它在一年中的大部分时间没有任何影响,但由于Daylight Saving Time更改可能会有所不同。

默认情况下,SimpleDateFormat使用JVM默认时区。如果两个日期之间有夏令时转换(或只是偏移更改),结果可能会有所不同。

示例:在Africa/Windhoek timezone中,在2017年9月3日 rd ,凌晨2点,时钟向前移动1小时,从凌晨2点到凌晨3点(偏移量从{{1到+01:00)。这意味着,在当天,上午2点到凌晨2点59分之间的所有当地时间都不存在于此时区(就像他们在这个时间“跳过”一样)。

因此,如果JVM默认时区为+02:00,则使用上述代码的差异将为97小时(而非98)。

即使您的JVM默认时区不是Africa/Windhoek,这仍然会发生,具体取决于所涉及的时区和日期。 不仅如此,还有默认时区can be changed without notice, even at runtime。最好指定您正在使用的时区而不是仅仅依赖默认值。

您无法避免DST效果(除非您使用UTC),但至少您可以选择使用哪个时区而不是依赖系统默认值(可以更改,恕不另行通知)。

可以在格式化程序中设置时区,因此将考虑此时区来解析所有日期。在下面的示例中,我使用Africa/Windhoek,但当然您可以更改为最适合您的情况:

Europe/London

现在所有解析的日期都将被认为是在伦敦时区(但提醒仍然会考虑DST效果 - 优点是您知道您正在使用的时区,并且JVM默认的任何更改都不会你的代码突然开始给出不同的意外结果。)

始终使用IANA timezones names(始终采用// set Europe/London timezone in the SimpleDateFormat df.setTimeZone(TimeZone.getTimeZone("Europe/London")); 格式,例如Continent/CityAmerica/Sao_Paulo。 避免使用3个字母的缩写(例如Europe/BerlinCST),因为它们是ambiguous and not standard

您可以使用PST获取所有时区的列表 - 然后您可以选择最适合您情况的时区。

如果您不想考虑DST效果,可以使用TimeZone.getAvailableIDs() - 因为UTC is a standard without DST changes

Java新日期/时间API

旧类(TimeZone.getTimeZone("UTC")DateCalendar)有lots of problemsdesign issues,它们将被新API取代。< / p>

如果您使用的是 Java 8 ,请考虑使用new java.time API。它更容易,less bugged and less error-prone than the old APIs

如果您使用的是 Java&lt; = 7 ,则可以使用ThreeTen Backport,这是Java 8新日期/时间类的绝佳后端。对于 Android ,有ThreeTenABP(更多关于如何使用它here)。

以下代码适用于两者。 唯一的区别是包名称(在Java 8中为SimpleDateFormat而在ThreeTen Backport(或Android的ThreeTenABP中)为java.time),但类和方法名称是一样的。

首先,您需要解析输入(使用org.threeten.bp)并指定它们的时区。由于日期也有时区,我使用的是DateTimeFormatter,这是此案例的最佳选择。

然后,您可以使用ZonedDateTime轻松计算小时数差异。在下面的例子中,我也使用伦敦时区作为例子:

ChronoUnit

如果您想使用UTC,只需将DateTimeFormatter fmt = new DateTimeFormatterBuilder() // case insensitive for month name in all caps .parseCaseInsensitive() // date/time pattern .appendPattern("dd-MMM-yy HH:mm:ss") // use English locale for month name .toFormatter(Locale.ENGLISH) // set a timezone .withZone(ZoneId.of("Europe/London")); // parse the dates ZonedDateTime z1 = ZonedDateTime.parse("01-SEP-17 10:00:00", fmt); ZonedDateTime z2 = ZonedDateTime.parse("05-SEP-17 12:00:00", fmt); // calculate the difference in hours long diffHours = ChronoUnit.HOURS.between(z1, z2); 更改为ZoneId常量即可。如果您想与当前日期进行比较,只需使用:

ZoneOffset.UTC

转换日期

如果您仍需要使用// use the same ZoneId used in the formatter if you want to consider DST effects ZonedDateTime.now(ZoneId.of("Europe/London")); ,则可以从/转换为新API。在Java 8中,您可以使用本机方法,在Java&lt; = 7中,ThreeTen Backport具有java.util.Date类。

org.threeten.bp.DateTimeUtils转换为新类:

Date

Date date = // java.util.Date // convert to zoneddatetime (java 8) ZonedDateTime z = date.toInstant().atZone(ZoneId.of("Europe/London")); // convert to zoneddatetime (java 7 ThreeTen Backport) ZonedDateTime z = DateTimeUtils.toInstant(date).atZone(ZoneId.of("Europe/London")); 转换回日期:

ZonedDateTime

答案 2 :(得分:1)

你基本上已经有了几毫秒的时间。你总是可以直接比较毫秒。

{{1}}