2017-10-04 52 views
7

Muszę obliczyć łączny czas przelotu między lotniskiem odlotu a lotniskiem przylotu.Błąd obliczania różnicy czasu

Ta praca jest wykonywana przez ten fragment kodu:

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

Oto problem:

Kiedy chcę, aby obliczyć czas trwania przyszłego lotniczej z tymi parametrami:

depLocalTime = 2017-11-06T14:50 
arrLocalTime = 2017-11-06T16:45 
depZoneOffset = +03:00 
arrZoneOffset = +02:00 

jako w wyniku tych parametrów obiekt flightDuration:

flightDuration = PT2H55M 

Wygląda na to, że wszystko jest w porządku, prawda? Ale to nie jest w porządku. Pozwól mi wyjaśnić;

kod lotniska wylotu jest IST (Turcja) i przyjazd kod lotniska jest AMS (Holandia) i tu jest klucz:

Po 29.10.2017 (przed czasem ja obliczonej), czas AMS będzie wspierane przez 1 godzinę, a jego przesunięcie będzie +01: 00, a przesunięcie IST nadal pozostanie +03: 00. Dlatego prawidłowym obiektem czasu trwania musi być:

flightDuration = PT3H55M 

Jak mogę rozwiązać ten problem? To jest naprawdę denerwujące. Dzięki za pomoc.

Edit po ZonedDateTime komentarze:

Chłopaki, ja też próbowałem z obiektu ZonedDateTime na obliczeniach. Oto kod z użytym obiektem ZonedDateTime, nie ma to wpływu na wynik.

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

Po odpowiedź @Joe C „s, zmieniłem ponownie kod i wierzę, że jest to sposób powinien iść:

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

ALE: Java zakłada, że ​​Stambuł również zmienić jego strefę czasową przesunięcie do +02: 00, ale TO NIE DZIAŁA. Myślę, że muszę również zaktualizować moją Javę. Oto wynik po zmianie kodu: czas trwania lotu

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] 

aaand pozostaje taka sama:

flightDuration = PT2H55M 

Dzięki za odpowiedzi facetów. Teraz muszę naprawić zmianę strefy czasowej w Stambule.

+0

Wskazówka - należy użyć 'ZonedDateTime' zamiast' OffsetDateTime'. Mam nadzieję, że to wystarczająca ilość informacji, które pomogą ci to rozwiązać. Napiszę pełną odpowiedź, jeśli będę miał czas później. –

+0

Witam @Jesper, to dlatego, że różnica musi być PT3H55M at 2017-11-06. W tym dniu przesunięcie AMS będzie wynosić +01: 00. –

+0

Ale lot nie będzie nagle o 1 godzinę dłuższy, tylko dlatego, że AMS przełącza się na czas zimowy? – Jesper

Odpowiedz

6

OffsetDateTime zakłada wspólny offset na cały rok (np. UTC + 2). Nie obejmuje niczego podobnego do Summer Time.

Jeśli chcesz uwzględnić czas letni, użyj zamiast tego ZonedDateTime, z ZoneId. W przypadku Europe/Amsterdam, wybierze UTC + 1 lub UTC + 2 w zależności od pory roku.

ZonedDateTime zonedDepTime = ZonedDateTime.of(depLocalTime, ZoneId.of("Asia/Istanbul")); 
ZonedDateTime zonedArrTime = ZonedDateTime.of(arrLocalTime, ZoneId.of("Europe/Amsterdam"));