繁体   English   中英

在java中获取两个日期之间的精确差异

[英]Get precise difference between two dates in java

我正在寻找一种方法来获取两个日期之间的差异,正如标题所说,在 Java 中。 例如,如果d1 = 2017-01-23 05:25:00d2 = 2018-03-20 07:29:50 ,某些方法会打印

Years: 1
Months: 1
Days: 25
Hours: 2
Minutes: 4
Seconds: 50

我尝试使用 LocalDateTime 对象来做到这一点,但我找不到一种方法来获得它们之间的月份。 我认为不需要包含该代码,但如果需要,我可以。 我不在乎日期是什么类型,但我不想使用 Joda 时间或其他外部库。 预先感谢您的帮助。

ISO 8601

我们必须解析你的字符串。 java.time 类在解析/生成字符串时默认使用标准 ISO 8601 格式。 您的输入接近合规; 我们只需要用T替换中间的 SPACE 。

String inputStart = "2017-01-23 05:25:00".replace ( " " , "T" );
String inputStop = "2018-03-20 07:29:50".replace ( " " , "T" );

LocalDateTime

您的输入缺少与 UTC 或时区偏移的任何指示。 因此,他们不会在时间线中,在时间轴上的时刻,可能只有模糊的概念上代表实际的时刻。 所以我们将其解析为LocalDateTime对象。 我们将执行的用于确定时间跨度的数学计算将基于通用的 24 小时制,并且将忽略诸如夏令时 (DST) 之类的异常情况。

LocalDateTime start = LocalDateTime.parse ( inputStart );
LocalDateTime stop = LocalDateTime.parse ( inputStop );

PeriodDuration

java.time 类将与时间线无关的时间跨度定义为两部分。 Period类代表年-月-日,而Duration类代表时-分-秒。

将时间跨度分成这两部分可以避免某些问题,我们必须解决这些问题才能解决您的请求。 您究竟想如何处理第一天可能不完整的一天和最后一天可能不完整的一天? 一天中午到第二天中午是一天还是24小时? 如果我们将第一天的小时数与最后一天的小时数相加,如果该数字超过 24 小时,我们是否应该挤出一整天?

计算

这里我采用全天数的方法,忽略第一天和最后一天。 然后我将第一天的小时数与最后一天的小时数相加。 正如我们在您的示例数据中看到的那样,这可能会导致我们的Duration超过 24 小时。 这种方法可能会也可能不会满足您未说明的意图/定义。

Period p = Period.between ( start.toLocalDate () , stop.toLocalDate () ).minusDays ( 1 );  // Subtract one, as we account for hours of first day.

// Get the Duration of first day's hours-minutes-seconds.
LocalDateTime startNextDay = start.toLocalDate ().plusDays ( 1 ).atStartOfDay ();
Duration dStart = Duration.between ( start , startNextDay );

// Get the Duration of first day's hours-minutes-seconds.
LocalDateTime stopStartOfDay = stop.toLocalDate ().atStartOfDay ();
Duration dStop = Duration.between ( stopStartOfDay , stop );

// Combine the pair of partial days into a single Duration.
Duration d = dStart.plus ( dStop );

转储到控制台。 Period & Duration类上的toString方法以 ISO 8601 的标准持续时间格式生成字符串: PnYnMnDTnHnMnS ,其中P标记开始, T将年-月-日与时-分-秒分开。

System.out.println ( "start/stop: " + start + "/" + stop );
System.out.println ( "p: " + p );
System.out.println ( "dStart: " + dStart + " and dStop: " + dStop );
System.out.println ( "d: " + d );

开始/停止:2017-01-23T05:25/2018-03-20T07:29:50

p: P1Y1M24D

dStart:PT18H35M 和 dStop:PT7H29M50S

d:PT26H4M50S

要获得所需的文本输出,您需要询问Period每个部分和Duration每个部分。

int years = p.getYears ();
int months = p.getMonths ();
int days = p.getDays ();

Java 8 莫名其妙地缺少从Duration方便地获取每个小时、分钟或秒部分的方法。 Java 9 添加了这样的方法。 有关更多讨论,请参阅此问题

long durationDays = d.toDaysPart();
long hours = d.toHoursPart();
long minutes = d.toMinutesPart();
long seconds = d.toSecondsPart();
int nanos = d.toNanosPart();

实时代码

请参阅在 IdeOne.com 中实时运行的示例代码


ZonedDateTime

上面的讨论是针对通用 24 小时制的,忽略了与 UTC/时区偏移的问题。

相反,如果您打算跟踪时间线上的实际时刻,则必须应用适用于这些日期时间字符串的时区。

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtStart = start.atZone( z );
…

其余代码将类似,但将ZoneId传递给atStartOfDay调用以生成ZonedDateTime对象而不是LocalDateTime对象。

请记住,当使用ZonedDateTime对象而不是LocalDateTime对象时,您可能会得到不同的结果。

请参阅IdeOne.com 中的示例代码

String inputStart = "2017-01-23 05:25:00".replace ( " " , "T" );
String inputStop = "2018-03-20 07:29:50".replace ( " " , "T" );

LocalDateTime ldtStart = LocalDateTime.parse ( inputStart ); // LocalDateTime used only briefly here, to parse inputs. Then we switch to `ZonedDateTime`.
LocalDateTime ldtStop = LocalDateTime.parse ( inputStop );

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtStart = ldtStart.atZone( z ); // Invalid values may be adjusted, such as during the hour of a "Spring-forward" Daylight Saving Time (DST) switch-over.
ZonedDateTime zdtStop = ldtStop.atZone( z );

Period p = Period.between ( zdtStart.toLocalDate () , zdtStop.toLocalDate () ).minusDays ( 1 );  // Subtract one, as we account for hours of first day.

// Get the Duration of first day's hours-minutes-seconds.
ZonedDateTime zdtStartNextDay = zdtStart.toLocalDate ().plusDays ( 1 ).atStartOfDay ( z );
Duration dStart = Duration.between ( zdtStart , zdtStartNextDay );

// Get the Duration of first day's hours-minutes-seconds.
ZonedDateTime zdtStopStartOfDay = zdtStop.toLocalDate ().atStartOfDay ( z );
Duration dStop = Duration.between ( zdtStopStartOfDay , zdtStop );

// Combine the pair of partial days into a single Duration.
Duration d = dStart.plus ( dStop );

System.out.println ( "zdtStart: " + zdtStart );
System.out.println ( "zdtStop: " + zdtStop );
System.out.println ( "p: " + p );
System.out.println ( "dStart: " + dStart + " and dStop: " + dStop );
System.out.println ( "d: " + d );

int years = p.getYears ();
int months = p.getMonths ();
int days = p.getDays ();
System.out.println( "Years: " + years + "\nMonths: " + months + "\nDays: " + days );

// Enable if in Java 9 or later (but not in Java 8)
// long durationDays = d.toDaysPart();
// long hours = d.toHoursPart();
// long minutes = d.toMinutesPart();
// long seconds = d.toSecondsPart();
// int nanos = d.toNanosPart();

提示: ThreeTen-Extra库提供了一个Interval类来跟踪一对Instant对象。 Instant是 UTC 时间线上的时刻。 您可以通过调用toInstantZonedDateTime提取Instant


关于 java.time

java.time框架内置于 Java 8 及更高版本中。 这些类取代麻烦的老传统日期时间类,如java.util.DateCalendar ,和SimpleDateFormat

现在处于维护模式Joda-Time项目建议迁移到java.time类。

要了解更多信息,请参阅Oracle 教程 并在 Stack Overflow 上搜索许多示例和解释。 规范是JSR 310

从哪里获得 java.time 类?

ThreeTen-Extra项目用额外的类扩展了 java.time。 该项目是未来可能添加到 java.time 的试验场。 您可以在这里找到一些有用的类,比如IntervalYearWeekYearQuarter ,和更多

包 com.mkyong.date;

导入 java.text.SimpleDateFormat; 导入 java.util.Date;

公共类 DateDifferentExample {

public static void main(String[] args) {

    String dateStart = "01/14/2012 09:29:58";
    String dateStop = "01/15/2012 10:31:48";

    //HH converts hour in 24 hours format (0-23), day calculation
    SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");

    java.util.Date d1 = null;
    java.util.Date d2 = null;

    try {
        d1 = format.parse(dateStart);
        d2 = format.parse(dateStop);

        //in milliseconds
        long diff = d2.getTime() - d1.getTime();

        long diffSeconds = diff / 1000 % 60;
        long diffMinutes = diff / (60 * 1000) % 60;
        long diffHours = diff / (60 * 60 * 1000) % 24;
        long diffDays = diff / (24 * 60 * 60 * 1000);

        System.out.print(diffDays + " days, ");
        System.out.print(diffHours + " hours, ");
        System.out.print(diffMinutes + " minutes, ");
        System.out.print(diffSeconds + " seconds.");

    } catch (Exception e) {
        e.printStackTrace();
    }

}

}

结果

1天1小时1分50秒。

我只会将您想要的两个日期和时间放入 SimpleDateFormat 中。 然后您可以执行 date.getTime() 并以毫秒为单位返回距离,然后可以将其转换回天数、年数或月数。 这是我写的一个例子:

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

public class DateTest{
    public static void main(String[] args) throws ParseException{
        System.out.println("Current time in milliseconds: " + System.currentTimeMillis());
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss MM/dd/yyyy");

        String dateAndTime1 = "2:30:00 1/23/2017";
        String dateAndTime2 = "1:45:00 5/23/2015";

        Date date1 = format.parse(dateAndTime1);
        Date date2 = format.parse(dateAndTime2);
        long difference = date1.getTime() - date2.getTime();


        System.out.println("The difference in milliseconds is " + difference);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM