Java 8 SimpleDateFormat 中可能存在错误?
Possible bug in Java 8 SimpleDateFormat?
Java8这里,我有如下代码:
public class PossibleBug {
public static void main(String[] args) {
new PossibleBug().run();
}
public void run() {
buildDate("20181205");
}
public Date buildDate(final String yyyyMmDd) throws ParseException {
TimeZone expectedTz = TimeZone.getTimeZone("America/New_York");
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.setTimeZone(expectedTz);
TimeZone actualTz = sdf.getTimeZone();
Date answer = sdf.parse(yyyyMmDd);
return answer;
}
}
非常基本的东西:
- 创建一个
SimpleDateFormat
并将其时区设置为 EST
- 使用 SDF 解析日期字符串
- 结果应该也是美国东部标准时间
然而在运行时,查看调试器结果:
这怎么可能?!?! sdf.parse(yyyyMmDd)
正在返回 GMT 格式的日期。是不是我遗漏了什么,或者这是 SimpleDateFormat
中的错误?
我可以从另一个 class 中调用 buildDate
和 运行 它并且它似乎工作正常:
如果你看一下 the Java-Doc for SimpleDateFormat.parse()
,你会发现 TimeZone 可能被覆盖了:
The TimeZone
value may be overwritten, depending on the given pattern and the time zone value in text
. Any TimeZone
value that has previously been set by a call to setTimeZone
may need to be restored for further operations.
documentation 说:"This parsing operation uses the calendar to produce a Date. All of the calendar's date-time fields are cleared before parsing, and the calendar's default values of the date-time fields are used for any missing date-time information. For example, the year value of the parsed Date is 1970 with GregorianCalendar if no year value is given from the parsing operation. The TimeZone value may be overwritten, depending on the given pattern and the time zone value in text. Any TimeZone value that has previously been set by a call to setTimeZone may need to be restored for further operations."
简而言之,SimpleDateFormat
是一个 formatter/parser,不是执行时区转换的实用程序。如果您正在解析的字符串中没有 TZ,您将从 Calendar
.
中获取默认值
考虑一下如果您调用 setTimeZone,
然后解析一个实际上包含时区本身的字符串会发生什么?您希望发生什么?
另外,请注意 Date
不包含时区。它被明确定义为自 1970 年 1 月 1 日 00:00 UTC 以来的毫秒数。库函数在需要时应用时区(例如转换为 String
时),如果您不指定时区,您将获得默认时区。你看到格林威治标准时间是因为你的默认时区是格林威治标准时间,或者因为你的 IDE 总是以格林威治标准时间显示 Date
对象,而说他得到美国东部标准时间的人必须将默认时区设置为美国东部标准时间。
在您的例子中,您正在解析一个根本不包含时区的字符串。事实上,它甚至不包含时间。使用 Date
来处理日期(我意识到这很混乱,我指的是没有时间的日期),可能会导致错误,尤其是当您的默认时区不是 UTC/GMT 时。我建议使用 LocalDate
和 LocalDate.parse
方法。
Date
不存储时区。它本质上只是一个 long
的包装器,在纪元后存储毫秒。
当您打印它时(或者当您的调试器调用 toString()
方法来获取要显示的字符串表示形式时),无论它是如何创建的,都会使用您的 JVM 的默认时区。
Date
,尽管有这个名字,但并没有模拟日期:它是一个 instant 时间。
鉴于您的输入是 "20181205"
,请不要使用 Date
:使用 java.time
中的 类,例如 java.time.LocalDate
。
Java8这里,我有如下代码:
public class PossibleBug {
public static void main(String[] args) {
new PossibleBug().run();
}
public void run() {
buildDate("20181205");
}
public Date buildDate(final String yyyyMmDd) throws ParseException {
TimeZone expectedTz = TimeZone.getTimeZone("America/New_York");
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.setTimeZone(expectedTz);
TimeZone actualTz = sdf.getTimeZone();
Date answer = sdf.parse(yyyyMmDd);
return answer;
}
}
非常基本的东西:
- 创建一个
SimpleDateFormat
并将其时区设置为 EST - 使用 SDF 解析日期字符串
- 结果应该也是美国东部标准时间
然而在运行时,查看调试器结果:
这怎么可能?!?! sdf.parse(yyyyMmDd)
正在返回 GMT 格式的日期。是不是我遗漏了什么,或者这是 SimpleDateFormat
中的错误?
我可以从另一个 class 中调用 buildDate
和 运行 它并且它似乎工作正常:
如果你看一下 the Java-Doc for SimpleDateFormat.parse()
,你会发现 TimeZone 可能被覆盖了:
The
TimeZone
value may be overwritten, depending on the given pattern and the time zone value intext
. AnyTimeZone
value that has previously been set by a call tosetTimeZone
may need to be restored for further operations.
documentation 说:"This parsing operation uses the calendar to produce a Date. All of the calendar's date-time fields are cleared before parsing, and the calendar's default values of the date-time fields are used for any missing date-time information. For example, the year value of the parsed Date is 1970 with GregorianCalendar if no year value is given from the parsing operation. The TimeZone value may be overwritten, depending on the given pattern and the time zone value in text. Any TimeZone value that has previously been set by a call to setTimeZone may need to be restored for further operations."
简而言之,SimpleDateFormat
是一个 formatter/parser,不是执行时区转换的实用程序。如果您正在解析的字符串中没有 TZ,您将从 Calendar
.
考虑一下如果您调用 setTimeZone,
然后解析一个实际上包含时区本身的字符串会发生什么?您希望发生什么?
另外,请注意 Date
不包含时区。它被明确定义为自 1970 年 1 月 1 日 00:00 UTC 以来的毫秒数。库函数在需要时应用时区(例如转换为 String
时),如果您不指定时区,您将获得默认时区。你看到格林威治标准时间是因为你的默认时区是格林威治标准时间,或者因为你的 IDE 总是以格林威治标准时间显示 Date
对象,而说他得到美国东部标准时间的人必须将默认时区设置为美国东部标准时间。
在您的例子中,您正在解析一个根本不包含时区的字符串。事实上,它甚至不包含时间。使用 Date
来处理日期(我意识到这很混乱,我指的是没有时间的日期),可能会导致错误,尤其是当您的默认时区不是 UTC/GMT 时。我建议使用 LocalDate
和 LocalDate.parse
方法。
Date
不存储时区。它本质上只是一个 long
的包装器,在纪元后存储毫秒。
当您打印它时(或者当您的调试器调用 toString()
方法来获取要显示的字符串表示形式时),无论它是如何创建的,都会使用您的 JVM 的默认时区。
Date
,尽管有这个名字,但并没有模拟日期:它是一个 instant 时间。
鉴于您的输入是 "20181205"
,请不要使用 Date
:使用 java.time
中的 类,例如 java.time.LocalDate
。