Java:SimpleDateFormat 未在所需的时区中格式化



我想为特定时区 GMT 格式化日期,并且我希望无论应用程序在哪个时区运行,该格式的结果始终相同。

例如,在 GMT 时区创建Calendar实例并填充其字段:

TimeZone gmtTimeZone = TimeZone.getTimeZone( "GMT" );
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone( gmtTimeZone );
calendar.set( Calendar.YEAR, 1982 );
calendar.set( Calendar.MONTH, Calendar.JANUARY );
calendar.set( Calendar.DAY_OF_MONTH, 23 );
calendar.set( Calendar.HOUR, 1 );
calendar.set( Calendar.MINUTE, 2 );
calendar.set( Calendar.SECOND, 3 );
calendar.set( Calendar.MILLISECOND, 4 );

从日历中检索 UTC 时间戳:

Date utcDate = calendar.getTime();

据我了解,utcDate现在是January 1, 1970, 00:00:00.000 GMTJanuary 23, 1982, 01:02:03.004 GMT之间的毫秒数。请参阅Date Javadocs:

    /**
     * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
     * represented by this <tt>Date</tt> object.
     *
     * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
     *          represented by this date.
     */

创建日期格式化程序并将其时区也设置为 GMT:

SimpleDateFormat dateTimeFormat = new SimpleDateFormat( "yyyy-MM-dd' 'HH:mm:ss.SSSZ" );
dateTimeFormat.setTimeZone( gmtTimeZone );

将日期对象格式化为字符串:

String stringDate = dateTimeFormat.format( utcDate );

现在,当我这样做时:

System.out.println( utcDate.getTime() );
System.out.println( stringDate );

我得到:

> 380638923004
> 1982-01-23 13:02:03.004+0000

但是,我所期望的是(注意13小时与01小时(:

> 1982-01-23 01:02:03.004+0000

也就是说,因为我用calendar.set( Calendar.HOUR, 1 );将时间设置为 1(凌晨 1 点(,我希望时间是 1 点(凌晨 1 点(而不是 13 点(下午 1 点(。

我哪里出错了?

SimpleDateFormat dateTimeFormat = new SimpleDateFormat( "yyyy-MM-dd' 'hh:mm:ss.SSSZ" );
dateTimeFormat.setTimeZone( gmtTimeZone );

这将为您提供预期的输出。

日期格式字符串中的"h"将根据 JavaDoc for SimpleDateFormat 显示为上午/下午 (1-12( 中的小时。

编辑:Calendar.HOUR_OF_DAY 应该用于设置 24 小时制的小时。

正如斯宾塞·布雷特(Spencer Brett(的正确答案所说,如果你的意思是12小时制而不是24小时制,你应该使用小写hh

java.time

使用 Java 8 及更高版本时,您应该避免这些众所周知的麻烦的旧日期时间类 (java.util.Date/.日历等(。它们已被java.time框架所取代。请参阅教程。

Instant

Instant是时间轴上的一个时刻,采用 UTC 格式。

Instant instant = Instant.now();

OffsetDateTime

但是,Instant的格式有限,实例化方式也有限。因此,让我们看一下OffsetDateTime您可以将它视为与偏移量 UTC(ZoneOffset(相结合的Instant。要指定偏移量,我们可以使用常量java.time.ZoneOffset.UTC .为了实例化OffsetDateTime我们首先构建一个仅日期和一个仅时间,然后与偏移量组合。

纳秒分辨率

java.time 类具有纳秒级分辨率。您在问题示例中打算使用毫秒。所以我们将使用 TimeUnit .您可以自己进行乘法,但这很容易出错。TimeUnit是自我记录的。

LocalDate localDate = LocalDate.of( 1982 , 1 , 23 );
long nanoseconds = TimeUnit.NANOSECONDS.convert( 4 , TimeUnit.MILLISECONDS );
LocalTime localTime = LocalTime.of( 1 , 2 , 3 , nanoseconds );
OffsetDateTime odt = OffsetDateTime.of( localDate , localTime , ZoneOffset.UTC );

ISO 8601

认证

java.time 类在其toString方法中默认使用 ISO 8601 标准格式。因此,您无需指定接近所需输出的格式。与标准格式不完全相同,包括中间的T而不是空格。

String output = odt.toString();

1982-01-23T01:02:03.004Z

要么用 SPACE 替换T,要么在 Stack Overflow 中搜索许多在 java.time 中使用 DateTimeFormatter 类的示例。

String output = odt.toString().replace( "T" , " " );

相关内容

  • 没有找到相关文章