【问题标题】:Epoch is not epoch if do a new Date(0L). Why?如果做一个新的日期(0L),纪元就不是纪元。为什么?
【发布时间】:2011-01-26 22:24:09
【问题描述】:

我的问题解释得很直截了当:

如果我这样做:

public class Main {

public static void main(String[] args) throws Exception {
        Date d = new Date(0L );
        System.out.println(d);
}

}

我得到以下输出:Thu Jan 01 01:00:00 CET 1970

根据文档,我期待:Thu Jan 01 00:00:00 CET 1970

我想错了……

编辑: 确实,我读文档的速度太快了。我应该有 Thu Jan 01 00:00:00 GMT 1970

那么,我怎样才能强制使用 GMT,而忽略所有当地时间?

编辑,解决方案:

public static void main(String[] args) throws Exception {
    SimpleDateFormat sdf = new SimpleDateFormat("H:m:s:S");
SimpleTimeZone tz = new SimpleTimeZone(0,"ID");
sdf.setTimeZone(tz) ;
Date d = new Date(0L );
System.out.println( sdf.format(d));
}

【问题讨论】:

标签: java date epoch


【解决方案1】:

Epoch 定义为 1970-1-1 UTC 的 00:00:00。由于 CET 是 UTC+1,因此它等于您的时间凌晨 1 点。

如果您查看Date(long) 构造函数,您会发现它期望的值是自纪元UTC 以来的毫秒数:

分配一个 Date 对象和 初始化它以表示 指定的毫秒数 标准基准时间称为“ 纪元”,即 1970 年 1 月 1 日, 格林威治标准时间 00:00:00。

关于您希望强制使用 GMT 而不是您的本地时区:简而言之,Date 实例始终使用 GMT。如果您只想格式化输出字符串以使其使用 GMT,则可以使用 DateFormat 类,特别是其 setTimeZone() 方法。

【讨论】:

  • 好的,但我在创建 Date 对象时看不到任何忽略本地时间或强制 GMT 的内容
  • 日期始终存储为与纪元 GMT 的偏移量。默认的 toString() 格式会考虑您的本地时区,但这仅用于演示。在内部,它只是与纪元的偏移量。
【解决方案2】:

这可能与您的区域设置有关。假设您是法国人而不是法裔加拿大人,您的时间戳似乎被视为没有时区的时间戳,Date 构造函数尝试对此进行更正,将日期增加一小时。

这是否是无证行为,我不能告诉你。

编辑:读取错误:CET != UTC :/

是的,Locale 时区。

重新编辑:为了绝对清晰。

输出:1970 年 1 月 1 日星期四 01:00:00 CET

您的预期输出:Thu Jan 01 00:00:00 CET 1970

实际预期输出:1970 年 1 月 1 日星期四 00:00:00 GMT (≡ 1970 年 1 月 1 日星期四 01:00:00 CET)

【讨论】:

  • 好吧,与其说是你的国籍,不如说是你的时钟设置在哪个时区,如果你明白我的意思的话。 ;)
【解决方案3】:

tl:dr

Instant.EPOCH
       .toString()

1970-01-01T00:00:00Z

Date::toString谎言

您已经了解了避免使用 java.util.Date/Calendar 类的众多原因之一:Date 实例没有时区信息,但它的 toString 方法在呈现用于显示的字符串。令人困惑,因为它暗示 Date 有一个时区,而实际上它没有。

避免Date/Calendar

您应该使用 Joda-Time 或 JSR 310 中的新 Java 8 类 java.time.* 而不是日期/日历。

java.time

Instant 类用作Date 的等效项,即UTC 时间轴上的时刻。

Instant.now()

对于纪元参考日期,使用常量。

Instant.EPOCH.toString()

1970-01-01T00:00:00Z

如果“忽略所有时间”是指您确实想要一个没有时间的仅日期值,请使用 LocalDate 类。

LocalDate.ofEpochDay( 0L )

1970-01-01

Joda-Time 示例

更新:Joda-Time 项目现在处于维护模式,团队建议迁移到 java.time 类。

在 Joda-Time 中,DateTime 实例确实知道自己的时区。如果需要,您可以使用格式化程序在其他时区创建字符串输出。

这是您针对 Unix time Epoch 的代码,但使用的是 Joda-Time 2.3。

// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;

DateTimeZone timeZone_Paris = DateTimeZone.forID( "Europe/Paris" );

DateTime epochParis = new DateTime( 0L, timeZone_Paris );
DateTime epochUtc = new DateTime( 0L, DateTimeZone.UTC );

转储到控制台...

System.out.println( "epochParis: " + epochParis );
System.out.println( "epochUtc: " + epochUtc );

运行时……

epochParis: 1970-01-01T01:00:00.000+01:00
epochUtc: 1970-01-01T00:00:00.000Z

转换为 UTC/GMT

那么,我怎样才能强制使用 GMT,而忽略所有本地时间?

要使用UTC/GMT(无时区偏移),要么:

  • 将 DateTime 转换为具有不同时区的另一个实例
    (Joda-Time 使事物不可变以确保线程安全,因此我们实际上并不转换,而是基于旧实例创建新实例。)
  • 使用格式化程序创建为指定时区显示的字符串。
// To use UTC/GMT instead of local time zone, create new instance of DateTime.
DateTime nowInParis = new DateTime( timeZone_Paris );
DateTime nowInUtcGmt = nowInParis.toDateTime( DateTimeZone.UTC );

转储到控制台...

System.out.println( "nowInParis: " + nowInParis );
System.out.println( "nowInUtcGmt: " + nowInUtcGmt );

运行时……

nowInParis: 2013-12-22T08:40:01.443+01:00
nowInUtcGmt: 2013-12-22T07:40:01.443Z

【讨论】:

    【解决方案4】:

    CET 比 GMT 早一小时,这是用于定义纪元的时区。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-23
      • 2021-08-29
      • 2012-04-28
      • 1970-01-01
      • 2012-07-16
      • 2018-05-05
      • 2013-04-24
      • 1970-01-01
      相关资源
      最近更新 更多