我目前对SimpleDateFormatter的以下简单用法不知所措:
import java.text.ParseException;
import java.text.SimpleDateFormat;
public static void main(String[] args) throws ParseException {
System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX").parse("2018-12-04T22:22:01+1000"));
}
我正在使用JDK 1.8.0_192运行此示例。
我的PC位于CET(+1000),因此时区相等。因此预期结果将是:
2018年12月4日星期二22:22:01
但是我得到以下输出:
2018年12月4日星期二13:22:01
有人知道这里发生了什么吗?
答案 0 :(得分:4)
您给它2018-12-04T22:22:01+1000
,在UTC中为2018-12-04T12:22:01
。 CET比UTC早1小时,因此您可以获得13
小时。
答案 1 :(得分:1)
您最初的问题是错字+1000
与错字+0100
。但是,以下所有建议仍然适用。您正在使用可怕的旧类,应该避免。
OffsetDateTime.parse(
"2018-12-04T22:22:01+1000" , // Input in standard ISO 8601, with the COLON omitted from the offset as allowed by the standard but breaking some libraries such as `OffsetDateTime.parse`.
DateTimeFormatter.ofPattern(
"uuuu-MM-dd'T'HH:mm:ssX"
)
) // Returns a `OffsetDateTime` object.
.toInstant() // Adjust into UTC. Returns an `Instant` object. Same moment, different wall-clock time.
.atZone( // Adjust from UTC to some time zone. Same moment, different wall-clock time.
ZoneId.of( "Europe/Brussels" )
) // Returns a `ZonedDateTime` object.
.toString() // Generate text representing this `ZonedDateTime` object in standard ISO 8601 format but wisely extending the standard by appending the name of the time zone in square brackets.
18-12-04T13:22:01 + 01:00 [欧洲/布鲁塞尔]
您正在使用与最早的Java版本捆绑在一起的可怕的旧日期时间类。几年前由 java.time 类取代。
仅供参考,CET
不是实时区域。
以continent/region
的格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用2-4个字母的缩写,例如EST
或IST
,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
ZoneId z = ZoneId.of( "America/Montreal" ) ;
您可能指的是时区,例如Europe/Brussels
,Europe/Paris
,Europe/Berlin
,Africa/Tunis
或Europe/Oslo
。
您的输入字符串2018-12-04T22:22:01+1000
为标准格式,由ISO 8601定义。
最后一部分+1000
是offset-from-UTC,意味着比UTC提前十个小时。因此,此值用于太平洋地区某个地区的人们使用的挂钟时间,例如时区Australia/Lindeman
。
该字符串+1000
是偏移量的缩写,省略了小时和分钟(以及秒,如果有)之间的冒号分隔符。尽管标准允许这种遗漏,但我建议始终包括以下冒号:2018-12-04T22:22:01+10:00
。以我的经验,某些库和协议在遇到此类字符串时会中断。而且,COLON的包含使该字符串对人类更具可读性。
OffsetDateTime
实际上,java.time.OffsetDateTime
类用于默认情况下解析这些标准字符串,在这方面有一个错误,当省略COLON时无法解析。讨论于:
解决方法:
OffsetDateTime odt =
OffsetDateTime.parse(
"2018-12-04T22:22:01+1000" ,
DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ssX" )
)
;
请参见代码示例running live at IdeOne.com。
odt.toString():2018-12-04T22:22:01 + 10:00
通过提取Instant
对象将该值调整为UTC。根据定义,Instant
始终使用UTC。
Instant instant = odt.toString() ;
instant.toString():2018-12-04T12:22:01Z
最后,我们可以调整到您自己的时区。
通过CET
,我假设您指的是一个时区,例如Europe/Paris
。
ZoneId z = ZoneId.of( "Europe/Paris" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
调用ZonedDateTime::toString
时,将以标准ISO 8601格式生成文本,但应明智地扩展标准以将时区的名称附加在方括号中。
zdt.toString(): 2018-12-04T13:22:01+01:00[Europe/Paris]
这些对象的所有三个(odt
,instant
和zdt
)都指向相同的同时时刻,即时间轴上的同一点。他们唯一的区别是挂钟时间。如果在澳大利亚,法国和冰岛的电话会议中的三个人(始终在UTC中)都同时抬起头来从各自墙上挂着的各自的时钟中读取当前时刻,则他们将为同一时刻读取三个不同的值。
查看所有此代码run live at that IdeOne.com page。
java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和SimpleDateFormat
。
目前位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
在哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如Interval
,YearWeek
,YearQuarter
和more。