Fix dbnav time zone bug (#25)

* fix dbnav time zone bug

* test fix of dbnav time zone bug

* exclude `test/parse/dbnav-journey.js` from spell check
This commit is contained in:
dabund24 2025-03-06 21:13:08 +01:00 committed by GitHub
parent a6e84be2df
commit 25cbb288ca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 535 additions and 1 deletions

View file

@ -626,7 +626,8 @@
"ignorePaths": [
"docs/dumps/**",
"test/e2e/fixtures/**",
"test/parse/remarks.js"
"test/parse/remarks.js",
"test/parse/dbnav-journey.js"
],
"dictionaries": [
"node"

View file

@ -8,6 +8,7 @@ import {formatStopReq} from './stop-req.js';
import {formatNearbyReq} from './nearby-req.js';
import {formatStationBoardReq} from './station-board-req.js';
import {parseStop} from './parse-stop.js';
import {parseJourney} from './parse-journey.js';
const profile = {
...baseProfile,
@ -24,6 +25,7 @@ const profile = {
formatStationBoardReq,
formatLocationFilter,
parseJourney,
parseStop,
};

34
p/dbnav/parse-journey.js Normal file
View file

@ -0,0 +1,34 @@
import {parseJourney as parseJourneyDefault} from '../../parse/journey.js';
const parseJourney = (ctx, jj) => {
const legs = (jj.verbindung || jj).verbindungsAbschnitte;
if (legs.length > 0) {
legs[0] = preprocessJourneyLeg(legs[0]);
}
if (legs.length > 1) {
legs[legs.length - 1] = preprocessJourneyLeg(legs.at(-1));
}
return parseJourneyDefault(ctx, jj);
};
const preprocessJourneyLeg = (pt) => { // fixes https://github.com/public-transport/db-vendo-client/issues/24
if (pt.typ === 'FUSSWEG' || pt.typ === 'TRANSFER') {
pt.ezAbgangsDatum = correctRealtimeTimeZone(pt.abgangsDatum, pt.ezAbgangsDatum);
pt.ezAnkunftsDatum = correctRealtimeTimeZone(pt.ankunftsDatum, pt.ezAnkunftsDatum);
}
return pt;
};
const correctRealtimeTimeZone = (planned, realtime) => {
if (planned && realtime) {
const timeZoneOffsetRegex = /([+-]\d\d:\d\d|Z)$/;
const timeZoneOffsetPlanned = timeZoneOffsetRegex.exec(planned)[0];
return realtime.replace(timeZoneOffsetRegex, timeZoneOffsetPlanned);
}
return realtime;
};
export {parseJourney};

497
test/parse/dbnav-journey.js Normal file
View file

@ -0,0 +1,497 @@
import tap from 'tap';
import {parseJourney as parseJourneyDbnav} from '../../p/dbnav/parse-journey.js';
import {parseJourney as parseJourneyDefault} from '../../parse/journey.js';
import {parseJourneyLeg} from '../../parse/journey-leg.js';
import {parseWhen} from '../../parse/when.js';
import {parseDateTime} from '../../parse/date-time.js';
import {parsePlatform} from '../../parse/platform.js';
const ctx = {
opt: {},
profile: {
enrichStation: (ctx, stop) => stop,
parseCancelled: _ => null,
parseDateTime,
parseJourneyLeg,
parseLine: _ => null,
parseLoadFactor: _ => null,
parseLocation: _ => ({latitude: null, longitude: null}),
parseOperator: _ => null,
parsePlatform,
parsePrice: _ => null,
parseTickets: _ => null,
parseWhen,
timezone: 'Europe/Berlin',
locale: 'de-DE',
},
};
const input = {
reiseDauer: 480,
alternative: true,
checksum: 'bfc0da75_3',
umstiegeAnzahl: 0,
schemaVersion: '1.23.8',
schemaName: 'trip',
kontext: '¶HKI¶G@F$A=4@O=Berlin, Fernsehturm (Tourismus)@X=13409694@Y=52521301@L=991671997@a=128@$A=1@O=Berlin Alexanderplatz@X=13410728@Y=52521409@L=618011155@a=128@$202503061452$202503061454$$$1$$$$$$§W$A=1@O=Berlin Alexanderplatz@X=13410728@Y=52521409@L=618011155@a=128@$A=1@O=Berlin Alexanderplatz@X=13410962@Y=52521481@L=8011155@a=128@$202503061454$202503061454$$$1$$$$$$§T$A=1@O=Berlin Alexanderplatz@X=13410962@Y=52521481@L=8011155@a=128@$A=1@O=Berlin Hbf@X=13369549@Y=52525589@L=8011160@a=128@$202503061454$202503061459$RE 73737$$1$$$$$$¶GP¶ft@0@2000@120@1@100@1@0@0@@@@@false@0@-1@0@-1@-1@$f@$f@$f@$f@$f@$§bt@0@2000@120@1@100@1@0@0@@@@@false@0@-1@0@-1@-1@$f@$f@$f@$f@$f@$§tf@$f@$f@$f@$f@$f@$§¶KC¶#VE#2#CF#100#CA#0#CM#0#SICT#0#AM#81#AM2#0#RT#7#¶KCC¶I1ZFIzEjRVJHIzIjSElOIzAjRUNLIzB8MHwwfDB8MHwwfDB8MHwwfDB8MHwwfDB8MCNHQU0jNjAzMjUxNDU0IwpGI1ZOIzAjU1QjMTc0MDU3ODc3MiNQSSMxI1BVIzkwI1pJIzMzNTU3OTIxMjQjREEjNjAzMjUjRlIjNjE4MDExMTU1I1RPIzgwMTExNTUjRlQjMTQ1NCNUVCMxNDU0I1RTIzMxI0ZGIyNGViMwI1NUIzE3NDEwMzIwNzkjUEkjMCNQVSM4MCMKWiNWTiMxI1NUIzE3NDEwMzIwNzkjUEkjMCNaSSM1NDI4NjMjVEEjMiNEQSM2MDMyNSMxUyM4MDEwMTEzIzFUIzEzNTUjTFMjODAxMDIyNCNMVCMxNjQ3I1BVIzgwI1JUIzEjQ0EjRFBOI1pFIzczNzM3I1pCI1JFIDczNzM3I1BDIzMjRlIjODAxMTE1NSNGVCMxNDU0I1RPIzgwMTExNjAjVFQjMTQ1OSM=¶KRCC¶#VE#1#VOLL#MRTF#IST#¶SC¶1_H4sIAAAAAAACA22PXUvDMBiF/8p4rxTqSPq1NVCoXSkoxY0xhiJehDXbKmkz8zEspf/dtFUQ9C7n8OSc83ZwZRII4PnSBwfYp7YiS+f7bI5da0j2AaSDxtQ5kMAZHikQ5IAwOqOaWdpFboA8FMJo7qp6MLEfBAhZ6zgm3GEH3ps251oWQF470O1lwDbbdWahWpSDenhaWXGl3IwRyPWgfxtHrc6nKdg2l+xSiMMUw6vSkvexn6zjlEleNc4sZ7JR7KyNrGc3O2FkpWqjbpMijiIcLnAULZLnGHs+isLIT17iwA1c7CGU2HKlp6PysZlK+acK26AlwhiH/3w4MZ1td0C0NGxUG8Fbu4r9sh7tpIa1qTBNqYAcKVffLFWKV0r/sOwgNlTS2kJd3/df/HilQasBAAA=',
echtzeitNotizen: [],
himNotizen: [],
auslastungsInfos: [
{
klasse: 'KLASSE_1',
stufe: 0,
anzeigeTextKurz: 'No occupancy information available',
},
{
klasse: 'KLASSE_2',
stufe: 0,
anzeigeTextKurz: 'No occupancy information available',
},
],
serviceDays: [
{
irregular: 'not 8. until 19. Mar 2025',
letztesDatumInZeitraum: '2025-12-13',
planungsZeitraumAnfang: '2024-12-15',
planungsZeitraumEnde: '2025-12-13',
regular: 'daily',
wochentage: [
'DO',
'FR',
],
},
],
verbindungsAbschnitte: [
{
reservierungsMeldungen: [],
nummer: 0,
abschnittsDauer: 120,
typ: 'FUSSWEG',
halte: [],
distanz: 137,
himNotizen: [],
echtzeitNotizen: [],
attributNotizen: [],
abgangsOrt: {
name: 'Berlin, Fernsehturm (Tourismus)',
locationId: 'A=4@O=Berlin, Fernsehturm (Tourismus)@X=13409694@Y=52521301@U=91@L=991671997@',
evaNr: '991671997',
position: {
latitude: 52.5213,
longitude: 13.409694,
},
},
abgangsDatum: '2025-03-06T14:52:00+01:00',
ezAbgangsDatum: '2025-03-06T14:52:00Z', // upstream bug: wrong time zone offset
ankunftsOrt: {
name: 'Berlin Alexanderplatz',
locationId: 'A=1@O=Berlin Alexanderplatz@X=13410962@Y=52521481@U=80@L=8011155@i=U×008003135@',
evaNr: '8011155',
position: {
latitude: 52.521526,
longitude: 13.411088,
},
stationId: '0053',
},
ankunftsDatum: '2025-03-06T14:54:00+01:00',
ezAnkunftsDatum: '2025-03-06T14:54:00Z', // upstream bug: wrong time zone offset
produktGattung: 'SONSTIGE',
wagenreihung: false,
auslastungsInfos: [
{
klasse: 'KLASSE_1',
stufe: 0,
anzeigeTextKurz: 'No occupancy information available',
},
{
klasse: 'KLASSE_2',
stufe: 0,
anzeigeTextKurz: 'No occupancy information available',
},
],
parallelZuege: [],
},
{
administrationId: 'OWRE__',
risZuglaufId: 'RE_73737',
risAbfahrtId: '8011155_2025-03-06T14:54:00+01:00',
kurztext: 'RE',
mitteltext: 'RE 1',
langtext: 'RE 1 (73737)',
zuglaufId: '2|#VN#1#ST#1741032079#PI#0#ZI#542863#TA#2#DA#60325#1S#8010113#1T#1355#LS#8010224#LT#1647#PU#80#RT#1#CA#DPN#ZE#73737#ZB#RE 73737#PC#3#FR#8010113#FT#1355#TO#8010224#TT#1647#',
reservierungsMeldungen: [],
nummer: 1,
abschnittsDauer: 300,
typ: 'FAHRZEUG',
halte: [
{
abgangsDatum: '2025-03-06T14:54:00+01:00',
ezAbgangsDatum: '2025-03-06T14:55:00+01:00',
ort: {
name: 'Berlin Alexanderplatz',
locationId: 'A=1@O=Berlin Alexanderplatz@X=13410962@Y=52521481@U=80@L=8011155@i=U×008003135@',
evaNr: '8011155',
position: {
latitude: 52.521526,
longitude: 13.411088,
},
stationId: '0053',
},
gleis: '2',
attributNotizen: [],
echtzeitNotizen: [],
himNotizen: [],
auslastungsInfos: [
{
klasse: 'KLASSE_1',
stufe: 0,
anzeigeTextKurz: 'No occupancy information available',
},
{
klasse: 'KLASSE_2',
stufe: 0,
anzeigeTextKurz: 'No occupancy information available',
},
],
},
{
ankunftsDatum: '2025-03-06T14:56:00+01:00',
abgangsDatum: '2025-03-06T14:57:00+01:00',
ezAbgangsDatum: '2025-03-06T14:58:00+01:00',
ezAnkunftsDatum: '2025-03-06T14:57:00+01:00',
ort: {
name: 'Berlin Friedrichstraße',
locationId: 'A=1@O=Berlin Friedrichstraße@X=13387203@Y=52520376@U=80@L=8011306@i=U×008003137@',
evaNr: '8011306',
position: {
latitude: 52.520332,
longitude: 13.386925,
},
stationId: '0527',
},
gleis: '4',
attributNotizen: [],
echtzeitNotizen: [],
himNotizen: [],
auslastungsInfos: [
{
klasse: 'KLASSE_1',
stufe: 0,
anzeigeTextKurz: 'No occupancy information available',
},
{
klasse: 'KLASSE_2',
stufe: 0,
anzeigeTextKurz: 'No occupancy information available',
},
],
},
{
ankunftsDatum: '2025-03-06T14:59:00+01:00',
ezAnkunftsDatum: '2025-03-06T15:00:00+01:00',
ort: {
name: 'Berlin Hbf',
locationId: 'A=1@O=Berlin Hbf@X=13369549@Y=52525589@U=80@L=8011160@i=U×008065969@',
evaNr: '8011160',
position: {
latitude: 52.524925,
longitude: 13.369629,
},
stationId: '1071',
},
gleis: '14',
attributNotizen: [],
echtzeitNotizen: [],
himNotizen: [],
auslastungsInfos: [
{
klasse: 'KLASSE_1',
stufe: 0,
anzeigeTextKurz: 'No occupancy information available',
},
{
klasse: 'KLASSE_2',
stufe: 0,
anzeigeTextKurz: 'No occupancy information available',
},
],
},
],
himNotizen: [],
echtzeitNotizen: [],
attributNotizen: [
{
text: 'Number of bicycles conveyed limited',
key: 'FB',
priority: 260,
},
{
text: 'Conveyance of groups is limited',
key: 'GL',
priority: 330,
},
{
text: 'space for wheelchairs',
key: 'RO',
priority: 560,
},
{
text: 'vehicle-mounted access aid',
key: 'EH',
priority: 560,
},
{
text: 'Behindertengerechte Ausstattung',
key: 'EA',
priority: 560,
},
{
text: 'power sockets for laptop',
key: 'LS',
priority: 605,
},
{
text: 'air conditioning',
key: 'KL',
priority: 610,
},
{
text: 'Wifi available',
key: 'WV',
priority: 710,
},
{
text: 'Ostdeutsche Eisenbahn GmbH',
key: 'OP',
},
],
abgangsOrt: {
name: 'Berlin Alexanderplatz',
locationId: 'A=1@O=Berlin Alexanderplatz@X=13410962@Y=52521481@U=80@L=8011155@i=U×008003135@',
evaNr: '8011155',
position: {
latitude: 52.521526,
longitude: 13.411088,
},
stationId: '0053',
},
abgangsDatum: '2025-03-06T14:54:00+01:00',
ezAbgangsDatum: '2025-03-06T14:55:00+01:00',
ankunftsOrt: {
name: 'Berlin Hbf',
locationId: 'A=1@O=Berlin Hbf@X=13369549@Y=52525589@U=80@L=8011160@i=U×008065969@',
evaNr: '8011160',
position: {
latitude: 52.524925,
longitude: 13.369629,
},
stationId: '1071',
},
ankunftsDatum: '2025-03-06T14:59:00+01:00',
ezAnkunftsDatum: '2025-03-06T15:00:00+01:00',
verkehrsmittelNummer: '73737',
richtung: 'Magdeburg Hbf',
produktGattung: 'RB',
wagenreihung: false,
auslastungsInfos: [
{
klasse: 'KLASSE_1',
stufe: 0,
anzeigeTextKurz: 'No occupancy information available',
},
{
klasse: 'KLASSE_2',
stufe: 0,
anzeigeTextKurz: 'No occupancy information available',
},
],
parallelZuege: [],
polylineGroup: {
polylineDesc: [
{
coordinates: [
{
longitude: 13.411088,
latitude: 52.521526,
},
{
longitude: 13.411088,
latitude: 52.521526,
},
],
delta: false,
},
{
coordinates: [
{
longitude: 13.411088,
latitude: 52.521526,
},
{
longitude: 13.409676,
latitude: 52.522344,
},
{
longitude: 13.408202,
latitude: 52.522964,
},
{
longitude: 13.407177,
latitude: 52.523243,
},
{
longitude: 13.406377,
latitude: 52.523324,
},
{
longitude: 13.40502,
latitude: 52.523252,
},
{
longitude: 13.402233,
latitude: 52.522533,
},
{
longitude: 13.402233,
latitude: 52.522533,
},
{
longitude: 13.401191,
latitude: 52.52238,
},
{
longitude: 13.398629,
latitude: 52.522281,
},
{
longitude: 13.397613,
latitude: 52.522137,
},
{
longitude: 13.396669,
latitude: 52.52185,
},
{
longitude: 13.394125,
latitude: 52.520618,
},
{
longitude: 13.392831,
latitude: 52.520259,
},
{
longitude: 13.389451,
latitude: 52.520025,
},
{
longitude: 13.388309,
latitude: 52.520088,
},
{
longitude: 13.386925,
latitude: 52.520331,
},
{
longitude: 13.38634,
latitude: 52.520564,
},
{
longitude: 13.386322,
latitude: 52.520555,
},
{
longitude: 13.386376,
latitude: 52.520636,
},
{
longitude: 13.382844,
latitude: 52.521391,
},
{
longitude: 13.380129,
latitude: 52.521436,
},
{
longitude: 13.378906,
latitude: 52.521679,
},
{
longitude: 13.377576,
latitude: 52.522308,
},
{
longitude: 13.375598,
latitude: 52.52416,
},
{
longitude: 13.37452,
latitude: 52.524744,
},
{
longitude: 13.373126,
latitude: 52.525158,
},
{
longitude: 13.372398,
latitude: 52.525257,
},
{
longitude: 13.370043,
latitude: 52.525239,
},
{
longitude: 13.370043,
latitude: 52.525239,
},
{
longitude: 13.369567,
latitude: 52.525203,
},
],
delta: false,
},
{
coordinates: [
{
longitude: 13.369567,
latitude: 52.525203,
},
{
longitude: 13.369629,
latitude: 52.524924,
},
],
delta: false,
},
],
},
},
],
}
tap.test('dbnav profile fixes time zone bug', (t) => { // see https://github.com/public-transport/db-vendo-client/issues/24
const parsedJourney = parseJourneyDbnav(ctx, structuredClone(input));
const expectedDeparture = '2025-03-06T14:52:00+01:00';
t.equal(parsedJourney.legs[0].departure, expectedDeparture)
const expectedArrival = '2025-03-06T14:52:00+01:00';
t.equal(parsedJourney.legs[0].arrival, expectedArrival)
const expectedDelay = 0;
t.equal(parsedJourney.legs[0].departureDelay, expectedDelay)
t.equal(parsedJourney.legs[0].arrivalDelay, expectedDelay)
t.end();
})
tap.test('dbnav profile parses journey without time zone bug like other profiles', (t) => {
const _input = structuredClone(input);
// fix bug by hand
_input.verbindungsAbschnitte[0].ezAbgangsDatum = '2025-03-06T14:52:00+01:00';
_input.verbindungsAbschnitte[0].ezAnkunftsDatum = '2025-03-06T14:54:00+01:00';
const expected = parseJourneyDefault(ctx, _input)
t.same(parseJourneyDbnav(ctx, _input), expected);
t.end();
})