我想为特定时区 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 GMT
和January 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" , " " );