Index: /trunk/data/opening_hours.js
===================================================================
--- /trunk/data/opening_hours.js	(revision 6419)
+++ /trunk/data/opening_hours.js	(revision 6420)
@@ -1102,9 +1102,12 @@
 				weekday:  'Mo-Fr',
 				weekdays: 'Mo-Fr',
+			}, 'Please ommit "<ko>" or use a colon instead: "12:00-14:00".': {
+				h: '',
 			}, 'Please ommit "<ko>".': {
-				h: '',
 				season: '',
 			}, 'Please ommit "<ko>". You might want to express open end which can be specified as "12:00+" for example': {
 				from: '',
+			}, 'Please use notation "<ok>" for "<ko>". If the times are unsure or variate consider a comment e.g. 12:00-14:00 "only on sunshine".': {
+				'~':  '-',
 			}, 'Please use notation "<ok>" for "<ko>".': {
 				'–':  '-',
@@ -1155,5 +1158,5 @@
 				nov: 10,
 				dec: 11,
-			}, 'Please use the englisch abbreviation "<ok>" for "<ko>".': {
+			}, 'Please use the English abbreviation "<ok>" for "<ko>".': {
 				january:    0,
 				february:   1,
@@ -1215,9 +1218,12 @@
 				fr: 5,
 				sa: 6,
+			}, 'Assuming "<ok>" for "<ko>"': {
+				m:          1,
+				w:          3,
+				f:          5,
 			}, 'Please use the abbreviation "<ok>" for "<ko>".': {
 				sun:        0,
 				sunday:     0,
 				sundays:    0,
-				m:          1,
 				mon:        1,
 				monday:     1,
@@ -1226,5 +1232,4 @@
 				tuesday:    2,
 				tuesdays:   2,
-				w:          3,
 				wed:        3,
 				wednesday:  3,
@@ -1233,5 +1238,4 @@
 				thursday:   4,
 				thursdays:  4,
-				f:          5,
 				fri:        5,
 				friday:     5,
@@ -1240,22 +1244,30 @@
 				saturday:   6,
 				saturdays:  6,
+			}, 'Bitte benutze die englische Abkürzung "<ok>" für "<ko>". Could also mean Saturday in Polish …': {
+				so:         0,
 			}, 'Bitte benutze die englische Abkürzung "<ok>" für "<ko>".': {
-				so:         0,
-				son:        0,
-				sonntag:    0,
-				montag:     1,
-				di:         2,
-				die:        2,
-				dienstag:   2,
-				mi:         3,
-				mit:        3,
-				mittwoch:   3,
-				'do':       4,
-				don:        4,
-				donnerstag: 4,
-				fre:        5,
-				freitag:    5,
-				sam:        6,
-				samstag:    6,
+				son:         0,
+				sonntag:     0,
+				sonntags:    0,
+				montag:      1,
+				montags:     1,
+				di:          2,
+				die:         2,
+				dienstag:    2,
+				dienstags:   2,
+				mi:          3,
+				mit:         3,
+				mittwoch:    3,
+				mittwochs:   3,
+				'do':        4,
+				don:         4,
+				donnerstag:  4,
+				donnerstags: 4,
+				fre:         5,
+				freitag:     5,
+				freitags:    5,
+				sam:         6,
+				samstag:     6,
+				samstags:    6,
 			}, 'S\'il vous plaît utiliser l\'abréviation "<ok>" pour "<ko>".': {
 				dim:      0,
@@ -1291,5 +1303,5 @@
 				zat:       6,
 				zaterdag:  6,
-			}, 'Please use the englisch abbreviation "<ok>" for "<ko>".': { // FIXME: Translate to Czech.
+			}, 'Please use the English abbreviation "<ok>" for "<ko>".': { // FIXME: Translate to Czech.
 				'neděle':  0,
 				'ne':      0,
@@ -1305,5 +1317,5 @@
 				'pá':      5,
 				'sobota':  6,
-			}, 'Please use the englisch abbreviation "<ok>" for "<ko>".': {
+			}, 'Please use the English abbreviation "<ok>" for "<ko>".': {
 				// Spanish.
 				'martes':    0,
@@ -1331,4 +1343,12 @@
 				'fredag':  5,
 				'lördag':  6,
+				// Polish
+				'niedziela': 0, 'niedz': 0, 'n': 0, 'ndz': 0,
+				'poniedziałek': 1, 'poniedzialek': 1, 'pon': 1, 'pn': 1,
+				'wtorek': 2, 'wt': 2,
+				'środa': 3, 'sroda': 3, 'śr': 3, 'sr': 3,
+				'czwartek': 4, 'czw': 4, 'cz': 4,
+				'piątek': 5, 'piatek': 5, 'pt': 5,
+				'sobota': 6, 'sob': 6, // 'so': 6 // abbreviation also used in German
 			},
 		},
@@ -1569,5 +1589,5 @@
 					curr_block_tokens.push([tmp[0].toLowerCase(), 'calcday', value.length ]);
 					value = value.substr(tmp[0].length);
-				} else if (tmp = value.match(/^(&|–|[a-zA-ZäÄàÀéÉ]+\b)\.?/i)) {
+				} else if (tmp = value.match(/^(&|–|~|[a-zA-ZäÄàÀéÉ]+\b)\.?/i)) {
 					// Handle all remaining words with error tolerance
 					var correct_val = returnCorrectWordOrToken(tmp[1].toLowerCase(), value.length);
@@ -1740,5 +1760,5 @@
 						|| matchTokens(tokens, at, 'year', 'event')
 						|| matchTokens(tokens, at, 'event')) {
-					at = parseMonthdayRange(tokens, at);
+					at = parseMonthdayRange(tokens, at, nblock);
 					week_stable = false;
 				} else if (matchTokens(tokens, at, 'year')) {
@@ -1751,8 +1771,12 @@
 					at = parseWeekRange(tokens, at + 1);
 					week_stable = false;
+
+					// if (prettified_group_value[-1] != ' ')
+					// 	prettified_group_value = prettified_group_value.substring(0, prettified_group_value.length - 1);
 				} else if (at != 0 && at != tokens.length - 1 && tokens[at][0] == ':') {
 					// Ignore colon if they appear somewhere else than as time separator.
+					// Except the start or end of the value.
 					// This provides compatibility with the syntax proposed by Netzwolf:
-					// http://www.netzwolf.info/en/cartography/osm/time_domain/specification
+					// http://wiki.openstreetmap.org/wiki/Key:opening_hours:specification
 					if (!done_with_warnings && matchTokens(tokens, at-1, 'weekday') || matchTokens(tokens, at-1, 'holiday'))
 						parsing_warnings.push([nblock, at, 'Please don’t use ":" after ' + tokens[at-1][1] + '.']);
@@ -1763,5 +1787,6 @@
 				} else if (matchTokens(tokens, at, 'number', 'timesep')
 						|| matchTokens(tokens, at, 'timevar')
-						|| matchTokens(tokens, at, '(', 'timevar')) {
+						|| matchTokens(tokens, at, '(', 'timevar')
+						|| matchTokens(tokens, at, 'number', '-')) {
 					at = parseTimeRange(tokens, at, selectors);
 
@@ -1833,4 +1858,15 @@
 
 				if (typeof conf != 'undefined') {
+
+					// 'Mo: 12:00-13:00' -> 'Mo 12:00-13:00'
+					if (used_subparsers['time ranges'] && old_at > 1 && tokens[old_at-1][0] == ':'
+							&& matchTokens(tokens, old_at - 2, 'weekday'))
+						prettified_group_value = prettified_group_value.substring(0, prettified_group_value.length - 2) + ' ';
+
+					// 'week 1, week 3' -> 'week 1,week 3'
+					if (prettified_group_value.substr(prettified_group_value.length -2, 2) == ', '
+							&& matchTokens(tokens, old_at, 'week'))
+						prettified_group_value = prettified_group_value.substring(0, prettified_group_value.length - 1);
+
 					prettified_group_value += prettifySelector(tokens, old_at, at, conf, used_subparsers['time ranges']);
 				}
@@ -2043,4 +2079,52 @@
 							(has_normal_time[1] ? 3 : (has_time_var_calc[1] ? 7 : !has_open_end))
 							);
+				} else if (matchTokens(tokens, at, 'number', '-', 'number')) { // "Mo 09-18" -> "Mo 09:00-18:00". Please don’t use this
+					var minutes_from = tokens[at][0]   * 60;
+					var minutes_to   = tokens[at+2][0] * 60;
+					if (!done_with_warnings)
+						parsing_warnings.push([nblock, at + 2,
+							'Time range without minutes specified. Not very explicit! Please use this syntax instead e.g. "12:00-14:00".']);
+
+					if (minutes_from >= minutes_in_day)
+						throw formatWarnErrorMessage(nblock, at,
+							'Time range starts outside of the current day');
+					if (minutes_to < minutes_from)
+						minutes_to += minutes_in_day;
+					if (minutes_to > minutes_in_day * 2)
+						throw formatWarnErrorMessage(nblock, at + 2,
+							'Time spanning more than two midnights not supported');
+
+					if (minutes_to > minutes_in_day) {
+						selectors.time.push(function(minutes_from, minutes_to) { return function(date) {
+							var ourminutes = date.getHours() * 60 + date.getMinutes();
+
+							if (ourminutes < minutes_from)
+								return [false, dateAtDayMinutes(date, minutes_from)];
+							else
+								return [true, dateAtDayMinutes(date, minutes_to)];
+						}}(minutes_from, minutes_to));
+
+						selectors.wraptime.push(function(minutes_from, minutes_to) { return function(date) {
+							var ourminutes = date.getHours() * 60 + date.getMinutes();
+
+							if (ourminutes < minutes_to)
+								return [true, dateAtDayMinutes(date, minutes_to)];
+							else
+								return [false, undefined];
+						}}(minutes_from, minutes_to - minutes_in_day));
+					} else {
+						selectors.time.push(function(minutes_from, minutes_to) { return function(date) {
+							var ourminutes = date.getHours() * 60 + date.getMinutes();
+
+							if (ourminutes < minutes_from)
+								return [false, dateAtDayMinutes(date, minutes_from)];
+							else if (ourminutes < minutes_to)
+								return [true, dateAtDayMinutes(date, minutes_to), has_open_end];
+							else
+								return [false, dateAtDayMinutes(date, minutes_from + minutes_in_day)];
+						}}(minutes_from, minutes_to));
+					}
+
+					at += 3;
 				} else { // additional block
 					if (matchTokens(tokens, at, '('))
@@ -2633,5 +2717,5 @@
 						var is_range   = true;
 						var has_period = true;
-						if (tokens[at+4][0] == 1 && !done_with_warnings)
+						if (!done_with_warnings && tokens[at+4][0] == 1)
 							parsing_warnings.push([nblock, at+1+3, 'Please don’t use year ranges with period equals one (see README)']);
 					} else {
@@ -2758,4 +2842,9 @@
 				if (!matchTokens(tokens, at, ','))
 					break;
+
+				if (!matchTokens(tokens, at+1, 'number')) {
+					at++; // we don‘t need the comma in parseGroup
+					break;
+				}
 			}
 
@@ -2889,5 +2978,5 @@
 		// Month day range parser (Jan 26-31; Jan 26-Feb 26)
 		//======================================================================
-		function parseMonthdayRange(tokens, at) {
+		function parseMonthdayRange(tokens, at, nblock) {
 			for (; at < tokens.length; at++) {
 				var has_year = [], has_month = [], has_event = [], has_calc = [], has_constrained_weekday = [], has_calc = [];
@@ -3055,5 +3144,7 @@
 							return [true, to_date];
 
-						var period = tokens[at+5][0];
+						var period = tokens[at+has_year+5][0];
+						if (!done_with_warnings && period == 1)
+							parsing_warnings.push([nblock, at+has_year+5, 'Please don’t use day ranges with period equals one (see README)']);
 						var nday = Math.floor((date.getTime() - from_date.getTime()) / msec_in_day);
 						var in_period = nday % period;
@@ -3063,4 +3154,5 @@
 						else
 							return [false, new Date(date.getFullYear(), date.getMonth(), date.getDate() + period - in_period)];
+
 					}}(tokens, at, is_range, has_period, has_year[0]));
 
@@ -3275,5 +3367,5 @@
 			var start_at = at;
 			while (at < last_at) {
-				if (matchTokens(tokens, at, 'weekday')) {
+				if (matchTokens(tokens, at, 'weekday')) { // FIXME
 					if (!conf.leave_weekday_sep_one_day_betw
 						&& at - start_at > 1 && (matchTokens(tokens, at-1, ',') || matchTokens(tokens, at-1, '-'))
@@ -3284,9 +3376,19 @@
 					value += weekdays[tokens[at][0]];
 				} else if (at - start_at > 0 && used_parseTimeRange > 0 && matchTokens(tokens, at-1, 'timesep')
-						&& matchTokens(tokens, at, 'number')) {
+						&& matchTokens(tokens, at, 'number')) { // '09:0' -> '09:00'
 					value += (tokens[at][0] < 10 ? '0' : '') + tokens[at][0].toString();
 				} else if (used_parseTimeRange > 0 && conf.leading_zero_hour && at != tokens.length
-						&& matchTokens(tokens, at+1, 'timesep')) {
+						&& matchTokens(tokens, at, 'number')
+						&& matchTokens(tokens, at+1, 'timesep')) { // '9:00' -> '19:00'
 					value += (tokens[at][0] < 10 ? (tokens[at][0] == 0 && conf.one_zero_if_hour_zero ? '' : '0') : '') + tokens[at][0].toString();
+				} else if (used_parseTimeRange > 0 && at + 2 < last_at
+						&& matchTokens(tokens, at, 'number')
+						&& matchTokens(tokens, at+1, '-')
+						&& matchTokens(tokens, at+2, 'number')) { // '9-18' -> '09:00-18:00'
+					value += (tokens[at][0] < 10 ? (tokens[at][0] == 0 && conf.one_zero_if_hour_zero ? '' : '0') : '') + tokens[at][0].toString();
+					value += ':00-';
+					value += (tokens[at+2][0] < 10 ? '0' : '') + tokens[at+2][0].toString();
+					value += ':00';
+					at += 3;
 				} else if (matchTokens(tokens, at, 'comment')) {
 					value += '"' + tokens[at][0].toString() + '"';
@@ -3307,5 +3409,5 @@
 					value += months[[tokens[at][0]]];
 					if (at + 1 < last_at && matchTokens(tokens, at+1, 'weekday'))
-					value += ' ';
+						value += ' ';
 				} else if (at + 2 < last_at
 						&& (matchTokens(tokens, at, '-') || matchTokens(tokens, at, '+'))
Index: /trunk/test/unit/org/openstreetmap/josm/data/validation/tests/OpeningHourTestTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/validation/tests/OpeningHourTestTest.java	(revision 6419)
+++ /trunk/test/unit/org/openstreetmap/josm/data/validation/tests/OpeningHourTestTest.java	(revision 6420)
@@ -82,4 +82,12 @@
 
     @Test
+    public void testCheckOpeningHourSyntaxTicket9367() throws Exception {
+        final String key = "opening_hours";
+        assertThat(OPENING_HOUR_TEST.checkOpeningHourSyntax(key, "Mo,Tu 04-17").get(0).getSeverity(), is(Severity.WARNING));
+        assertThat(OPENING_HOUR_TEST.checkOpeningHourSyntax(key, "Mo,Tu 04-17").get(0).getMessage(), is("Mo,Tu 04-17 <--- (Time range without minutes specified. Not very explicit! Please use this syntax instead e.g. \"12:00-14:00\".)"));
+        assertThat(OPENING_HOUR_TEST.checkOpeningHourSyntax(key, "Mo,Tu 04-17").get(0).getPrettifiedValue(), is("Mo,Tu 04:00-17:00"));
+    }
+
+    @Test
     public void testCheckServiceTimeSyntax1() throws Exception {
         final String key = "service_times";
