时差计算错误

Fır*_*lut 7 java time duration datetimeoffset timezone-offset

我必须计算出发机场和到达机场之间的总飞行时间.

这项工作由以下代码片段完成:

    public int calculateFlightDuration(String departureDateTime, String depAirportCode, String arrivalDateTime,
        String arrAirportCode) {
    try {
        LocalDateTime depLocalTime = LocalDateTime.parse(departureDateTime, formatter);
        LocalDateTime arrLocalTime = LocalDateTime.parse(arrivalDateTime, formatter);

        ZoneOffset depZoneOffset = getTimeZoneOffset(depAirportCode);
        ZoneOffset arrZoneOffset = getTimeZoneOffset(arrAirportCode);

        if (depZoneOffset != null && arrZoneOffset != null) {

            OffsetDateTime offsetDepTime = OffsetDateTime.of(depLocalTime, depZoneOffset);
            OffsetDateTime offsetArrTime = OffsetDateTime.of(arrLocalTime, arrZoneOffset);

            Duration flightDuration = Duration.between(offsetArrTime, offsetDepTime).abs();

            return (int) flightDuration.toMinutes();

        }

    } catch (Exception e) {
        LOG.warn("::calculateFlightDuration depTime:{} dep.code:{} arrTime:{} arr.code:{}", departureDateTime,
                depAirportCode, arrivalDateTime, arrAirportCode);
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是问题所在:

当我想用这些参数计算未来航班的持续时间时:

depLocalTime = 2017-11-06T14:50
arrLocalTime = 2017-11-06T16:45
depZoneOffset = +03:00
arrZoneOffset = +02:00
Run Code Online (Sandbox Code Playgroud)

作为这些参数的结果,flightDuration对象是:

flightDuration = PT2H55M
Run Code Online (Sandbox Code Playgroud)

似乎一切都好,对吧?但实际上并不好.让我解释;

出发机场代码是IST(土耳其),抵达机场代码是AMS(荷兰),这里是关键:

2017-10-29之后(在我计算的时间之前),AMS时间将由1小时支持,其偏移量为+01:00,IST偏移量仍为+03:00.所以正确的持续时间对象必须是:

flightDuration = PT3H55M
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题?真的很烦人.谢谢你的帮助.

在ZonedDateTime评论后编辑:

大家,我也尝试过ZonedDateTime对象,进行计算.这是使用ZonedDateTime对象的代码,它对结果没有影响.

    public int calculateFlightDuration(String departureDateTime, String depAirportCode, String arrivalDateTime,
        String arrAirportCode) {
    try {
        LocalDateTime depLocalTime = LocalDateTime.parse(departureDateTime, formatter);
        LocalDateTime arrLocalTime = LocalDateTime.parse(arrivalDateTime, formatter);

        ZoneOffset depZoneOffset = getTimeZoneOffset(depAirportCode);
        ZoneOffset arrZoneOffset = getTimeZoneOffset(arrAirportCode);

        if (depZoneOffset != null && arrZoneOffset != null) {

            ZonedDateTime zonedDepTime = ZonedDateTime.of(depLocalTime, depZoneOffset);
            ZonedDateTime zonedArrTime = ZonedDateTime.of(arrLocalTime, arrZoneOffset);

//              OffsetDateTime offsetDepTime = OffsetDateTime.of(depLocalTime, depZoneOffset);
//              OffsetDateTime offsetArrTime = OffsetDateTime.of(arrLocalTime, arrZoneOffset);

            Duration flightDuration = Duration.between(zonedDepTime, zonedArrTime).abs();

            return (int) flightDuration.toMinutes();

        }

    } catch (Exception e) {
        LOG.warn("::calculateFlightDuration depTime:{} dep.code:{} arrTime:{} arr.code:{}", departureDateTime,
                depAirportCode, arrivalDateTime, arrAirportCode);
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在@Joe C的回答之后,我再次更改了代码,我相信这是我应该去的方式:

    public int calculateFlightDuration(String departureDateTime, String depAirportCode, String arrivalDateTime,
        String arrAirportCode) {
    try {
        LocalDateTime depLocalTime = LocalDateTime.parse(departureDateTime, formatter);
        LocalDateTime arrLocalTime = LocalDateTime.parse(arrivalDateTime, formatter);

        ZoneId depZoneId = getTimeZoneId(depAirportCode);
        ZoneId arrZoneId = getTimeZoneId(arrAirportCode);

        if (depZoneId != null && arrZoneId != null) {

            ZonedDateTime zonedDepTime = ZonedDateTime.of(depLocalTime, depZoneId);
            ZonedDateTime zonedArrTime = ZonedDateTime.of(arrLocalTime, arrZoneId);

            Duration flightDuration = Duration.between(zonedDepTime, zonedArrTime).abs();

            return (int) flightDuration.toMinutes();

        }

    } catch (Exception e) {
        LOG.warn("::calculateFlightDuration depTime:{} dep.code:{} arrTime:{} arr.code:{}", departureDateTime,
                depAirportCode, arrivalDateTime, arrAirportCode);
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是:Java假设伊斯坦布尔也将其时区偏移量改为+02:00,但不会发生.我想我还需要更新我的Java.以下是代码更改后的结果:

depZoneId = Europe/Istanbul
arrZoneId = Europe/Amsterdam
zonedDepTime = 2017-11-06T14:50+02:00[Europe/Istanbul] //damn it's really annoying!
zonedArrTime = 2017-11-06T16:45+01:00[Europe/Amsterdam]
Run Code Online (Sandbox Code Playgroud)

aaand飞行时间保持不变:

flightDuration = PT2H55M
Run Code Online (Sandbox Code Playgroud)

谢谢你的回答.现在我必须修改伊斯坦布尔的时区变化.

Joe*_*e C 6

OffsetDateTime假设整年都有一个共同的偏移量(例如UTC + 2).它没有涵盖夏令时的任何内容.

如果你想考虑夏令时,你应该用a ZonedDateTime代替ZoneId.在这种情况下Europe/Amsterdam,它将根据一年中的时间选择UTC + 1或UTC + 2.

ZonedDateTime zonedDepTime = ZonedDateTime.of(depLocalTime, ZoneId.of("Asia/Istanbul"));
ZonedDateTime zonedArrTime = ZonedDateTime.of(arrLocalTime, ZoneId.of("Europe/Amsterdam"));
Run Code Online (Sandbox Code Playgroud)