时区的Java时间格式



我试图以格式( String)的日期获得输出:

20170801 123030美国/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

如果可以使用Java 8,则可以使用DateTimeFormatter及其符号V显示区域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美国/los_angeles

请注意,SimpleDateFormat不支持Alexandr答案中提到的此标志。

如果您java.util.Date开始,但可以使用Java 8,您可以先将其转换为Instant

Instant now = new java.util.Date().toInstant();
...

正如 @Alexandr的答案所指向的,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美国/los_angeles

请注意,我仅更改了America/Los_Angeles时区的区域名称。您可以修改if以更改所需的任何区域 - 或仅删除if以更改所有区域。

另一个细节是您在小时内使用hh。根据Javadoc的说法,这是AM/PM 段中的小时(值为1到12)。如果没有AM/PM指定器(模式a),则输出可能是模棱两可的。您可以将其更改为HH Day 字段,值为0到23)或kk(值为1到24)(如果需要)。


Java新日期/时间API

旧类(DateCalendarSimpleDateFormat)有很多问题和设计问题,它们被新的API替换。

如果您使用的是 Java 8 ,请考虑使用新的Java.Time API。它比旧的API容易,更小,并且容易出错。

如果您使用的是 Java 6或7 ,则可以使用Threeten Backport,这是Java 8的新日期/时间类别。对于 android ,您还需要Threetenabp(有关如何在此处使用它的更多信息)。

下面的代码都适用于两者。唯一的区别是软件包名称(在Java 8中是java.time,在Threeten Backport(或Android的Threetenabp)中是org.threeten.bp),但是类和方法 names> names 是相同的。

实际上,这个新的API非常直截了当,以至于代码将与@Juan和@Jens发布的其他答案完全相同。但是这些之间有一个微妙的区别。

让我们假设我有2个不同的ZonedDateTime对象:一个代表America/Los_Angeles TimeZone中的当前日期/时间,另一个代表Asia/Tokyo TimeZone中的当前日期/时间相同:

>
// 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 [美国/los_angeles]
2017-10-05T21:04:31.253 09:00 [ASIA/TOKYO]

现在让我们看看区别。@jens的答案在格式化器中设置了时区。这意味着在格式化时所有日期都将转换为该特定时区(我刚刚修改了代码,直接设置了该语言环境 - 而不是使用withLocale-但所得的formatter是等效的):

>
// 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美国/los_angeles
20171005 050431美国/los_angeles

在 @juan的回答中,格式化器没有时区集,这意味着它将保留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美国/los_angeles
20171005 090431亚洲/东京

这是一个微妙的差异,您必须选择最适合自己的情况的方法。请注意,关于hhHH的同一问题在这里也适用:变量nowTokyo将值等效于21:04:31(9:04:31 pm pm 在东京),但它的形式为090431--32--32--32--32--32--32---没有AM/PM指示符,这次是模棱两可的,因此IMO该模式应使用HH(因此输出为210431)。但这取决于您决定。

在Javadoc中,您可以看到有关所有可用模式的详细信息。

相关内容

  • 没有找到相关文章

最新更新