Proposal:Charge:conditional with nested conditions and sequences
| charge:conditional with nested conditions and sequences | |
|---|---|
| Proposal status: | Draft (under way) |
| Proposed by: | Zschoche |
| Tagging: | charge:conditional=*
|
| Applies to: | |
| Definition: | More powerful and compact syntax for charges with complex conditions |
| Statistics: |
|
| Draft started: | 2026-03-30 |
Problem Statement

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 clearly 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
Rationale
Being able to capture mobility related prices strengthens OSMs profile as map for everyday use. I consider it particularly important to have an non-commercial alternative to commercial parking information platforms (not everything with "-opedia" in the name is open source…).
Tagging
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 between 24 and 29 hours.) However, it 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 lists 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 €)
|
| Time ranges may also be split so that certain conditions apply for the parts | 2 EUR/hour @ 07:00-19:00; 3 EUR @ 19:00-07:00 – the charge for a stay from 18:20 to 19:20 is 5 € (2 € + 3 €)
|
Examples
TODO
Impact on Data Consumers
With the current use of charge:conditional=*, it seems unlikely, that there are already automated consumers of the data. If there were, they would need to be adapted to also cope with the new syntax options. In any case, the previously existing syntax remains valid, so accepting the proposal would not break existing tags.
Through the clarification of semantics of a conditional charge specification, the semantics of existing tags may change. However, at first glance this more often fixes the semantics rather than breaking them - which supports the claim that the new semantics are intuitive.
TODO review existing tags
Features/Pages affected
External discussions
None
Comments
Please comment on the discussion page.