Key:opening hours/specification

From OpenStreetMap Wiki
Jump to navigation Jump to search

Grammar for opening_hours values

This specification is an enhanced version based on the original specification at netzwolf.info (mirror).

It is a formal description of the syntax used for the tag opening_hours=* which the community defined over the years and is intended as reference for mappers and developers. The most sophisticated implementation of this specification is opening_hours.js which can also be used to test if your opening_hours value complies with this specification.

To make it easier for mappers to refer to this specification the evaluation tool links to this specification. Check out the section „prettified opening_hours value for displaying“ from which all the parts of the value are linked to the corresponding documentation on this page.

Note that the syntax was originally introduced to describe opening hours for facilities, but as the syntax has become flexible and powerful it is now also used for many other time related tags in OSM which are listed here.

Overview of the general construction of the syntax

Each opening_hours value (described by the syntax symbol <time_domain>) consists of one or more rules (symbol <rule_sequence>), separated by rule separators (<any_rule_separator>).

Each rule specifies a set of dates (using <wide_range_selectors>), a set of weekdays (<weekday_selectors>), and a set of hours (<time_selector>) that apply to those weekdays in the given date set. If a date set is not given, then the rule applies to all dates; if a weekday set is not given, then the rule applies to all weekdays.

By default, a rule specifies hours when the facility is open, but this can be changed by appending a rule modifier (<rule_modifier>), for example to closed. Rule modifiers can also contain natural language comments enclosed in double quotes.

If several rules apply to a given day, then the type of rule separator determines how the hours specified by those rules are to be combined.

Known issues

Legend

  • "|" separates alternatives.
  • "[" and "]" optional components.
  • "{" and "}" optional repeatable components.
  • Multiple productions for one symbol connote alternatives.
  • Characters or words which are bold are keywords (or tokens) in the syntax.
  • Example values are emphasized.
  • Symbols in the syntax diagram are referenced like this: <selector_sequence>

Syntax diagram

Specification version 0.7.1. The specification versioning complies with Semantic Versioning. Increase the version accordingly when updating the specification.

Note that the English version of the specification is considered the official documentation. Translations of the specification might not be up-to-date or in compliance with the latest version yet.

time_domain
Symbol Definition Comment
<time_domain> <rule_sequence> { <any_rule_separator> <rule_sequence> } Explanation
<rule_sequence>

<selector_sequence> <space> <rule_modifier>

Limitations and Explanation
Rule separators
<any_rule_separator> <normal_rule_separator> | <additional_rule_separator> | <fallback_rule_separator>
<normal_rule_separator> ; <space>
<additional_rule_separator> , <space> Limitations and Explanation
<fallback_rule_separator>

<space> || <space>

Explanation
Rule modifiers
<rule_modifier> → open (Explanation)
open [ <space> <comment> ] → open
closed | off [ <space> <comment> ] → closed (Explanation)
unknown [ <space> <comment> ] → unknown
<comment>
Selectors
<selector_sequence> 24/7 Explanation
<wide_range_selectors> <small_range_selectors>
<wide_range_selectors>

[ <year_selector> ] [ <monthday_selector> ] [ <week_selector> ] [ <separator_for_readability> ]

<comment>: Explanation
<small_range_selectors>

[ <weekday_selector> ] [ <time_selector> ]

<separator_for_readability> : Explanation
Time selector
<time_selector> <timespan> { , <timespan> }
<timespan>
<time> Limitations and Explanation
<time> + Explanation
<time> - <extended_time> +
<time> - <extended_time>
<time> - <extended_time> / <minute> Limitations and Explanation
<time> - <extended_time> / <hour_minutes>
<time> <hour_minutes> | <variable_time>
<extended_time>

<extended_hour_minutes> | <variable_time>

<variable_time> <event>
( <event> <plus_or_minus> <hour_minutes> )
<event>

dawn | sunrise | sunset | dusk

Weekday selector
<weekday_selector> <weekday_sequence> Explanation
<holiday_sequence>
<holiday_sequence> , <weekday_sequence>
<weekday_sequence> , <holiday_sequence>
<holiday_sequence> <space> <weekday_sequence>
<weekday_sequence> <weekday_range> { , <weekday_range> }
<weekday_range> <wday>
<wday> - <wday>
<wday> [ <nth_entry> { , <nth_entry> } ] Explanation
<wday> [ <nth_entry> { , <nth_entry> } ] <day_offset>
<holiday_sequence> <holiday> { , <holiday> }
<holiday> <public_holiday> [ <day_offset> ] Limitations and Explanation
<school_holiday>
<public_holiday> PH
<school_holiday> SH Explanation
<nth_entry> <nth>
<nth> - <nth>
- <nth>
<nth> 1 | 2 | 3 | 4 | 5
<day_offset> <space> <plus_or_minus> <positive_number> <space> day[s]
Week selector
<week_selector> week <week> { , <week> }
<week> <weeknum>
<weeknum> - <weeknum>
<weeknum> - <weeknum> / <positive_number> Explanation
Month selector
<monthday_selector> <monthday_range> { , <monthday_range> }
<monthday_range> [ <year> ] <month>
[ <year> ] <month> - <month>
<date_from> Explanation
<date_from> [ <date_offset> ] + Explanation
<date_from> [ <date_offset> ] - <date_to> [ <date_offset> ] Explanation
<date_offset> [ <plus_or_minus> <wday> ] [ <day_offset> ] Explanation
<date_from> [ <year> ] <month> <daynum>
[ <year> ] <variable_date>
<date_to> <date_from>
<daynum> Explanation
<variable_date> easter Explanation
Year selector
<year_selector> <year_range> { , <year_range> }
<year_range> <year>
<year> - <year>
<year> - <year> / <positive_number>
<year> +
Basic elements
<plus_or_minus>

+ | -

<hour>

00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24

<extended_hour>

<hour> | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48

<minute>

00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59

<hour_minutes> <hour>:<minute>
<extended_hour_minutes> <extended_hour>:<minute> Explanation
<wday>

Su | Mo | Tu | We | Th | Fr | Sa

<daynum>

01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31

<weeknum>

01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53

Explanation
<month>

Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec

<year> Four digit number greater than 1900.
<positive_number> Integer greater than zero (not zero padded).
<comment> " <comment_character> { <comment_character> } " Explanation
<comment_character> Any character except ".
<space> " "

Explanations

time_domain
Symbol Explanations
<time_domain> This is a list of rules, each being an instance of <rule_sequence>.

The first rule, as well as all rules that come before the <normal_rule_separator> (a semicolon), are considered normal rules; all rules preceded by the <additional_rule_separator> (a comma) are considered additional rules, and a rule preceded by the <fallback_rule_separator> (||) is considered a fallback rule.

Rules are evaluated from left to right. If a normal rule that specifies open hours applies to a given day, then this rule overrides all earlier rules applying to that day. If an additional rule applies to a given day, then earlier rules are not overridden, but the hours are added on.

Examples:

  • normal rule; --notice the semicolon after the normal rule
  • additional rule, --notice the comma after the additional rule
  • fallback rule || --notice the double bars after the fallback rule

Please note that the first rule is considered a normal rule.

In Practice:

  • "Mo-Sa 09:00-12:00; We 15:00-18:00" is closed on Wednesday morning since the earlier rule is overridden
  • "Mo-Sa 09:00-12:00, We 15:00-18:00" is open on Wednesday morning and on Wednesday afternoon.
  • "Sa 16:00-03:00, Su 16:00-23:00" is open on early Sunday morning.
  • "Sa 16:00-03:00; Su 16:00-23:00" is closed on early Sunday morning, which was probably not intended.
<rule_sequence> Note that a <rule_sequence> cannot be empty of course. Only insert <space> if neither <selector_sequence> nor <rule_modifier> is empty.
<additional_rule_separator> Read more about additional rules (including some examples) in this issue on github.

Because of the peskiness that the <additional_rule_separator> is the same token as the token to separate lists (e.g. <timespan> { , <timespan> }) the , (comma) is only interpreted as <additional_rule_separator> if it follows after one of these symbols:

<fallback_rule_separator> The rule which follows this separator (token) will match every time frame not covered by previous rules.
<rule_modifier> (empty) Default state is open (for one rule). If no <rule_modifier> is specified, then the <rule_sequence> is interpreted as open.
<rule_modifier> (closed) Rules with the closed or off modifier will cut off the times they match. Note that they will not overwrite anything else as rules with other <rule_modifier> would do. See this issue on github for more details.
<selector_sequence> (empty) Meant as "always". This selector will match anytime.
<wide_range_selectors> (no syntax) Sometimes you cannot (yet) specify exactly the valid calendar days.

In this case you can use plain text in a comment followed by :.

<separator_for_readability> Optional. Does not change the meaning in any way. Was introduced to enhance the readability. Some implementations might still rely on this. If you implement this syntax, consider the <separator_for_readability> as optional.
<timespan> (point in time) This is only valid in point in time mode (tags like collection_times=*).
<timespan> (open end) The opening time starts at the given time without defined closing time.

This kind of indication is used quite often; but of course it is impossible to evaluate it verbatim. The evaluations is described here.

18:00+ is open from 18:00 with open end.

18:00-22:00+ is open from 18:00 till 22:00 with open end after 22:00.

<timespan> (shortcut for pattern points in time) This notation describes a repeated event:

10:00-16:00/90 and 10:00-16:00/1:30 are evaluated as "from ten am to four pm every 1½ hours". Especially departure times can be written very concise and compact using this notation. The interval time following the "/" is valid but ignored for opening_hours.

This is only valid in point in time mode (tags like collection_times=*.

<weekday_selector> Symbols (<holiday_sequence> or <weekday_sequence> in this case) separated by <space> are and combined meaning both parts must match in order for the rule to apply.

Comma separated symbols are as usual or combined meaning that at least one part must match.

<weekday_range> (n-th weekday in month) Su represents all Sundays, Su[1] represents the first Sunday of a month, Su[-1] represents the last Sunday of a month.
<holiday> Only a day shift around one day (± 1 day) is currently defined.
<school_holiday> Can be used to express holidays as explained here or on the Key page. There are other shortcuts used as discussed on the talk page but they are not yet included in the specification.
<week> This notation is borrowed from cron and enables to express "in even weeks" or "on odd days".
<monthday_range> Evaluates to true of the date to check equals this day, to false otherwise.
<monthday_range> (plus) "Until further notice": the calendar range starts at this date and has no upper limit.
<monthday_range> (range) Evaluates to true, if from-dateday-to-checkto-date holds.

Evaluates to true, if from-date > to-date holds, year is not specified and either day-to-checkfrom-date or day-to-checkto-date holds. Evaluates to false otherwise.

<date_offset> Given any calendar day, the notation + Su selects the first Sunday after this calendar day, the notation - Su selects the last Sunday before this calendar day.
<date_to> (daynum) A day missing a month is assumed to refer to the last month found before. So Jan 23-25 is evaluated as Jan 23-Jan 25.
<variable_date> There may be more <variable_date> s which are worth adding but until now only easter is supported. If something is missing please yell.
<extended_hour_minutes> Can be used to express opening hours wrapping over midnight. Opening hours wrapping over midnight can also be expressed if the second time (e.g. 04:00) is less than the first time (e.g. 22:00) for a value like Fr,Sa 22:00-04:00 which is probably easier to read especially if the second time is greater (compare Fr,Sa 22:00-20:00 with Fr,Sa 22:00-44:00).
<weeknum> The ISO 8601 definition for week 01 is the same week as January 4, i.e. (equivalently) the ISO week (starting on Monday) with the year's first Thursday in it. See Wikipedia. The first and last ISO weeks of the year may have up to 3 days in the next or previous Gregorian year: each ISO week always includes 7 consecutive days, and ISO weeks in the same "ISO year" are numbered from 01 to 52 or 53.
An alternate business week numbering frequently used in US is defined so that week 01 is also the same week as January 4, but it is the first US week (starting on Sunday) with the year's first Wednesday in it.
Business week numbering will then be offsetted by 1 thoughout the year (except on Sundays) between the ISO and US week calendars whenever January 4 is on Sunday.
In both cases, week 01 does not necessarily include January 1-3, which could be counted as part of the last week of the previous year.
A more rarely used week numbering defines week 01 as the same week with January 1 in it.
<comment> Comments can be used to give the user additional information or limitations. It can also be used when the opening hours cannot be reliable determined by software because they depend on some subjective information e.g. weather. The language should be the native language of the region to which the opening hours apply.

Examples:

  • Mo-Fr 08:00-09:00 open "only service", Mo-Fr 09:00-16:00 open "service and sales"
  • Mo-Sa "on appointment"
  • Mo 12:00-14:00 open "female only", Mo 14:00-16:00 open "male only"
  • Mo-Sa 08:00-13:00,14:00-17:00 || "on appointment"
  • Tu 17:00-19:30 "days on schedule (see website)"
  • Mo-Sa 08:00-13:00,14:00-17:00 || "on appointment"; PH off (This means that there are no appointments on public holidays.)
  • Mo-Sa 08:00-13:00,14:00-17:00 unknown "not on bad weather days!"