亲宝软件园·资讯

展开

Java.Util.Date

 sofia   人气:0

前言:

很少有类能像java.util.Date那样在堆栈溢出方面引起如此多的类似问题,有四个原因:

了解java.util.Date最重要的事情为:

现在,关于细节…

Java.Util.Date有什么问题?

java.util.Date(从现在开始就是Date)是一种糟糕的类型,这解释了为什么Java 1.1中有这么多的Date被弃用(但不幸的是,它仍然在使用)。

设计缺陷包括:

我可以发现更多的问题,但他们会越来越挑剔。这是一个非常丰富的列表。好的一面是:

不幸的是,开发人员对这一“好方面”的理解也很差。让我们把它打开…

什么是“瞬间”

注意:在这篇文章的其余部分,我忽略了相对论和闰秒。它们对一些人来说非常重要,但对大多数读者来说,它们只会带来更多的困惑。

当我谈论“瞬间”时,我指的是可以用来识别什么时候发生了什么的概念。(这可能发生在将来,但最容易从过去的事情来考虑。)它独立于时区和日历系统,因此多个使用“本地”时间表示的人可以用不同的方式谈论它。

让我们用一个非常具体的例子来说明发生在不使用我们熟悉的时区的地方的事情:尼尔·阿姆斯特朗在月球上行走。月球行走开始于一个特定的时刻——如果来自世界各地的多个人同时观看,他们会(几乎)同时说“我现在可以看到它正在发生”。

如果你在休斯顿的任务控制中心观看,你可能会想到那一刻是“1969年7月20日,CDT晚上9:56:20”。如果你在伦敦观看,你可能会想到那一刻是“1969年7月21日,英国夏令时凌晨3:26:20”。如果你在利雅得观看,你可能会认为那一刻是“1389年7月7日上午5:56:20(+03)”(使用《古拉经》日历)。尽管不同的观察者会在他们的时钟上看到不同的时间,甚至不同的年份,但他们仍然会考虑同一时刻。他们只是在应用不同的时区和日历系统,将即时转换为更人性化的概念。

那么,计算机如何表示实例呢?它们通常在一个特定的瞬间之前或之后存储一定量的时间,而这个瞬间实际上是一个原点。许多系统使用Unix纪元,这是格里高历中以UTC表示的1970年1月1日开始的午夜。这并不意味着纪元本质上是“在”UTC中的——Unix纪元同样可以定义为“1969年12月31日纽约下午7点的那一刻”。

Date类使用“自Unix纪元以来的毫秒数”——这是getTime()返回的值,由Date(long)构造函数或setTime()方法设置。由于月球行走发生在Unix纪元之前,因此该值为负值:实际上是-14159020000

为了演示日期如何与系统时区交互,让我们展示前面提到的三个时区–休斯顿(美国/芝加哥)、伦敦(欧洲/伦敦)和利雅得(亚洲/利雅得)。当我们从历元毫秒值构建日期时,系统时区是什么并不重要,这根本不取决于本地时区。但如果我们使用Date.toString(),它转换为当前默认时区以显示结果。更改默认时区根本不会更改日期值。对象的内部状态完全相同。它仍然表示相同的瞬间,但toString()getMonth()getDate()等方法将受到影响。

下面的示例代码显示:

import java.util.Date;
import java.util.TimeZone;

public class Test {

    public static void main(String[] args) {
        // The default time zone makes no difference when constructing
        // a Date from a milliseconds-since-Unix-epoch value
        Date date = new Date(-14159020000L);

        // Display the instant in three different time zones
        TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago"));
        System.out.println(date);

        TimeZone.setDefault(TimeZone.getTimeZone("Europe/London"));
        System.out.println(date);

        TimeZone.setDefault(TimeZone.getTimeZone("Asia/Riyadh"));
        System.out.println(date);

        // Prove that the instant hasn't changed...
        System.out.println(date.getTime());
    }
}

输出如下:

Sun Jul 20 21:56:20 CDT 1969
Mon Jul 21 03:56:20 GMT 1969
Mon Jul 21 05:56:20 AST 1969
-14159020000

这里的输出中的“GMT”和“AST”缩写非常不幸——java.util.TimeZone并非在所有情况下都具有1970年之前值的正确名称。不过时机已经成熟。

常见问题

如何将Date日期转换为其他时区?

你没有——因为约会没有时区。这是一个瞬间。不要被toString()的输出所愚弄。这会显示默认时区中的瞬间。这不是值的一部分。

如果代码以日期作为输入,则已经发生了从“本地时区”到即时的任何转换。(希望操作正确……)

如果您开始编写一个带有这样签名的方法,那么您并没有帮助自己:

// A method like this is always wrong
Date convertTimeZone(Date input, TimeZone fromZone, TimeZone toZone)

如何将Date日期转换为其他格式?

你没有——因为日期没有格式。不要被toString()的输出所愚弄。始终使用相同的格式,如文档所述。要以特定方式格式化日期,请使用合适的日期格式(可能是SimpleDataFormat)——记住将时区设置为适合您使用的适当区域。

加载全部内容

相关教程
猜你喜欢
用户评论