public-transport / hafas-client

JavaScript client for HAFAS public transport APIs.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Is there a way to query journeys from a certain timepoint to a certain time point?

bognar-dev opened this issue · comments

Here is my request:

{
from_location: '8098096',
  from_time: '2023-01-24',
  to_time: '2023-01-25'
}

this is how I try to call it

const { journeys } = await hafas.journeys(location, '8000261', {
        results: 20,
    })

I just couldn't find an option to pass in for the two date times.
I am also aware that i would probably have to convert the Dates to Date objects.

Is it possible to get journey data from all connections between two stations?
If you have any other questions regarding this, please ask me.

You can pass the start/from date+time as departure into the options object:

await HAFAS.journeys('8098096', '8000261', {
	results: 20,
	// make an ISO 8601 string
	departure: from_time + 'T00:00+01:00',
})

This effectively queries journeys by their earliest departure time. Alternatively, you can pass in the latest acceptable arrival time as opt.arrival, and HAFAS will "search backwards in time". Passing both opt.departure and opt.arrival is not possible, due to limitations in the HAFAS API – It's been a while since have checked wether these limitations still apply though.

I am also aware that i would probably have to convert the Dates to Date objects.

Currently, with hafas-client@6, you can pass anything that new Date(input) can handle, so (almost all) ISO 8601 strings, Date objects, millisecond UNIX timestamps.

Is it possible to get journey data from all connections between two stations?

What does "all" mean in your context?

It might sound obvious, but there is an almost infinite number of possible journeys between two stops. Even if you only keep those that departure after from_time (from your example) and arrive before to_time, there are usually dozens or hundreds of possible journeys.

When called via hafas.journeys(), HAFAS's routing engine tries to find those that, according to some weighting of several factors (e.g. travel time, nr of changes, amount of walking, potentially many more), "fit well" (or "fit best", not sure if HAFAS has pareto-optimal routing).

This leads me to the question: What do you actually want to do?

@derhuerst

Let's say we pass the opt:

transfers: 0 // Maximum nr of transfers.

That should mean HAFAS is searching for only direct trains, correct?

Then combine it with the constraint of a timeframe of

from_time : 26.01.2023T09:00
to_time :25.01.2023T17:00
That should be a timeframe of 8 hours and with like a direct train once an hour it should return 8 trains possible?

If there is not such an option,
Then maybe looping with variable times could be an option.

Thank you very much for your fast replies.

What do you actually want to do?

Using the method you described, you can iterate over those direct trains between the stops that the routing algorithm deemed "good enough". You don't necessarily get all trains running between those stops.

What do you actually want to do?

I want to get the ICE's between let's say Düsseldorf and Hamburg for the next 8 hours, and then filter for the one with the cheapest price?

How do tell the api to just give me the ICE's for 8 hours departure time slot?

As I elaborated, that won't necessarily (as in: there are no guarantees) give you all ICEs between the two stations, and thus not necessarily give you the cheapest. For pricing, there is a different API (flavour) used by db-prices.

Nevertheless, here's a snippet with the aforementioned limitations:

import {createClient} from 'hafas-client/index.js'
import {profile as dbProfile} from 'hafas-client/p/db/index.js'

// don't send `rtMode: REALTIME`, breaks iteration
// see https://github.com/public-transport/hafas-client/issues/282#issuecomment-1373612431
const dbProfileWithoutRtModeRealtime = {
	...dbProfile,
	transformReqBody: (ctx, body) => {
		const reqBody = dbProfile.transformReqBody(ctx, body)
		delete reqBody.svcReqL[0].cfg.rtMode
		return reqBody
	}
}

const hafas = createClient(dbProfileWithoutRtModeRealtime, 'journeys iteration demo')

const from = '8000085' // Düsseldorf Hbf
const to = '8096009' // HAMBURG
const start = Date.parse('2023-02-14T07:00+01:00')

const latestJourneyDep = (journeys) => {
	const deps = journeys.map((journey) => {
		const dep = journey.legs[0].departure || j.legs[0].plannedDeparture
		return +Date.parse(dep)
	})
	deps.sort()
	return deps[0]
}

const collectedJourneys = []
let journeysOpts = {departure: start}
while (true) {
	const {
		journeys,
		laterRef,
	} = await hafas.journeys(from, to, journeysOpts)

	if (journeys.length === 0) break
	collectedJourneys.push(...journeys)
	if ((latestJourneyDep(journeys) - start) > 8 * 3600 * 1000) break

	journeysOpts = {laterThan: laterRef}
}

console.log(collectedJourneys)

Due to #282 (comment), currently, the default DB profile does not allow iterating ("scrolling") through journeys() results using opt.laterThan, so we patch transformReqBody() not to send rtMode: 'REALTIME'.

Does that answer your question?

Yes thank you very much for the effort

How do tell the api to just give me the ICE's for 8 hours departure time slot?

Just as a side note, I think for the use case of direct connections it is much easier to query the departure board for the origin station and the arrival board for the destination station and join the trips on your own (easy since they will have the same tripId). For the departure/arrival boards, you can specify a duration and/or maxResults. You don't get pricing information then though.