1 引言
SimpleDateFormat (java.text.SimpleDateFormat ) 可以将 Date (java.util.Date) 对象格式化成字符串(如 “2022-06-23 04:32:16”),也可以将字符串解析成 Date 对象(下文将这 2 种操作统称为转换时间)。Date 对象代表一个确定时刻,但不存储或代表时区,所以 SimpleDateFormat 转换时间时需要知道时区信息。即将 Date 对象格式化成字符串时,需要知道格式化成哪个时区的时间,而将字符串解析成 Date 对象时,需要知道字符串代表哪个时区的时间。
2 SimpleDateFormat 使用时区的方式
SimpleDateFormat 按以下方式使用时区来转换时间:
- 格式化时间
- SimpleDateFormat 对象拥有 timeZone 属性(对应 getTimeZone/setTimeZone 方法),该属性代表时区。用 setTimeZone 方法设置 timeZone 属性,则 format 方法会把 Date 对象格式化成 timeZone 属性代表的时区的时间。
- timeZone 属性默认值为 java.util.TimeZone.getDefault() 【待核实】
解析时间
- 在时间模式中指定时区字符(z, Z, X),在时间字符串中指定时区,则 SimpleDateFormat.parse 方法会按照时间字符串中的时区来解释时间字符串中的时间。例如,对于时间模式 “yyyy-MM-dd HH:mm:ssZ”,和时间字符串 “2022-06-23 05:32:16+0100”,SimpleDateFormat.parse 方法会把时间解释成东1区 “2022-06-23 05:32:16”。
若时间模式中不包含时区字符,则 SimpleDateFormat.parse 方法会按照 timeZone 属性代表的时区来解释时间字符串中的时间。
3 示例
源码:
static void testSimpleDateFormatOnTimeZone() throws ParseException {
long unixMilliSeconds = 1655958736000L;
Date date = new Date(unixMilliSeconds);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
System.out.println("【用默认时区格式化时间】");
System.out.println("默认时区: " + dateFormat.getTimeZone().getID());
System.out.println(date.getTime() + " -> " + dateFormat.format(date));
System.out.println("\n【用指定时区格式化时间】");
String[] timezones = {"GMT+00:00", "GMT+01:00", "GMT-01:00"};
for (String timezone : timezones) {
dateFormat.setTimeZone(TimeZone.getTimeZone(timezone));
System.out.printf("%d(%s) -> %s%n", date.getTime(), timezone, dateFormat.format(date));
}
System.out.println("\n【解析带时区的时间】");
String[] dateStrings = {"2022-06-23 04:32:16+0000", "2022-06-23 05:32:16+0100", "2022-06-23 03:32:16-0100"};
for (String dateString : dateStrings) {
date = dateFormat.parse(dateString);
System.out.println(dateString + " -> " + date.getTime());
}
System.out.println("\n【用指定时区解析不带时区的时间】");
dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateStrings = new String[] {"2022-06-23 04:32:16", "2022-06-23 05:32:16", "2022-06-23 03:32:16"};
for (int i = 0; i < dateStrings.length; i++) {
String dateString = dateStrings[i];
String timezone = timezones[i];
dateFormat.setTimeZone(TimeZone.getTimeZone(timezone));
date = dateFormat.parse(dateString);
System.out.printf("%s(%s) -> %d%n", dateString, timezone, date.getTime());
}
}
输出: ``` 【用默认时区格式化时间】 默认时区: Asia/Shanghai 1655958736000 -> 2022-06-23 12:32:16+0800
【用指定时区格式化时间】 1655958736000(GMT+00:00) -> 2022-06-23 04:32:16+0000 1655958736000(GMT+01:00) -> 2022-06-23 05:32:16+0100 1655958736000(GMT-01:00) -> 2022-06-23 03:32:16-0100
【解析带时区的时间】 2022-06-23 04:32:16+0000 -> 1655958736000 2022-06-23 05:32:16+0100 -> 1655958736000 2022-06-23 03:32:16-0100 -> 1655958736000
【用指定时区解析不带时区的时间】 2022-06-23 04:32:16(GMT+00:00) -> 1655958736000 2022-06-23 05:32:16(GMT+01:00) -> 1655958736000 2022-06-23 03:32:16(GMT-01:00) -> 1655958736000 ```