- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
决定问这个,因为我在 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/
如何使用 SPListCollection.Add(String, String, String, String, Int32, String, SPListTemplate.QuickLaunchO
我刚刚开始使用 C++ 并且对 C# 有一些经验,所以我有一些一般的编程经验。然而,似乎我马上就被击落了。我试过在谷歌上寻找,以免浪费任何人的时间,但没有结果。 int main(int argc,
这个问题已经有答案了: In Java 8 how do I transform a Map to another Map using a lambda? (8 个回答) Convert a Map>
我正在使用 node + typescript 和集成的 swagger 进行 API 调用。我 Swagger 提出以下要求 http://localhost:3033/employees/sear
我是 C++ 容器模板的新手。我收集了一些记录。每条记录都有一个唯一的名称,以及一个字段/值对列表。将按名称访问记录。字段/值对的顺序很重要。因此我设计如下: typedef string
我需要这两种方法,但j2me没有,我找到了一个replaceall();但这是 replaceall(string,string,string); 第二个方法是SringBuffer但在j2me中它没
If string is an alias of String in the .net framework为什么会发生这种情况,我应该如何解释它: type JustAString = string
我有两个列表(或字符串):一个大,另一个小。 我想检查较大的(A)是否包含小的(B)。 我的期望如下: 案例 1. B 是 A 的子集 A = [1,2,3] B = [1,2] contains(A
我有一个似乎无法解决的小问题。 这里...我有一个像这样创建的输入... var input = $(''); 如果我这样做......一切都很好 $(this).append(input); 如果我
我有以下代码片段 string[] lines = objects.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.No
这可能真的很简单,但我已经坚持了一段时间了。 我正在尝试输出一个字符串,然后输出一个带有两位小数的 double ,后跟另一个字符串,这是我的代码。 System.out.printf("成本:%.2
以下是 Cloud Firestore 列表查询中的示例之一 citiesRef.where("state", ">=", "CA").where("state", "= 字符串,我们在Stack O
我正在尝试检查一个字符串是否包含在另一个字符串中。后面的代码非常简单。我怎样才能在 jquery 中做到这一点? function deleteRow(locName, locID) { if
这个问题在这里已经有了答案: How to implement big int in C++ (14 个答案) 关闭 9 年前。 我有 2 个字符串,都只包含数字。这些数字大于 uint64_t 的
我有一个带有自定义转换器的 Dozer 映射: com.xyz.Customer com.xyz.CustomerDAO customerName
这个问题在这里已经有了答案: How do I compare strings in Java? (23 个回答) 关闭 6 年前。 我想了解字符串池的工作原理以及一个字符串等于另一个字符串的规则是
我已阅读 this问题和其他一些问题。但它们与我的问题有些无关 对于 UILabel 如果你不指定 ? 或 ! 你会得到这样的错误: @IBOutlet property has non-option
这两种方法中哪一种在理论上更快,为什么? (指向字符串的指针必须是常量。) destination[count] 和 *destination++ 之间的确切区别是什么? destination[co
This question already has answers here: Closed 11 years ago. Possible Duplicates: Is String.Format a
我有一个Stream一个文件的,现在我想将相同的单词组合成 Map这很重要,这个词在 Stream 中出现的频率. 我知道我必须使用 collect(Collectors.groupingBy(..)
我是一名优秀的程序员,十分优秀!