mirror of
https://github.com/public-transport/db-vendo-client.git
synced 2025-02-23 07:09:35 +02:00
parseDateTime: parse timezone offset if given 💥
This commit is contained in:
parent
a9fd9ff814
commit
ca1105f139
5 changed files with 49 additions and 33 deletions
|
@ -14,11 +14,12 @@ const createParseArrOrDep = (profile, opt, data, prefix) => {
|
||||||
|
|
||||||
const parseArrOrDep = (d) => {
|
const parseArrOrDep = (d) => {
|
||||||
const t = d.stbStop[prefix + 'TimeR'] || d.stbStop[prefix + 'TimeS']
|
const t = d.stbStop[prefix + 'TimeR'] || d.stbStop[prefix + 'TimeS']
|
||||||
|
const tz = d.stbStop[prefix + 'TZOffset'] || null
|
||||||
|
|
||||||
const res = {
|
const res = {
|
||||||
tripId: d.jid,
|
tripId: d.jid,
|
||||||
stop: locations[parseInt(d.stbStop.locX)] || null,
|
stop: locations[parseInt(d.stbStop.locX)] || null,
|
||||||
when: profile.parseDateTime(profile, d.date, t),
|
when: profile.parseDateTime(profile, d.date, t, tz),
|
||||||
// todo: for arrivals, this is the *origin*, not the *direction*
|
// todo: for arrivals, this is the *origin*, not the *direction*
|
||||||
direction: prefix === DEPARTURE && profile.parseStationName(d.dirTxt) || null,
|
direction: prefix === DEPARTURE && profile.parseStationName(d.dirTxt) || null,
|
||||||
line: lines[parseInt(d.prodX)] || null,
|
line: lines[parseInt(d.prodX)] || null,
|
||||||
|
@ -32,8 +33,8 @@ const createParseArrOrDep = (profile, opt, data, prefix) => {
|
||||||
const tR = d.stbStop[prefix + 'TimeR']
|
const tR = d.stbStop[prefix + 'TimeR']
|
||||||
const tP = d.stbStop[prefix + 'TimeS']
|
const tP = d.stbStop[prefix + 'TimeS']
|
||||||
if (tR && tP) {
|
if (tR && tP) {
|
||||||
const realtime = profile.parseDateTime(profile, d.date, tR, true)
|
const realtime = profile.parseDateTime(profile, d.date, tR, tz, true)
|
||||||
const planned = profile.parseDateTime(profile, d.date, tP, true)
|
const planned = profile.parseDateTime(profile, d.date, tP, tz, true)
|
||||||
res.delay = Math.round((realtime - planned) / 1000)
|
res.delay = Math.round((realtime - planned) / 1000)
|
||||||
} else res.delay = null
|
} else res.delay = null
|
||||||
|
|
||||||
|
@ -50,7 +51,7 @@ const createParseArrOrDep = (profile, opt, data, prefix) => {
|
||||||
res.cancelled = true
|
res.cancelled = true
|
||||||
Object.defineProperty(res, 'canceled', {value: true})
|
Object.defineProperty(res, 'canceled', {value: true})
|
||||||
res.when = res.delay = null
|
res.when = res.delay = null
|
||||||
res.formerScheduledWhen = profile.parseDateTime(profile, d.date, tP)
|
res.formerScheduledWhen = profile.parseDateTime(profile, d.date, tP, tz)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt.remarks) {
|
if (opt.remarks) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ const {DateTime, IANAZone} = require('luxon')
|
||||||
const timezones = new WeakMap()
|
const timezones = new WeakMap()
|
||||||
|
|
||||||
// todo: change to `(profile) => (date, time) => {}`
|
// todo: change to `(profile) => (date, time) => {}`
|
||||||
const parseDateTime = (profile, date, time, timestamp = false) => {
|
const parseDateTime = (profile, date, time, tzOffset = null, timestamp = false) => {
|
||||||
const pDate = [date.substr(-8, 4), date.substr(-4, 2), date.substr(-2, 2)]
|
const pDate = [date.substr(-8, 4), date.substr(-4, 2), date.substr(-2, 2)]
|
||||||
if (!pDate[0] || !pDate[1] || !pDate[2]) {
|
if (!pDate[0] || !pDate[1] || !pDate[2]) {
|
||||||
throw new Error('invalid date format: ' + date)
|
throw new Error('invalid date format: ' + date)
|
||||||
|
@ -16,7 +16,7 @@ const parseDateTime = (profile, date, time, timestamp = false) => {
|
||||||
throw new Error('invalid time format: ' + time)
|
throw new Error('invalid time format: ' + time)
|
||||||
}
|
}
|
||||||
|
|
||||||
const offset = time.length > 6 ? parseInt(time.slice(0, -6)) : 0
|
const daysOffset = time.length > 6 ? parseInt(time.slice(0, -6)) : 0
|
||||||
|
|
||||||
let timezone
|
let timezone
|
||||||
if (timezones.has(profile)) timezone = timezones.get(profile)
|
if (timezones.has(profile)) timezone = timezones.get(profile)
|
||||||
|
@ -25,12 +25,20 @@ const parseDateTime = (profile, date, time, timestamp = false) => {
|
||||||
timezones.set(profile, timezone)
|
timezones.set(profile, timezone)
|
||||||
}
|
}
|
||||||
|
|
||||||
let dt = DateTime.fromISO(pDate.join('-') + 'T' + pTime.join(':'), {
|
if (tzOffset !== null) {
|
||||||
locale: profile.locale,
|
// We don't know the timezone, but only the *timezone offset*, which is why we
|
||||||
zone: timezone
|
// can't use Luxon to process the offset.
|
||||||
})
|
const isoOffset = ('0' + (tzOffset / 60 | 0)).slice(-2) + ('0' + (tzOffset % 60)).slice(-2)
|
||||||
if (offset > 0) dt = dt.plus({days: offset})
|
const isoStr = pDate.join('-') + 'T' + pTime.join(':') + '+' + isoOffset
|
||||||
return timestamp ? dt.toMillis() : dt.toISO()
|
return timestamp ? +new Date(isoStr) : isoStr
|
||||||
|
} else {
|
||||||
|
let dt = DateTime.fromISO(pDate.join('-') + 'T' + pTime.join(':'), {
|
||||||
|
locale: profile.locale,
|
||||||
|
zone: timezone
|
||||||
|
})
|
||||||
|
if (daysOffset > 0) dt = dt.plus({days: daysOffset})
|
||||||
|
return timestamp ? dt.toMillis() : dt.toISO()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = parseDateTime
|
module.exports = parseDateTime
|
||||||
|
|
|
@ -49,8 +49,8 @@ const createParseJourneyLeg = (profile, opt, data) => {
|
||||||
// j = journey, pt = part
|
// j = journey, pt = part
|
||||||
// todo: pt.planrtTS
|
// todo: pt.planrtTS
|
||||||
const parseJourneyLeg = (j, pt, parseStopovers = true) => {
|
const parseJourneyLeg = (j, pt, parseStopovers = true) => {
|
||||||
const dep = profile.parseDateTime(profile, j.date, pt.dep.dTimeR || pt.dep.dTimeS)
|
const dep = profile.parseDateTime(profile, j.date, pt.dep.dTimeR || pt.dep.dTimeS, pt.dep.dTZOffset)
|
||||||
const arr = profile.parseDateTime(profile, j.date, pt.arr.aTimeR || pt.arr.aTimeS)
|
const arr = profile.parseDateTime(profile, j.date, pt.arr.aTimeR || pt.arr.aTimeS, pt.arr.aTZOffset)
|
||||||
const res = {
|
const res = {
|
||||||
origin: clone(locations[parseInt(pt.dep.locX)]) || null,
|
origin: clone(locations[parseInt(pt.dep.locX)]) || null,
|
||||||
destination: clone(locations[parseInt(pt.arr.locX)]),
|
destination: clone(locations[parseInt(pt.arr.locX)]),
|
||||||
|
@ -61,13 +61,13 @@ const createParseJourneyLeg = (profile, opt, data) => {
|
||||||
// todo: DRY with parseDeparture
|
// todo: DRY with parseDeparture
|
||||||
// todo: DRY with parseStopover
|
// todo: DRY with parseStopover
|
||||||
if (pt.dep.dTimeR && pt.dep.dTimeS) {
|
if (pt.dep.dTimeR && pt.dep.dTimeS) {
|
||||||
const realtime = profile.parseDateTime(profile, j.date, pt.dep.dTimeR, true)
|
const realtime = profile.parseDateTime(profile, j.date, pt.dep.dTimeR, pt.dep.dTZOffset, true)
|
||||||
const planned = profile.parseDateTime(profile, j.date, pt.dep.dTimeS, true)
|
const planned = profile.parseDateTime(profile, j.date, pt.dep.dTimeS, pt.dep.dTZOffset, true)
|
||||||
res.departureDelay = Math.round((realtime - planned) / 1000)
|
res.departureDelay = Math.round((realtime - planned) / 1000)
|
||||||
}
|
}
|
||||||
if (pt.arr.aTimeR && pt.arr.aTimeS) {
|
if (pt.arr.aTimeR && pt.arr.aTimeS) {
|
||||||
const realtime = profile.parseDateTime(profile, j.date, pt.arr.aTimeR, true)
|
const realtime = profile.parseDateTime(profile, j.date, pt.arr.aTimeR, pt.dep.aTZOffset, true)
|
||||||
const planned = profile.parseDateTime(profile, j.date, pt.arr.aTimeS, true)
|
const planned = profile.parseDateTime(profile, j.date, pt.arr.aTimeS, pt.dep.aTZOffset, true)
|
||||||
res.arrivalDelay = Math.round((realtime - planned) / 1000)
|
res.arrivalDelay = Math.round((realtime - planned) / 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,9 +136,9 @@ const createParseJourneyLeg = (profile, opt, data) => {
|
||||||
|
|
||||||
let when = null, delay = null
|
let when = null, delay = null
|
||||||
if (st0) {
|
if (st0) {
|
||||||
const planned = st0.dTimeS && profile.parseDateTime(profile, j.date, st0.dTimeS)
|
const planned = st0.dTimeS && profile.parseDateTime(profile, j.date, st0.dTimeS, st0.dTZOffset)
|
||||||
if (st0.dTimeR && planned) {
|
if (st0.dTimeR && planned) {
|
||||||
const realtime = profile.parseDateTime(profile, j.date, st0.dTimeR)
|
const realtime = profile.parseDateTime(profile, j.date, st0.dTimeR, st0.dTZOffset)
|
||||||
when = realtime
|
when = realtime
|
||||||
delay = Math.round((new Date(realtime) - new Date(planned)) / 1000)
|
delay = Math.round((new Date(realtime) - new Date(planned)) / 1000)
|
||||||
} else if (planned) when = planned
|
} else if (planned) when = planned
|
||||||
|
@ -161,11 +161,13 @@ const createParseJourneyLeg = (profile, opt, data) => {
|
||||||
Object.defineProperty(res, 'canceled', {value: true})
|
Object.defineProperty(res, 'canceled', {value: true})
|
||||||
if (pt.arr.aCncl) {
|
if (pt.arr.aCncl) {
|
||||||
res.arrival = res.arrivalPlatform = res.arrivalDelay = null
|
res.arrival = res.arrivalPlatform = res.arrivalDelay = null
|
||||||
res.formerScheduledArrival = profile.parseDateTime(profile, j.date, pt.arr.aTimeS)
|
const arr = profile.parseDateTime(profile, j.date, pt.arr.aTimeS, pt.arr.aTZOffset)
|
||||||
|
res.formerScheduledArrival = arr
|
||||||
}
|
}
|
||||||
if (pt.dep.dCncl) {
|
if (pt.dep.dCncl) {
|
||||||
res.departure = res.departurePlatform = res.departureDelay = null
|
res.departure = res.departurePlatform = res.departureDelay = null
|
||||||
res.formerScheduledDeparture = profile.parseDateTime(profile, j.date, pt.dep.dTimeS)
|
const dep = profile.parseDateTime(profile, j.date, pt.dep.dTimeS, pt.dep.dTZOffset)
|
||||||
|
res.formerScheduledDeparture = dep
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,20 +19,22 @@ const createParseStopover = (profile, opt, data, date) => {
|
||||||
// todo: DRY with parseDeparture
|
// todo: DRY with parseDeparture
|
||||||
// todo: DRY with parseJourneyLeg
|
// todo: DRY with parseJourneyLeg
|
||||||
if (st.aTimeR || st.aTimeS) {
|
if (st.aTimeR || st.aTimeS) {
|
||||||
res.arrival = profile.parseDateTime(profile, date, st.aTimeR || st.aTimeS)
|
const arr = profile.parseDateTime(profile, date, st.aTimeR || st.aTimeS, st.aTZOffset)
|
||||||
|
res.arrival = arr
|
||||||
}
|
}
|
||||||
if (st.aTimeR && st.aTimeS) {
|
if (st.aTimeR && st.aTimeS) {
|
||||||
const realtime = profile.parseDateTime(profile, date, st.aTimeR, true)
|
const realtime = profile.parseDateTime(profile, date, st.aTimeR, st.aTZOffset, true)
|
||||||
const planned = profile.parseDateTime(profile, date, st.aTimeS, true)
|
const planned = profile.parseDateTime(profile, date, st.aTimeS, st.aTZOffset, true)
|
||||||
res.arrivalDelay = Math.round((realtime - planned) / 1000)
|
res.arrivalDelay = Math.round((realtime - planned) / 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st.dTimeR || st.dTimeS) {
|
if (st.dTimeR || st.dTimeS) {
|
||||||
res.departure = profile.parseDateTime(profile, date, st.dTimeR || st.dTimeS)
|
const dep = profile.parseDateTime(profile, date, st.dTimeR || st.dTimeS, st.dTZOffset)
|
||||||
|
res.departure = dep
|
||||||
}
|
}
|
||||||
if (st.dTimeR && st.dTimeS) {
|
if (st.dTimeR && st.dTimeS) {
|
||||||
const realtime = profile.parseDateTime(profile, date, st.dTimeR, true)
|
const realtime = profile.parseDateTime(profile, date, st.dTimeR, st.dTZOffset, true)
|
||||||
const planned = profile.parseDateTime(profile, date, st.dTimeS, true)
|
const planned = profile.parseDateTime(profile, date, st.dTimeS, st.dTZOffset, true)
|
||||||
res.departureDelay = Math.round((realtime - planned) / 1000)
|
res.departureDelay = Math.round((realtime - planned) / 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,14 +57,16 @@ const createParseStopover = (profile, opt, data, date) => {
|
||||||
res.formerArrivalDelay = res.arrivalDelay
|
res.formerArrivalDelay = res.arrivalDelay
|
||||||
res.arrival = res.arrivalDelay = null
|
res.arrival = res.arrivalDelay = null
|
||||||
if (st.aTimeS) {
|
if (st.aTimeS) {
|
||||||
res.formerScheduledArrival = profile.parseDateTime(profile, date, st.aTimeS)
|
const arr = profile.parseDateTime(profile, date, st.aTimeS, st.aTZOffset)
|
||||||
|
res.formerScheduledArrival = arr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (st.dCncl) {
|
if (st.dCncl) {
|
||||||
res.formerDepartureDelay = res.departureDelay
|
res.formerDepartureDelay = res.departureDelay
|
||||||
res.departure = res.departureDelay = null
|
res.departure = res.departureDelay = null
|
||||||
if (st.dTimeS) {
|
if (st.dTimeS) {
|
||||||
res.formerScheduledDeparture = profile.parseDateTime(profile, date, st.dTimeS)
|
const arr = profile.parseDateTime(profile, date, st.dTimeS, st.dTZOffset)
|
||||||
|
res.formerScheduledDeparture = arr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,9 +35,10 @@ const parseWarning = (profile, w, icons) => {
|
||||||
category: w.cat || null // todo: parse to sth meaningful
|
category: w.cat || null // todo: parse to sth meaningful
|
||||||
}
|
}
|
||||||
|
|
||||||
if (w.sDate && w.sTime) res.validFrom = parseDateTime(profile, w.sDate, w.sTime)
|
// todo: pass tzOffset to `parseDateTime`
|
||||||
if (w.eDate && w.eTime) res.validUntil = parseDateTime(profile, w.eDate, w.eTime)
|
if (w.sDate && w.sTime) res.validFrom = parseDateTime(profile, w.sDate, w.sTime, null)
|
||||||
if (w.lModDate && w.lModTime) res.modified = parseDateTime(profile, w.lModDate, w.lModTime)
|
if (w.eDate && w.eTime) res.validUntil = parseDateTime(profile, w.eDate, w.eTime, null)
|
||||||
|
if (w.lModDate && w.lModTime) res.modified = parseDateTime(profile, w.lModDate, w.lModTime, null)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue