【问题标题】:SimpleDateFormat fails to format Date interval?SimpleDateFormat 无法格式化日期间隔?
【发布时间】:2013-01-05 12:01:45
【问题描述】:

我尝试使用 SimpleDateFormat 格式化时间间隔。

import java.text.*;
import java.util.*;

public class DateFormatTest {
  public static void main(String[] args) {
    SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
    long interval = 1000;
    System.out.println("Interval in millis: " + interval);
    System.out.println("Expected result: 00:00:01");
    System.out.println("Result using Date and SimpleDateFormat: " +
      sdf.format(new Date(interval)));
  }
}

我得到以下结果:

Interval in millis: 1000
Expected result: 00:00:01
Result using Date and SimpleDateFormat: 01:00:01

我在 GMT+1 时区。但它不应该反映在结果中。

当然可以用 System.out.printf 解决,但我要找的是原因。

【问题讨论】:

  • SimpleDateFormat 用于格式化日期,而不是间隔,因此它实际打印的是 GMT+1 纪元过去 1000 毫秒的正确时间。您应该将 SimpleDateFormat 的时区设置为 UTC
  • 对于 24 小时日期格式,也使用“HH:mm:ss”,而不是“hh:mm:ss”。 hh 是一个带有有趣后果的错误。
  • System.out.printf 解决方案详细的地方有一个类似的问题:Timemillisecond to hh:mm:ss format in java

标签: java date timezone


【解决方案1】:

我在 GMT+1 时区。但不应该反映在结果中。

是什么让你这么认为? new Date(0) 位于 1970 年 1 月 1 日格林威治标准时间上午 00:00。因此,如果您的默认时区为 GMT + 1,则为上午 01:00。

【讨论】:

  • 对不起,我只是觉得 Date 使用了本地时区。
【解决方案2】:

我在 GMT+1 时区。但它不应该反映在结果中。

那么你应该在SimpleDateFormat中设置时区。 SimpleDateFormat 正在做完全正确的事情 - 它正在格式化它正在工作的时区中的即时时间(就在 UTC 1970 年午夜之后)。

要更改时区,只需使用:

sdf.setTimeZone(TimeZone.getTimeZone("etc/UTC"));

目前还不清楚您是否应该真的使用SimpleDateFormat。您不是在尝试格式化日期/时间 - 您是在尝试格式化 interval,给定变量名称。

我建议你使用Joda Time,它有一个更丰富的类型系统,可以让你表达你真正想要的。

另外,如果您真的想使用SimpleDateFormat,您可能想在格式字符串中使用HH 而不是hh。 (hh 是 12 小时值,1-12。你想要 00:00:01,而不是 12:00:01。)hh 在你不这样做时很少适合在你的模式中有一个 am/pm 指示符。

【讨论】:

  • 根据 javadoc,它是 GMT 而不是 UTC(尽管该特定日期似乎相同)。
  • @assylias:国际海事组织,UTC 是一个更好的表达方式——它根本不与某个地方联系在一起。将 UTC 用于 Unix 纪元特别很有帮助,因为人们通常会假设英国在 1970 年初观察到 GMT,而实际上并非如此。 (有一个使用 UTC+1 的实验。)我怀疑文档是历史性的,但我认为使用 UTC 通常更清晰。诚然,UTC 是在 1970 年以后才作为一个术语引入的,但是......
【解决方案3】:

错误的数据类型

您使用了错误的类。您试图表示毫秒的持续时间和一天中的时间。都不适合 Date 类。该类代表一个时刻(在 UTC 的上下文中,一个日期,带有一天中的时间)。

另外,java.util.Date 是一个糟糕的课程,由不懂日期时间处理的人设计。现在已经过时了。

java.time

现代解决方案使用 java.time 类。

LocalTime

具体来说,LocalTime 表示使用通用 24 小时制的一天中的时间,没有日期,也没有时区的上下文或与 UTC 的偏移量。

一般日子的一天的开始时间是 00:00:00。我们有一个常数:LocalTime.MIN。但是要知道,在不同的时区,在不同的日期,一天可能从另一个时间开始,例如 01:00:00。

LocalTime lt = LocalTime.of( 15 , 30 ) ;  // 3:30 PM.

Duration

要表示与时间线无关的时间跨度,以小时-分钟-秒为单位,请使用Duration 类。

Duration d = Duration.ofMilliseconds( 1_000 ) ;

我们可以用日期时间对象做数学运算。

LocalTime lt = LocalTime.MIN.plus( d ) ;

您应该知道 java.time 类使用nanoseconds 的分辨率,比传统日期时间类使用的milliseconds 精细得多。


关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

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

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-05
    • 1970-01-01
    • 2012-11-09
    • 1970-01-01
    • 1970-01-01
    • 2016-10-21
    相关资源
    最近更新 更多