String to ZonedDateTime is changing format

2019-03-01 10:13发布

String ip="2011-05-01T06:47:35.422-05:00";
ZonedDateTime mzt = ZonedDateTime.parse(ip).toInstant().atZone(ZoneOffset.UTC);
System.out.println(mzt);

System.out.println("-----");

String ip2="2011-05-01T00:00:00.000-05:00";
ZonedDateTime mzt2 = ZonedDateTime.parse(ip2).toInstant().atZone(ZoneOffset.UTC);
System.out.println(mzt2);

Output:

2011-05-01T11:47:35.422Z
-----
2011-05-01T05:00Z

Why is the date format getting changed in case 2? I am getting SQLServer Database error due to this.

2条回答
够拽才男人
2楼-- · 2019-03-01 10:37

Just to complement YCF_L's answer:

Using a quoted letter in the pattern, like it was done with the Z (it's inside quotes: 'Z') is wrong. This will treat Z as a literal and ignore the object's offset.

For this particular case, it works, but the "Z" in the end means that the date is in UTC, and you can't hardcode it as a literal. Putting it inside quotes will always print "Z" no matter what's the offset, giving wrong results.

Example:

// wrong: it uses Z inside quotes
DateTimeFormatter wrong = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss:SSS'Z'");

// correct: it uses the offset pattern (X)
DateTimeFormatter correct = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss:SSSXXX");

// print a date/time not in UTC
String ip2 = "2011-05-01T00:00:00.000-05:00";
ZonedDateTime mzt = ZonedDateTime.parse(ip2);

System.out.println(mzt.format(wrong)); // 2011-05-01T00:00:00:000Z
System.out.println(mzt.format(correct)); // 2011-05-01T00:00:00:000-05:00

Note that the wrong formatter prints Z, which is wrong, because the offset of mzt is -05:00.

The wrong formatter works for your case because you're using UTC:

// convert to UTC
ZonedDateTime mzt2 = mzt.withZoneSameInstant(ZoneOffset.UTC);
System.out.println(mzt2.format(wrong)); // 2011-05-01T05:00:00:000Z
System.out.println(mzt2.format(correct)); // 2011-05-01T05:00:00:000Z

In this case, both formatters prints the correct result, but that's a coincidence, because mzt2 is in UTC (so the offset is "Z"). But for any offset different than UTC, only the correct formatter will work.

Also note that I used withZoneSameInstant, that has the same result as using .toInstant().atZone(ZoneOffset.UTC).

查看更多
Root(大扎)
3楼-- · 2019-03-01 10:52

This is what toString from documentation said

The format used will be the shortest that outputs the full value of the time where the omitted parts are implied to be zero.

To solve this problem, you need another formatter :

String result = mzt2.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss:SSS'Z'"));

Output

2011-05-01T11:47:35.422Z
2011-05-01T05:00:00:000Z
查看更多
登录 后发表回答