>为什么:当我给出带有GMT时区的输入日期字符串时,SimpleDateFormat
解析它并输出EET时区?
public static String DATE_FORMAT="dd MMM yyyy hh:mm:ss z";
public static String CURRENT_DATE_STRING ="31 October 2011 11:19:56 GMT";
...
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_FORMAT, Locale.US);
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(simpleDateFormat.parseObject(CURRENT_DATE_STRING));
输出为:
周一 10月 31 13:19:56 EET 2011
而不是
2011年10月31日星期一 13:19:56 GMT
您正在打印Date.toString()
的结果。Date
没有任何时区的概念 - 它只是自UTC Unix纪元以来的毫秒数。 Date.toString()
始终使用系统默认时区。
请注意,您不应该期待"2011 年 10 月 31 日星期一 13:19:56 GMT",因为您给出的时间指定了 GMT 小时 11,而不是 13。
如果要使用特定时区进行打印,则应使用其他DateFormat
进行打印,而不是使用 Date.toString()
。(Date.toString()
不断造成这样的混乱;这真的很不幸。
java.util.Date
不保存时区信息。
java.util.Date
对象仅表示自称为"纪元"的标准基准时间(即 1970 年 1 月 1 日 00:00:00 GMT(或 UTC((以来的毫秒数。由于它不保存任何时区信息,因此其 toString
函数应用 JVM 的时区以从此毫秒值派生的格式 EEE MMM dd HH:mm:ss zzz yyyy
返回String
。要以不同的格式和时区获取java.util.Date
对象的String
表示形式,您需要使用具有所需格式和适用时区的SimpleDateFormat
。
除此之外,您的代码还存在一些问题:
- 使用
H
而不是h
表示 24 小时制格式。字母h
用于 12 小时格式(即带有 AM/PM 标记(。 - 尽管
MMM
用于用SimpleDateFormat
解析月份的长名称(例如一月(,但它适用于 3 个字母的月份名称(例如 Jan(。如果您尝试使用现代日期时间 API 执行此操作,您将看到DateTimeParseException
.您应该使用MMMM
作为月份的长名称。
包含以下几点的演示:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
String strDateTime = "31 October 2011 11:19:56 GMT";
SimpleDateFormat sdf = new SimpleDateFormat("dd MMMM yyyy HH:mm:ss z", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
Date date = sdf.parse(strDateTime);
String strDate = sdf.format(date);
System.out.println(strDate);
// Some other format
sdf = new SimpleDateFormat("MMMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
strDate = sdf.format(date);
System.out.println(strDate);
// The last format with some other timezone
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
strDate = sdf.format(date);
System.out.println(strDate);
}
}
输出:
31 October 2011 11:19:56 GMT
October 31 11:19:56 GMT 2011
October 31 07:19:56 EDT 2011
在线演示
Switch to java.time
API.
java.util
日期时间 API 及其格式设置 API SimpleDateFormat
已过时且容易出错。建议完全停止使用它们,并切换到现代日期-时间 API*。
使用 java.time
的解决方案,现代日期时间 API:
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String strDateTime = "31 October 2011 11:19:56 GMT";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd MMMM uuuu HH:mm:ss z", Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtf);
System.out.println(zdt);
// Some other format
DateTimeFormatter dtfAnother = DateTimeFormatter.ofPattern("MMMM dd HH:mm:ss z uuuu", Locale.ENGLISH);
String strDate = dtfAnother.format(zdt);
System.out.println(strDate);
}
}
输出:
2011-10-31T11:19:56Z[GMT]
October 31 11:19:56 GMT 2011
在线演示
输出中的Z
是零时区偏移量的时区指示符。它代表祖鲁语,并指定Etc/UTC
时区(时区偏移量为 +00:00
小时(。
要了解有关现代日期-时间 API 的更多信息,请参阅跟踪:日期时间。
<小时 />出于任何原因,如果你必须坚持使用Java 6或Java 7,你可以使用ThreeTen-Backport,它将大部分java.time功能向后移植到Java 6和7。如果您正在为 Android 项目工作,并且您的 Android API 级别仍然不符合 Java-8,请查看通过脱糖提供的 Java 8+ API 和如何在 Android Project 中使用 ThreeTenABP。