Java 时区的时间格式
Java time format for time zone
我正在尝试获取格式为 (String
) 的日期输出:
20170801 123030 America/Los_Angeles
但使用此代码:
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd hhmmss Z", Locale.US);
sdf.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
System.out.println(sdf.format(new java.util.Date()));
我得到的输出为(注意区域部分):
20174904 024908 -0700
知道如何解决吗?我需要打印 "America/Los_Angeles"
而不是 "-0700"
.
看起来 SimpleDateFormat 不支持您想要的。
以下是可能的格式:
z Time zone General time zone Pacific Standard Time; PST; GMT-08:00
Z Time zone RFC 822 time zone -0800
X Time zone ISO 8601 time zone -08; -0800; -08:00
您可以在格式化日期后添加 "America/Los_Angeles":
TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
DateFormat sdf = new SimpleDateFormat("yyyyMMdd hhmmss", Locale.US);
sdf.setTimeZone(timeZone);
System.out.println(sdf.format(new Date()) + " " + timeZone.getID());
DateFormat sdfWithTimeZone = new SimpleDateFormat("yyyyMMdd hhmmss zzzz", Locale.US);
sdfWithTimeZone.setTimeZone(timeZone);
System.out.println(sdfWithTimeZone.format(new Date()));
输出:
20171004 031611 America/Los_Angeles
20171004 031611 Pacific Daylight Time
如果可以使用Java8,可以使用DateTimeFormatter
及其符号V
来显示Zone ID:
Instant now = Instant.now();
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd hhmmss VV")
.withLocale(Locale.US)
.withZone(ZoneId.of("America/Los_Angeles"));
System.out.println(fmt.format(now));
打印:
20171004 032552 America/Los_Angeles
注意 SimpleDateFormat
doesn't support this flag as mentioned in .
如果您有从java.util.Date
开始但仍然可以使用Java 8,您可以先将其转换为Instant
:
Instant now = new java.util.Date().toInstant();
...
正如 所指出的,SimpleDateFormat
中没有内置模式来打印时区 ID。但是有一种方法可以覆盖它。
首先,您使用 z
模式创建一个格式化程序,它对应于时区短名称。 我不确定区域设置是否对此很重要(我知道它会影响长名称,不确定短名称,但无论如何我都会保留它)。
然后我从格式化程序中获取 java.text.DateFormatSymbols
并覆盖对应于短名称的字符串:
// use "z" (short timezone name)
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd hhmmss z", Locale.US);
sdf.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
// get the java.text.DateFormatSymbols
DateFormatSymbols symbols = sdf.getDateFormatSymbols();
// get the zones names
String[][] zones = symbols.getZoneStrings();
// overwrite zone short names
for (int i = 0; i < zones.length; i++) {
String zoneId = zones[i][0];
if ("America/Los_Angeles".equals(zoneId)) {
zones[i][2] = zoneId; // short name for standard time
zones[i][4] = zoneId; // short name for Daylight Saving Time
}
}
// update the symbols in the formatter
symbols.setZoneStrings(zones);
sdf.setDateFormatSymbols(symbols);
System.out.println(sdf.format(new java.util.Date()));
这将打印:
20171005 045317 America/Los_Angeles
请注意,我只更改了 America/Los_Angeles
时区的时区名称。您可以修改 if
以更改您想要的任何区域 - 或者只需删除 if
以更改所有区域。
另一个细节是您使用 hh
的时间。 According to javadoc,这是 am/pm 字段中的 小时(值从 1 到 12)。如果没有 AM/PM 指示符(模式 a
),输出可能不明确。如果需要,您可以将其更改为 HH
( 天中的小时 字段,值从 0 到 23)或 kk
(值从 1 到 24)。
Java新Date/TimeAPI
旧的 类(Date
、Calendar
和 SimpleDateFormat
)有 lots of problems and design issues,它们正在被新的 APIs.
如果您正在使用 Java 8,请考虑使用 new java.time API. It's easier, less bugged and less error-prone than the old APIs.
如果您使用 Java 6 或 7,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP (more on how to use it ).
下面的代码适用于两者。
唯一的区别是包名称(在 Java 8 中是 java.time
,在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp
),但是 类和方法名称相同。
实际上,这个新的 API 非常简单,代码将与@Juan 和@Jens 发布的其他答案完全相同。但它们之间存在细微差别。
假设我有 2 个不同的 ZonedDateTime
对象:一个代表 America/Los_Angeles
时区中的当前 date/time,另一个代表 [=] 中相同的当前 date/time 31=] 时区:
// current date/time
Instant now = Instant.now();
// get the same instant in different timezones
ZonedDateTime nowLA = now.atZone(ZoneId.of("America/Los_Angeles"));
ZonedDateTime nowTokyo = now.atZone(ZoneId.of("Asia/Tokyo"));
System.out.println(nowLA); // 2017-10-05T05:04:31.253-07:00[America/Los_Angeles]
System.out.println(nowTokyo); // 2017-10-05T21:04:31.253+09:00[Asia/Tokyo]
这些日期是:
2017-10-05T05:04:31.253-07:00[America/Los_Angeles]
2017-10-05T21:04:31.253+09:00[Asia/Tokyo]
现在让我们看看区别。 在格式化程序中设置时区。这意味着格式化时所有日期都将转换为该特定时区(我只是稍微修改了代码,直接设置语言环境 - 而不是使用 withLocale
- 但生成的格式化程序是等效的):
// set the timezone in the formatter
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd hhmmss VV", Locale.US)
// use Los Angeles timezone
.withZone(ZoneId.of("America/Los_Angeles"));
// it converts all dates to Los Angeles timezone
System.out.println(nowLA.format(fmt)); // 20171005 050431 America/Los_Angeles
System.out.println(nowTokyo.format(fmt)); // 20171005 050431 America/Los_Angeles
由于在格式化程序中设置了时区,因此两个日期都转换为该时区(包括日期和时间值):
20171005 050431 America/Los_Angeles
20171005 050431 America/Los_Angeles
虽然在 @Juan's answer 中,格式化程序没有设置时区,这意味着它将保留 ZonedDateTime
对象中使用的时区:
// formatter without a timezone set
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd hhmmss VV", Locale.US);
// it keeps the timezone set in the date
System.out.println(nowLA.format(fmt)); // 20171005 050431 America/Los_Angeles
System.out.println(nowTokyo.format(fmt)); // 20171005 090431 Asia/Tokyo
现在保留时区(以及日期和时间值):
20171005 050431 America/Los_Angeles
20171005 090431 Asia/Tokyo
这是一个细微的差别,您必须选择最适合您的情况的方法。请注意,关于 hh
与 HH
的相同问题也适用于此:变量 nowTokyo
保存的值相当于 21:04:31 (9:04:31 PM 在东京),但它的格式为 090431
- 没有 AM/PM 指示符,这次是模棱两可的,所以 IMO 模式应该使用 HH
(因此输出将是210431
)。但由您决定。
In the javadoc 您可以查看所有可用模式的详细信息。
我正在尝试获取格式为 (String
) 的日期输出:
20170801 123030 America/Los_Angeles
但使用此代码:
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd hhmmss Z", Locale.US);
sdf.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
System.out.println(sdf.format(new java.util.Date()));
我得到的输出为(注意区域部分):
20174904 024908 -0700
知道如何解决吗?我需要打印 "America/Los_Angeles"
而不是 "-0700"
.
看起来 SimpleDateFormat 不支持您想要的。
以下是可能的格式:
z Time zone General time zone Pacific Standard Time; PST; GMT-08:00
Z Time zone RFC 822 time zone -0800
X Time zone ISO 8601 time zone -08; -0800; -08:00
您可以在格式化日期后添加 "America/Los_Angeles":
TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
DateFormat sdf = new SimpleDateFormat("yyyyMMdd hhmmss", Locale.US);
sdf.setTimeZone(timeZone);
System.out.println(sdf.format(new Date()) + " " + timeZone.getID());
DateFormat sdfWithTimeZone = new SimpleDateFormat("yyyyMMdd hhmmss zzzz", Locale.US);
sdfWithTimeZone.setTimeZone(timeZone);
System.out.println(sdfWithTimeZone.format(new Date()));
输出:
20171004 031611 America/Los_Angeles
20171004 031611 Pacific Daylight Time
如果可以使用Java8,可以使用DateTimeFormatter
及其符号V
来显示Zone ID:
Instant now = Instant.now();
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd hhmmss VV")
.withLocale(Locale.US)
.withZone(ZoneId.of("America/Los_Angeles"));
System.out.println(fmt.format(now));
打印:
20171004 032552 America/Los_Angeles
注意 SimpleDateFormat
doesn't support this flag as mentioned in
如果您有从java.util.Date
开始但仍然可以使用Java 8,您可以先将其转换为Instant
:
Instant now = new java.util.Date().toInstant();
...
正如 SimpleDateFormat
中没有内置模式来打印时区 ID。但是有一种方法可以覆盖它。
首先,您使用 z
模式创建一个格式化程序,它对应于时区短名称。 我不确定区域设置是否对此很重要(我知道它会影响长名称,不确定短名称,但无论如何我都会保留它)。
然后我从格式化程序中获取 java.text.DateFormatSymbols
并覆盖对应于短名称的字符串:
// use "z" (short timezone name)
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd hhmmss z", Locale.US);
sdf.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
// get the java.text.DateFormatSymbols
DateFormatSymbols symbols = sdf.getDateFormatSymbols();
// get the zones names
String[][] zones = symbols.getZoneStrings();
// overwrite zone short names
for (int i = 0; i < zones.length; i++) {
String zoneId = zones[i][0];
if ("America/Los_Angeles".equals(zoneId)) {
zones[i][2] = zoneId; // short name for standard time
zones[i][4] = zoneId; // short name for Daylight Saving Time
}
}
// update the symbols in the formatter
symbols.setZoneStrings(zones);
sdf.setDateFormatSymbols(symbols);
System.out.println(sdf.format(new java.util.Date()));
这将打印:
20171005 045317 America/Los_Angeles
请注意,我只更改了 America/Los_Angeles
时区的时区名称。您可以修改 if
以更改您想要的任何区域 - 或者只需删除 if
以更改所有区域。
另一个细节是您使用 hh
的时间。 According to javadoc,这是 am/pm 字段中的 小时(值从 1 到 12)。如果没有 AM/PM 指示符(模式 a
),输出可能不明确。如果需要,您可以将其更改为 HH
( 天中的小时 字段,值从 0 到 23)或 kk
(值从 1 到 24)。
Java新Date/TimeAPI
旧的 类(Date
、Calendar
和 SimpleDateFormat
)有 lots of problems and design issues,它们正在被新的 APIs.
如果您正在使用 Java 8,请考虑使用 new java.time API. It's easier, less bugged and less error-prone than the old APIs.
如果您使用 Java 6 或 7,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP (more on how to use it
下面的代码适用于两者。
唯一的区别是包名称(在 Java 8 中是 java.time
,在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp
),但是 类和方法名称相同。
实际上,这个新的 API 非常简单,代码将与@Juan 和@Jens 发布的其他答案完全相同。但它们之间存在细微差别。
假设我有 2 个不同的 ZonedDateTime
对象:一个代表 America/Los_Angeles
时区中的当前 date/time,另一个代表 [=] 中相同的当前 date/time 31=] 时区:
// current date/time
Instant now = Instant.now();
// get the same instant in different timezones
ZonedDateTime nowLA = now.atZone(ZoneId.of("America/Los_Angeles"));
ZonedDateTime nowTokyo = now.atZone(ZoneId.of("Asia/Tokyo"));
System.out.println(nowLA); // 2017-10-05T05:04:31.253-07:00[America/Los_Angeles]
System.out.println(nowTokyo); // 2017-10-05T21:04:31.253+09:00[Asia/Tokyo]
这些日期是:
2017-10-05T05:04:31.253-07:00[America/Los_Angeles]
2017-10-05T21:04:31.253+09:00[Asia/Tokyo]
现在让我们看看区别。 withLocale
- 但生成的格式化程序是等效的):
// set the timezone in the formatter
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd hhmmss VV", Locale.US)
// use Los Angeles timezone
.withZone(ZoneId.of("America/Los_Angeles"));
// it converts all dates to Los Angeles timezone
System.out.println(nowLA.format(fmt)); // 20171005 050431 America/Los_Angeles
System.out.println(nowTokyo.format(fmt)); // 20171005 050431 America/Los_Angeles
由于在格式化程序中设置了时区,因此两个日期都转换为该时区(包括日期和时间值):
20171005 050431 America/Los_Angeles
20171005 050431 America/Los_Angeles
虽然在 @Juan's answer 中,格式化程序没有设置时区,这意味着它将保留 ZonedDateTime
对象中使用的时区:
// formatter without a timezone set
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd hhmmss VV", Locale.US);
// it keeps the timezone set in the date
System.out.println(nowLA.format(fmt)); // 20171005 050431 America/Los_Angeles
System.out.println(nowTokyo.format(fmt)); // 20171005 090431 Asia/Tokyo
现在保留时区(以及日期和时间值):
20171005 050431 America/Los_Angeles
20171005 090431 Asia/Tokyo
这是一个细微的差别,您必须选择最适合您的情况的方法。请注意,关于 hh
与 HH
的相同问题也适用于此:变量 nowTokyo
保存的值相当于 21:04:31 (9:04:31 PM 在东京),但它的格式为 090431
- 没有 AM/PM 指示符,这次是模棱两可的,所以 IMO 模式应该使用 HH
(因此输出将是210431
)。但由您决定。
In the javadoc 您可以查看所有可用模式的详细信息。