时间差计算错误

7

我需要计算出发机场和到达机场之间的总飞行时间(以分钟为单位)。

以下代码片段可完成此任务:

    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;
}

这里是问题:
当我想要用以下参数计算未来航班的飞行时间时:
depLocalTime = 2017-11-06T14:50
arrLocalTime = 2017-11-06T16:45
depZoneOffset = +03:00
arrZoneOffset = +02:00

由于这些参数的影响,flightDuration对象为:
flightDuration = PT2H55M

似乎一切都很正常,对吗?但实际上并不是这样。让我来解释一下:

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

在2017年10月29日后(在我计算的时间之前),AMS时间将会倒退1小时,其偏移量将是+01:00,而IST的偏移量仍然为+03:00。因此,正确的持续时间对象应该是:

flightDuration = PT3H55M

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

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;
}

在@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;
}

但是: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]

同时航班时长保持不变:

flightDuration = PT2H55M

感谢大家的回答。现在我需要修复伊斯坦布尔的时区变更。


请使用ZonedDateTime而不是OffsetDateTime。希望这些信息足以帮助您解决问题。如果我有时间,我会写一个完整的答案。 - Dawood ibn Kareem
嗨@ Jesper,这是因为差异必须在2017-11-06的PT3H55M。 在此日期,AMS的偏移量将为+01:00。 - Fırat Çağlar Akbulut
但是仅仅因为阿姆斯特丹改到冬令时,航班不会突然变长1个小时,对吧? - Jesper
你绝对是正确的 :) 它只是两个本地时间之间差异的表示,可能会让人感到困惑。 - Fırat Çağlar Akbulut
1个回答

6

OffsetDateTime 假设整年使用相同的偏移量(例如 UTC+2),不包括夏令时相关内容。

如果您想考虑夏令时,应改用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"));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接