Java8LocalDateTime与日期

Java8LocalDateTime与日期,java,datetime,java-8,Java,Datetime,Java 8,我有一个字符串2017-07-31T01:01:00-07:00,我正在尝试将其解析为日期和CST时区。当我使用Date和Java8 ZoneDateTime解析这个字符串时,我得到了不同的结果。我不明白为什么会这样,我做错了什么 String dateStr = "2017-07-31T01:01:00-07:00"; LocalDateTime time = null; SimpleDateFormat format = new SimpleDateFormat("y

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

    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());

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

new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX")
您不应该使用时区CST,因为这是不明确的(中央标准时间、中国标准时间、古巴标准时间)。使用
America/Chicago
(我想这就是你的意思)

因此,要使用新旧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");
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
如果要查看时区,可以执行以下操作:

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:00CDT

请注意第一个示例如何更改
ZoneDateTime
时区,将其转换为
LocalDateTime
,然后在不使用格式设置程序的情况下打印,而在第二个示例中,
DateTimeFormatter
设置为在特定时区中格式化值,类似于
SimpleDateFormat
的操作方式。只是实现相同结果的不同方法。

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

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

对于我认为您试图获得的,我建议:

    ZonedDateTime dateTime = OffsetDateTime.parse(dateStr)
            .atZoneSameInstant(ZoneId.of("America/Chicago"));
    System.out.println(dateTime.toLocalDateTime());
输出与第二个输出相同:

2017-07-31T03:01


<> P>如果你觉得它更适合你的情况,而不是美国/芝加哥,你可以考虑例如美国/ Baaaai-Bangelas,美国/印第安娜/诺克斯,美国/印第安娜/特里尔城,美国/马塔莫罗斯,美国/梅诺米尼或美国/温尼伯。不要依赖三个或四个字母的时区缩写。CST不是真正的时区,因为它只用于一年中的一些时间,而且它是不明确的,它可能指澳大利亚中部标准时间、北美和中美洲中部标准时间、中国标准时间或古巴标准时间。而且也不能保证Java会为您提供哪种时区。

为什么要手动提取时区-限制为0..9。这将在世界上很多地方遇到问题。“我得到了不同的结果”告诉我们。不要期望我们运行您的代码来查看它。编辑问题并显示结果。如果您可以使用
java.time
LocalDateTime
ZoneDateTime
所属的现代java日期和时间API,那么您为什么还要担心像
SimpleDateFormat
date
这样的过时类呢?我的建议是忘掉它们。CST指的是中国标准时间还是古巴标准时间?这三个和四个字母的时区缩写是如此的模棱两可。