从字符串解析时区使用的SimpleDateFormat偏移(Parsing timezone fro

2019-10-24 12:48发布

决定要求这一点,因为我无法找到StackOverflow的一个类似的例子。

我想分析使用SimpleDateFormat的日期字符串和时区。 我(希望)我仔细阅读文档,并写了这个程序,重复的问题。

import java.text.DateFormat;
import java.util.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;

public class SDF {

  private static final String FORMAT = "EEE, d MMM yyyy HH:mm:ss Z";  

  public static void main(String[] args) throws ParseException {
    DateFormat formatter = new SimpleDateFormat(FORMAT, Locale.ENGLISH);
    formatter.setLenient(false);
    String dateString = args[0];

    System.out.println(" Format: " + FORMAT);
    Date date = formatter.parse(dateString);
    System.out.println(" Parsed time in millis: " + date.getTime());
    System.out.println(" Parsed timezone: " +  formatter.getTimeZone().getDisplayName());
    System.out.println(" Parsed offset: " + formatter.getTimeZone().getRawOffset() / 1000 / 60 / 60 + "hrs.");
    }
}

如果我使用“EDT”或在我的输入字符串任何其他支持时区标志,然后调用getTimeZone获取()在DateFormat对象上返回正确的时区和原始的GMT偏移量。

$ java SDF "Thu, 1 Jan 2015 00:00:00 EDT"
  Parsed time in millis: 1420084800000
  Parsed timezone: Eastern Standard Time
  Parsed offset: -5hrs.

$ java SDF "Thu, 1 Jan 2015 00:00:00 PST"
  Parsed time in millis: 1420099200000
  Parsed timezone: Pacific Standard Time
  Parsed offset: -8hrs.

然而,当我使用+0000符号,日期millisconds返回正确的,因为在UTC纪元的时间,但该时区始终默认为我的本地时区。

$ java SDF "Thu, 1 Jan 2015 00:00:00 +0000"
  Parsed time in millis: 1420070400000
  Parsed timezone: Central European Time
  Parsed offset: 1hrs.

$ java SDF "Thu, 1 Jan 2015 00:00:00 -0800"
  Parsed time in millis: 1420099200000
  Parsed timezone: Central European Time
  Parsed offset: 1hrs.

这是否意味着我只能在输入字符串使用“EDT”,“BST”还是我误用SimpleDateFormat的API?

Answer 1:

当使用时区说明符,如“+0000”和“-0800”,DateFormat类将解析日期字符串,尊重ZoneOffset,因为你已经通过比较,因为时代的米利斯证明。 然而,日期格式的内部时区不会被改变!

现在,这里是奇数位。 如果您使用的时区修饰符如GMT或PST,这将在实际的DateFormat的内部时区改变。 这是由我的程序演示了,但我不知道这点是什么。 我相信你是期待DateFormat对象,以反映“最后的解析”日期的时区滥用API,但您的代码以及矿山节目,这是情况并非如此。 事实上, Java文档的DateFormat.parse()没有提及该怎么办TimeZone的格式会改变,所以我们不应该依赖这个“功能”。

事实上,如果我们检查上可用的API Date对象,我们发现的时区支持是真的很差。 注意:在我的程序, Date.toString()给出了相同的输出,无论解析输入字符串。 Java的通过自嘲的认识到这一点很早就Date.getTimezoneOffset()在Java 1.1的方法。 得出的结论是, Date对象只表示从时代米利斯-无时区支持!

这种古怪的行为,以及其他许多这样的例子,这就是为什么你应该避免Java 7的日期和时间处理类。 从对Java 7的日期甲骨文网站:

一些日期和时间类[Java中7]也表现出相当差的API设计。

如果你能使用Java 8,你会发现类的行为java.time包更好的设计。 我已经在我的程序给出一个例子。 如果你不能移动到Java 8,然后乔达时间是要走的路。 下面有说明如何解析,甚至后,时区信息被记住和尊敬的一个Java 8例。 乔达时间的作品一样好,而这些方法的执行将避免你在这里面临的问题。

我的程序:

package com.company;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;

public class Main {

    private static final String FORMAT = "EEE, d MMM yyyy HH:mm:ss Z";

    public static void main(String[] args) throws ParseException {
        DateFormat formatter = new SimpleDateFormat(FORMAT, Locale.ENGLISH);
        formatter.setLenient(false);
        String dateString = "Thu, 1 Jan 2015 00:00:00 EDT";
        String dateString2 = "Thu, 1 Jan 2015 00:00:00 PST";
        String dateString3 = "Thu, 1 Jan 2015 00:00:00 +0000";
        String dateString4 = "Thu, 1 Jan 2015 00:00:00 -0800";


        runParseTest(dateString, formatter);
        runParseTest(dateString2, formatter);
        runParseTest(dateString3, formatter);
        runParseTest(dateString4, formatter);

        runJava8Test();
    }

    private static void runParseTest(String dateString, DateFormat formatter) throws ParseException {
        System.out.println(" Format: " + FORMAT);
        System.out.println(" Formatter time zone: " + formatter.getTimeZone().getDisplayName());
        System.out.println(" Parse String: " + dateString);
        Date date = formatter.parse(dateString);
        System.out.println(" Formatter time zone: " + formatter.getTimeZone().getDisplayName());
        System.out.println(" Parsed time in millis: " + date.getTime());
        System.out.println(" Parsed date: " +  date.toString());
        System.out.println();
    }

    private static void runJava8Test() {
        OffsetDateTime parsed = OffsetDateTime
                .parse(
                        "Thu, 1 Jan 2015 00:00:00 -1300",
                        DateTimeFormatter.ofPattern(FORMAT)
                );

        System.out.println(" Java 8 parsed offset: " + parsed.getOffset().toString());
    }
}

和输出:

 Format: EEE, d MMM yyyy HH:mm:ss Z
 Formatter time zone: Greenwich Mean Time
 Parse String: Thu, 1 Jan 2015 00:00:00 EDT
 Formatter time zone: Eastern Standard Time
 Parsed time in millis: 1420084800000
 Parsed date: Thu Jan 01 04:00:00 GMT 2015

 Format: EEE, d MMM yyyy HH:mm:ss Z
 Formatter time zone: Eastern Standard Time
 Parse String: Thu, 1 Jan 2015 00:00:00 PST
 Formatter time zone: Pacific Standard Time
 Parsed time in millis: 1420099200000
 Parsed date: Thu Jan 01 08:00:00 GMT 2015

 Format: EEE, d MMM yyyy HH:mm:ss Z
 Formatter time zone: Pacific Standard Time
 Parse String: Thu, 1 Jan 2015 00:00:00 +0000
 Formatter time zone: Pacific Standard Time
 Parsed time in millis: 1420070400000
 Parsed date: Thu Jan 01 00:00:00 GMT 2015

 Format: EEE, d MMM yyyy HH:mm:ss Z
 Formatter time zone: Pacific Standard Time
 Parse String: Thu, 1 Jan 2015 00:00:00 -0800
 Formatter time zone: Pacific Standard Time
 Parsed time in millis: 1420099200000
 Parsed date: Thu Jan 01 08:00:00 GMT 2015

 Java 8 parsed offset: -13:00


文章来源: Parsing timezone from a string with offset using SimpleDateFormat