Java 8 localdatetime vs Date

时间:2018-05-17 17:41:45

标签: java datetime java-8

我有一个字符串2017-07-31T01:01:00-07:00,我正在尝试将其解析为日期和CST时区。当我使用Date和Java 8 ZonedDateTime解析此字符串时,我得到了不同的结果。我不明白为什么会这样,我做错了。

    String dateStr = "2017-07-31T01:01:00-07:00";
    LocalDateTime time = null;
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss-hh");

    String[] dateArray = dateStr.split("-");
    String[] timeZones = TimeZone
            .getAvailableIDs(TimeZone.getTimeZone("GMT-" + dateArray[dateArray.length - 1]).getRawOffset());
    format.setTimeZone(TimeZone.getTimeZone(timeZones[0]));
    Date dateObj = null;
    try {
        dateObj = format.parse(dateStr);
    } catch (ParseException e) {
        e.printStackTrace();
    }
    time = dateObj.toInstant().atZone(TimeZone.getTimeZone("CST").toZoneId()).toLocalDateTime();
    ZonedDateTime time2 = ZonedDateTime.parse(dateStr).toInstant().atZone(TimeZone.getTimeZone("CST").toZoneId());
    System.out.println(time);
    System.out.println(time2.toLocalDateTime());

2 个答案:

答案 0 :(得分:5)

您不应该自己解析时区偏移量。只需使用CST模式:

America/Chicago

你不应该使用时区String dateStr = "2017-07-31T01:01:00-07:00"; // Using Date SimpleDateFormat parseFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX"); Date date = parseFormat.parse(dateStr); SimpleDateFormat printFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm"); printFormat.setTimeZone(TimeZone.getTimeZone("America/Chicago")); System.out.println(printFormat.format(date)); // Using ZonedDateTime ZonedDateTime zonedDateTime = ZonedDateTime.parse(dateStr); zonedDateTime = zonedDateTime.withZoneSameInstant(ZoneId.of("America/Chicago")); System.out.println(zonedDateTime.toLocalDateTime()); ,因为这是不明确的(中央标准时间,中国标准时间,古巴标准时间)。使用2017-07-31T03:01 2017-07-31T03:01 (我认为这就是你的意思)。

因此,要使用旧的和新的API解析日期字符串:

String dateStr = "2017-07-31T01:01:00-07:00";

// Using Date
SimpleDateFormat parseFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
Date date = parseFormat.parse(dateStr);

SimpleDateFormat printFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm XXX z");
printFormat.setTimeZone(TimeZone.getTimeZone("America/Chicago"));
System.out.println(printFormat.format(date));

// Using ZonedDateTime
ZonedDateTime zonedDateTime = ZonedDateTime.parse(dateStr);

DateTimeFormatter printFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm XXX z")
                                                    .withZone(ZoneId.of("America/Chicago"));
System.out.println(zonedDateTime.format(printFormatter));

输出

2017-07-31T03:01 -05:00 CDT
2017-07-31T03:01 -05:00 CDT

如果您想查看时区,可以执行以下操作:

ZonedDateTime

输出

LocalDateTime

请注意第一个示例如何更改DateTimeFormatter时区,将其转换为SimpleDateFormat,然后在没有格式化程序的情况下打印,而在第二个示例中设置Sub Test() Dim Sheet As Worksheet Application.ScreenUpdating = False Set Sheet = Sheets("Original Index Goes Here") Dim rng As Range, sel As Range, selrange As String, r As Long Set rng = Range("B1:B10000") rng.AutoFilter Field:=1, Criteria1:="=SS*", _ Operator:=xlAnd, visibledropdown:=True ActiveSheet.AutoFilter.Range.Offset(1,0) _ .Rows.SpecialCells(xlCellTypeVisible).Select End Sub 以格式化特定时区中的值,类似于delegate()正在执行的操作。只是通过不同的方式来实现相同的结果。

答案 1 :(得分:1)

我不确定TimeZone.getAvailableIDs的确切行为(它没有完整记录)。当我在Java 9.0.4上运行代码时,它返回的第一个ID是America / Boise。美国爱达荷州博伊西市冬季山区标准时间(UTC-07:00)和山区日光时间(UTC-06:00)。您将format设置为使用它进行解析。您的格式将01解析为一天中的小时(大写HH,00到23) 07作为上午或下午的小时(小写hh ,01到12)。所以这里有冲突。显然前者获胜,我不知道为什么(不要总是坚持理解SimpleDateFormat)。由于7月31日是夏令时(DST)的一年中的某个时间,因此您将获得01:01-06:00的时间,等于北美中部夏令时02:01(-05:00)。这是不正确的。

ZonedDateTime.parse正确解析您的字符串。 TimeZone.getTimeZone("CST").toZoneId()将CST解释为美国/芝加哥(严格来说,这是不正确的,因为芝加哥仅在一年中的较小部分使用CST)。因此,在time2中,您获得2017-07-31T03:01-05:00[America/Chicago],这是正确的。

对于我认为你想要获得的东西,我建议:

    ZonedDateTime dateTime = OffsetDateTime.parse(dateStr)
            .atZoneSameInstant(ZoneId.of("America/Chicago"));
    System.out.println(dateTime.toLocalDateTime());

输出与第二个输出相同:

  

2017-07-31T03:01

如果您发现它更适合您的情况,您可以考虑使用例如America / Bahia_Banderas,America / Indiana / Knox,America / Indiana / Tell_City,America / Matamoros,America / Menominee或America / Winnipeg 。不要依赖三个或四个字母的时区缩写。 CST不是真正的时区,因为它仅在一年中的某些时段使用,并且它含糊不清,可能是指澳大利亚中央标准时间,北美和中美洲中部标准时间,中国标准时间或古巴标准时间。并且无法保证Java会为您提供哪些内容。