时差 - 奇怪的结果

时间:2013-08-07 14:32:28

标签: java date time

我有非常简单的代码来计算两次之间的差异:

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

public class JavaApplication8 {
    private static final SimpleDateFormat timeFormat = new SimpleDateFormat("hh:mm:ss.SSS");

    public static void main(String[] args) throws InterruptedException {
        Date start = GregorianCalendar.getInstance().getTime();
        Thread.sleep(100);
        Date end   = GregorianCalendar.getInstance().getTime();

        long diff = end.getTime() - start.getTime();
        System.out.println(timeFormat.format(diff));
    }
}

但它会打印01:00:00.100而不是00:00:00.100,为什么?

4 个答案:

答案 0 :(得分:5)

解决此问题的其他方法。实际上你所拥有的时间差异不是当前时间的毫秒数。它只是时间差异,所以做一个简单的划分你可以有几个小时:分钟:秒。 它非常快。

Date start = GregorianCalendar.getInstance().getTime();
        Thread.sleep(100);
        Date end = GregorianCalendar.getInstance().getTime();

        long longVal = end.getTime() - start.getTime();

        long hours = longVal / 3600000;
        long mins = (longVal % 3600) / 60000;
        long secs = longVal % 60000;

        System.out.println(hours + " " + mins + " " + secs);

答案 1 :(得分:4)

这是一个时区问题。默认情况下,DateFormat.format()会将默认时区格式设置为UTC+1

您应该将timeFormat的时区设为UTC

timeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(timeFormat.format(diff));

此外,您应该在DateFormat中使用HH代替hhhh是12小时制。

new SimpleDateFormat("HH:mm:ss.SSS");

更新:

但还有其他一些重大问题。目前您正在尝试格式化持续时间,您不应该这样做。 Java Date API,没有任何句点或持续时间的概念。

您从格式化中获得的值只不过是来自纪元的毫秒数(相当于差异)。它正在返回一个Date对象。虽然结果似乎是正确的,但从技术上讲,两个日期之间的差异表示一个时期或持续时间,这与日期(表示特定时刻)不同。

您应该考虑转移到此Joda Time此任务,该任务包含代表PeriodInstantDuration等概念的类。

答案 2 :(得分:4)

你混淆了两个概念:

  • 您正在测量时间间隔(两个时间点之间的差异)
  • 您正在打印日期(单个时间点)

两者不兼容,你总会得到如此奇怪的效果。在你的情况下,正如其他评论中指出的那样,时区会混入。时区的概念仅存在于日期(时间点),但对于间隔没有意义。

您可以使用Jodatime库或JSR 310:日期和时间API(我认为Java 8附带)。

使用Jodatime,你可以明确地构建一个区间:

DateTime start = new DateTime(2004, 12, 25, 0, 0, 0, 0);
DateTime end = new DateTime(2005, 1, 1, 0, 0, 0, 0);
Period period = new Period(start, end);

然后使用PeriodFormatter

对其进行格式化
PeriodFormatter daysHoursMinutes = new PeriodFormatterBuilder()
   .appendDays()
   .appendSuffix(" day", " days")
    .appendSeparator(" and ")
    .appendMinutes()
    .appendSuffix(" minute", " minutes")
    .appendSeparator(" and ")
    .appendSeconds()
    .appendSuffix(" second", " seconds")
    .toFormatter();

System.out.println(daysHoursMinutes.print(period));

通过分离ONE时间点和两个时间点之间的时间概念,您可以确保没有任何其他意外(例如闰秒)。

答案 3 :(得分:0)

因为您的时区是GMT + 1。

If you read the documentation,您会找到getTime()所做的事情:

  

返回自1970年1月1日00:00:00 GMT以来的毫秒数   由此Date对象表示。

所以100毫秒意味着January 1, 1970, 00:00:00.100 GMT,即January 1, 1970, 01:00:00.100 GMT+1

您只需设置您希望时间转换为的时区:

timeFormat.setTimeZone(TimeZone.getTimeZone("GMT"));

你想要24小时格式:HH:mm:ss.SSS,否则它将显示12而不是00小时。

编辑:正如 jarnbjo 所说:你正在尝试将日期格式化程序应用到一段时间,这显然不会像你期望的那样工作。 Java API中没有这样的时间间隔格式化程序。你必须自己写。