Proposal:Charge:conditional with nested conditions and sequences

From OpenStreetMap Wiki
Jump to navigation Jump to search
charge:conditional with nested conditions and sequences
Proposal status: Draft (under way)
Proposed by: Zschoche
Tagging: charge:conditional=*
Applies to: node, way, area, relation
Definition: More powerful and compact syntax for charges with complex conditions
Statistics:

Draft started: 2026-03-30

Problem Statement

Tariff board with a common tariff, that can currently not be captured in OSM.

Parking tariffs often have complex conditions, which are (close to) impossible to encode correctly with the existing charge:conditional=* syntax.

In the example from the image on the right, there are different tariffs for day and night, the price per hour decreases for longer stays, and there is a maximum price per day. Using the current syntax, one could attempt to capture this as follows:

charge:conditional = 2.50 EUR/hour @ 07:00-19:00; 2 EUR/hour @ (07:00-19:00 AND stay > 2 hours); 3 EUR @ 19:00-07:00; 16 EUR/24 hours

However, this is not correct: When the second condition matches, the specified value is 2 EUR/hour. So for a stay of three hours, the charge is specified to be 6 €. In reality it is 7 € – namely 5 € for the first two hours plus 2 € for one additional hour.

One could try to spell out the calculated prices for three, four, five, six and seven hours – each with the 07:00-19:00 restriction – but it is clear, that this is not practical.

Proposal

The proposal is to extend the syntax of charge:conditional=* so that

  • Conditions may be factored out – hence applying to multiple charge specifications at once, and
  • Sequences of charge specifications are allowed – for a simple specification of varying charges.
  • In case of multiple matching charge specifications, the lowest price shall apply – which is intuitive and simple.

With the proposed syntax, the example above could be captured as

charge:conditional = @ 07:00-19:00 (2.50 EUR/hour|2.50 EUR/hour|2 EUR/hour); 3 EUR @ 19:00-07:00; 16 EUR/24 hours

or

charge:conditional = @ 07:00-19:00 (2 hours:2.50 EUR/hour|2 EUR/hour); 3 EUR @ 19:00-07:00; 16 EUR/24 hours

Syntax scheme

The proposed full syntax is as follows (fields in square brackets [ ] are optional, three dots ... show where a list may be continued):

charge:conditional= <charge-conditional> [;  <charge-conditional> [; ...]]

where  <charge-conditional>  may be one of the following:

A simple charge specification  <charge> 
A charge specification sequence [ <for amount> :] <charge> |[ <for amount> :] <charge> [|...]
A simple conditional charge specification  <charge> @ <condition> 
A nested conditional charge specification @ <condition> ( <charge-conditional> )

Charge specifications

Simple charge specifications use the existing syntax: <amount> <currency code> [/<unit>][/<time unit>].

Sequences

Sequences are a proposed new feature. They allow to capture prices that change after a specific number of units. With the  <for amount>  prefix, each sequence item may specify, for how many units the charge specification applies. If the charge specification has only one "per unit" section,  <for amount>  defaults to that unit. The last sequence entry is by default unlimited.

While the formal specification sounds quite complicated, the actual values are reasonably easy to understand. For example, charge:conditional=2 EUR/hour|2 hours:1.50 EUR/hour|1 EUR/hour means "The charge for the first hour is 2 €, for the next two hours 1.50 € per hour, and then 1 € per hour".

Sequences use the pipe symbol (|) as separator, similar to the lanes specification. (However unlike in lanes, sequence entries of charge:conditional=* may not contain semicolons.)

Conditional specifications

Similar to conditional restrictions, conditions may be specified with an "@ condition" suffix:  <charge> @ <condition> .

We propose to also allow "@ condition" as a prefix of a specification enclosed in parenthesis: @ <condition> ( <charge-conditional> ). In this way, the condition applies to all entries within the parenthesis (separated by semicolon ;), leading to less repetition. Also, the entries may again specify additional conditions – which means that both the outer and the inner condition apply.

Semantics of charge specifications

When we write charge:conditional = 2 EUR/hour @ Mo-Sa; 10 EUR/day @ Mo-Sa, it is intuitively clear what this shall mean: Monday to Saturday, the charge is 2 € per hour, but not more than 10 € per day.

If we applied the general resolution rules of conditional restrictions, the meaning would however be different: Monday to Friday, the conditions of both entries would match – so according to the general rules, the last entry would win. So the specification above would mean: Monday to Saturday, the charge is 10 € per day.

One could try to fix this by specifying charge:conditional = 10 EUR/day @ Mo-Sa; 2 EUR/hour @ (Mo-Sa AND stay < 5 hours). This is not particularly elegant, but it (almost) works in this case. (It doesn't work for stays over 1 day.) Still, this approach does not work in general: For the intuitive specification charge:conditional = 2.00 EUR/hour @ (06:00-22:00); 1.50 EUR/hour @ (22:00-06:00); 15.00 EUR/day, there is no way to specify this formally correct if we use the general resolution rules of conditional restrictions. Therefore it is clear, that the charge:conditional values need to be interpreted in a different way.

We propose to use the intuitive interpretation of price list for charge:conditional. Formally, this means the following:

Rule Examples
"Per x units" means "for amounts up to that unit" 3 EUR/2 hours – the charge for 1 hour is 3 €
If there are multiple specifications whose conditions match, the lowest charge amount applies 2 EUR/hour; 10 EUR/24 hours – the charge for 1 hour is 2 €
Unit and time unit amounts may be split to calculate the total charge amount 1 EUR/hour – the charge for 90 minutes is 2 € (1 € + 1 €)

2 EUR/person; 8 EUR/5 persons – the charge for 6 persons is 10 € (8 € + 2 €)

Time ranges may also be split so that certain conditions apply for the parts ...


It shall be clarified that in case of multiple charge specifications whose conditions apply (or are empty), the lowest prices (per currency) applies. This is different to the resolution logic of conditional restrictions (item 6 in ).

Also, we propose to allow time units as condition in the simple form  <charge> @ <condition> . This for example would allow to specify 4 EUR @ 1 hour; 6 EUR @ 1.5 hours; 7 EUR @ 2 hours;… instead of 4 EUR/1 hour; 6 EUR/1.5 hours; 7 EUR/2 hours;…. If the prices are spelled out like in the example – the price for every time interval is explicitly specified and not computed from a "per time unit" specification – the syntax with "@ time unit" is more intuitive.

... semantics

Rationale

Tagging

Examples

Impact on Data Consumers

Features/Pages affected

External discussions

Comments

Please comment on the discussion page.