gpt4 book ai didi

java - 使用 SimpleDateFormat 从带有偏移量的字符串中解析时区

转载 作者:行者123 更新时间:2023-11-30 08:01:47 31 4
gpt4 key购买 nike

决定问这个,因为我在 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”或任何其他受支持的时区指示符,则对 dateFormat 对象调用 getTimeZone() 将返回正确的时区以及相对于 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 表示法时,日期毫秒会正确返回为 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?

最佳答案

当使用时区说明符(例如“+0000”和“-0800”)时,DateFormat 类将解析日期字符串并尊重 ZoneOffset,正如您通过比较自纪元以来的毫秒数所证明的那样。但是,DateFormat 的内部时区不会改变!

现在奇怪的事情来了。如果您使用 GMT 或 PST 等时区说明符,这实际上会改变 DateFormat 的内部时区。我的程序证明了这一点,但我不确定这是什么意思。我相信您通过期望 DateFormat 对象的 TimeZone 反射(reflect)“最后解析的”日期来滥用 API,但正如您的代码和我的代码所示,情况并非如此。事实上,Java Doc for DateFormat.parse() 没有提及格式化程序的 TimeZone 将如何改变,因此我们不应该依赖这个“功能”。

事实上,如果我们检查 Date 对象上可用的 API,我们会发现 TimeZone 支持确实很差。请注意,在我的程序中,无论解析的输入字符串如何,Date.toString() 都会给出相同的输出。 Java 很早就认识到了这一点,在 Java 1.1 中弃用了 Date.getTimezoneOffset() 方法。 结论是,Date 对象仅代表纪元中的毫秒 - 不支持 TimeZone!

这种奇怪的行为以及许多其他此类示例就是您应该避免使用 Java 7 日期和时间处理类的原因。来自 Oracle website on Java 7 Dates:

Some of the date and time classes [in Java 7] also exhibit quite poor API design.

如果您能够使用 Java 8,您会发现 java.time 包中的类的行为设计得更好。我在我的程序中举了一个例子。如果您无法迁移到 Java 8,则 Joda time是要走的路。下面有一个 Java 8 示例,展示了即使在解析之后,时区信息也是如何被记住和尊重的。 Joda Time 也同样有效,这两种方法都可以避免您在这里遇到的问题。

我的程序:

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

关于java - 使用 SimpleDateFormat 从带有偏移量的字符串中解析时区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31818533/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com