60

代码:

 SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss z");
    sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
    System.out.println(new Date());
    try {
        String d = sdf.format(new Date());
        System.out.println(d);
        System.out.println(sdf.parse(d));
    } catch (Exception e) {
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    }

输出:

Thu Aug 08 17:26:32 GMT+08:00 2013
2013.08.08 09:26:32 GMT
Thu Aug 08 17:26:32 GMT+08:00 2013

请注意,format()格式Date正确为 GMT,但parse()丢失了 GMT 详细信息。我知道我可以使用substring()和解决这个问题,但这种现象背后的原因是什么?

这是一个没有任何答案的重复问题。

编辑:让我以另一种方式提出问题,检索 Date 对象以使其始终处于 GMT 的方式是什么?

4

3 回答 3

62

我只需要这个:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));

SimpleDateFormat sdfLocal = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");

try {
    String d = sdf.format(new Date());
    System.out.println(d);
    System.out.println(sdfLocal.parse(d));
} catch (Exception e) {
    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
}

输出:有点可疑,但我只希望日期保持一致

2013.08.08 11:01:08
Thu Aug 08 11:01:08 GMT+08:00 2013
于 2013-08-08T11:04:07.497 回答
9
于 2017-09-04T00:19:37.913 回答
8

正如他所说,OP 对他的问题的解决方案有可疑的输出。该代码仍然显示出对时间表示的混淆。为了消除这种混乱,并制作不会导致错误时间的代码,请考虑他所做的扩展:

public static void _testDateFormatting() {
    SimpleDateFormat sdfGMT1 = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
    sdfGMT1.setTimeZone(TimeZone.getTimeZone("GMT"));
    SimpleDateFormat sdfGMT2 = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss z");
    sdfGMT2.setTimeZone(TimeZone.getTimeZone("GMT"));

    SimpleDateFormat sdfLocal1 = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
    SimpleDateFormat sdfLocal2 = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss z");

    try {
        Date d = new Date();
        String s1 = d.toString();
        String s2 = sdfLocal1.format(d);
        // Store s3 or s4 in database.
        String s3 = sdfGMT1.format(d);
        String s4 = sdfGMT2.format(d);
        // Retrieve s3 or s4 from database, using LOCAL sdf.
        String s5 = sdfLocal1.parse(s3).toString();
        //EXCEPTION String s6 = sdfLocal2.parse(s3).toString();
        String s7 = sdfLocal1.parse(s4).toString();
        String s8 = sdfLocal2.parse(s4).toString();
        // Retrieve s3 from database, using GMT sdf.
        // Note that this is the SAME sdf that created s3.
        Date d2 = sdfGMT1.parse(s3);
        String s9 = d2.toString();
        String s10 = sdfGMT1.format(d2);
        String s11 = sdfLocal2.format(d2);
    } catch (Exception e) {
        e.printStackTrace();
    }       
}

在调试器中检查值:

s1  "Mon Sep 07 06:11:53 EDT 2015" (id=831698113128)    
s2  "2015.09.07 06:11:53" (id=831698114048) 
s3  "2015.09.07 10:11:53" (id=831698114968) 
s4  "2015.09.07 10:11:53 GMT+00:00" (id=831698116112)   
s5  "Mon Sep 07 10:11:53 EDT 2015" (id=831698116944)    
s6  -- omitted, gave parse exception    
s7  "Mon Sep 07 10:11:53 EDT 2015" (id=831698118680)    
s8  "Mon Sep 07 06:11:53 EDT 2015" (id=831698119584)    
s9  "Mon Sep 07 06:11:53 EDT 2015" (id=831698120392)    
s10 "2015.09.07 10:11:53" (id=831698121312) 
s11 "2015.09.07 06:11:53 EDT" (id=831698122256) 

sdf2 和 sdfLocal2 包括时区,所以我们可以看到真正发生了什么。s1 和 s2 位于美国东部夏令时间 06:11:53。s3 和 s4 位于格林威治标准时间区的 10:11:53 - 相当于原始 EDT 时间。想象一下,我们将 s3 或 s4 保存在数据库中,我们使用 GMT 来保持一致性,因此我们可以从世界任何地方获取时间,而无需存储不同的时区。

s5 解析 GMT 时间,但将其视为本地时间。所以它说“10:11:53”——格林威治标准时间——但认为它是当地时间的10:11:53。不好。

s7 解析 GMT 时间,但忽略字符串中的 GMT,因此仍将其视为本地时间。

s8 有效,因为现在我们在字符串中包含 GMT,并且本地区域解析器使用它从一个时区转换为另一个时区。

现在假设您不想存储区域,您希望能够解析 s3,但将其显示为本地时间。答案是使用存储它的同一时区进行解析——因此使用与它在 sdfGMT1 中创建时相同的 sdf。s9、s10 和 s11 都是原始时间的表示。他们都是“正确的”。也就是说,d2 == d1。那么这只是你想如何显示它的问题。如果你想显示存储在 DB 中的内容——GMT 时间——那么你需要使用 GMT sdf 对其进行格式化。这是s10。

所以这是最终的解决方案,如果您不想在字符串中显式存储“GMT”,并希望以 GMT 格式显示:

public static void _testDateFormatting() {
    SimpleDateFormat sdfGMT1 = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
    sdfGMT1.setTimeZone(TimeZone.getTimeZone("GMT"));

    try {
        Date d = new Date();
        String s3 = sdfGMT1.format(d);
        // Store s3 in DB.
        // ...
        // Retrieve s3 from database, using GMT sdf.
        Date d2 = sdfGMT1.parse(s3);
        String s10 = sdfGMT1.format(d2);
    } catch (Exception e) {
        e.printStackTrace();
    }       
}
于 2015-09-07T10:44:59.057 回答