[6370] | 1 | (function (root, factory) {
|
---|
[7046] | 2 | // constants (holidays, error correction) {{{
|
---|
| 3 | // holidays {{{
|
---|
[6370] | 4 | var holidays = {
|
---|
[6489] | 5 | 'fr': {
|
---|
| 6 | 'PH': { // http://fr.wikipedia.org/wiki/F%C3%AAtes_et_jours_f%C3%A9ri%C3%A9s_en_France
|
---|
| 7 | "Jour de l'an" : [ 1, 1 ],
|
---|
| 8 | "Vendredi saint" : [ 'easter', -2, [ 'Moselle', 'Bas-Rhin', 'Haut-Rhin', 'Guadeloupe', 'Martinique', 'Polynésie française' ] ],
|
---|
| 9 | "Lundi de Pâques" : [ 'easter', 1 ],
|
---|
| 10 | "Saint-Pierre-Chanel" : [ 4, 28, [ 'Wallis-et-Futuna' ] ],
|
---|
| 11 | "Fête du Travail" : [ 5, 1 ],
|
---|
| 12 | "Fête de la Victoire" : [ 5, 8 ],
|
---|
| 13 | "Abolition de l'esclavage" : [ 5, 22, [ 'Martinique' ] ],
|
---|
| 14 | "Abolition de l'esclavage" : [ 5, 27, [ 'Guadeloupe' ] ],
|
---|
| 15 | "Jeudi de l'Ascension" : [ 'easter', 39 ],
|
---|
| 16 | "Lundi de Pentecôte" : [ 'easter', 50 ],
|
---|
| 17 | "Abolition de l'esclavage" : [ 6, 10, [ 'Guyane' ] ],
|
---|
| 18 | "Fête de l'autonomie" : [ 6, 29, [ 'Polynésie française' ] ],
|
---|
| 19 | "Fête nationale" : [ 7, 14 ],
|
---|
| 20 | "Fête Victor Schoelcher" : [ 7, 21, [ 'Guadeloupe', 'Martinique' ] ],
|
---|
| 21 | "Fête du Territoire" : [ 7, 29, [ 'Wallis-et-Futuna' ] ],
|
---|
| 22 | "Assomption" : [ 8, 15 ],
|
---|
| 23 | "Fête de la citoyenneté" : [ 9, 24, [ 'Nouvelle-Calédonie' ] ],
|
---|
| 24 | "Toussaint" : [ 11, 1 ],
|
---|
| 25 | "Armistice" : [ 11, 11 ],
|
---|
| 26 | "Abolition de l'esclavage" : [ 12, 20, [ 'Réunion' ] ],
|
---|
| 27 | "Noël" : [ 12, 25 ],
|
---|
| 28 | "Saint-Étienne " : [ 12, 26, [ 'Moselle', 'Bas-Rhin', 'Haut-Rhin' ] ]
|
---|
| 29 | }
|
---|
| 30 | },
|
---|
[6370] | 31 | 'de': {
|
---|
| 32 | 'PH': { // http://de.wikipedia.org/wiki/Feiertage_in_Deutschland
|
---|
| 33 | 'Neujahrstag' : [ 1, 1 ], // month 1, day 1, whole Germany
|
---|
| 34 | 'Heilige Drei Könige' : [ 1, 6, [ 'Baden-Württemberg', 'Bayern', 'Sachsen-Anhalt'] ], // only in the specified states
|
---|
| 35 | 'Tag der Arbeit' : [ 5, 1 ], // whole Germany
|
---|
| 36 | 'Karfreitag' : [ 'easter', -2 ], // two days before easter
|
---|
| 37 | 'Ostersonntag' : [ 'easter', 0, [ 'Brandenburg'] ],
|
---|
| 38 | 'Ostermontag' : [ 'easter', 1 ],
|
---|
| 39 | 'Christi Himmelfahrt' : [ 'easter', 39 ],
|
---|
| 40 | 'Pfingstsonntag' : [ 'easter', 49, [ 'Brandenburg'] ],
|
---|
| 41 | 'Pfingstmontag' : [ 'easter', 50 ],
|
---|
| 42 | 'Fronleichnam' : [ 'easter', 60, [ 'Baden-Württemberg', 'Bayern', 'Hessen', 'Nordrhein-Westfalen', 'Rheinland-Pfalz', 'Saarland' ] ],
|
---|
| 43 | 'Mariä Himmelfahrt' : [ 8, 15, [ 'Saarland'] ],
|
---|
| 44 | 'Tag der Deutschen Einheit' : [ 10, 3 ],
|
---|
| 45 | 'Reformationstag' : [ 10, 31, [ 'Brandenburg', 'Mecklenburg-Vorpommern', 'Sachsen', 'Sachsen-Anhalt', 'Thüringen'] ],
|
---|
| 46 | 'Allerheiligen' : [ 11, 1, [ 'Baden-Württemberg', 'Bayern', 'Nordrhein-Westfalen', 'Rheinland-Pfalz', 'Saarland' ] ],
|
---|
| 47 | '1. Weihnachtstag' : [ 12, 25 ],
|
---|
| 48 | '2. Weihnachtstag' : [ 12, 26 ],
|
---|
| 49 | // 'Silvester' : [ 12, 31 ], // for testing
|
---|
| 50 | },
|
---|
| 51 | 'Baden-Württemberg': { // does only apply in Baden-Württemberg
|
---|
| 52 | // This more specific rule set overwrites the country wide one (they are just ignored).
|
---|
| 53 | // You may use this instead of the country wide with some
|
---|
| 54 | // additional holidays for some states, if one state
|
---|
| 55 | // totally disagrees about how to do public holidays …
|
---|
| 56 | // 'PH': {
|
---|
| 57 | // '2. Weihnachtstag' : [ 12, 26 ],
|
---|
| 58 | // },
|
---|
| 59 |
|
---|
| 60 | // school holiday normally variate between states
|
---|
| 61 | 'SH': [ // generated by convert_ical_to_json
|
---|
| 62 | // You may can adjust this script to use other resources (for other countries) too.
|
---|
| 63 | {
|
---|
| 64 | name: 'Osterferien',
|
---|
| 65 | 2005: [ 3, 24, /* to */ 3, 24, 3, 29, /* to */ 4, 2 ],
|
---|
| 66 | 2006: [ 4, 18, /* to */ 4, 22 ],
|
---|
| 67 | 2007: [ 4, 2, /* to */ 4, 14 ],
|
---|
| 68 | 2008: [ 3, 17, /* to */ 3, 28 ],
|
---|
| 69 | 2009: [ 4, 9, /* to */ 4, 9, 4, 14, /* to */ 4, 17 ],
|
---|
| 70 | 2010: [ 4, 1, /* to */ 4, 1, 4, 6, /* to */ 4, 10 ],
|
---|
| 71 | 2011: [ 4, 21, /* to */ 4, 21, 4, 26, /* to */ 4, 30 ],
|
---|
| 72 | 2012: [ 4, 2, /* to */ 4, 13 ],
|
---|
| 73 | 2013: [ 3, 25, /* to */ 4, 5 ],
|
---|
| 74 | 2014: [ 4, 14, /* to */ 4, 25 ],
|
---|
| 75 | 2015: [ 3, 30, /* to */ 4, 10 ],
|
---|
| 76 | 2016: [ 3, 29, /* to */ 4, 2 ],
|
---|
| 77 | 2017: [ 4, 10, /* to */ 4, 21 ],
|
---|
| 78 | },
|
---|
| 79 | {
|
---|
| 80 | name: 'Pfingstferien',
|
---|
| 81 | 2005: [ 5, 17, /* to */ 5, 28 ],
|
---|
| 82 | 2006: [ 5, 29, /* to */ 6, 10 ],
|
---|
| 83 | 2007: [ 5, 29, /* to */ 6, 9 ],
|
---|
| 84 | 2008: [ 5, 13, /* to */ 5, 23 ],
|
---|
| 85 | 2009: [ 5, 25, /* to */ 6, 6 ],
|
---|
| 86 | 2010: [ 5, 25, /* to */ 6, 5 ],
|
---|
| 87 | 2011: [ 6, 14, /* to */ 6, 25 ],
|
---|
| 88 | 2012: [ 5, 29, /* to */ 6, 9 ],
|
---|
| 89 | 2013: [ 5, 21, /* to */ 6, 1 ],
|
---|
| 90 | 2014: [ 6, 10, /* to */ 6, 21 ],
|
---|
| 91 | 2015: [ 5, 26, /* to */ 6, 6 ],
|
---|
| 92 | 2016: [ 5, 17, /* to */ 5, 28 ],
|
---|
| 93 | 2017: [ 6, 6, /* to */ 6, 16 ],
|
---|
| 94 | },
|
---|
| 95 | {
|
---|
| 96 | name: 'Sommerferien',
|
---|
| 97 | 2005: [ 7, 28, /* to */ 9, 10 ],
|
---|
| 98 | 2006: [ 8, 3, /* to */ 9, 16 ],
|
---|
| 99 | 2007: [ 7, 26, /* to */ 9, 8 ],
|
---|
| 100 | 2008: [ 7, 24, /* to */ 9, 6 ],
|
---|
| 101 | 2009: [ 7, 30, /* to */ 9, 12 ],
|
---|
| 102 | 2010: [ 7, 29, /* to */ 9, 11 ],
|
---|
| 103 | 2011: [ 7, 28, /* to */ 9, 10 ],
|
---|
| 104 | 2012: [ 7, 26, /* to */ 9, 8 ],
|
---|
| 105 | 2013: [ 7, 25, /* to */ 9, 7 ],
|
---|
| 106 | 2014: [ 7, 31, /* to */ 9, 13 ],
|
---|
| 107 | 2015: [ 7, 30, /* to */ 9, 12 ],
|
---|
| 108 | 2016: [ 7, 28, /* to */ 9, 10 ],
|
---|
| 109 | 2017: [ 7, 27, /* to */ 9, 9 ],
|
---|
| 110 | },
|
---|
| 111 | {
|
---|
| 112 | name: 'Herbstferien',
|
---|
| 113 | 2005: [ 11, 2, /* to */ 11, 4 ],
|
---|
| 114 | 2006: [ 10, 30, /* to */ 11, 3 ],
|
---|
| 115 | 2007: [ 10, 29, /* to */ 11, 3 ],
|
---|
| 116 | 2008: [ 10, 27, /* to */ 10, 31 ],
|
---|
| 117 | 2009: [ 10, 26, /* to */ 10, 31 ],
|
---|
| 118 | 2010: [ 11, 2, /* to */ 11, 6 ],
|
---|
| 119 | 2011: [ 10, 31, /* to */ 10, 31, 11, 2, /* to */ 11, 4 ],
|
---|
| 120 | 2012: [ 10, 29, /* to */ 11, 2 ],
|
---|
| 121 | 2013: [ 10, 28, /* to */ 10, 30 ],
|
---|
| 122 | 2014: [ 10, 27, /* to */ 10, 30 ],
|
---|
| 123 | 2015: [ 11, 2, /* to */ 11, 6 ],
|
---|
| 124 | 2016: [ 11, 2, /* to */ 11, 4 ],
|
---|
| 125 | },
|
---|
| 126 | {
|
---|
| 127 | name: 'Weihnachtsferien',
|
---|
| 128 | 2005: [ 12, 22, /* to */ 1, 5 ],
|
---|
| 129 | 2006: [ 12, 27, /* to */ 1, 5 ],
|
---|
| 130 | 2007: [ 12, 24, /* to */ 1, 5 ],
|
---|
| 131 | 2008: [ 12, 22, /* to */ 1, 10 ],
|
---|
| 132 | 2009: [ 12, 23, /* to */ 1, 9 ],
|
---|
| 133 | 2010: [ 12, 23, /* to */ 1, 8 ],
|
---|
| 134 | 2011: [ 12, 23, /* to */ 1, 5 ],
|
---|
| 135 | 2012: [ 12, 24, /* to */ 1, 5 ],
|
---|
| 136 | 2013: [ 12, 23, /* to */ 1, 4 ],
|
---|
| 137 | 2014: [ 12, 22, /* to */ 1, 5 ],
|
---|
| 138 | 2015: [ 12, 23, /* to */ 1, 9 ],
|
---|
| 139 | 2016: [ 12, 23, /* to */ 1, 7 ],
|
---|
| 140 | },
|
---|
| 141 | ],
|
---|
| 142 | },
|
---|
| 143 | 'Mecklenburg-Vorpommern': {
|
---|
| 144 | 'SH': [
|
---|
| 145 | {
|
---|
| 146 | name: 'Winterferien',
|
---|
| 147 | 2010: [ 2, 6, /* to */ 2, 20 ],
|
---|
| 148 | 2011: [ 2, 7, /* to */ 2, 19 ],
|
---|
| 149 | 2012: [ 2, 6, /* to */ 2, 17 ],
|
---|
| 150 | 2013: [ 2, 4, /* to */ 2, 15 ],
|
---|
| 151 | 2014: [ 2, 3, /* to */ 2, 15 ],
|
---|
| 152 | 2015: [ 2, 2, /* to */ 2, 14 ],
|
---|
| 153 | 2016: [ 2, 1, /* to */ 2, 13 ],
|
---|
| 154 | 2017: [ 2, 6, /* to */ 2, 18 ],
|
---|
| 155 | },
|
---|
| 156 | {
|
---|
| 157 | name: 'Osterferien',
|
---|
| 158 | 2010: [ 3, 29, /* to */ 4, 7 ],
|
---|
| 159 | 2011: [ 4, 16, /* to */ 4, 27 ],
|
---|
| 160 | 2012: [ 4, 2, /* to */ 4, 11 ],
|
---|
| 161 | 2013: [ 3, 25, /* to */ 4, 3 ],
|
---|
| 162 | 2014: [ 4, 14, /* to */ 4, 23 ],
|
---|
| 163 | 2015: [ 3, 30, /* to */ 4, 8 ],
|
---|
| 164 | 2016: [ 3, 21, /* to */ 3, 30 ],
|
---|
| 165 | 2017: [ 4, 10, /* to */ 4, 19 ],
|
---|
| 166 | },
|
---|
| 167 | {
|
---|
| 168 | name: 'Pfingstferien',
|
---|
| 169 | 2010: [ 5, 21, /* to */ 5, 22 ],
|
---|
| 170 | 2011: [ 6, 10, /* to */ 6, 14 ],
|
---|
| 171 | 2012: [ 5, 25, /* to */ 5, 29 ],
|
---|
| 172 | 2013: [ 5, 17, /* to */ 5, 21 ],
|
---|
| 173 | 2014: [ 6, 6, /* to */ 6, 10 ],
|
---|
| 174 | 2015: [ 5, 22, /* to */ 5, 26 ],
|
---|
| 175 | 2016: [ 5, 14, /* to */ 5, 17 ],
|
---|
| 176 | 2017: [ 6, 2, /* to */ 6, 6 ],
|
---|
| 177 | },
|
---|
| 178 | {
|
---|
| 179 | name: 'Sommerferien',
|
---|
| 180 | 2010: [ 7, 12, /* to */ 8, 21 ],
|
---|
| 181 | 2011: [ 7, 4, /* to */ 8, 13 ],
|
---|
| 182 | 2012: [ 6, 23, /* to */ 8, 4 ],
|
---|
| 183 | 2013: [ 6, 22, /* to */ 8, 3 ],
|
---|
| 184 | 2014: [ 7, 14, /* to */ 8, 23 ],
|
---|
| 185 | 2015: [ 7, 20, /* to */ 8, 29 ],
|
---|
| 186 | 2016: [ 7, 25, /* to */ 9, 3 ],
|
---|
| 187 | 2017: [ 7, 24, /* to */ 9, 2 ],
|
---|
| 188 | },
|
---|
| 189 | {
|
---|
| 190 | name: 'Herbstferien',
|
---|
| 191 | 2010: [ 10, 18, /* to */ 10, 23 ],
|
---|
| 192 | 2011: [ 10, 17, /* to */ 10, 21 ],
|
---|
| 193 | 2012: [ 10, 1, /* to */ 10, 5 ],
|
---|
| 194 | 2013: [ 10, 14, /* to */ 10, 19 ],
|
---|
| 195 | 2014: [ 10, 20, /* to */ 10, 25 ],
|
---|
| 196 | 2015: [ 10, 24, /* to */ 10, 30 ],
|
---|
| 197 | 2016: [ 10, 24, /* to */ 10, 28 ],
|
---|
| 198 | },
|
---|
| 199 | {
|
---|
| 200 | name: 'Weihnachtsferien',
|
---|
| 201 | 2010: [ 12, 23, /* to */ 12, 31 ],
|
---|
| 202 | 2011: [ 12, 23, /* to */ 1, 3 ],
|
---|
| 203 | 2012: [ 12, 21, /* to */ 1, 4 ],
|
---|
| 204 | 2013: [ 12, 23, /* to */ 1, 3 ],
|
---|
| 205 | 2014: [ 12, 22, /* to */ 1, 2 ],
|
---|
| 206 | 2015: [ 12, 21, /* to */ 1, 2 ],
|
---|
| 207 | 2016: [ 12, 22, /* to */ 1, 2 ],
|
---|
| 208 | },
|
---|
| 209 | ],
|
---|
| 210 | },
|
---|
| 211 | 'Hessen': {
|
---|
| 212 | 'SH': [
|
---|
| 213 | {
|
---|
| 214 | name: 'Osterferien',
|
---|
| 215 | 2010: [ 3, 29, /* to */ 4, 10 ],
|
---|
| 216 | 2011: [ 4, 18, /* to */ 4, 30 ],
|
---|
| 217 | 2012: [ 4, 2, /* to */ 4, 14 ],
|
---|
| 218 | 2013: [ 3, 25, /* to */ 4, 6 ],
|
---|
| 219 | 2014: [ 4, 14, /* to */ 4, 26 ],
|
---|
| 220 | 2015: [ 3, 30, /* to */ 4, 11 ],
|
---|
| 221 | 2016: [ 3, 29, /* to */ 4, 9 ],
|
---|
| 222 | 2017: [ 4, 3, /* to */ 4, 15 ],
|
---|
| 223 | 2018: [ 3, 26, /* to */ 4, 7 ],
|
---|
| 224 | },
|
---|
| 225 | {
|
---|
| 226 | name: 'Sommerferien',
|
---|
| 227 | 2010: [ 7, 5, /* to */ 8, 14 ],
|
---|
| 228 | 2011: [ 6, 27, /* to */ 8, 5 ],
|
---|
| 229 | 2012: [ 7, 2, /* to */ 8, 10 ],
|
---|
| 230 | 2013: [ 7, 8, /* to */ 8, 16 ],
|
---|
| 231 | 2014: [ 7, 28, /* to */ 9, 5 ],
|
---|
| 232 | 2015: [ 7, 27, /* to */ 9, 5 ],
|
---|
| 233 | 2016: [ 7, 18, /* to */ 8, 26 ],
|
---|
| 234 | 2017: [ 7, 3, /* to */ 8, 11 ],
|
---|
| 235 | },
|
---|
| 236 | {
|
---|
| 237 | name: 'Herbstferien',
|
---|
| 238 | 2010: [ 10, 11, /* to */ 10, 22 ],
|
---|
| 239 | 2011: [ 10, 10, /* to */ 10, 22 ],
|
---|
| 240 | 2012: [ 10, 15, /* to */ 10, 27 ],
|
---|
| 241 | 2013: [ 10, 14, /* to */ 10, 26 ],
|
---|
| 242 | 2014: [ 10, 20, /* to */ 11, 1 ],
|
---|
| 243 | 2015: [ 10, 19, /* to */ 10, 31 ],
|
---|
| 244 | 2016: [ 10, 17, /* to */ 10, 29 ],
|
---|
| 245 | 2017: [ 10, 9, /* to */ 10, 21 ],
|
---|
| 246 | },
|
---|
| 247 | {
|
---|
| 248 | name: 'Weihnachtsferien',
|
---|
| 249 | 2010: [ 12, 20, /* to */ 1, 7 ],
|
---|
| 250 | 2011: [ 12, 21, /* to */ 1, 6 ],
|
---|
| 251 | 2012: [ 12, 24, /* to */ 1, 12 ],
|
---|
| 252 | 2013: [ 12, 23, /* to */ 1, 11 ],
|
---|
| 253 | 2014: [ 12, 22, /* to */ 1, 10 ],
|
---|
| 254 | 2015: [ 12, 23, /* to */ 1, 9 ],
|
---|
| 255 | 2016: [ 12, 22, /* to */ 1, 7 ],
|
---|
| 256 | 2017: [ 12, 24, /* to */ 1, 13 ],
|
---|
| 257 | },
|
---|
| 258 | ],
|
---|
| 259 | },
|
---|
| 260 | 'Schleswig-Holstein': {
|
---|
| 261 | 'SH': [
|
---|
| 262 | {
|
---|
| 263 | name: 'Osterferien',
|
---|
| 264 | 2010: [ 4, 3, /* to */ 4, 17 ],
|
---|
| 265 | 2011: [ 4, 15, /* to */ 4, 30 ],
|
---|
| 266 | 2012: [ 3, 30, /* to */ 4, 13 ],
|
---|
| 267 | 2013: [ 3, 25, /* to */ 4, 9 ],
|
---|
| 268 | 2014: [ 4, 16, /* to */ 5, 2 ],
|
---|
| 269 | 2015: [ 4, 1, /* to */ 4, 17 ],
|
---|
| 270 | 2016: [ 3, 24, /* to */ 4, 9 ],
|
---|
| 271 | 2017: [ 4, 7, /* to */ 4, 21 ],
|
---|
| 272 | },
|
---|
| 273 | {
|
---|
| 274 | name: 'Sommerferien',
|
---|
| 275 | 2010: [ 7, 12, /* to */ 8, 21 ],
|
---|
| 276 | 2011: [ 7, 4, /* to */ 8, 13 ],
|
---|
| 277 | 2012: [ 6, 25, /* to */ 8, 4 ],
|
---|
| 278 | 2013: [ 6, 24, /* to */ 8, 3 ],
|
---|
| 279 | 2014: [ 7, 14, /* to */ 8, 23 ],
|
---|
| 280 | 2015: [ 7, 20, /* to */ 8, 29 ],
|
---|
| 281 | 2016: [ 7, 25, /* to */ 9, 3 ],
|
---|
| 282 | 2017: [ 7, 24, /* to */ 9, 2 ],
|
---|
| 283 | },
|
---|
| 284 | {
|
---|
| 285 | name: 'Pfingstferien',
|
---|
| 286 | 2011: [ 6, 3, /* to */ 6, 4 ],
|
---|
| 287 | 2012: [ 5, 18, /* to */ 5, 18 ],
|
---|
| 288 | 2013: [ 5, 10, /* to */ 5, 10 ],
|
---|
| 289 | 2014: [ 5, 30, /* to */ 5, 30 ],
|
---|
| 290 | 2015: [ 5, 15, /* to */ 5, 15 ],
|
---|
| 291 | 2016: [ 5, 6, /* to */ 5, 6 ],
|
---|
| 292 | 2017: [ 5, 26, /* to */ 5, 26 ],
|
---|
| 293 | },
|
---|
| 294 | {
|
---|
| 295 | name: 'Herbstferien',
|
---|
| 296 | 2010: [ 10, 11, /* to */ 10, 23 ],
|
---|
| 297 | 2011: [ 10, 10, /* to */ 10, 22 ],
|
---|
| 298 | 2012: [ 10, 4, /* to */ 10, 19 ],
|
---|
| 299 | 2013: [ 10, 4, /* to */ 10, 18 ],
|
---|
| 300 | 2014: [ 10, 13, /* to */ 10, 25 ],
|
---|
| 301 | 2015: [ 10, 19, /* to */ 10, 31 ],
|
---|
| 302 | 2016: [ 10, 17, /* to */ 10, 29 ],
|
---|
| 303 | },
|
---|
| 304 | {
|
---|
| 305 | name: 'Weihnachtsferien',
|
---|
| 306 | 2010: [ 12, 23, /* to */ 1, 7 ],
|
---|
| 307 | 2011: [ 12, 23, /* to */ 1, 6 ],
|
---|
| 308 | 2012: [ 12, 24, /* to */ 1, 5 ],
|
---|
| 309 | 2013: [ 12, 23, /* to */ 1, 6 ],
|
---|
| 310 | 2014: [ 12, 22, /* to */ 1, 6 ],
|
---|
| 311 | 2015: [ 12, 21, /* to */ 1, 6 ],
|
---|
| 312 | 2016: [ 12, 23, /* to */ 1, 6 ],
|
---|
| 313 | },
|
---|
| 314 | ],
|
---|
| 315 | },
|
---|
| 316 | 'Berlin': {
|
---|
| 317 | 'SH': [
|
---|
| 318 | {
|
---|
| 319 | name: 'Winterferien',
|
---|
| 320 | 2010: [ 2, 1, /* to */ 2, 6 ],
|
---|
| 321 | 2011: [ 1, 31, /* to */ 2, 5 ],
|
---|
| 322 | 2012: [ 1, 30, /* to */ 2, 4 ],
|
---|
| 323 | 2013: [ 2, 4, /* to */ 2, 9 ],
|
---|
| 324 | 2014: [ 2, 3, /* to */ 2, 8 ],
|
---|
| 325 | 2015: [ 2, 2, /* to */ 2, 7 ],
|
---|
| 326 | 2016: [ 2, 1, /* to */ 2, 6 ],
|
---|
| 327 | 2017: [ 1, 30, /* to */ 2, 4 ],
|
---|
| 328 | },
|
---|
| 329 | {
|
---|
| 330 | name: 'Osterferien',
|
---|
| 331 | 2010: [ 3, 31, /* to */ 4, 10 ],
|
---|
| 332 | 2011: [ 4, 18, /* to */ 4, 30 ],
|
---|
| 333 | 2012: [ 4, 2, /* to */ 4, 14, 4, 30, /* to */ 4, 30 ],
|
---|
| 334 | 2013: [ 3, 25, /* to */ 4, 6 ],
|
---|
| 335 | 2014: [ 4, 14, /* to */ 4, 26, 5, 2, /* to */ 5, 2 ],
|
---|
| 336 | 2015: [ 3, 30, /* to */ 4, 11 ],
|
---|
| 337 | 2016: [ 3, 21, /* to */ 4, 2 ],
|
---|
| 338 | 2017: [ 4, 10, /* to */ 4, 22 ],
|
---|
| 339 | },
|
---|
| 340 | {
|
---|
| 341 | name: 'Pfingstferien',
|
---|
| 342 | 2010: [ 5, 14, /* to */ 5, 14, 5, 25, /* to */ 5, 25 ],
|
---|
| 343 | 2011: [ 6, 3, /* to */ 6, 3 ],
|
---|
| 344 | 2012: [ 5, 18, /* to */ 5, 18 ],
|
---|
| 345 | 2013: [ 5, 10, /* to */ 5, 10, 5, 21, /* to */ 5, 21 ],
|
---|
| 346 | 2014: [ 5, 30, /* to */ 5, 30 ],
|
---|
| 347 | 2015: [ 5, 15, /* to */ 5, 15 ],
|
---|
| 348 | 2016: [ 5, 6, /* to */ 5, 6, 5, 17, /* to */ 5, 17 ],
|
---|
| 349 | 2017: [ 5, 26, /* to */ 5, 26 ],
|
---|
| 350 | },
|
---|
| 351 | {
|
---|
| 352 | name: 'Sommerferien',
|
---|
| 353 | 2010: [ 7, 7, /* to */ 8, 21 ],
|
---|
| 354 | 2011: [ 6, 29, /* to */ 8, 12 ],
|
---|
| 355 | 2012: [ 6, 20, /* to */ 8, 3 ],
|
---|
| 356 | 2013: [ 6, 19, /* to */ 8, 2 ],
|
---|
| 357 | 2014: [ 7, 9, /* to */ 8, 22 ],
|
---|
| 358 | 2015: [ 7, 15, /* to */ 8, 28 ],
|
---|
| 359 | 2016: [ 7, 20, /* to */ 9, 2 ],
|
---|
| 360 | 2017: [ 7, 19, /* to */ 9, 1 ],
|
---|
| 361 | },
|
---|
| 362 | {
|
---|
| 363 | name: 'Herbstferien',
|
---|
| 364 | 2010: [ 10, 11, /* to */ 10, 23 ],
|
---|
| 365 | 2011: [ 10, 4, /* to */ 10, 14 ],
|
---|
| 366 | 2012: [ 10, 1, /* to */ 10, 13 ],
|
---|
| 367 | 2013: [ 9, 30, /* to */ 10, 12 ],
|
---|
| 368 | 2014: [ 10, 20, /* to */ 11, 1 ],
|
---|
| 369 | 2015: [ 10, 19, /* to */ 10, 31 ],
|
---|
| 370 | 2016: [ 10, 17, /* to */ 10, 28 ],
|
---|
| 371 | },
|
---|
| 372 | {
|
---|
| 373 | name: 'Weihnachtsferien',
|
---|
| 374 | 2010: [ 12, 23, /* to */ 1, 1 ],
|
---|
| 375 | 2011: [ 12, 23, /* to */ 1, 3 ],
|
---|
| 376 | 2012: [ 12, 24, /* to */ 1, 4 ],
|
---|
| 377 | 2013: [ 12, 23, /* to */ 1, 3 ],
|
---|
| 378 | 2014: [ 12, 22, /* to */ 1, 2 ],
|
---|
| 379 | 2015: [ 12, 23, /* to */ 1, 2 ],
|
---|
| 380 | 2016: [ 12, 23, /* to */ 1, 3 ],
|
---|
| 381 | },
|
---|
| 382 | ],
|
---|
| 383 | },
|
---|
| 384 | 'Saarland': {
|
---|
| 385 | 'SH': [
|
---|
| 386 | {
|
---|
| 387 | name: 'Winterferien',
|
---|
| 388 | 2010: [ 2, 15, /* to */ 2, 20 ],
|
---|
| 389 | 2011: [ 3, 7, /* to */ 3, 12 ],
|
---|
| 390 | 2012: [ 2, 20, /* to */ 2, 25 ],
|
---|
| 391 | 2013: [ 2, 11, /* to */ 2, 16 ],
|
---|
| 392 | 2014: [ 3, 3, /* to */ 3, 8 ],
|
---|
| 393 | 2015: [ 2, 16, /* to */ 2, 21 ],
|
---|
| 394 | },
|
---|
| 395 | {
|
---|
| 396 | name: 'Osterferien',
|
---|
| 397 | 2010: [ 3, 29, /* to */ 4, 10 ],
|
---|
| 398 | 2011: [ 4, 18, /* to */ 4, 30 ],
|
---|
| 399 | 2012: [ 4, 2, /* to */ 4, 14 ],
|
---|
| 400 | 2013: [ 3, 25, /* to */ 4, 6 ],
|
---|
| 401 | 2014: [ 4, 14, /* to */ 4, 26 ],
|
---|
| 402 | 2015: [ 3, 30, /* to */ 4, 11 ],
|
---|
| 403 | },
|
---|
| 404 | {
|
---|
| 405 | name: 'Sommerferien',
|
---|
| 406 | 2010: [ 7, 5, /* to */ 8, 14 ],
|
---|
| 407 | 2011: [ 6, 24, /* to */ 8, 6 ],
|
---|
| 408 | 2012: [ 7, 2, /* to */ 8, 14 ],
|
---|
| 409 | 2013: [ 7, 8, /* to */ 8, 17 ],
|
---|
| 410 | 2014: [ 7, 28, /* to */ 9, 6 ],
|
---|
| 411 | 2015: [ 7, 27, /* to */ 9, 4 ],
|
---|
| 412 | 2016: [ 7, 18, /* to */ 8, 26 ],
|
---|
| 413 | 2017: [ 7, 3, /* to */ 8, 14 ],
|
---|
| 414 | },
|
---|
| 415 | {
|
---|
| 416 | name: 'Herbstferien',
|
---|
| 417 | 2010: [ 10, 11, /* to */ 10, 23 ],
|
---|
| 418 | 2011: [ 10, 4, /* to */ 10, 15 ],
|
---|
| 419 | 2012: [ 10, 22, /* to */ 11, 3 ],
|
---|
| 420 | 2013: [ 10, 21, /* to */ 11, 2 ],
|
---|
| 421 | 2014: [ 10, 20, /* to */ 10, 31 ],
|
---|
| 422 | },
|
---|
| 423 | {
|
---|
| 424 | name: 'Weihnachtsferien',
|
---|
| 425 | 2010: [ 12, 20, /* to */ 1, 1 ],
|
---|
| 426 | 2011: [ 12, 23, /* to */ 1, 4 ],
|
---|
| 427 | 2012: [ 12, 24, /* to */ 1, 5 ],
|
---|
| 428 | 2013: [ 12, 20, /* to */ 1, 4 ],
|
---|
| 429 | 2014: [ 12, 22, /* to */ 1, 7 ],
|
---|
| 430 | },
|
---|
| 431 | ],
|
---|
| 432 | },
|
---|
| 433 | 'Bremen': {
|
---|
| 434 | 'SH': [
|
---|
| 435 | {
|
---|
| 436 | name: 'Winterferien',
|
---|
| 437 | 2010: [ 2, 1, /* to */ 2, 2 ],
|
---|
| 438 | 2011: [ 1, 31, /* to */ 2, 1 ],
|
---|
| 439 | 2012: [ 1, 30, /* to */ 1, 31 ],
|
---|
| 440 | 2013: [ 1, 31, /* to */ 2, 1 ],
|
---|
| 441 | 2014: [ 1, 30, /* to */ 1, 31 ],
|
---|
| 442 | 2015: [ 2, 2, /* to */ 2, 3 ],
|
---|
| 443 | 2016: [ 1, 28, /* to */ 1, 29 ],
|
---|
| 444 | 2017: [ 1, 30, /* to */ 1, 31 ],
|
---|
| 445 | },
|
---|
| 446 | {
|
---|
| 447 | name: 'Osterferien',
|
---|
| 448 | 2010: [ 3, 19, /* to */ 4, 6 ],
|
---|
| 449 | 2011: [ 4, 16, /* to */ 4, 30 ],
|
---|
| 450 | 2012: [ 3, 26, /* to */ 4, 11, 4, 30, /* to */ 4, 30 ],
|
---|
| 451 | 2013: [ 3, 16, /* to */ 4, 2 ],
|
---|
| 452 | 2014: [ 4, 3, /* to */ 4, 22, 5, 2, /* to */ 5, 2 ],
|
---|
| 453 | 2015: [ 3, 25, /* to */ 4, 10 ],
|
---|
| 454 | 2016: [ 3, 18, /* to */ 4, 2 ],
|
---|
| 455 | 2017: [ 4, 10, /* to */ 4, 22 ],
|
---|
| 456 | },
|
---|
| 457 | {
|
---|
| 458 | name: 'Pfingstferien',
|
---|
| 459 | 2010: [ 5, 14, /* to */ 5, 14, 5, 25, /* to */ 5, 25 ],
|
---|
| 460 | 2011: [ 6, 3, /* to */ 6, 3, 6, 14, /* to */ 6, 14 ],
|
---|
| 461 | 2012: [ 5, 18, /* to */ 5, 18, 5, 29, /* to */ 5, 29 ],
|
---|
| 462 | 2013: [ 5, 10, /* to */ 5, 10, 5, 21, /* to */ 5, 21 ],
|
---|
| 463 | 2014: [ 5, 30, /* to */ 5, 30, 6, 10, /* to */ 6, 10 ],
|
---|
| 464 | 2015: [ 5, 15, /* to */ 5, 15, 5, 26, /* to */ 5, 26 ],
|
---|
| 465 | 2016: [ 5, 6, /* to */ 5, 6, 5, 17, /* to */ 5, 17 ],
|
---|
| 466 | 2017: [ 5, 26, /* to */ 5, 26, 6, 6, /* to */ 6, 6 ],
|
---|
| 467 | },
|
---|
| 468 | {
|
---|
| 469 | name: 'Sommerferien',
|
---|
| 470 | 2010: [ 6, 24, /* to */ 8, 4 ],
|
---|
| 471 | 2011: [ 7, 7, /* to */ 8, 17 ],
|
---|
| 472 | 2012: [ 7, 23, /* to */ 8, 31 ],
|
---|
| 473 | 2013: [ 6, 27, /* to */ 8, 7 ],
|
---|
| 474 | 2014: [ 7, 31, /* to */ 9, 10 ],
|
---|
| 475 | 2015: [ 7, 23, /* to */ 9, 2 ],
|
---|
| 476 | 2016: [ 6, 23, /* to */ 8, 3 ],
|
---|
| 477 | 2017: [ 6, 22, /* to */ 8, 2 ],
|
---|
| 478 | },
|
---|
| 479 | {
|
---|
| 480 | name: 'Herbstferien',
|
---|
| 481 | 2010: [ 10, 9, /* to */ 10, 23 ],
|
---|
| 482 | 2011: [ 10, 17, /* to */ 10, 29 ],
|
---|
| 483 | 2012: [ 10, 22, /* to */ 11, 3 ],
|
---|
| 484 | 2013: [ 10, 4, /* to */ 10, 18 ],
|
---|
| 485 | 2014: [ 10, 27, /* to */ 11, 8 ],
|
---|
| 486 | 2015: [ 10, 19, /* to */ 10, 31 ],
|
---|
| 487 | 2016: [ 10, 4, /* to */ 10, 15 ],
|
---|
| 488 | },
|
---|
| 489 | {
|
---|
| 490 | name: 'Weihnachtsferien',
|
---|
| 491 | 2010: [ 12, 22, /* to */ 1, 5 ],
|
---|
| 492 | 2011: [ 12, 23, /* to */ 1, 4 ],
|
---|
| 493 | 2012: [ 12, 24, /* to */ 1, 5 ],
|
---|
| 494 | 2013: [ 12, 23, /* to */ 1, 3 ],
|
---|
| 495 | 2014: [ 12, 22, /* to */ 1, 5 ],
|
---|
| 496 | 2015: [ 12, 23, /* to */ 1, 6 ],
|
---|
| 497 | 2016: [ 12, 21, /* to */ 1, 6 ],
|
---|
| 498 | },
|
---|
| 499 | ],
|
---|
| 500 | },
|
---|
| 501 | 'Bayern': {
|
---|
| 502 | 'SH': [
|
---|
| 503 | {
|
---|
| 504 | name: 'Winterferien',
|
---|
| 505 | 2010: [ 2, 15, /* to */ 2, 20 ],
|
---|
| 506 | 2011: [ 3, 7, /* to */ 3, 11 ],
|
---|
| 507 | 2012: [ 2, 20, /* to */ 2, 24 ],
|
---|
| 508 | 2013: [ 2, 11, /* to */ 2, 15 ],
|
---|
| 509 | 2014: [ 3, 3, /* to */ 3, 7 ],
|
---|
| 510 | 2015: [ 2, 16, /* to */ 2, 20 ],
|
---|
| 511 | 2016: [ 2, 8, /* to */ 2, 12 ],
|
---|
| 512 | 2017: [ 2, 27, /* to */ 3, 3 ],
|
---|
| 513 | },
|
---|
| 514 | {
|
---|
| 515 | name: 'Osterferien',
|
---|
| 516 | 2010: [ 3, 29, /* to */ 4, 10 ],
|
---|
| 517 | 2011: [ 4, 18, /* to */ 4, 30 ],
|
---|
| 518 | 2012: [ 4, 2, /* to */ 4, 14 ],
|
---|
| 519 | 2013: [ 3, 25, /* to */ 4, 6 ],
|
---|
| 520 | 2014: [ 4, 14, /* to */ 4, 26 ],
|
---|
| 521 | 2015: [ 3, 30, /* to */ 4, 11 ],
|
---|
| 522 | 2016: [ 3, 21, /* to */ 4, 1 ],
|
---|
| 523 | 2017: [ 4, 10, /* to */ 4, 22 ],
|
---|
| 524 | },
|
---|
| 525 | {
|
---|
| 526 | name: 'Pfingstferien',
|
---|
| 527 | 2010: [ 5, 25, /* to */ 6, 5 ],
|
---|
| 528 | 2011: [ 6, 14, /* to */ 6, 25 ],
|
---|
| 529 | 2012: [ 5, 29, /* to */ 6, 9 ],
|
---|
| 530 | 2013: [ 5, 21, /* to */ 5, 31 ],
|
---|
| 531 | 2014: [ 6, 10, /* to */ 6, 21 ],
|
---|
| 532 | 2015: [ 5, 26, /* to */ 6, 5 ],
|
---|
| 533 | 2016: [ 5, 17, /* to */ 5, 28 ],
|
---|
| 534 | 2017: [ 6, 6, /* to */ 6, 16 ],
|
---|
| 535 | },
|
---|
| 536 | {
|
---|
| 537 | name: 'Sommerferien',
|
---|
| 538 | 2010: [ 8, 2, /* to */ 9, 13 ],
|
---|
| 539 | 2011: [ 7, 30, /* to */ 9, 12 ],
|
---|
| 540 | 2012: [ 8, 1, /* to */ 9, 12 ],
|
---|
| 541 | 2013: [ 7, 31, /* to */ 9, 11 ],
|
---|
| 542 | 2014: [ 7, 30, /* to */ 9, 15 ],
|
---|
| 543 | 2015: [ 8, 1, /* to */ 9, 14 ],
|
---|
| 544 | 2016: [ 7, 30, /* to */ 9, 12 ],
|
---|
| 545 | 2017: [ 7, 29, /* to */ 9, 11 ],
|
---|
| 546 | },
|
---|
| 547 | {
|
---|
| 548 | name: 'Herbstferien',
|
---|
| 549 | 2010: [ 11, 2, /* to */ 11, 5 ],
|
---|
| 550 | 2011: [ 10, 31, /* to */ 11, 5 ],
|
---|
| 551 | 2012: [ 10, 29, /* to */ 11, 3 ],
|
---|
| 552 | 2013: [ 10, 28, /* to */ 10, 31 ],
|
---|
| 553 | 2014: [ 10, 27, /* to */ 10, 31 ],
|
---|
| 554 | 2015: [ 11, 2, /* to */ 11, 7 ],
|
---|
| 555 | 2016: [ 10, 31, /* to */ 11, 4 ],
|
---|
| 556 | },
|
---|
| 557 | {
|
---|
| 558 | name: 'Weihnachtsferien',
|
---|
| 559 | 2010: [ 12, 24, /* to */ 1, 7 ],
|
---|
| 560 | 2011: [ 12, 27, /* to */ 1, 5 ],
|
---|
| 561 | 2012: [ 12, 24, /* to */ 1, 5 ],
|
---|
| 562 | 2013: [ 12, 23, /* to */ 1, 4 ],
|
---|
| 563 | 2014: [ 12, 24, /* to */ 1, 5 ],
|
---|
| 564 | 2015: [ 12, 24, /* to */ 1, 5 ],
|
---|
| 565 | 2016: [ 12, 24, /* to */ 1, 5 ],
|
---|
| 566 | },
|
---|
| 567 | ],
|
---|
| 568 | },
|
---|
| 569 | 'Niedersachsen': {
|
---|
| 570 | 'SH': [
|
---|
| 571 | {
|
---|
| 572 | name: 'Winterferien',
|
---|
| 573 | 2010: [ 2, 1, /* to */ 2, 2 ],
|
---|
| 574 | 2011: [ 1, 31, /* to */ 2, 1 ],
|
---|
| 575 | 2012: [ 1, 30, /* to */ 1, 31 ],
|
---|
| 576 | 2013: [ 1, 31, /* to */ 2, 1 ],
|
---|
| 577 | 2014: [ 1, 30, /* to */ 1, 31 ],
|
---|
| 578 | 2015: [ 2, 2, /* to */ 2, 3 ],
|
---|
| 579 | 2016: [ 1, 28, /* to */ 1, 29 ],
|
---|
| 580 | 2017: [ 1, 30, /* to */ 1, 31 ],
|
---|
| 581 | },
|
---|
| 582 | {
|
---|
| 583 | name: 'Osterferien',
|
---|
| 584 | 2010: [ 3, 19, /* to */ 4, 6 ],
|
---|
| 585 | 2011: [ 4, 16, /* to */ 4, 30 ],
|
---|
| 586 | 2012: [ 3, 26, /* to */ 4, 11, 4, 30, /* to */ 4, 30 ],
|
---|
| 587 | 2013: [ 3, 16, /* to */ 4, 2 ],
|
---|
| 588 | 2014: [ 4, 3, /* to */ 4, 22, 5, 2, /* to */ 5, 2 ],
|
---|
| 589 | 2015: [ 3, 25, /* to */ 4, 10 ],
|
---|
| 590 | 2016: [ 3, 18, /* to */ 4, 2 ],
|
---|
| 591 | 2017: [ 4, 10, /* to */ 4, 22 ],
|
---|
| 592 | },
|
---|
| 593 | {
|
---|
| 594 | name: 'Pfingstferien',
|
---|
| 595 | 2010: [ 5, 14, /* to */ 5, 14, 5, 25, /* to */ 5, 25 ],
|
---|
| 596 | 2011: [ 6, 3, /* to */ 6, 3, 6, 14, /* to */ 6, 14 ],
|
---|
| 597 | 2012: [ 5, 18, /* to */ 5, 18, 5, 29, /* to */ 5, 29 ],
|
---|
| 598 | 2013: [ 5, 10, /* to */ 5, 10, 5, 21, /* to */ 5, 21 ],
|
---|
| 599 | 2014: [ 5, 30, /* to */ 5, 30, 6, 10, /* to */ 6, 10 ],
|
---|
| 600 | 2015: [ 5, 15, /* to */ 5, 15, 5, 26, /* to */ 5, 26 ],
|
---|
| 601 | 2016: [ 5, 6, /* to */ 5, 6, 5, 17, /* to */ 5, 17 ],
|
---|
| 602 | 2017: [ 5, 26, /* to */ 5, 26, 6, 6, /* to */ 6, 6 ],
|
---|
| 603 | },
|
---|
| 604 | {
|
---|
| 605 | name: 'Sommerferien',
|
---|
| 606 | 2010: [ 6, 24, /* to */ 8, 4 ],
|
---|
| 607 | 2011: [ 7, 7, /* to */ 8, 17 ],
|
---|
| 608 | 2012: [ 7, 23, /* to */ 8, 31 ],
|
---|
| 609 | 2013: [ 6, 27, /* to */ 8, 7 ],
|
---|
| 610 | 2014: [ 7, 31, /* to */ 9, 10 ],
|
---|
| 611 | 2015: [ 7, 23, /* to */ 9, 2 ],
|
---|
| 612 | 2016: [ 6, 23, /* to */ 8, 3 ],
|
---|
| 613 | 2017: [ 6, 22, /* to */ 8, 2 ],
|
---|
| 614 | },
|
---|
| 615 | {
|
---|
| 616 | name: 'Herbstferien',
|
---|
| 617 | 2010: [ 10, 9, /* to */ 10, 23 ],
|
---|
| 618 | 2011: [ 10, 17, /* to */ 10, 29 ],
|
---|
| 619 | 2012: [ 10, 22, /* to */ 11, 3 ],
|
---|
| 620 | 2013: [ 10, 4, /* to */ 10, 18 ],
|
---|
| 621 | 2014: [ 10, 27, /* to */ 11, 8 ],
|
---|
| 622 | 2015: [ 10, 19, /* to */ 10, 31 ],
|
---|
| 623 | 2016: [ 10, 4, /* to */ 10, 15 ],
|
---|
| 624 | },
|
---|
| 625 | {
|
---|
| 626 | name: 'Weihnachtsferien',
|
---|
| 627 | 2010: [ 12, 22, /* to */ 1, 5 ],
|
---|
| 628 | 2011: [ 12, 23, /* to */ 1, 4 ],
|
---|
| 629 | 2012: [ 12, 24, /* to */ 1, 5 ],
|
---|
| 630 | 2013: [ 12, 23, /* to */ 1, 3 ],
|
---|
| 631 | 2014: [ 12, 22, /* to */ 1, 5 ],
|
---|
| 632 | 2015: [ 12, 23, /* to */ 1, 6 ],
|
---|
| 633 | 2016: [ 12, 21, /* to */ 1, 6 ],
|
---|
| 634 | },
|
---|
| 635 | ],
|
---|
| 636 | },
|
---|
| 637 | 'Nordrhein-Westfalen': {
|
---|
| 638 | 'SH': [
|
---|
| 639 | {
|
---|
| 640 | name: 'Osterferien',
|
---|
| 641 | 2010: [ 3, 27, /* to */ 4, 10 ],
|
---|
| 642 | 2011: [ 4, 18, /* to */ 4, 30 ],
|
---|
| 643 | 2012: [ 4, 2, /* to */ 4, 14 ],
|
---|
| 644 | 2013: [ 3, 25, /* to */ 4, 6 ],
|
---|
| 645 | 2014: [ 4, 14, /* to */ 4, 26 ],
|
---|
| 646 | 2015: [ 3, 30, /* to */ 4, 11 ],
|
---|
| 647 | 2016: [ 3, 21, /* to */ 4, 2 ],
|
---|
| 648 | 2017: [ 4, 10, /* to */ 4, 22 ],
|
---|
| 649 | },
|
---|
| 650 | {
|
---|
| 651 | name: 'Pfingstferien',
|
---|
| 652 | 2010: [ 5, 25, /* to */ 5, 25 ],
|
---|
| 653 | 2012: [ 5, 29, /* to */ 5, 29 ],
|
---|
| 654 | 2013: [ 5, 21, /* to */ 5, 21 ],
|
---|
| 655 | 2014: [ 6, 10, /* to */ 6, 10 ],
|
---|
| 656 | 2015: [ 5, 26, /* to */ 5, 26 ],
|
---|
| 657 | 2016: [ 5, 17, /* to */ 5, 17 ],
|
---|
| 658 | 2017: [ 6, 6, /* to */ 6, 6 ],
|
---|
| 659 | },
|
---|
| 660 | {
|
---|
| 661 | name: 'Sommerferien',
|
---|
| 662 | 2010: [ 7, 15, /* to */ 8, 27 ],
|
---|
| 663 | 2011: [ 7, 25, /* to */ 9, 6 ],
|
---|
| 664 | 2012: [ 7, 9, /* to */ 8, 21 ],
|
---|
| 665 | 2013: [ 7, 22, /* to */ 9, 3 ],
|
---|
| 666 | 2014: [ 7, 7, /* to */ 8, 19 ],
|
---|
| 667 | 2015: [ 6, 29, /* to */ 8, 11 ],
|
---|
| 668 | 2016: [ 7, 11, /* to */ 8, 23 ],
|
---|
| 669 | 2017: [ 7, 17, /* to */ 8, 29 ],
|
---|
| 670 | },
|
---|
| 671 | {
|
---|
| 672 | name: 'Herbstferien',
|
---|
| 673 | 2010: [ 10, 11, /* to */ 10, 23 ],
|
---|
| 674 | 2011: [ 10, 24, /* to */ 11, 5 ],
|
---|
| 675 | 2012: [ 10, 8, /* to */ 10, 20 ],
|
---|
| 676 | 2013: [ 10, 21, /* to */ 11, 2 ],
|
---|
| 677 | 2014: [ 10, 6, /* to */ 10, 18 ],
|
---|
| 678 | 2015: [ 10, 5, /* to */ 10, 17 ],
|
---|
| 679 | 2016: [ 10, 10, /* to */ 10, 21 ],
|
---|
| 680 | },
|
---|
| 681 | {
|
---|
| 682 | name: 'Weihnachtsferien',
|
---|
| 683 | 2010: [ 12, 24, /* to */ 1, 8 ],
|
---|
| 684 | 2011: [ 12, 23, /* to */ 1, 6 ],
|
---|
| 685 | 2012: [ 12, 21, /* to */ 1, 4 ],
|
---|
| 686 | 2013: [ 12, 23, /* to */ 1, 7 ],
|
---|
| 687 | 2014: [ 12, 22, /* to */ 1, 6 ],
|
---|
| 688 | 2015: [ 12, 23, /* to */ 1, 6 ],
|
---|
| 689 | 2016: [ 12, 23, /* to */ 1, 6 ],
|
---|
| 690 | },
|
---|
| 691 | ],
|
---|
| 692 | },
|
---|
| 693 | 'Sachsen': {
|
---|
| 694 | 'SH': [
|
---|
| 695 | {
|
---|
| 696 | name: 'Winterferien',
|
---|
| 697 | 2010: [ 2, 8, /* to */ 2, 20 ],
|
---|
| 698 | 2011: [ 2, 12, /* to */ 2, 26 ],
|
---|
| 699 | 2012: [ 2, 13, /* to */ 2, 25 ],
|
---|
| 700 | 2013: [ 2, 4, /* to */ 2, 15 ],
|
---|
| 701 | 2014: [ 2, 17, /* to */ 3, 1 ],
|
---|
| 702 | 2015: [ 2, 9, /* to */ 2, 21 ],
|
---|
| 703 | 2016: [ 2, 8, /* to */ 2, 20 ],
|
---|
| 704 | 2017: [ 2, 13, /* to */ 2, 24 ],
|
---|
| 705 | },
|
---|
| 706 | {
|
---|
| 707 | name: 'Osterferien',
|
---|
| 708 | 2010: [ 4, 1, /* to */ 4, 10 ],
|
---|
| 709 | 2011: [ 4, 22, /* to */ 4, 30 ],
|
---|
| 710 | 2012: [ 4, 6, /* to */ 4, 14 ],
|
---|
| 711 | 2013: [ 3, 29, /* to */ 4, 6 ],
|
---|
| 712 | 2014: [ 4, 18, /* to */ 4, 26 ],
|
---|
| 713 | 2015: [ 4, 2, /* to */ 4, 11 ],
|
---|
| 714 | 2016: [ 3, 25, /* to */ 4, 2 ],
|
---|
| 715 | 2017: [ 4, 13, /* to */ 4, 22 ],
|
---|
| 716 | },
|
---|
| 717 | {
|
---|
| 718 | name: 'Pfingstferien',
|
---|
| 719 | 2010: [ 5, 14, /* to */ 5, 14 ],
|
---|
| 720 | 2011: [ 6, 3, /* to */ 6, 3 ],
|
---|
| 721 | 2012: [ 5, 18, /* to */ 5, 18 ],
|
---|
| 722 | 2013: [ 5, 10, /* to */ 5, 10, 5, 18, /* to */ 5, 22 ],
|
---|
| 723 | 2014: [ 5, 30, /* to */ 5, 30 ],
|
---|
| 724 | 2015: [ 5, 15, /* to */ 5, 15 ],
|
---|
| 725 | 2016: [ 5, 6, /* to */ 5, 6 ],
|
---|
| 726 | 2017: [ 5, 26, /* to */ 5, 26 ],
|
---|
| 727 | },
|
---|
| 728 | {
|
---|
| 729 | name: 'Sommerferien',
|
---|
| 730 | 2010: [ 6, 28, /* to */ 8, 6 ],
|
---|
| 731 | 2011: [ 7, 11, /* to */ 8, 19 ],
|
---|
| 732 | 2012: [ 7, 23, /* to */ 8, 31 ],
|
---|
| 733 | 2013: [ 7, 15, /* to */ 8, 23 ],
|
---|
| 734 | 2014: [ 7, 21, /* to */ 8, 29 ],
|
---|
| 735 | 2015: [ 7, 13, /* to */ 8, 21 ],
|
---|
| 736 | 2016: [ 6, 27, /* to */ 8, 5 ],
|
---|
| 737 | 2017: [ 6, 26, /* to */ 8, 4 ],
|
---|
| 738 | },
|
---|
| 739 | {
|
---|
| 740 | name: 'Herbstferien',
|
---|
| 741 | 2010: [ 10, 4, /* to */ 10, 16 ],
|
---|
| 742 | 2011: [ 10, 17, /* to */ 10, 28 ],
|
---|
| 743 | 2012: [ 10, 22, /* to */ 11, 2 ],
|
---|
| 744 | 2013: [ 10, 21, /* to */ 11, 1 ],
|
---|
| 745 | 2014: [ 10, 20, /* to */ 10, 31 ],
|
---|
| 746 | 2015: [ 10, 12, /* to */ 10, 24 ],
|
---|
| 747 | 2016: [ 10, 3, /* to */ 10, 15 ],
|
---|
| 748 | },
|
---|
| 749 | {
|
---|
| 750 | name: 'Weihnachtsferien',
|
---|
| 751 | 2010: [ 12, 23, /* to */ 1, 1 ],
|
---|
| 752 | 2011: [ 12, 23, /* to */ 1, 2 ],
|
---|
| 753 | 2012: [ 12, 22, /* to */ 1, 2 ],
|
---|
| 754 | 2013: [ 12, 21, /* to */ 1, 3 ],
|
---|
| 755 | 2014: [ 12, 22, /* to */ 1, 3 ],
|
---|
| 756 | 2015: [ 12, 21, /* to */ 1, 2 ],
|
---|
| 757 | 2016: [ 12, 23, /* to */ 1, 2 ],
|
---|
| 758 | },
|
---|
| 759 | ],
|
---|
| 760 | },
|
---|
| 761 | 'Thüringen': {
|
---|
| 762 | 'SH': [
|
---|
| 763 | {
|
---|
| 764 | name: 'Winterferien',
|
---|
| 765 | 2010: [ 2, 1, /* to */ 2, 6 ],
|
---|
| 766 | 2011: [ 1, 31, /* to */ 2, 5 ],
|
---|
| 767 | 2012: [ 2, 6, /* to */ 2, 11 ],
|
---|
| 768 | 2013: [ 2, 18, /* to */ 2, 23 ],
|
---|
| 769 | 2014: [ 2, 17, /* to */ 2, 22 ],
|
---|
| 770 | 2015: [ 2, 2, /* to */ 2, 7 ],
|
---|
| 771 | 2016: [ 2, 1, /* to */ 2, 6 ],
|
---|
| 772 | 2017: [ 2, 6, /* to */ 2, 11 ],
|
---|
| 773 | },
|
---|
| 774 | {
|
---|
| 775 | name: 'Osterferien',
|
---|
| 776 | 2010: [ 3, 29, /* to */ 4, 9 ],
|
---|
| 777 | 2011: [ 4, 18, /* to */ 4, 30 ],
|
---|
| 778 | 2012: [ 4, 2, /* to */ 4, 13 ],
|
---|
| 779 | 2013: [ 3, 25, /* to */ 4, 6 ],
|
---|
| 780 | 2014: [ 4, 19, /* to */ 5, 2 ],
|
---|
| 781 | 2015: [ 3, 30, /* to */ 4, 11 ],
|
---|
| 782 | 2016: [ 3, 24, /* to */ 4, 2 ],
|
---|
| 783 | 2017: [ 4, 10, /* to */ 4, 21 ],
|
---|
| 784 | },
|
---|
| 785 | {
|
---|
| 786 | name: 'Sommerferien',
|
---|
| 787 | 2010: [ 6, 24, /* to */ 8, 4 ],
|
---|
| 788 | 2011: [ 7, 11, /* to */ 8, 19 ],
|
---|
| 789 | 2012: [ 7, 23, /* to */ 8, 31 ],
|
---|
| 790 | 2013: [ 7, 15, /* to */ 8, 23 ],
|
---|
| 791 | 2014: [ 7, 21, /* to */ 8, 29 ],
|
---|
| 792 | 2015: [ 7, 13, /* to */ 8, 21 ],
|
---|
| 793 | 2016: [ 6, 27, /* to */ 8, 10 ],
|
---|
| 794 | 2017: [ 6, 26, /* to */ 8, 9 ],
|
---|
| 795 | },
|
---|
| 796 | {
|
---|
| 797 | name: 'Pfingstferien',
|
---|
| 798 | 2011: [ 6, 11, /* to */ 6, 14 ],
|
---|
| 799 | 2012: [ 5, 25, /* to */ 5, 29 ],
|
---|
| 800 | 2013: [ 5, 10, /* to */ 5, 10 ],
|
---|
| 801 | 2014: [ 5, 30, /* to */ 5, 30 ],
|
---|
| 802 | 2015: [ 5, 15, /* to */ 5, 15 ],
|
---|
| 803 | 2016: [ 5, 6, /* to */ 5, 6 ],
|
---|
| 804 | 2017: [ 5, 26, /* to */ 5, 26 ],
|
---|
| 805 | },
|
---|
| 806 | {
|
---|
| 807 | name: 'Herbstferien',
|
---|
| 808 | 2010: [ 10, 9, /* to */ 10, 23 ],
|
---|
| 809 | 2011: [ 10, 17, /* to */ 10, 28 ],
|
---|
| 810 | 2012: [ 10, 22, /* to */ 11, 3 ],
|
---|
| 811 | 2013: [ 10, 21, /* to */ 11, 2 ],
|
---|
| 812 | 2014: [ 10, 6, /* to */ 10, 18 ],
|
---|
| 813 | 2015: [ 10, 5, /* to */ 10, 17 ],
|
---|
| 814 | 2016: [ 10, 10, /* to */ 10, 22 ],
|
---|
| 815 | },
|
---|
| 816 | {
|
---|
| 817 | name: 'Weihnachtsferien',
|
---|
| 818 | 2010: [ 12, 23, /* to */ 1, 1 ],
|
---|
| 819 | 2011: [ 12, 23, /* to */ 1, 1 ],
|
---|
| 820 | 2012: [ 12, 24, /* to */ 1, 5 ],
|
---|
| 821 | 2013: [ 12, 23, /* to */ 1, 4 ],
|
---|
| 822 | 2014: [ 12, 22, /* to */ 1, 3 ],
|
---|
| 823 | 2015: [ 12, 23, /* to */ 1, 2 ],
|
---|
| 824 | 2016: [ 12, 23, /* to */ 12, 31 ],
|
---|
| 825 | },
|
---|
| 826 | ],
|
---|
| 827 | },
|
---|
| 828 | 'Hamburg': {
|
---|
| 829 | 'SH': [
|
---|
| 830 | {
|
---|
| 831 | name: 'Winterferien',
|
---|
| 832 | 2010: [ 1, 29, /* to */ 1, 29 ],
|
---|
| 833 | 2011: [ 1, 31, /* to */ 1, 31 ],
|
---|
| 834 | 2012: [ 1, 30, /* to */ 1, 30 ],
|
---|
| 835 | 2013: [ 2, 1, /* to */ 2, 1 ],
|
---|
| 836 | 2014: [ 1, 31, /* to */ 1, 31 ],
|
---|
| 837 | 2015: [ 1, 30, /* to */ 1, 30 ],
|
---|
| 838 | 2016: [ 1, 29, /* to */ 1, 29 ],
|
---|
| 839 | 2017: [ 1, 30, /* to */ 1, 30 ],
|
---|
| 840 | },
|
---|
| 841 | {
|
---|
| 842 | name: 'Osterferien',
|
---|
| 843 | 2010: [ 3, 8, /* to */ 3, 20 ],
|
---|
| 844 | 2011: [ 3, 7, /* to */ 3, 18 ],
|
---|
| 845 | 2012: [ 3, 5, /* to */ 3, 16 ],
|
---|
| 846 | 2013: [ 3, 4, /* to */ 3, 15 ],
|
---|
| 847 | 2014: [ 3, 3, /* to */ 3, 14 ],
|
---|
| 848 | 2015: [ 3, 2, /* to */ 3, 13 ],
|
---|
| 849 | 2016: [ 3, 7, /* to */ 3, 18 ],
|
---|
| 850 | 2017: [ 3, 6, /* to */ 3, 17 ],
|
---|
| 851 | },
|
---|
| 852 | {
|
---|
| 853 | name: 'Pfingstferien',
|
---|
| 854 | 2010: [ 5, 14, /* to */ 5, 22 ],
|
---|
| 855 | 2011: [ 4, 26, /* to */ 4, 29, 6, 3, /* to */ 6, 3 ],
|
---|
| 856 | 2012: [ 4, 30, /* to */ 5, 4, 5, 18, /* to */ 5, 18 ],
|
---|
| 857 | 2013: [ 5, 2, /* to */ 5, 10 ],
|
---|
| 858 | 2014: [ 4, 28, /* to */ 5, 2, 5, 30, /* to */ 5, 30 ],
|
---|
| 859 | 2015: [ 5, 11, /* to */ 5, 15 ],
|
---|
| 860 | 2016: [ 5, 6, /* to */ 5, 6, 5, 17, /* to */ 5, 20 ],
|
---|
| 861 | 2017: [ 5, 22, /* to */ 5, 26 ],
|
---|
| 862 | },
|
---|
| 863 | {
|
---|
| 864 | name: 'Sommerferien',
|
---|
| 865 | 2010: [ 7, 8, /* to */ 8, 18 ],
|
---|
| 866 | 2011: [ 6, 30, /* to */ 8, 10 ],
|
---|
| 867 | 2012: [ 6, 21, /* to */ 8, 1 ],
|
---|
| 868 | 2013: [ 6, 20, /* to */ 7, 31 ],
|
---|
| 869 | 2014: [ 7, 10, /* to */ 8, 20 ],
|
---|
| 870 | 2015: [ 7, 16, /* to */ 8, 26 ],
|
---|
| 871 | 2016: [ 7, 21, /* to */ 8, 31 ],
|
---|
| 872 | 2017: [ 7, 20, /* to */ 8, 30 ],
|
---|
| 873 | },
|
---|
| 874 | {
|
---|
| 875 | name: 'Herbstferien',
|
---|
| 876 | 2010: [ 10, 4, /* to */ 10, 15 ],
|
---|
| 877 | 2011: [ 10, 4, /* to */ 10, 14 ],
|
---|
| 878 | 2012: [ 10, 1, /* to */ 10, 12 ],
|
---|
| 879 | 2013: [ 9, 30, /* to */ 10, 11 ],
|
---|
| 880 | 2014: [ 10, 13, /* to */ 10, 24 ],
|
---|
| 881 | 2015: [ 10, 19, /* to */ 10, 30 ],
|
---|
| 882 | 2016: [ 10, 17, /* to */ 10, 28 ],
|
---|
| 883 | },
|
---|
| 884 | {
|
---|
| 885 | name: 'Weihnachtsferien',
|
---|
| 886 | 2010: [ 12, 23, /* to */ 1, 3 ],
|
---|
| 887 | 2011: [ 12, 27, /* to */ 1, 6 ],
|
---|
| 888 | 2012: [ 12, 21, /* to */ 1, 4 ],
|
---|
| 889 | 2013: [ 12, 19, /* to */ 1, 3 ],
|
---|
| 890 | 2014: [ 12, 22, /* to */ 1, 6 ],
|
---|
| 891 | 2015: [ 12, 21, /* to */ 1, 1 ],
|
---|
| 892 | 2016: [ 12, 27, /* to */ 1, 6 ],
|
---|
| 893 | },
|
---|
| 894 | ],
|
---|
| 895 | },
|
---|
| 896 | 'Sachsen-Anhalt': {
|
---|
| 897 | 'SH': [
|
---|
| 898 | {
|
---|
| 899 | name: 'Winterferien',
|
---|
| 900 | 2010: [ 2, 8, /* to */ 2, 13 ],
|
---|
| 901 | 2011: [ 2, 5, /* to */ 2, 12 ],
|
---|
| 902 | 2012: [ 2, 4, /* to */ 2, 11 ],
|
---|
| 903 | 2013: [ 2, 1, /* to */ 2, 8 ],
|
---|
| 904 | 2014: [ 2, 1, /* to */ 2, 12 ],
|
---|
| 905 | 2015: [ 2, 2, /* to */ 2, 14 ],
|
---|
| 906 | 2016: [ 2, 1, /* to */ 2, 10 ],
|
---|
| 907 | 2017: [ 2, 4, /* to */ 2, 11 ],
|
---|
| 908 | },
|
---|
| 909 | {
|
---|
| 910 | name: 'Osterferien',
|
---|
| 911 | 2010: [ 3, 29, /* to */ 4, 9 ],
|
---|
| 912 | 2011: [ 4, 18, /* to */ 4, 27 ],
|
---|
| 913 | 2012: [ 4, 2, /* to */ 4, 7 ],
|
---|
| 914 | 2013: [ 3, 25, /* to */ 3, 30 ],
|
---|
| 915 | 2014: [ 4, 14, /* to */ 4, 17 ],
|
---|
| 916 | 2015: [ 4, 2, /* to */ 4, 2 ],
|
---|
| 917 | 2016: [ 3, 24, /* to */ 3, 24 ],
|
---|
| 918 | 2017: [ 4, 10, /* to */ 4, 13 ],
|
---|
| 919 | },
|
---|
| 920 | {
|
---|
| 921 | name: 'Pfingstferien',
|
---|
| 922 | 2010: [ 5, 14, /* to */ 5, 22 ],
|
---|
| 923 | 2011: [ 6, 14, /* to */ 6, 18 ],
|
---|
| 924 | 2012: [ 5, 18, /* to */ 5, 25 ],
|
---|
| 925 | 2013: [ 5, 10, /* to */ 5, 18 ],
|
---|
| 926 | 2014: [ 5, 30, /* to */ 6, 7 ],
|
---|
| 927 | 2015: [ 5, 15, /* to */ 5, 23 ],
|
---|
| 928 | 2016: [ 5, 6, /* to */ 5, 14 ],
|
---|
| 929 | 2017: [ 5, 26, /* to */ 5, 26 ],
|
---|
| 930 | },
|
---|
| 931 | {
|
---|
| 932 | name: 'Sommerferien',
|
---|
| 933 | 2010: [ 6, 24, /* to */ 8, 4 ],
|
---|
| 934 | 2011: [ 7, 11, /* to */ 8, 24 ],
|
---|
| 935 | 2012: [ 7, 23, /* to */ 9, 5 ],
|
---|
| 936 | 2013: [ 7, 15, /* to */ 8, 28 ],
|
---|
| 937 | 2014: [ 7, 21, /* to */ 9, 3 ],
|
---|
| 938 | 2015: [ 7, 13, /* to */ 8, 26 ],
|
---|
| 939 | 2016: [ 6, 27, /* to */ 8, 10 ],
|
---|
| 940 | 2017: [ 6, 26, /* to */ 8, 9 ],
|
---|
| 941 | },
|
---|
| 942 | {
|
---|
| 943 | name: 'Herbstferien',
|
---|
| 944 | 2010: [ 10, 18, /* to */ 10, 23 ],
|
---|
| 945 | 2011: [ 10, 17, /* to */ 10, 22 ],
|
---|
| 946 | 2012: [ 10, 29, /* to */ 11, 2 ],
|
---|
| 947 | 2013: [ 10, 21, /* to */ 10, 25 ],
|
---|
| 948 | 2014: [ 10, 27, /* to */ 10, 30 ],
|
---|
| 949 | 2015: [ 10, 17, /* to */ 10, 24 ],
|
---|
| 950 | 2016: [ 10, 4, /* to */ 10, 15 ],
|
---|
| 951 | },
|
---|
| 952 | {
|
---|
| 953 | name: 'Weihnachtsferien',
|
---|
| 954 | 2010: [ 12, 22, /* to */ 1, 5 ],
|
---|
| 955 | 2011: [ 12, 22, /* to */ 1, 7 ],
|
---|
| 956 | 2012: [ 12, 19, /* to */ 1, 4 ],
|
---|
| 957 | 2013: [ 12, 21, /* to */ 1, 3 ],
|
---|
| 958 | 2014: [ 12, 22, /* to */ 1, 5 ],
|
---|
| 959 | 2015: [ 12, 21, /* to */ 1, 5 ],
|
---|
| 960 | 2016: [ 12, 19, /* to */ 1, 2 ],
|
---|
| 961 | },
|
---|
| 962 | ],
|
---|
| 963 | },
|
---|
| 964 | 'Rheinland-Pfalz': {
|
---|
| 965 | 'SH': [
|
---|
| 966 | {
|
---|
| 967 | name: 'Osterferien',
|
---|
| 968 | 2010: [ 3, 26, /* to */ 4, 9 ],
|
---|
| 969 | 2011: [ 4, 18, /* to */ 4, 29 ],
|
---|
| 970 | 2012: [ 3, 29, /* to */ 4, 13 ],
|
---|
| 971 | 2013: [ 3, 20, /* to */ 4, 5 ],
|
---|
| 972 | 2014: [ 4, 11, /* to */ 4, 25 ],
|
---|
| 973 | 2015: [ 3, 26, /* to */ 4, 10 ],
|
---|
| 974 | 2016: [ 3, 18, /* to */ 4, 1 ],
|
---|
| 975 | 2017: [ 4, 10, /* to */ 4, 21 ],
|
---|
| 976 | },
|
---|
| 977 | {
|
---|
| 978 | name: 'Sommerferien',
|
---|
| 979 | 2010: [ 7, 5, /* to */ 8, 13 ],
|
---|
| 980 | 2011: [ 6, 27, /* to */ 8, 5 ],
|
---|
| 981 | 2012: [ 7, 2, /* to */ 8, 10 ],
|
---|
| 982 | 2013: [ 7, 8, /* to */ 8, 16 ],
|
---|
| 983 | 2014: [ 7, 28, /* to */ 9, 5 ],
|
---|
| 984 | 2015: [ 7, 27, /* to */ 9, 4 ],
|
---|
| 985 | 2016: [ 7, 18, /* to */ 8, 26 ],
|
---|
| 986 | 2017: [ 7, 3, /* to */ 8, 11 ],
|
---|
| 987 | },
|
---|
| 988 | {
|
---|
| 989 | name: 'Herbstferien',
|
---|
| 990 | 2010: [ 10, 11, /* to */ 10, 22 ],
|
---|
| 991 | 2011: [ 10, 4, /* to */ 10, 14 ],
|
---|
| 992 | 2012: [ 10, 1, /* to */ 10, 12 ],
|
---|
| 993 | 2013: [ 10, 4, /* to */ 10, 18 ],
|
---|
| 994 | 2014: [ 10, 20, /* to */ 10, 31 ],
|
---|
| 995 | 2015: [ 10, 19, /* to */ 10, 30 ],
|
---|
| 996 | 2016: [ 10, 10, /* to */ 10, 21 ],
|
---|
| 997 | },
|
---|
| 998 | {
|
---|
| 999 | name: 'Weihnachtsferien',
|
---|
| 1000 | 2010: [ 12, 23, /* to */ 1, 7 ],
|
---|
| 1001 | 2011: [ 12, 22, /* to */ 1, 6 ],
|
---|
| 1002 | 2012: [ 12, 20, /* to */ 1, 4 ],
|
---|
| 1003 | 2013: [ 12, 23, /* to */ 1, 7 ],
|
---|
| 1004 | 2014: [ 12, 22, /* to */ 1, 7 ],
|
---|
| 1005 | 2015: [ 12, 23, /* to */ 1, 8 ],
|
---|
| 1006 | 2016: [ 12, 22, /* to */ 1, 6 ],
|
---|
| 1007 | },
|
---|
| 1008 | ],
|
---|
| 1009 | },
|
---|
| 1010 | 'Brandenburg': {
|
---|
| 1011 | 'SH': [
|
---|
| 1012 | {
|
---|
| 1013 | name: 'Winterferien',
|
---|
| 1014 | 2010: [ 2, 1, /* to */ 2, 6 ],
|
---|
| 1015 | 2011: [ 1, 31, /* to */ 2, 5 ],
|
---|
| 1016 | 2012: [ 1, 30, /* to */ 2, 4 ],
|
---|
| 1017 | 2013: [ 2, 4, /* to */ 2, 9 ],
|
---|
| 1018 | 2014: [ 2, 3, /* to */ 2, 8 ],
|
---|
| 1019 | 2015: [ 2, 2, /* to */ 2, 7 ],
|
---|
| 1020 | 2016: [ 2, 1, /* to */ 2, 6 ],
|
---|
| 1021 | 2017: [ 1, 30, /* to */ 2, 4 ],
|
---|
| 1022 | },
|
---|
| 1023 | {
|
---|
| 1024 | name: 'Osterferien',
|
---|
| 1025 | 2010: [ 3, 31, /* to */ 4, 10 ],
|
---|
| 1026 | 2011: [ 4, 20, /* to */ 4, 30 ],
|
---|
| 1027 | 2012: [ 4, 4, /* to */ 4, 14, 4, 30, /* to */ 4, 30 ],
|
---|
| 1028 | 2013: [ 3, 27, /* to */ 4, 6 ],
|
---|
| 1029 | 2014: [ 4, 16, /* to */ 4, 26, 5, 2, /* to */ 5, 2 ],
|
---|
| 1030 | 2015: [ 4, 1, /* to */ 4, 11 ],
|
---|
| 1031 | 2016: [ 3, 23, /* to */ 4, 2 ],
|
---|
| 1032 | 2017: [ 4, 12, /* to */ 4, 22 ],
|
---|
| 1033 | },
|
---|
| 1034 | {
|
---|
| 1035 | name: 'Pfingstferien',
|
---|
| 1036 | 2010: [ 5, 14, /* to */ 5, 14 ],
|
---|
| 1037 | 2011: [ 6, 3, /* to */ 6, 3 ],
|
---|
| 1038 | 2012: [ 5, 18, /* to */ 5, 18 ],
|
---|
| 1039 | 2013: [ 5, 10, /* to */ 5, 10 ],
|
---|
| 1040 | 2014: [ 5, 30, /* to */ 5, 30 ],
|
---|
| 1041 | 2015: [ 5, 15, /* to */ 5, 15 ],
|
---|
| 1042 | 2016: [ 5, 6, /* to */ 5, 6, 5, 17, /* to */ 5, 17 ],
|
---|
| 1043 | 2017: [ 5, 26, /* to */ 5, 26 ],
|
---|
| 1044 | },
|
---|
| 1045 | {
|
---|
| 1046 | name: 'Sommerferien',
|
---|
| 1047 | 2010: [ 7, 8, /* to */ 8, 21 ],
|
---|
| 1048 | 2011: [ 6, 30, /* to */ 8, 13 ],
|
---|
| 1049 | 2012: [ 6, 21, /* to */ 8, 3 ],
|
---|
| 1050 | 2013: [ 6, 20, /* to */ 8, 2 ],
|
---|
| 1051 | 2014: [ 7, 10, /* to */ 8, 22 ],
|
---|
| 1052 | 2015: [ 7, 16, /* to */ 8, 28 ],
|
---|
| 1053 | 2016: [ 7, 21, /* to */ 9, 3 ],
|
---|
| 1054 | 2017: [ 7, 20, /* to */ 9, 1 ],
|
---|
| 1055 | },
|
---|
| 1056 | {
|
---|
| 1057 | name: 'Herbstferien',
|
---|
| 1058 | 2010: [ 10, 11, /* to */ 10, 23 ],
|
---|
| 1059 | 2011: [ 10, 4, /* to */ 10, 14 ],
|
---|
| 1060 | 2012: [ 10, 1, /* to */ 10, 13 ],
|
---|
| 1061 | 2013: [ 9, 30, /* to */ 10, 12, 11, 1, /* to */ 11, 1 ],
|
---|
| 1062 | 2014: [ 10, 20, /* to */ 11, 1 ],
|
---|
| 1063 | 2015: [ 10, 19, /* to */ 10, 30 ],
|
---|
| 1064 | 2016: [ 10, 17, /* to */ 10, 28 ],
|
---|
| 1065 | },
|
---|
| 1066 | {
|
---|
| 1067 | name: 'Weihnachtsferien',
|
---|
| 1068 | 2010: [ 12, 23, /* to */ 1, 1 ],
|
---|
| 1069 | 2011: [ 12, 23, /* to */ 1, 3 ],
|
---|
| 1070 | 2012: [ 12, 24, /* to */ 1, 4 ],
|
---|
| 1071 | 2013: [ 12, 23, /* to */ 1, 3 ],
|
---|
| 1072 | 2014: [ 12, 22, /* to */ 1, 2 ],
|
---|
| 1073 | 2015: [ 12, 23, /* to */ 1, 2 ],
|
---|
| 1074 | 2016: [ 12, 23, /* to */ 1, 3 ],
|
---|
| 1075 | },
|
---|
| 1076 | ],
|
---|
| 1077 | },
|
---|
| 1078 | },
|
---|
| 1079 | 'at': {
|
---|
| 1080 | 'PH': { // http://de.wikipedia.org/wiki/Feiertage_in_%C3%96sterreich
|
---|
| 1081 | 'Neujahrstag' : [ 1, 1 ],
|
---|
| 1082 | 'Heilige Drei Könige' : [ 1, 6 ],
|
---|
| 1083 | // 'Josef' : [ 3, 19, [ 'Kärnten', 'Steiermark', 'Tirol', 'Vorarlberg' ] ],
|
---|
| 1084 | // 'Karfreitag' : [ 'easter', -2 ],
|
---|
| 1085 | 'Ostermontag' : [ 'easter', 1 ],
|
---|
| 1086 | 'Staatsfeiertag' : [ 5, 1 ],
|
---|
| 1087 | // 'Florian' : [ 5, 4, [ 'Oberösterreich' ] ],
|
---|
| 1088 | 'Christi Himmelfahrt' : [ 'easter', 39 ],
|
---|
| 1089 | 'Pfingstmontag' : [ 'easter', 50 ],
|
---|
| 1090 | 'Fronleichnam' : [ 'easter', 60 ],
|
---|
| 1091 | 'Mariä Himmelfahrt' : [ 8, 15 ],
|
---|
| 1092 | // 'Rupert' : [ 9, 24, [ 'Salzburg' ] ],
|
---|
| 1093 | // 'Tag der Volksabstimmung' : [ 10, 10, [ 'Kärnten' ] ],
|
---|
| 1094 | 'Nationalfeiertag' : [ 10, 26 ],
|
---|
| 1095 | 'Allerheiligen' : [ 11, 1 ],
|
---|
| 1096 | // 'Martin' : [ 11, 11, [ 'Burgenland' ] ],
|
---|
| 1097 | // 'Leopold' : [ 11, 15, [ 'Niederösterreich', 'Wien' ] ],
|
---|
| 1098 | 'Mariä Empfängnis' : [ 12, 8 ],
|
---|
| 1099 | // 'Heiliger Abend' : [ 12, 24 ],
|
---|
| 1100 | 'Christtag' : [ 12, 25 ],
|
---|
| 1101 | 'Stefanitag' : [ 12, 26 ],
|
---|
| 1102 | // 'Silvester' : [ 12, 31 ],
|
---|
| 1103 | },
|
---|
| 1104 | },
|
---|
[7046] | 1105 | 'ca': {
|
---|
| 1106 | 'PH': { // https://en.wikipedia.org/wiki/Public_holidays_in_Canada
|
---|
| 1107 | "New Year's Day" : [ 1, 1 ],
|
---|
| 1108 | "Good Friday" : [ 'easter', -2 ],
|
---|
| 1109 | "Canada Day" : [ 'canadaDay', 0 ],
|
---|
| 1110 | "Labour Day" : [ 'firstSeptemberMonday', 0 ],
|
---|
| 1111 | "Christmas Day" : [ 12, 25 ]
|
---|
| 1112 | },
|
---|
| 1113 | 'Alberta': {
|
---|
| 1114 | 'PH': {
|
---|
| 1115 | "New Year's Day" : [ 1, 1 ],
|
---|
| 1116 | "Alberta Family Day" : [ 'firstFebruaryMonday', 14 ],
|
---|
| 1117 | "Good Friday" : [ 'easter', -2 ],
|
---|
| 1118 | "Easter Monday" : [ 'easter', 1 ],
|
---|
| 1119 | "Victoria Day" : [ 'victoriaDay', 0 ],
|
---|
| 1120 | "Canada Day" : [ 'canadaDay', 0 ],
|
---|
| 1121 | "Heritage Day" : [ 'firstAugustMonday', 0 ],
|
---|
| 1122 | "Labour Day" : [ 'firstSeptemberMonday', 0 ],
|
---|
| 1123 | "Thanksgiving" : [ 'firstOctoberMonday', 7 ],
|
---|
| 1124 | "Remembrance Day" : [ 11, 11 ],
|
---|
| 1125 | "Christmas Day" : [ 12, 25 ],
|
---|
| 1126 | "Boxing Day" : [ 12, 26 ]
|
---|
| 1127 | },
|
---|
| 1128 | },
|
---|
| 1129 | 'British Columbia': {
|
---|
| 1130 | 'PH': {
|
---|
| 1131 | "New Year's Day" : [ 1, 1 ],
|
---|
| 1132 | "Family Day" : [ 'firstFebruaryMonday', 7 ],
|
---|
| 1133 | "Good Friday" : [ 'easter', -2 ],
|
---|
| 1134 | "Victoria Day" : [ 'victoriaDay', 0 ],
|
---|
| 1135 | "Canada Day" : [ 'canadaDay', 0 ],
|
---|
| 1136 | "British Columbia Day" : [ 'firstAugustMonday', 0 ],
|
---|
| 1137 | "Labour Day" : [ 'firstSeptemberMonday', 0 ],
|
---|
| 1138 | "Thanksgiving" : [ 'firstOctoberMonday', 7 ],
|
---|
| 1139 | "Remembrance Day" : [ 11, 11 ],
|
---|
| 1140 | "Christmas Day" : [ 12, 25 ]
|
---|
| 1141 | },
|
---|
| 1142 | },
|
---|
| 1143 | 'Manitoba': {
|
---|
| 1144 | 'PH': {
|
---|
| 1145 | "New Year's Day" : [ 1, 1 ],
|
---|
| 1146 | "Louis Riel Day" : [ 'firstFebruaryMonday', 14 ],
|
---|
| 1147 | "Good Friday" : [ 'easter', -2 ],
|
---|
| 1148 | "Victoria Day" : [ 'victoriaDay', 0 ],
|
---|
| 1149 | "Canada Day" : [ 'canadaDay', 0 ],
|
---|
| 1150 | "Civic Holiday" : [ 'firstAugustMonday', 0 ],
|
---|
| 1151 | "Labour Day" : [ 'firstSeptemberMonday', 0 ],
|
---|
| 1152 | "Thanksgiving" : [ 'firstOctoberMonday', 7 ],
|
---|
| 1153 | "Remembrance Day" : [ 11, 11 ],
|
---|
| 1154 | "Christmas Day" : [ 12, 25 ]
|
---|
| 1155 | },
|
---|
| 1156 | },
|
---|
| 1157 | 'New Brunswick': {
|
---|
| 1158 | 'PH': {
|
---|
| 1159 | "New Year's Day" : [ 1, 1 ],
|
---|
| 1160 | "Good Friday" : [ 'easter', -2 ],
|
---|
| 1161 | "Victoria Day" : [ 'victoriaDay', 0 ],
|
---|
| 1162 | "Canada Day" : [ 'canadaDay', 0 ],
|
---|
| 1163 | "New Brunswick Day" : [ 'firstAugustMonday', 0 ],
|
---|
| 1164 | "Labour Day" : [ 'firstSeptemberMonday', 0 ],
|
---|
| 1165 | "Thanksgiving" : [ 'firstOctoberMonday', 7 ],
|
---|
| 1166 | "Remembrance Day" : [ 11, 11 ],
|
---|
| 1167 | "Christmas Day" : [ 12, 25 ],
|
---|
| 1168 | "Boxing Day" : [ 12, 26 ]
|
---|
| 1169 | },
|
---|
| 1170 | },
|
---|
| 1171 | 'Newfoundland and Labrador': {
|
---|
| 1172 | 'PH': {
|
---|
| 1173 | "New Year's Day" : [ 1, 1 ],
|
---|
| 1174 | "Saint Patrick's Day" : [ 3, 17 ],
|
---|
| 1175 | "Good Friday" : [ 'easter', -2 ],
|
---|
| 1176 | "Saint George's Day" : [ 4, 23 ],
|
---|
| 1177 | "Discovery Day" : [ 6, 24 ],
|
---|
| 1178 | "Memorial Day" : [ 7, 1 ],
|
---|
| 1179 | "Orangemen's Day" : [ 7, 12 ],
|
---|
| 1180 | "Labour Day" : [ 'firstSeptemberMonday', 0 ],
|
---|
| 1181 | "Armistice Day" : [ 11, 11 ],
|
---|
| 1182 | "Christmas Day" : [ 12, 25 ]
|
---|
| 1183 | },
|
---|
| 1184 | },
|
---|
| 1185 | 'Northwest Territories': {
|
---|
| 1186 | 'PH': {
|
---|
| 1187 | "New Year's Day" : [ 1, 1 ],
|
---|
| 1188 | "Good Friday" : [ 'easter', -2 ],
|
---|
| 1189 | "Victoria Day" : [ 'victoriaDay', 0 ],
|
---|
| 1190 | "National Aboriginal Day" : [ 6, 21 ],
|
---|
| 1191 | "Canada Day" : [ 'canadaDay', 0 ],
|
---|
| 1192 | "Civic Holiday" : [ 'firstAugustMonday', 0 ],
|
---|
| 1193 | "Labour Day" : [ 'firstSeptemberMonday', 0 ],
|
---|
| 1194 | "Thanksgiving" : [ 'firstOctoberMonday', 7 ],
|
---|
| 1195 | "Remembrance Day" : [ 11, 11 ],
|
---|
| 1196 | "Christmas Day" : [ 12, 25 ]
|
---|
| 1197 | },
|
---|
| 1198 | },
|
---|
| 1199 | 'Nova Scotia': {
|
---|
| 1200 | 'PH': {
|
---|
| 1201 | "New Year's Day" : [ 1, 1 ],
|
---|
| 1202 | "Good Friday" : [ 'easter', -2 ],
|
---|
| 1203 | "Victoria Day" : [ 'victoriaDay', 0 ],
|
---|
| 1204 | "Canada Day" : [ 'canadaDay', 0 ],
|
---|
| 1205 | "Natal Day" : [ 'firstAugustMonday', 0 ],
|
---|
| 1206 | "Labour Day" : [ 'firstSeptemberMonday', 0 ],
|
---|
| 1207 | "Thanksgiving" : [ 'firstOctoberMonday', 7 ],
|
---|
| 1208 | "Remembrance Day" : [ 11, 11 ],
|
---|
| 1209 | "Christmas Day" : [ 12, 25 ],
|
---|
| 1210 | "Boxing Day" : [ 12, 26 ]
|
---|
| 1211 | },
|
---|
| 1212 | },
|
---|
| 1213 | 'Nunavut': {
|
---|
| 1214 | 'PH': {
|
---|
| 1215 | "New Year's Day" : [ 1, 1 ],
|
---|
| 1216 | "Good Friday" : [ 'easter', -2 ],
|
---|
| 1217 | "Victoria Day" : [ 'victoriaDay', 0 ],
|
---|
| 1218 | "Canada Day" : [ 'canadaDay', 0 ],
|
---|
| 1219 | "Nunavut Day" : [ 7, 9 ],
|
---|
| 1220 | "Civic Holiday" : [ 'firstAugustMonday', 0 ],
|
---|
| 1221 | "Labour Day" : [ 'firstSeptemberMonday', 0 ],
|
---|
| 1222 | "Thanksgiving" : [ 'firstOctoberMonday', 7 ],
|
---|
| 1223 | "Remembrance Day" : [ 11, 11 ],
|
---|
| 1224 | "Christmas Day" : [ 12, 25 ]
|
---|
| 1225 | },
|
---|
| 1226 | },
|
---|
| 1227 | 'Ontario': {
|
---|
| 1228 | 'PH': {
|
---|
| 1229 | "New Year's Day" : [ 1, 1 ],
|
---|
| 1230 | "Family Day" : [ 'firstFebruaryMonday', 14 ],
|
---|
| 1231 | "Good Friday" : [ 'easter', -2 ],
|
---|
| 1232 | "Victoria Day" : [ 'victoriaDay', 0 ],
|
---|
| 1233 | "Canada Day" : [ 'canadaDay', 0 ],
|
---|
| 1234 | "August Civic Public Holiday" : [ 'firstAugustMonday', 0 ],
|
---|
| 1235 | "Labour Day" : [ 'firstSeptemberMonday', 0 ],
|
---|
| 1236 | "Thanksgiving" : [ 'firstOctoberMonday', 7 ],
|
---|
| 1237 | "Remembrance Day" : [ 11, 11 ],
|
---|
| 1238 | "Christmas Day" : [ 12, 25 ],
|
---|
| 1239 | "Boxing Day" : [ 12, 26 ]
|
---|
| 1240 | },
|
---|
| 1241 | },
|
---|
| 1242 | 'Prince Edward Island': {
|
---|
| 1243 | 'PH': {
|
---|
| 1244 | "New Year's Day" : [ 1, 1 ],
|
---|
| 1245 | "Islander Day" : [ 'firstFebruaryMonday', 14 ],
|
---|
| 1246 | "Good Friday" : [ 'easter', -2 ],
|
---|
| 1247 | "Easter Monday" : [ 'easter', 1 ],
|
---|
| 1248 | "Victoria Day" : [ 'victoriaDay', 0 ],
|
---|
| 1249 | "Canada Day" : [ 'canadaDay', 0 ],
|
---|
| 1250 | "Civic Holiday" : [ 'firstAugustMonday', 0 ],
|
---|
| 1251 | "Gold Cup Parade Day" : [ 'firstAugustMonday', 18 ],
|
---|
| 1252 | "Labour Day" : [ 'firstSeptemberMonday', 0 ],
|
---|
| 1253 | "Thanksgiving" : [ 'firstOctoberMonday', 7 ],
|
---|
| 1254 | "Remembrance Day" : [ 11, 11 ],
|
---|
| 1255 | "Christmas Day" : [ 12, 25 ],
|
---|
| 1256 | "Boxing Day" : [ 12, 26 ]
|
---|
| 1257 | },
|
---|
| 1258 | },
|
---|
| 1259 | 'Quebec': {
|
---|
| 1260 | 'PH': {
|
---|
| 1261 | "Jour de l'an" : [ 1, 1 ],
|
---|
| 1262 | "Vendredi saint" : [ 'easter', -2 ],
|
---|
| 1263 | "Lundi de Pâques" : [ 'easter', 1 ],
|
---|
| 1264 | "Journée nationale des patriotes" : [ 'victoriaDay', 0 ],
|
---|
| 1265 | "Fête nationale du Québec" : [ 6, 24 ],
|
---|
| 1266 | "Fête du Canada" : [ 'canadaDay', 0 ],
|
---|
| 1267 | "Fête du Travail" : [ 'firstSeptemberMonday', 0 ],
|
---|
| 1268 | "Jour de l'Action de grâce" : [ 'firstOctoberMonday', 7 ],
|
---|
| 1269 | "Noël" : [ 12, 25 ]
|
---|
| 1270 | },
|
---|
| 1271 | },
|
---|
| 1272 | 'Saskatchewan': {
|
---|
| 1273 | 'PH': {
|
---|
| 1274 | "New Year's Day" : [ 1, 1 ],
|
---|
| 1275 | "Family Day" : [ 'firstFebruaryMonday', 14 ],
|
---|
| 1276 | "Good Friday" : [ 'easter', -2 ],
|
---|
| 1277 | "Victoria Day" : [ 'victoriaDay', 0 ],
|
---|
| 1278 | "Canada Day" : [ 'canadaDay', 0 ],
|
---|
| 1279 | "Saskatchewan Day" : [ 'firstAugustMonday', 0 ],
|
---|
| 1280 | "Labour Day" : [ 'firstSeptemberMonday', 0 ],
|
---|
| 1281 | "Thanksgiving" : [ 'firstOctoberMonday', 7 ],
|
---|
| 1282 | "Remembrance Day" : [ 11, 11 ],
|
---|
| 1283 | "Christmas Day" : [ 12, 25 ]
|
---|
| 1284 | },
|
---|
| 1285 | },
|
---|
| 1286 | 'Yukon': {
|
---|
| 1287 | 'PH': {
|
---|
| 1288 | "New Year's Day" : [ 1, 1 ],
|
---|
| 1289 | "Heritage Day" : [ 'lastFebruarySunday', -2 ],
|
---|
| 1290 | "Good Friday" : [ 'easter', -2 ],
|
---|
| 1291 | "Easter Monday" : [ 'easter', 1 ],
|
---|
| 1292 | "Victoria Day" : [ 'victoriaDay', 0 ],
|
---|
| 1293 | "Canada Day" : [ 'canadaDay', 0 ],
|
---|
| 1294 | "Discovery Day" : [ 'firstAugustMonday', 14 ],
|
---|
| 1295 | "Labour Day" : [ 'firstSeptemberMonday', 0 ],
|
---|
| 1296 | "Thanksgiving" : [ 'firstOctoberMonday', 7 ],
|
---|
| 1297 | "Remembrance Day" : [ 11, 11 ],
|
---|
| 1298 | "Christmas Day" : [ 12, 25 ],
|
---|
| 1299 | "Boxing Day" : [ 12, 26 ]
|
---|
| 1300 | },
|
---|
| 1301 | },
|
---|
| 1302 | },
|
---|
| 1303 | 'ua': {
|
---|
| 1304 | 'PH': { // http://uk.wikipedia.org/wiki/%D0%A1%D0%B2%D1%8F%D1%82%D0%B0_%D1%82%D0%B0_%D0%BF%D0%B0%D0%BC%27%D1%8F%D1%82%D0%BD%D1%96_%D0%B4%D0%BD%D1%96_%D0%B2_%D0%A3%D0%BA%D1%80%D0%B0%D1%97%D0%BD%D1%96
|
---|
| 1305 | "Новий рік" : [ 1, 1 ],
|
---|
| 1306 | "Різдво" : [ 1, 7 ],
|
---|
| 1307 | "Міжнародний жіночий день" : [ 3, 8 ],
|
---|
| 1308 | "Великдень" : [ 'orthodox easter', 1 ],
|
---|
| 1309 | "День Праці 1" : [ 5, 1 ],
|
---|
| 1310 | "День Праці 2" : [ 5, 2 ],
|
---|
| 1311 | "День Перемоги" : [ 5, 9 ],
|
---|
| 1312 | "День Конституції України" : [ 6, 28 ],
|
---|
| 1313 | "День Незалежності України" : [ 8, 24 ],
|
---|
| 1314 | }
|
---|
| 1315 | },
|
---|
| 1316 | 'si': {
|
---|
| 1317 | 'PH': { // http://www.vlada.si/o_sloveniji/politicni_sistem/prazniki/
|
---|
| 1318 | 'novo leto' : [ 1, 1 ],
|
---|
| 1319 | 'Prešernov dan, slovenski kulturni praznik' : [ 2, 8 ],
|
---|
| 1320 | 'velikonočna nedelja' : [ 'easter', 0 ],
|
---|
| 1321 | 'velikonočni ponedeljek' : [ 'easter', 1 ],
|
---|
| 1322 | 'dan upora proti okupatorju' : [ 4, 27 ],
|
---|
| 1323 | 'praznik dela 1' : [ 5, 1 ],
|
---|
| 1324 | 'praznik dela 2' : [ 5, 2 ],
|
---|
| 1325 | 'binkoštna nedelja - binkošti' : [ 'easter', 49 ],
|
---|
| 1326 | 'dan državnosti' : [ 6, 25 ],
|
---|
| 1327 | 'Marijino vnebovzetje' : [ 8, 15 ],
|
---|
| 1328 | 'dan reformacije' : [ 10, 31 ],
|
---|
| 1329 | 'dan spomina na mrtve' : [ 11, 1 ],
|
---|
| 1330 | 'božič' : [ 12, 25 ],
|
---|
| 1331 | 'dan samostojnosti in enotnosti' : [ 12, 26 ],
|
---|
| 1332 | },
|
---|
| 1333 | },
|
---|
[6370] | 1334 | };
|
---|
[7046] | 1335 | // }}}
|
---|
[6370] | 1336 |
|
---|
[7046] | 1337 | // error correction {{{
|
---|
| 1338 | // Taken form http://www.netzwolf.info/j/osm/time_domain.js
|
---|
| 1339 | // Credits go to Netzwolf
|
---|
[6370] | 1340 | //
|
---|
[7046] | 1341 | // Key to word_error_correction is the token name except wrong_words
|
---|
[6370] | 1342 | var word_error_correction = {
|
---|
| 1343 | wrong_words: {
|
---|
| 1344 | 'Assuming "<ok>" for "<ko>"': {
|
---|
[7046] | 1345 | spring: 'Mar-May',
|
---|
| 1346 | summer: 'Jun-Aug',
|
---|
| 1347 | autumn: 'Sep-Nov',
|
---|
| 1348 | winter: 'Dec-Feb',
|
---|
| 1349 | // morning: '08:00-12:00',
|
---|
| 1350 | // evening: '13:00-18:00',
|
---|
| 1351 | '_': '-',
|
---|
| 1352 | 'daytime': 'sunrise-sunset',
|
---|
[6370] | 1353 | }, 'Bitte benutze die englische Schreibweise "<ok>" für "<ko>".': {
|
---|
| 1354 | sommer: 'summer',
|
---|
[7046] | 1355 | 'werktag': 'Mo-Fr',
|
---|
| 1356 | 'werktags': 'Mo-Fr',
|
---|
[6489] | 1357 | }, 'Bitte benutze "<ok>" für "<ko>". Beispiel: "Mo-Fr 08:00-12:00; Tu off"': {
|
---|
| 1358 | ruhetag: 'off',
|
---|
| 1359 | ruhetage: 'off',
|
---|
| 1360 | geschlossen: 'off',
|
---|
[7046] | 1361 | ausser: 'off',
|
---|
| 1362 | außer: 'off',
|
---|
| 1363 | }, 'Neem de engelse afkorting "<ok>" voor "<ko>" alstublieft.': {
|
---|
| 1364 | 'gesloten': 'off',
|
---|
| 1365 | 'feestdag': 'PH',
|
---|
[6370] | 1366 | }, 'Assuming "<ok>" for "<ko>". Please avoid using "workday": http://wiki.openstreetmap.org/wiki/Talk:Key:opening_hours#need_syntax_for_holidays_and_workingdays': {
|
---|
| 1367 | // // Used around 260 times but the problem is, that work day might be different in other countries.
|
---|
[7046] | 1368 | 'wd': 'Mo-Fr',
|
---|
| 1369 | 'weekday': 'Mo-Fr',
|
---|
| 1370 | 'weekdays': 'Mo-Fr',
|
---|
| 1371 | 'vardagar': 'Mo-Fr',
|
---|
| 1372 | }, 'Please use notation something like "Mo off" instead "<ko>".': {
|
---|
| 1373 | except: 'off',
|
---|
[6420] | 1374 | }, 'Please ommit "<ko>" or use a colon instead: "12:00-14:00".': {
|
---|
| 1375 | h: '',
|
---|
[6370] | 1376 | }, 'Please ommit "<ko>".': {
|
---|
| 1377 | season: '',
|
---|
[6489] | 1378 | hs: '',
|
---|
| 1379 | hrs: '',
|
---|
| 1380 | hours: '',
|
---|
[7046] | 1381 | }, 'Please ommit "<ko>". The key must not be in the value.': {
|
---|
| 1382 | 'opening_hours=': '',
|
---|
| 1383 | }, 'Please ommit "<ko>". You might want to express open end which can be specified as "12:00+" for example.': {
|
---|
[6370] | 1384 | from: '',
|
---|
[7046] | 1385 | }, 'You can use notation "<ok>" for "<ko>". You might want to express open end which can be specified as "12:00+" for example.': {
|
---|
| 1386 | '-late': '+',
|
---|
[6489] | 1387 | }, 'Please use notation "<ok>" for "<ko>". If the times are unsure or vary consider a comment e.g. 12:00-14:00 "only on sunshine".': {
|
---|
[6420] | 1388 | '~': '-',
|
---|
[6489] | 1389 | '~': '-',
|
---|
[7046] | 1390 | }, 'Please use notation "<ok>" for "<ko>". Fallback rule: 12:00-14:00 || "call us"': {
|
---|
| 1391 | 'otherwise': '||',
|
---|
| 1392 | }, 'You can use notation "<ok>" for "<ko>" temporally if the syntax will still be valid.': {
|
---|
| 1393 | '?': 'unknown "please add this if known"',
|
---|
[6370] | 1394 | }, 'Please use notation "<ok>" for "<ko>".': {
|
---|
[7046] | 1395 | '→': '-',
|
---|
[6370] | 1396 | '–': '-',
|
---|
[7046] | 1397 | '−': '-',
|
---|
| 1398 | '=': '-',
|
---|
| 1399 | 'ー': '-',
|
---|
[6370] | 1400 | to: '-',
|
---|
[7046] | 1401 | 'до': '-',
|
---|
| 1402 | a: '-', // language unknown
|
---|
| 1403 | as: '-', // language unknown
|
---|
| 1404 | 'á': '-', // language unknown
|
---|
| 1405 | 'ás': '-', // language unknown
|
---|
| 1406 | 'à': '-', // language unknown
|
---|
| 1407 | 'às': '-', // language unknown
|
---|
| 1408 | 'ate': '-', // language unknown
|
---|
| 1409 | 'till': '-',
|
---|
| 1410 | 'til': '-',
|
---|
| 1411 | 'until': '-',
|
---|
| 1412 | 'through': '-',
|
---|
[6370] | 1413 | and: ',',
|
---|
| 1414 | '&': ',',
|
---|
[6489] | 1415 | ':': ':',
|
---|
[7046] | 1416 | '°°': ':00',
|
---|
| 1417 | 'daily': 'Mo-Su',
|
---|
| 1418 | 'everyday': 'Mo-Su',
|
---|
| 1419 | 'every day': 'Mo-Su',
|
---|
[6489] | 1420 | always: '24/7',
|
---|
| 1421 | nonstop: '24/7',
|
---|
[7046] | 1422 | '24x7': '24/7',
|
---|
| 1423 | 'anytime': '24/7',
|
---|
| 1424 | 'all day': '24/7',
|
---|
| 1425 | 'all days': 'Mo-Su',
|
---|
| 1426 | 'every day': 'Mo-Su',
|
---|
| 1427 | '7days': 'Mo-Su',
|
---|
| 1428 | '7j/7': 'Mo-Su', // I guess that it means that
|
---|
| 1429 | '7/7': 'Mo-Su', // I guess that it means that
|
---|
| 1430 | '7 days': 'Mo-Su',
|
---|
| 1431 | '7 days a week': 'Mo-Su',
|
---|
| 1432 | 'midnight': '00:00',
|
---|
[6489] | 1433 | holiday: 'PH',
|
---|
| 1434 | holidays: 'PH',
|
---|
[7046] | 1435 | 'public holidays': 'PH',
|
---|
| 1436 | 'public holiday': 'PH',
|
---|
[6489] | 1437 | // summerholiday: 'SH',
|
---|
| 1438 | // summerholidays: 'SH',
|
---|
[7046] | 1439 | weekend: 'Sa,Su',
|
---|
| 1440 | weekends: 'Sa,Su',
|
---|
| 1441 | 'daylight': 'sunrise-sunset',
|
---|
| 1442 | 'оff': 'off', // Russian o
|
---|
| 1443 | }, 'Please use time format in 24 hours notation ("<ko>"). If PM is used you might have to convert the hours to the 24 hours notation.': {
|
---|
| 1444 | 'pm': '',
|
---|
| 1445 | 'рм': '',
|
---|
| 1446 | 'am': '',
|
---|
| 1447 | 'ам': '',
|
---|
[6370] | 1448 | }, 'Bitte verzichte auf "<ko>".': {
|
---|
[7046] | 1449 | 'uhr': '',
|
---|
| 1450 | 'geöffnet': '',
|
---|
[6370] | 1451 | }, 'Bitte verzichte auf "<ko>". Sie möchten eventuell eine Öffnungszeit ohne vorgegebenes Ende angeben. Beispiel: "12:00+"': {
|
---|
| 1452 | ab: '',
|
---|
| 1453 | von: '',
|
---|
| 1454 | }, 'Bitte benutze die Schreibweise "<ok>" für "<ko>".': {
|
---|
| 1455 | bis: '-',
|
---|
[6489] | 1456 | 'täglich': 'Mo-Su',
|
---|
| 1457 | }, 'Bitte benutze die Schreibweise "<ok>" als Ersatz für "und" bzw. "u.".': {
|
---|
[6370] | 1458 | und: ',',
|
---|
[6489] | 1459 | u: ',',
|
---|
[6370] | 1460 | }, 'Bitte benutze die englische Abkürzung "<ok>" für "<ko>".': {
|
---|
| 1461 | feiertag: 'PH',
|
---|
[6489] | 1462 | feiertags: 'PH',
|
---|
[6370] | 1463 | feiertage: 'PH',
|
---|
| 1464 | feiertagen: 'PH'
|
---|
| 1465 | }, 'S\'il vous plaît utiliser "<ok>" pour "<ko>".': {
|
---|
| 1466 | 'fermé': 'off',
|
---|
| 1467 | 'et': ',',
|
---|
| 1468 | 'à': '-',
|
---|
[7046] | 1469 | 'jours fériés': 'PH',
|
---|
[6370] | 1470 | }, 'Neem de engelse afkorting "<ok>" voor "<ko>" alstublieft.': {
|
---|
| 1471 | feestdag: 'PH',
|
---|
| 1472 | feestdagen: 'PH',
|
---|
| 1473 | }
|
---|
| 1474 | },
|
---|
| 1475 |
|
---|
| 1476 | month: {
|
---|
| 1477 | 'default': {
|
---|
| 1478 | jan: 0,
|
---|
| 1479 | feb: 1,
|
---|
| 1480 | mar: 2,
|
---|
| 1481 | apr: 3,
|
---|
| 1482 | may: 4,
|
---|
| 1483 | jun: 5,
|
---|
| 1484 | jul: 6,
|
---|
| 1485 | aug: 7,
|
---|
| 1486 | sep: 8,
|
---|
| 1487 | oct: 9,
|
---|
| 1488 | nov: 10,
|
---|
| 1489 | dec: 11,
|
---|
[6420] | 1490 | }, 'Please use the English abbreviation "<ok>" for "<ko>".': {
|
---|
[7046] | 1491 | 'jänner': 0, // Austria
|
---|
[6370] | 1492 | january: 0,
|
---|
| 1493 | february: 1,
|
---|
| 1494 | march: 2,
|
---|
| 1495 | april: 3,
|
---|
| 1496 | // may: 4,
|
---|
| 1497 | june: 5,
|
---|
| 1498 | july: 6,
|
---|
| 1499 | august: 7,
|
---|
| 1500 | september: 8,
|
---|
| 1501 | sept: 8,
|
---|
| 1502 | october: 9,
|
---|
| 1503 | november: 10,
|
---|
| 1504 | december: 11,
|
---|
| 1505 | }, 'Bitte benutze die englische Abkürzung "<ok>" für "<ko>".': {
|
---|
| 1506 | januar: 0,
|
---|
| 1507 | februar: 1,
|
---|
| 1508 | 'märz': 2,
|
---|
| 1509 | maerz: 2,
|
---|
| 1510 | mai: 4,
|
---|
| 1511 | juni: 5,
|
---|
| 1512 | juli: 6,
|
---|
| 1513 | okt: 9,
|
---|
| 1514 | oktober: 9,
|
---|
| 1515 | dez: 11,
|
---|
| 1516 | dezember: 11,
|
---|
| 1517 | }, 'S\'il vous plaît utiliser l\'abréviation "<ok>" pour "<ko>".': {
|
---|
| 1518 | janvier: 0,
|
---|
| 1519 | février: 1,
|
---|
| 1520 | fév: 1,
|
---|
| 1521 | mars: 2,
|
---|
| 1522 | avril: 3,
|
---|
| 1523 | avr: 3,
|
---|
| 1524 | mai: 4,
|
---|
| 1525 | juin: 5,
|
---|
| 1526 | juillet: 6,
|
---|
| 1527 | août: 7,
|
---|
| 1528 | aoû: 7,
|
---|
| 1529 | septembre: 8,
|
---|
| 1530 | octobre: 9,
|
---|
| 1531 | novembre: 10,
|
---|
| 1532 | décembre: 11,
|
---|
| 1533 | }, 'Neem de engelse afkorting "<ok>" voor "<ko>" alstublieft.': {
|
---|
| 1534 | januari: 0,
|
---|
| 1535 | februari: 1,
|
---|
| 1536 | maart: 2,
|
---|
| 1537 | mei: 4,
|
---|
| 1538 | augustus: 7,
|
---|
| 1539 | }
|
---|
| 1540 | },
|
---|
| 1541 |
|
---|
| 1542 | weekday: { // good source: http://www.omniglot.com/language/time/days.htm
|
---|
| 1543 | 'default': {
|
---|
| 1544 | su: 0,
|
---|
| 1545 | mo: 1,
|
---|
| 1546 | tu: 2,
|
---|
| 1547 | we: 3,
|
---|
| 1548 | th: 4,
|
---|
| 1549 | fr: 5,
|
---|
| 1550 | sa: 6,
|
---|
[6420] | 1551 | }, 'Assuming "<ok>" for "<ko>"': {
|
---|
| 1552 | m: 1,
|
---|
| 1553 | w: 3,
|
---|
| 1554 | f: 5,
|
---|
[6370] | 1555 | }, 'Please use the abbreviation "<ok>" for "<ko>".': {
|
---|
| 1556 | sun: 0,
|
---|
| 1557 | sunday: 0,
|
---|
| 1558 | sundays: 0,
|
---|
| 1559 | mon: 1,
|
---|
| 1560 | monday: 1,
|
---|
| 1561 | mondays: 1,
|
---|
| 1562 | tue: 2,
|
---|
| 1563 | tuesday: 2,
|
---|
| 1564 | tuesdays: 2,
|
---|
| 1565 | wed: 3,
|
---|
| 1566 | wednesday: 3,
|
---|
| 1567 | wednesdays: 3,
|
---|
| 1568 | thu: 4,
|
---|
[7046] | 1569 | thur: 4,
|
---|
[6370] | 1570 | thursday: 4,
|
---|
| 1571 | thursdays: 4,
|
---|
| 1572 | fri: 5,
|
---|
| 1573 | friday: 5,
|
---|
| 1574 | fridays: 5,
|
---|
| 1575 | sat: 6,
|
---|
| 1576 | saturday: 6,
|
---|
| 1577 | saturdays: 6,
|
---|
[6420] | 1578 | }, 'Bitte benutze die englische Abkürzung "<ok>" für "<ko>". Could also mean Saturday in Polish …': {
|
---|
| 1579 | so: 0,
|
---|
[6370] | 1580 | }, 'Bitte benutze die englische Abkürzung "<ok>" für "<ko>".': {
|
---|
[6420] | 1581 | son: 0,
|
---|
| 1582 | sonntag: 0,
|
---|
[7046] | 1583 | 'sonn-': 0,
|
---|
[6420] | 1584 | sonntags: 0,
|
---|
| 1585 | montag: 1,
|
---|
| 1586 | montags: 1,
|
---|
| 1587 | di: 2,
|
---|
| 1588 | die: 2,
|
---|
| 1589 | dienstag: 2,
|
---|
| 1590 | dienstags: 2,
|
---|
| 1591 | mi: 3,
|
---|
| 1592 | mit: 3,
|
---|
| 1593 | mittwoch: 3,
|
---|
| 1594 | mittwochs: 3,
|
---|
| 1595 | 'do': 4,
|
---|
| 1596 | don: 4,
|
---|
| 1597 | donnerstag: 4,
|
---|
| 1598 | donnerstags: 4,
|
---|
| 1599 | fre: 5,
|
---|
| 1600 | freitag: 5,
|
---|
| 1601 | freitags: 5,
|
---|
| 1602 | sam: 6,
|
---|
| 1603 | samstag: 6,
|
---|
| 1604 | samstags: 6,
|
---|
[6370] | 1605 | }, 'S\'il vous plaît utiliser l\'abréviation "<ok>" pour "<ko>".': {
|
---|
| 1606 | dim: 0,
|
---|
| 1607 | dimanche: 0,
|
---|
| 1608 | lu: 1,
|
---|
| 1609 | lun: 1,
|
---|
| 1610 | lundi: 1,
|
---|
| 1611 | mardi: 2,
|
---|
| 1612 | mer: 3,
|
---|
| 1613 | mercredi: 3,
|
---|
| 1614 | je: 4,
|
---|
| 1615 | jeu: 4,
|
---|
| 1616 | jeudi: 4,
|
---|
| 1617 | ve: 5,
|
---|
| 1618 | ven: 5,
|
---|
| 1619 | vendredi: 5,
|
---|
| 1620 | samedi: 6,
|
---|
| 1621 | }, 'Neem de engelse afkorting "<ok>" voor "<ko>" alstublieft.': {
|
---|
| 1622 | zo: 0,
|
---|
| 1623 | zon: 0,
|
---|
[7046] | 1624 | zontag: 0, // correct?
|
---|
| 1625 | zondag: 0,
|
---|
[6370] | 1626 | maandag: 1,
|
---|
| 1627 | din: 2,
|
---|
| 1628 | dinsdag: 2,
|
---|
| 1629 | wo: 3,
|
---|
| 1630 | woe: 3,
|
---|
| 1631 | woensdag: 3,
|
---|
| 1632 | donderdag: 4,
|
---|
| 1633 | vr: 5,
|
---|
| 1634 | vri: 5,
|
---|
| 1635 | vrijdag: 5,
|
---|
| 1636 | za: 6,
|
---|
| 1637 | zat: 6,
|
---|
| 1638 | zaterdag: 6,
|
---|
[6420] | 1639 | }, 'Please use the English abbreviation "<ok>" for "<ko>".': { // FIXME: Translate to Czech.
|
---|
[6370] | 1640 | 'neděle': 0,
|
---|
| 1641 | 'ne': 0,
|
---|
| 1642 | 'pondělí': 1,
|
---|
| 1643 | 'po': 1,
|
---|
| 1644 | 'úterý': 2,
|
---|
| 1645 | 'út': 2,
|
---|
| 1646 | 'středa': 3,
|
---|
| 1647 | 'st': 3,
|
---|
| 1648 | 'čtvrtek': 4,
|
---|
| 1649 | 'čt': 4,
|
---|
| 1650 | 'pátek': 5,
|
---|
| 1651 | 'pá': 5,
|
---|
| 1652 | 'sobota': 6,
|
---|
[6420] | 1653 | }, 'Please use the English abbreviation "<ok>" for "<ko>".': {
|
---|
[6370] | 1654 | // Spanish.
|
---|
| 1655 | 'martes': 0,
|
---|
| 1656 | 'miércoles': 1,
|
---|
| 1657 | 'jueves': 2,
|
---|
| 1658 | 'viernes': 3,
|
---|
| 1659 | 'sábado': 4,
|
---|
| 1660 | 'domingo': 5,
|
---|
| 1661 | 'lunes': 6,
|
---|
| 1662 | // Indonesian.
|
---|
| 1663 | 'selasa': 0,
|
---|
| 1664 | 'rabu': 1,
|
---|
| 1665 | 'kami': 2,
|
---|
| 1666 | 'jumat': 3,
|
---|
| 1667 | 'sabtu': 4,
|
---|
| 1668 | 'minggu': 5,
|
---|
| 1669 | 'senin': 6,
|
---|
| 1670 | // Swedish
|
---|
[7046] | 1671 | 'söndag': 0,
|
---|
| 1672 | 'söndagar': 0,
|
---|
| 1673 | 'måndag': 1,
|
---|
| 1674 | 'ma': 1,
|
---|
| 1675 | 'tisdag': 2,
|
---|
| 1676 | 'onsdag': 3,
|
---|
| 1677 | 'torsdag': 4,
|
---|
| 1678 | 'fredag': 5,
|
---|
| 1679 | 'lördag': 6,
|
---|
| 1680 | 'lördagar': 6,
|
---|
[6420] | 1681 | // Polish
|
---|
| 1682 | 'niedziela': 0, 'niedz': 0, 'n': 0, 'ndz': 0,
|
---|
| 1683 | 'poniedziałek': 1, 'poniedzialek': 1, 'pon': 1, 'pn': 1,
|
---|
| 1684 | 'wtorek': 2, 'wt': 2,
|
---|
| 1685 | 'środa': 3, 'sroda': 3, 'śr': 3, 'sr': 3,
|
---|
| 1686 | 'czwartek': 4, 'czw': 4, 'cz': 4,
|
---|
| 1687 | 'piątek': 5, 'piatek': 5, 'pt': 5,
|
---|
| 1688 | 'sobota': 6, 'sob': 6, // 'so': 6 // abbreviation also used in German
|
---|
[7046] | 1689 | // Russian
|
---|
| 1690 | 'воскресенье' : 0,
|
---|
| 1691 | 'Вс' : 0,
|
---|
| 1692 | "voskresen'ye": 0,
|
---|
| 1693 | 'понедельник' : 1,
|
---|
| 1694 | 'Пн' : 1,
|
---|
| 1695 | "ponedel'nik" : 1,
|
---|
| 1696 | 'вторник' : 2,
|
---|
| 1697 | 'vtornik' : 2,
|
---|
| 1698 | 'среда' : 3,
|
---|
| 1699 | 'sreda' : 3,
|
---|
| 1700 | 'четверг' : 4,
|
---|
| 1701 | 'chetverk' : 4,
|
---|
| 1702 | 'пятница' : 5,
|
---|
| 1703 | 'pyatnitsa' : 5,
|
---|
| 1704 | 'суббота' : 6,
|
---|
| 1705 | 'subbota' : 6,
|
---|
| 1706 | // Danish
|
---|
| 1707 | 'søndag' : 0,
|
---|
| 1708 | 'mandag' : 1,
|
---|
| 1709 | 'tirsdag': 2,
|
---|
| 1710 | 'onsdag' : 3,
|
---|
| 1711 | 'torsdag': 4,
|
---|
| 1712 | 'fredag' : 5,
|
---|
| 1713 | 'lørdag' : 6,
|
---|
[6370] | 1714 | },
|
---|
| 1715 | },
|
---|
| 1716 |
|
---|
| 1717 | timevar: { // Special time variables which actual value depends on the date and the position of the facility.
|
---|
| 1718 | 'default': {
|
---|
[7046] | 1719 | 'sunrise': 'sunrise',
|
---|
| 1720 | 'sunset': 'sunset',
|
---|
| 1721 | 'dawn': 'dawn',
|
---|
| 1722 | 'dusk': 'dusk',
|
---|
[6370] | 1723 | }, 'Please use notation "<ok>" for "<ko>".': {
|
---|
[7046] | 1724 | 'sundown': 'sunset',
|
---|
[6370] | 1725 | }, 'Bitte benutze die Schreibweise "<ok>" für "<ko>".': {
|
---|
| 1726 | 'morgendämmerung': 'dawn',
|
---|
| 1727 | 'abenddämmerung': 'dusk',
|
---|
[7046] | 1728 | 'sonnenaufgang': 'sunrise',
|
---|
| 1729 | 'sonnenuntergang': 'sunset',
|
---|
[6370] | 1730 | },
|
---|
| 1731 | },
|
---|
| 1732 |
|
---|
| 1733 | 'event': { // variable events
|
---|
| 1734 | 'default': {
|
---|
[7046] | 1735 | 'easter': 'easter',
|
---|
[6370] | 1736 | }, 'Bitte benutze die Schreibweise "<ok>" für "<ko>".': {
|
---|
[7046] | 1737 | 'ostern': 'easter',
|
---|
[6370] | 1738 | },
|
---|
| 1739 | },
|
---|
| 1740 | };
|
---|
[7046] | 1741 | // }}}
|
---|
| 1742 | // }}}
|
---|
[6370] | 1743 |
|
---|
[7046] | 1744 | // make the library accessible for the outside world {{{
|
---|
[6370] | 1745 | if (typeof exports === 'object') {
|
---|
| 1746 | // For nodejs
|
---|
| 1747 | var SunCalc = require('suncalc');
|
---|
| 1748 | module.exports = factory(SunCalc, holidays, word_error_correction);
|
---|
| 1749 | } else {
|
---|
| 1750 | // For browsers
|
---|
| 1751 | root.opening_hours = factory(root.SunCalc, holidays, word_error_correction);
|
---|
| 1752 | }
|
---|
[7046] | 1753 | /// }}}
|
---|
[6370] | 1754 | }(this, function (SunCalc, holidays, word_error_correction) {
|
---|
| 1755 | return function(value, nominatiomJSON, oh_mode) {
|
---|
[7046] | 1756 | // short constants {{{
|
---|
[6370] | 1757 | var word_value_replacement = { // if the correct values can not be calculated
|
---|
| 1758 | dawn : 60 * 5 + 30,
|
---|
| 1759 | sunrise : 60 * 6,
|
---|
| 1760 | sunset : 60 * 18,
|
---|
| 1761 | dusk : 60 * 18 + 30,
|
---|
| 1762 | };
|
---|
| 1763 | var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
|
---|
| 1764 | var weekdays = ['Su','Mo','Tu','We','Th','Fr','Sa'];
|
---|
| 1765 | var default_prettify_conf = {
|
---|
| 1766 | 'leading_zero_hour': true, // enforce leading zero
|
---|
| 1767 | 'one_zero_if_hour_zero': false, // only one zero "0" if hour is zero "0"
|
---|
| 1768 | 'leave_off_closed': true, // leave keywords of and closed as is
|
---|
| 1769 | 'keyword_for_off_closed': 'off', // use given keyword instead of "off" or "closed"
|
---|
| 1770 | 'block_sep_string': ' ', // separate blocks by string
|
---|
| 1771 | 'print_semicolon': true, // print token which separates normal blocks
|
---|
| 1772 | 'leave_weekday_sep_one_day_betw': true, // use the separator (either "," or "-" which is used to separate days which follow to each other like Sa,Su or Su-Mo
|
---|
| 1773 | 'sep_one_day_between': ',' // separator which should be used
|
---|
| 1774 | };
|
---|
| 1775 |
|
---|
| 1776 | var minutes_in_day = 60 * 24;
|
---|
| 1777 | var msec_in_day = 1000 * 60 * minutes_in_day;
|
---|
| 1778 | var msec_in_week = msec_in_day * 7;
|
---|
[7046] | 1779 | // }}}
|
---|
[6370] | 1780 |
|
---|
[7046] | 1781 | // The big picture -- How does this library work? {{{
|
---|
[6370] | 1782 | //======================================================================
|
---|
| 1783 | // Constructor - entry to parsing code
|
---|
| 1784 | //======================================================================
|
---|
| 1785 | // Terminology:
|
---|
| 1786 | //
|
---|
| 1787 | // Mo-Fr 10:00-11:00; Th 10:00-12:00
|
---|
| 1788 | // \_____block_____/ \____block___/
|
---|
| 1789 | //
|
---|
| 1790 | // The README refers to blocks as rules, which is more intuitive but less clear.
|
---|
| 1791 | // Because of that only the README uses the term rule in that context.
|
---|
| 1792 | // In all internal parts of this project, the term block is used.
|
---|
| 1793 | //
|
---|
| 1794 | // Mo-Fr Jan 10:00-11:00
|
---|
| 1795 | // \__/ \_/ \_________/
|
---|
| 1796 | // selectors (left to right: weekday, month, time)
|
---|
| 1797 | //
|
---|
| 1798 | // Logic:
|
---|
| 1799 | // - Tokenize
|
---|
| 1800 | // Foreach block:
|
---|
[7046] | 1801 | // - Run top-level (block) parser
|
---|
| 1802 | // - Which calls sub parser for specific selector types
|
---|
[6370] | 1803 | // - Which produce selector functions
|
---|
[7046] | 1804 | // }}}
|
---|
[6370] | 1805 |
|
---|
[7046] | 1806 | // constructor parameters {{{
|
---|
[6370] | 1807 | // Evaluate additional information which can be given. They are
|
---|
[7046] | 1808 | // required to reasonably calculate 'sunrise' and to use the correct
|
---|
| 1809 | // holidays.
|
---|
[6370] | 1810 | var location_cc, location_state, lat, lon;
|
---|
| 1811 | if (typeof nominatiomJSON != 'undefined') {
|
---|
| 1812 | if (typeof nominatiomJSON.address != 'undefined' &&
|
---|
| 1813 | typeof nominatiomJSON.address.state != 'undefined') { // country_code will be tested later …
|
---|
| 1814 | location_cc = nominatiomJSON.address.country_code;
|
---|
| 1815 | location_state = nominatiomJSON.address.state;
|
---|
| 1816 | }
|
---|
| 1817 |
|
---|
| 1818 | if (typeof nominatiomJSON.lon != 'undefined') { // lat will be tested later …
|
---|
| 1819 | lat = nominatiomJSON.lat;
|
---|
| 1820 | lon = nominatiomJSON.lon;
|
---|
| 1821 | }
|
---|
| 1822 | }
|
---|
| 1823 |
|
---|
[7046] | 1824 | // 0: time ranges (default), tags: opening_hours, lit, …
|
---|
| 1825 | // 1: points in time
|
---|
| 1826 | // 2: both (time ranges and points in time), tags: collection_times, service_times
|
---|
[6370] | 1827 | if (typeof oh_mode == 'undefined') {
|
---|
| 1828 | oh_mode = 0;
|
---|
| 1829 | } else if (!(typeof oh_mode == 'number' && (oh_mode == 0 || oh_mode == 1 || oh_mode == 2))) {
|
---|
| 1830 | throw 'The third constructor parameter is oh_mode and must be a number (0, 1 or 2)'
|
---|
| 1831 | }
|
---|
[7046] | 1832 | // }}}
|
---|
[6370] | 1833 |
|
---|
[7046] | 1834 | // put tokenized blocks into list {{{
|
---|
[6370] | 1835 | if (value.match(/^(\s*;?\s*)+$/))
|
---|
| 1836 | throw 'Value contains nothing meaningful which can be parsed';
|
---|
| 1837 |
|
---|
| 1838 | var parsing_warnings = [];
|
---|
| 1839 | var done_with_warnings = false; // The functions which throw warnings can be called multiple times.
|
---|
| 1840 | var has_token = {};
|
---|
| 1841 | var tokens = tokenize(value);
|
---|
| 1842 | // console.log(JSON.stringify(tokens, null, '\t'));
|
---|
| 1843 | var prettified_value = '';
|
---|
[7174] | 1844 | var used_subparsers = {}; // Used sub parsers for one block, will be reset for each block. Declared in global namespace, because it is manipulation inside various sub parsers.
|
---|
[6370] | 1845 | var week_stable = true;
|
---|
| 1846 |
|
---|
| 1847 | var blocks = [];
|
---|
| 1848 |
|
---|
| 1849 | for (var nblock = 0; nblock < tokens.length; nblock++) {
|
---|
| 1850 | if (tokens[nblock][0].length == 0) continue;
|
---|
| 1851 | // Block does contain nothing useful e.g. second block of '10:00-12:00;' (empty) which needs to be handled.
|
---|
| 1852 |
|
---|
| 1853 | var continue_at = 0;
|
---|
| 1854 | do {
|
---|
| 1855 | if (continue_at == tokens[nblock][0].length) break;
|
---|
[6489] | 1856 | // Additional block does contain nothing useful e.g. second block of '10:00-12:00,' (empty) which needs to be handled.
|
---|
[6370] | 1857 |
|
---|
| 1858 | var selectors = {
|
---|
| 1859 | // Time selectors
|
---|
| 1860 | time: [],
|
---|
| 1861 |
|
---|
| 1862 | // Temporary array of selectors from time wrapped to the next day
|
---|
| 1863 | wraptime: [],
|
---|
| 1864 |
|
---|
| 1865 | // Date selectors
|
---|
| 1866 | weekday: [],
|
---|
| 1867 | holiday: [],
|
---|
| 1868 | week: [],
|
---|
| 1869 | month: [],
|
---|
| 1870 | monthday: [],
|
---|
| 1871 | year: [],
|
---|
| 1872 |
|
---|
| 1873 | // Array with non-empty date selector types, with most optimal ordering
|
---|
| 1874 | date: [],
|
---|
| 1875 |
|
---|
| 1876 | fallback: tokens[nblock][1],
|
---|
| 1877 | additional: continue_at ? true : false,
|
---|
| 1878 | meaning: true,
|
---|
| 1879 | unknown: false,
|
---|
| 1880 | comment: undefined,
|
---|
[6489] | 1881 | build_from_token_block: undefined,
|
---|
[6370] | 1882 | };
|
---|
| 1883 |
|
---|
[6489] | 1884 | selectors.build_from_token_block = [ nblock, continue_at ];
|
---|
[6370] | 1885 | continue_at = parseGroup(tokens[nblock][0], continue_at, selectors, nblock);
|
---|
| 1886 | if (typeof continue_at == 'object')
|
---|
| 1887 | continue_at = continue_at[0];
|
---|
| 1888 | else
|
---|
| 1889 | continue_at = 0;
|
---|
| 1890 |
|
---|
| 1891 | if (selectors.year.length > 0)
|
---|
| 1892 | selectors.date.push(selectors.year);
|
---|
| 1893 | if (selectors.holiday.length > 0)
|
---|
| 1894 | selectors.date.push(selectors.holiday);
|
---|
| 1895 | if (selectors.month.length > 0)
|
---|
| 1896 | selectors.date.push(selectors.month);
|
---|
| 1897 | if (selectors.monthday.length > 0)
|
---|
| 1898 | selectors.date.push(selectors.monthday);
|
---|
| 1899 | if (selectors.week.length > 0)
|
---|
| 1900 | selectors.date.push(selectors.week);
|
---|
| 1901 | if (selectors.weekday.length > 0)
|
---|
| 1902 | selectors.date.push(selectors.weekday);
|
---|
| 1903 |
|
---|
[7046] | 1904 | // console.log('weekday: ' + JSON.stringify(selectors.weekday, null, '\t'));
|
---|
[6370] | 1905 | blocks.push(selectors);
|
---|
| 1906 |
|
---|
[7174] | 1907 | // This handles selectors with time ranges wrapping over midnight (e.g. 10:00-02:00)
|
---|
| 1908 | // it generates wrappers for all selectors and creates a new block.
|
---|
[6370] | 1909 | if (selectors.wraptime.length > 0) {
|
---|
| 1910 | var wrapselectors = {
|
---|
| 1911 | time: selectors.wraptime,
|
---|
| 1912 | date: [],
|
---|
| 1913 |
|
---|
| 1914 | meaning: selectors.meaning,
|
---|
| 1915 | unknown: selectors.unknown,
|
---|
| 1916 | comment: selectors.comment,
|
---|
| 1917 |
|
---|
| 1918 | wrapped: true,
|
---|
| 1919 | };
|
---|
| 1920 |
|
---|
| 1921 | for (var dselg = 0; dselg < selectors.date.length; dselg++) {
|
---|
| 1922 | wrapselectors.date.push([]);
|
---|
| 1923 | for (var dsel = 0; dsel < selectors.date[dselg].length; dsel++) {
|
---|
| 1924 | wrapselectors.date[wrapselectors.date.length-1].push(
|
---|
| 1925 | generateDateShifter(selectors.date[dselg][dsel], -msec_in_day)
|
---|
| 1926 | );
|
---|
| 1927 | }
|
---|
| 1928 | }
|
---|
| 1929 |
|
---|
| 1930 | blocks.push(wrapselectors);
|
---|
| 1931 | }
|
---|
| 1932 | } while (continue_at)
|
---|
| 1933 | }
|
---|
[7046] | 1934 | // }}}
|
---|
[6370] | 1935 |
|
---|
[7174] | 1936 | /* Tokenization function: Splits string into parts. {{{
|
---|
| 1937 | *
|
---|
| 1938 | * :param value: Raw opening_hours value.
|
---|
| 1939 | * :returns: Tokenized list object. Complex structure. You can print the
|
---|
| 1940 | * thing as JSON if you would like to know in details.
|
---|
| 1941 | * The most inner list has the following items: [ internal_value, token_name, value_length ].
|
---|
| 1942 | */
|
---|
[6370] | 1943 | function tokenize(value) {
|
---|
[7174] | 1944 | var all_tokens = new Array();
|
---|
[6370] | 1945 | var curr_block_tokens = new Array();
|
---|
| 1946 |
|
---|
| 1947 | var last_block_fallback_terminated = false;
|
---|
| 1948 |
|
---|
| 1949 | while (value != '') {
|
---|
| 1950 | var tmp;
|
---|
[7174] | 1951 | if (tmp = value.match(/^(?:week\b|open\b|unknown\b)/i)) {
|
---|
| 1952 | // Reserved keywords.
|
---|
[6370] | 1953 | curr_block_tokens.push([tmp[0].toLowerCase(), tmp[0].toLowerCase(), value.length ]);
|
---|
| 1954 | value = value.substr(tmp[0].length);
|
---|
| 1955 | } else if (tmp = value.match(/^24\/7/i)) {
|
---|
[7174] | 1956 | // Reserved keyword.
|
---|
[6370] | 1957 | has_token[tmp[0]] = true;
|
---|
| 1958 | curr_block_tokens.push([tmp[0], tmp[0], value.length ]);
|
---|
| 1959 | value = value.substr(tmp[0].length);
|
---|
| 1960 | } else if (tmp = value.match(/^(?:off|closed)/i)) {
|
---|
[7174] | 1961 | // Reserved keywords.
|
---|
[6370] | 1962 | curr_block_tokens.push([tmp[0].toLowerCase(), 'closed', value.length ]);
|
---|
| 1963 | value = value.substr(tmp[0].length);
|
---|
| 1964 | } else if (tmp = value.match(/^(?:PH|SH)/i)) {
|
---|
| 1965 | // special day name (holidays)
|
---|
| 1966 | curr_block_tokens.push([tmp[0].toUpperCase(), 'holiday', value.length ]);
|
---|
| 1967 | value = value.substr(2);
|
---|
| 1968 | } else if (tmp = value.match(/^days?/i)) {
|
---|
| 1969 | curr_block_tokens.push([tmp[0].toLowerCase(), 'calcday', value.length ]);
|
---|
| 1970 | value = value.substr(tmp[0].length);
|
---|
[7046] | 1971 | } else if (tmp = value.match(/^(&|_|→|–|−|=|opening_hours=|ー|\?|~|~|:|°°|25x7|7[ ]?days( a week|)|all days?|every day|-late|public holidays?|7j?\/7|every day|до|рм|ам|jours fériés|sonn-|[a-zäößàáéøčěíúýřПнВсо]+\b)\.?/i)) {
|
---|
[7174] | 1972 | // Handle all remaining words with error tolerance.
|
---|
[6370] | 1973 | var correct_val = returnCorrectWordOrToken(tmp[1].toLowerCase(), value.length);
|
---|
| 1974 | if (typeof correct_val == 'object') {
|
---|
| 1975 | curr_block_tokens.push([ correct_val[0], correct_val[1], value.length ]);
|
---|
| 1976 | value = value.substr(tmp[0].length);
|
---|
| 1977 | } else if (typeof correct_val == 'string') {
|
---|
[7174] | 1978 | if (tmp[1].toLowerCase() == 'pm') {
|
---|
| 1979 | var hours_token_at = curr_block_tokens.length - 3;
|
---|
| 1980 | if (hours_token_at > 0) {
|
---|
| 1981 | if (matchTokens(curr_block_tokens, hours_token_at,
|
---|
| 1982 | 'number', 'timesep', 'number')
|
---|
| 1983 | ) {
|
---|
| 1984 | var hours_token = curr_block_tokens[hours_token_at];
|
---|
| 1985 | } else if (matchTokens(curr_block_tokens, hours_token_at + 2,
|
---|
| 1986 | 'number')
|
---|
| 1987 | ) {
|
---|
| 1988 | hours_token_at += 2;
|
---|
| 1989 | var hours_token = curr_block_tokens[hours_token_at];
|
---|
| 1990 | }
|
---|
| 1991 | if (hours_token[0] <= 12) {
|
---|
| 1992 | hours_token[0] += 12;
|
---|
| 1993 | curr_block_tokens[hours_token_at] = hours_token;
|
---|
| 1994 | }
|
---|
| 1995 | }
|
---|
| 1996 | }
|
---|
[6370] | 1997 | value = correct_val + value.substr(tmp[0].length);
|
---|
| 1998 | } else {
|
---|
| 1999 | // other single-character tokens
|
---|
| 2000 | curr_block_tokens.push([value[0].toLowerCase(), value[0].toLowerCase(), value.length - 1 ]);
|
---|
| 2001 | value = value.substr(1);
|
---|
| 2002 | }
|
---|
| 2003 | } else if (tmp = value.match(/^\d+/)) {
|
---|
| 2004 | // number
|
---|
[7174] | 2005 | if (tmp[0] > 1900) // Assumed to be a year number.
|
---|
[6370] | 2006 | curr_block_tokens.push([tmp[0], 'year', value.length ]);
|
---|
| 2007 | else
|
---|
| 2008 | curr_block_tokens.push([+tmp[0], 'number', value.length ]);
|
---|
| 2009 | value = value.substr(tmp[0].length);
|
---|
| 2010 | } else if (tmp = value.match(/^"([^"]*)"/)) {
|
---|
| 2011 | // comment
|
---|
| 2012 | curr_block_tokens.push([tmp[1], 'comment', value.length ]);
|
---|
| 2013 | value = value.substr(tmp[0].length);
|
---|
| 2014 | } else if (value.match(/^;/)) {
|
---|
| 2015 | // semicolon terminates block
|
---|
| 2016 | // next tokens belong to a new block
|
---|
| 2017 | all_tokens.push([ curr_block_tokens, last_block_fallback_terminated, value.length ]);
|
---|
| 2018 | value = value.substr(1);
|
---|
| 2019 |
|
---|
| 2020 | curr_block_tokens = [];
|
---|
| 2021 | last_block_fallback_terminated = false;
|
---|
| 2022 | } else if (value.match(/^\|\|/)) {
|
---|
| 2023 | // || terminates block
|
---|
| 2024 | // next tokens belong to a fallback block
|
---|
| 2025 | if (curr_block_tokens.length == 0)
|
---|
| 2026 | throw formatWarnErrorMessage(-1, value.length - 2, 'Rule before fallback rule does not contain anything useful');
|
---|
| 2027 |
|
---|
| 2028 | all_tokens.push([ curr_block_tokens, last_block_fallback_terminated, value.length ]);
|
---|
| 2029 | value = value.substr(2);
|
---|
| 2030 |
|
---|
| 2031 | curr_block_tokens = [];
|
---|
| 2032 | last_block_fallback_terminated = true;
|
---|
| 2033 | } else if (value.match(/^(?:␣|\s)/)) {
|
---|
| 2034 | // Using "␣" as space is not expected to be a normal mistake. Just ignore it to make using taginfo easier.
|
---|
| 2035 | value = value.substr(1);
|
---|
| 2036 | } else if (tmp = value.match(/^\s+/)) {
|
---|
| 2037 | // whitespace is ignored
|
---|
| 2038 | value = value.substr(tmp[0].length);
|
---|
| 2039 | } else if (value.match(/^[:.]/)) {
|
---|
| 2040 | // time separator
|
---|
| 2041 | if (value[0] == '.' && !done_with_warnings)
|
---|
| 2042 | parsing_warnings.push([ -1, value.length - 1, 'Please use ":" as hour/minute-separator' ]);
|
---|
| 2043 | curr_block_tokens.push([ ':', 'timesep', value.length ]);
|
---|
| 2044 | value = value.substr(1);
|
---|
| 2045 | } else {
|
---|
| 2046 | // other single-character tokens
|
---|
| 2047 | curr_block_tokens.push([value[0].toLowerCase(), value[0].toLowerCase(), value.length ]);
|
---|
| 2048 | value = value.substr(1);
|
---|
| 2049 | }
|
---|
| 2050 | }
|
---|
| 2051 |
|
---|
| 2052 | all_tokens.push([ curr_block_tokens, last_block_fallback_terminated ]);
|
---|
| 2053 |
|
---|
| 2054 | return all_tokens;
|
---|
| 2055 | }
|
---|
[7046] | 2056 | // }}}
|
---|
[6370] | 2057 |
|
---|
[7174] | 2058 | /* error correction/tolerance function {{{
|
---|
| 2059 | * Go through word_error_correction hash and get correct value back.
|
---|
| 2060 | *
|
---|
| 2061 | * :param word: Wrong Word or character.
|
---|
| 2062 | * :param value_length: Current value_length (used for warnings).
|
---|
| 2063 | * :returns:
|
---|
| 2064 | * * (valid) opening_hours sub string.
|
---|
| 2065 | * * object with [ internal_value, token_name ] if value is correct.
|
---|
| 2066 | * * undefined if word could not be found (and thus not be corrected).
|
---|
| 2067 | */
|
---|
[6370] | 2068 | function returnCorrectWordOrToken(word, value_length) {
|
---|
| 2069 | for (var token_name in word_error_correction) {
|
---|
| 2070 | for (var comment in word_error_correction[token_name]) {
|
---|
| 2071 | for (var old_val in word_error_correction[token_name][comment]) {
|
---|
| 2072 | if (old_val == word) {
|
---|
| 2073 | var val = word_error_correction[token_name][comment][old_val];
|
---|
[7174] | 2074 | if (comment == 'default') {
|
---|
| 2075 | // Return internal representation of word.
|
---|
| 2076 | return [ val, token_name ];
|
---|
| 2077 | } else if (token_name == 'wrong_words' && !done_with_warnings) {
|
---|
| 2078 | // Replace wrong words or characters with correct ones.
|
---|
| 2079 | // This will return a string which is then being tokenized.
|
---|
[6370] | 2080 | parsing_warnings.push([ -1, value_length - old_val.length,
|
---|
| 2081 | comment.replace(/<ko>/, old_val).replace(/<ok>/, val) ]);
|
---|
| 2082 | return val;
|
---|
[7174] | 2083 | } else {
|
---|
| 2084 | // Get correct string value from the 'default' hash and generate warning.
|
---|
[6370] | 2085 | var correct_abbr;
|
---|
| 2086 | for (correct_abbr in word_error_correction[token_name]['default']) {
|
---|
| 2087 | if (word_error_correction[token_name]['default'][correct_abbr] == val)
|
---|
[7174] | 2088 | break;
|
---|
[6370] | 2089 | }
|
---|
[7174] | 2090 | if (typeof correct_abbr == 'undefined') {
|
---|
| 2091 | throw 'Please file a bug for opening_hours.js.'
|
---|
| 2092 | + ' Including the stacktrace.'
|
---|
[6370] | 2093 | }
|
---|
[7174] | 2094 | if (token_name != 'timevar') {
|
---|
| 2095 | // Everything else than timevar:
|
---|
| 2096 | // E.g. 'Mo' are start with a upper case letter.
|
---|
| 2097 | // It just looks better.
|
---|
| 2098 | correct_abbr = correct_abbr.charAt(0).toUpperCase()
|
---|
| 2099 | + correct_abbr.slice(1);
|
---|
| 2100 | }
|
---|
[6370] | 2101 | if (!done_with_warnings)
|
---|
| 2102 | parsing_warnings.push([ -1, value_length - old_val.length,
|
---|
| 2103 | comment.replace(/<ko>/, old_val).replace(/<ok>/, correct_abbr) ]);
|
---|
[7174] | 2104 | return [ val, token_name ];
|
---|
[6370] | 2105 | }
|
---|
| 2106 | }
|
---|
| 2107 | }
|
---|
| 2108 | }
|
---|
| 2109 | }
|
---|
[7174] | 2110 | return undefined;
|
---|
[6370] | 2111 | }
|
---|
[7046] | 2112 | // }}}
|
---|
[6370] | 2113 |
|
---|
[7174] | 2114 | /* return warnings as list {{{
|
---|
| 2115 | *
|
---|
| 2116 | * :param it: Iterator object if available (optional).
|
---|
| 2117 | * :returns: Warnings as list with one warning per element.
|
---|
| 2118 | */
|
---|
[6370] | 2119 | function getWarnings(it) {
|
---|
| 2120 | if (typeof it == 'object') { // getWarnings was called in a state without critical errors. We can do extended tests.
|
---|
| 2121 |
|
---|
[7046] | 2122 | // Check if 24/7 is used and it does not mean 24/7 because there are other blocks.
|
---|
[6370] | 2123 | var has_advanced = it.advance();
|
---|
| 2124 |
|
---|
| 2125 | if (has_advanced === true && has_token['24/7'] && !done_with_warnings) {
|
---|
| 2126 | parsing_warnings.push([ -1, 0, 'You used 24/7 in a way that is probably not interpreted as "24 hours 7 days a week".'
|
---|
| 2127 | // Probably because of: "24/7; 12:00-14:00 open", ". Needs extra testing.
|
---|
| 2128 | + ' For correctness you might want to use "open" or "closed"'
|
---|
| 2129 | + ' for this rule and then write your exceptions which should achieve the same goal and is more clear'
|
---|
| 2130 | + ' e.g. "open; Mo 12:00-14:00 off".']);
|
---|
| 2131 | }
|
---|
| 2132 | }
|
---|
| 2133 |
|
---|
| 2134 | var warnings = [];
|
---|
| 2135 | for (var i = 0; i < parsing_warnings.length; i++) {
|
---|
| 2136 | warnings.push( formatWarnErrorMessage(parsing_warnings[i][0], parsing_warnings[i][1], parsing_warnings[i][2]) );
|
---|
| 2137 | }
|
---|
| 2138 | return warnings;
|
---|
| 2139 | }
|
---|
[7046] | 2140 | // }}}
|
---|
[6370] | 2141 |
|
---|
[7174] | 2142 | /* Function to check token array for specific pattern {{{
|
---|
| 2143 | *
|
---|
| 2144 | * :param tokens: List of token objects.
|
---|
| 2145 | * :param at: Position at which the matching should begin.
|
---|
| 2146 | * :param token_name(s): One or many token_name strings which have to match in that order.
|
---|
| 2147 | * :returns: true if token_name(s) match in order false otherwise.
|
---|
| 2148 | */
|
---|
[6370] | 2149 | function matchTokens(tokens, at /*, matches... */) {
|
---|
| 2150 | if (at + arguments.length - 2 > tokens.length)
|
---|
| 2151 | return false;
|
---|
| 2152 | for (var i = 0; i < arguments.length - 2; i++) {
|
---|
| 2153 | if (tokens[at + i][1] !== arguments[i + 2])
|
---|
| 2154 | return false;
|
---|
| 2155 | }
|
---|
| 2156 |
|
---|
| 2157 | return true;
|
---|
| 2158 | }
|
---|
[7046] | 2159 | // }}}
|
---|
[6370] | 2160 |
|
---|
[7174] | 2161 | /* Generate selector wrapper with time offset {{{
|
---|
| 2162 | *
|
---|
| 2163 | * :param func: Generated selector code function.
|
---|
| 2164 | * :param shirt: Time to shift in milliseconds.
|
---|
| 2165 | * :param token_name(s): One or many token_name strings which have to match in that order.
|
---|
| 2166 | * :returns: See selector code.
|
---|
| 2167 | */
|
---|
[6370] | 2168 | function generateDateShifter(func, shift) {
|
---|
| 2169 | return function(date) {
|
---|
| 2170 | var res = func(new Date(date.getTime() + shift));
|
---|
| 2171 |
|
---|
| 2172 | if (typeof res[1] === 'undefined')
|
---|
| 2173 | return res;
|
---|
| 2174 | return [ res[0], new Date(res[1].getTime() - shift) ];
|
---|
| 2175 | }
|
---|
| 2176 | }
|
---|
[7046] | 2177 | // }}}
|
---|
[6370] | 2178 |
|
---|
[7174] | 2179 | /* Top-level parser {{{
|
---|
| 2180 | *
|
---|
| 2181 | * :param tokens: List of token objects.
|
---|
| 2182 | * :param at: Position at which the matching should begin.
|
---|
| 2183 | * :param selectors: Reference to selector object.
|
---|
| 2184 | * :param nblock: Block number starting with 0.
|
---|
| 2185 | * :param conf: Configuration for prettifyValue.
|
---|
| 2186 | * :returns: See selector code.
|
---|
| 2187 | */
|
---|
[6370] | 2188 | function parseGroup(tokens, at, selectors, nblock, conf) {
|
---|
| 2189 | var prettified_group_value = '';
|
---|
[6489] | 2190 | used_subparsers = { 'time ranges': [ ] };
|
---|
[6370] | 2191 |
|
---|
| 2192 | // console.log(tokens); // useful for debugging of tokenize
|
---|
| 2193 | while (at < tokens.length) {
|
---|
| 2194 | var old_at = at;
|
---|
| 2195 | // console.log('Parsing at position', at +':', tokens[at]);
|
---|
| 2196 | if (matchTokens(tokens, at, 'weekday')) {
|
---|
| 2197 | at = parseWeekdayRange(tokens, at, selectors);
|
---|
| 2198 | } else if (matchTokens(tokens, at, '24/7')) {
|
---|
[7046] | 2199 | selectors.time.push(function(date) { return [true]; });
|
---|
[6370] | 2200 | // Not needed. If there is no selector it automatically matches everything.
|
---|
[7046] | 2201 | // WRONG: This only works if there is no other selector in this selector group ...
|
---|
[6370] | 2202 | at++;
|
---|
| 2203 | } else if (matchTokens(tokens, at, 'holiday')) {
|
---|
| 2204 | if (matchTokens(tokens, at+1, ','))
|
---|
| 2205 | at = parseHoliday(tokens, at, selectors, true);
|
---|
| 2206 | else
|
---|
| 2207 | at = parseHoliday(tokens, at, selectors, false);
|
---|
| 2208 | week_stable = false;
|
---|
| 2209 | } else if (matchTokens(tokens, at, 'month', 'number')
|
---|
| 2210 | || matchTokens(tokens, at, 'month', 'weekday')
|
---|
| 2211 | || matchTokens(tokens, at, 'year', 'month', 'number')
|
---|
| 2212 | || matchTokens(tokens, at, 'year', 'event')
|
---|
| 2213 | || matchTokens(tokens, at, 'event')) {
|
---|
[6420] | 2214 | at = parseMonthdayRange(tokens, at, nblock);
|
---|
[6370] | 2215 | week_stable = false;
|
---|
| 2216 | } else if (matchTokens(tokens, at, 'year')) {
|
---|
| 2217 | at = parseYearRange(tokens, at);
|
---|
| 2218 | week_stable = false;
|
---|
| 2219 | } else if (matchTokens(tokens, at, 'month')) {
|
---|
| 2220 | at = parseMonthRange(tokens, at);
|
---|
| 2221 | // week_stable = false; // decided based on actual values
|
---|
| 2222 | } else if (matchTokens(tokens, at, 'week')) {
|
---|
| 2223 | at = parseWeekRange(tokens, at + 1);
|
---|
| 2224 | week_stable = false;
|
---|
[6420] | 2225 |
|
---|
| 2226 | // if (prettified_group_value[-1] != ' ')
|
---|
| 2227 | // prettified_group_value = prettified_group_value.substring(0, prettified_group_value.length - 1);
|
---|
[6370] | 2228 | } else if (at != 0 && at != tokens.length - 1 && tokens[at][0] == ':') {
|
---|
| 2229 | // Ignore colon if they appear somewhere else than as time separator.
|
---|
[6420] | 2230 | // Except the start or end of the value.
|
---|
[6370] | 2231 | // This provides compatibility with the syntax proposed by Netzwolf:
|
---|
[6420] | 2232 | // http://wiki.openstreetmap.org/wiki/Key:opening_hours:specification
|
---|
[7046] | 2233 | if (!done_with_warnings && (matchTokens(tokens, at-1, 'weekday') || matchTokens(tokens, at-1, 'holiday')))
|
---|
[6370] | 2234 | parsing_warnings.push([nblock, at, 'Please don’t use ":" after ' + tokens[at-1][1] + '.']);
|
---|
| 2235 |
|
---|
| 2236 | if (prettified_group_value[-1] != ' ')
|
---|
| 2237 | prettified_group_value = prettified_group_value.substring(0, prettified_group_value.length - 1);
|
---|
| 2238 | at++;
|
---|
| 2239 | } else if (matchTokens(tokens, at, 'number', 'timesep')
|
---|
| 2240 | || matchTokens(tokens, at, 'timevar')
|
---|
[6420] | 2241 | || matchTokens(tokens, at, '(', 'timevar')
|
---|
| 2242 | || matchTokens(tokens, at, 'number', '-')) {
|
---|
[7046] | 2243 | at = parseTimeRange(tokens, at, selectors, false);
|
---|
[6370] | 2244 |
|
---|
[6489] | 2245 | used_subparsers['time ranges'].push(at);
|
---|
[6370] | 2246 | } else if (matchTokens(tokens, at, 'closed')) {
|
---|
| 2247 | selectors.meaning = false;
|
---|
| 2248 | at++;
|
---|
| 2249 | if (matchTokens(tokens, at, ',')) // additional block
|
---|
| 2250 | at = [ at + 1 ];
|
---|
| 2251 |
|
---|
[6489] | 2252 | if (typeof used_subparsers['state keywords'] != 'object')
|
---|
| 2253 | used_subparsers['state keywords'] = [ at ];
|
---|
[6370] | 2254 | else
|
---|
[6489] | 2255 | used_subparsers['state keywords'].push(at);
|
---|
[6370] | 2256 | } else if (matchTokens(tokens, at, 'open')) {
|
---|
| 2257 | selectors.meaning = true;
|
---|
| 2258 | at++;
|
---|
| 2259 | if (matchTokens(tokens, at, ',')) // additional block
|
---|
| 2260 | at = [ at + 1 ];
|
---|
| 2261 |
|
---|
[6489] | 2262 | if (typeof used_subparsers['state keywords'] != 'object')
|
---|
| 2263 | used_subparsers['state keywords'] = [ at ];
|
---|
[6370] | 2264 | else
|
---|
[6489] | 2265 | used_subparsers['state keywords'].push(at);
|
---|
[6370] | 2266 | } else if (matchTokens(tokens, at, 'unknown')) {
|
---|
| 2267 | selectors.meaning = false;
|
---|
| 2268 | selectors.unknown = true;
|
---|
| 2269 | at++;
|
---|
| 2270 | if (matchTokens(tokens, at, ',')) // additional block
|
---|
| 2271 | at = [ at + 1 ];
|
---|
| 2272 |
|
---|
[6489] | 2273 | if (typeof used_subparsers['state keywords'] != 'object')
|
---|
| 2274 | used_subparsers['state keywords'] = [ at ];
|
---|
[6370] | 2275 | else
|
---|
[6489] | 2276 | used_subparsers['state keywords'].push(at);
|
---|
[6370] | 2277 | } else if (matchTokens(tokens, at, 'comment')) {
|
---|
| 2278 | selectors.comment = tokens[at][0];
|
---|
| 2279 | if (at > 0) {
|
---|
| 2280 | if (!matchTokens(tokens, at - 1, 'open')
|
---|
| 2281 | && !matchTokens(tokens, at - 1, 'closed')) {
|
---|
| 2282 | // Then it is unknown. Either with unknown explicitly
|
---|
| 2283 | // specified or just a comment behind.
|
---|
| 2284 | selectors.meaning = false;
|
---|
| 2285 | selectors.unknown = true;
|
---|
| 2286 | }
|
---|
| 2287 | } else { // block starts with comment
|
---|
[7046] | 2288 | selectors.time.push(function(date) { return [true]; });
|
---|
[6370] | 2289 | // Not needed. If there is no selector it automatically matches everything.
|
---|
[7046] | 2290 | // WRONG: This only works if there is no other selector in this selector group ...
|
---|
[6370] | 2291 | selectors.meaning = false;
|
---|
| 2292 | selectors.unknown = true;
|
---|
| 2293 | }
|
---|
| 2294 | at++;
|
---|
| 2295 | if (matchTokens(tokens, at, ',')) // additional block
|
---|
| 2296 | at = [ at + 1 ];
|
---|
| 2297 |
|
---|
[6489] | 2298 | if (typeof used_subparsers['comments'] != 'object')
|
---|
| 2299 | used_subparsers['comments'] = [ at ];
|
---|
[6370] | 2300 | else
|
---|
[6489] | 2301 | used_subparsers['comments'].push(at);
|
---|
[6370] | 2302 | } else {
|
---|
| 2303 | var warnings = getWarnings();
|
---|
| 2304 | throw formatWarnErrorMessage(nblock, at, 'Unexpected token: "' + tokens[at][1]
|
---|
| 2305 | + '" This means that the syntax is not valid at that point or it is currently not supported.')
|
---|
| 2306 | + (warnings ? ' ' + warnings.join('; ') : '');
|
---|
| 2307 | }
|
---|
| 2308 |
|
---|
| 2309 | if (typeof conf != 'undefined') {
|
---|
[6420] | 2310 | // 'Mo: 12:00-13:00' -> 'Mo 12:00-13:00'
|
---|
| 2311 | if (used_subparsers['time ranges'] && old_at > 1 && tokens[old_at-1][0] == ':'
|
---|
| 2312 | && matchTokens(tokens, old_at - 2, 'weekday'))
|
---|
| 2313 | prettified_group_value = prettified_group_value.substring(0, prettified_group_value.length - 2) + ' ';
|
---|
| 2314 |
|
---|
| 2315 | // 'week 1, week 3' -> 'week 1,week 3'
|
---|
| 2316 | if (prettified_group_value.substr(prettified_group_value.length -2, 2) == ', '
|
---|
| 2317 | && matchTokens(tokens, old_at, 'week'))
|
---|
| 2318 | prettified_group_value = prettified_group_value.substring(0, prettified_group_value.length - 1);
|
---|
| 2319 |
|
---|
[6489] | 2320 | prettified_group_value += prettifySelector(tokens, old_at, at, conf, used_subparsers['time ranges'].length);
|
---|
[6370] | 2321 | }
|
---|
| 2322 |
|
---|
| 2323 | if (typeof at == 'object') // additional block
|
---|
| 2324 | break;
|
---|
| 2325 | }
|
---|
| 2326 |
|
---|
| 2327 | prettified_value += prettified_group_value.replace(/\s+$/, '');
|
---|
| 2328 |
|
---|
| 2329 | if (!done_with_warnings) {
|
---|
| 2330 | for (var subparser_name in used_subparsers) {
|
---|
[6489] | 2331 | if (used_subparsers[subparser_name].length > 1) {
|
---|
| 2332 | parsing_warnings.push([nblock, used_subparsers[subparser_name][used_subparsers[subparser_name].length - 1] - 1,
|
---|
| 2333 | 'You have used ' + used_subparsers[subparser_name].length
|
---|
| 2334 | + (subparser_name.match(/^(?:comments|state keywords)/) ?
|
---|
| 2335 | ' ' + subparser_name + ' in one rule.'
|
---|
[6370] | 2336 | + ' You may only use one in one rule.'
|
---|
[6489] | 2337 | :
|
---|
| 2338 | ' not connected ' + subparser_name + ' in one rule.'
|
---|
[6370] | 2339 | + ' This is probably an error.'
|
---|
| 2340 | + ' Equal selector types can (and should) always be written in conjunction separated by comma or something.'
|
---|
[6489] | 2341 | + ' Example for time ranges "12:00-13:00,15:00-18:00".'
|
---|
[7046] | 2342 | + ' Example for weekdays "Mo-We,Fr".'
|
---|
[6489] | 2343 | )
|
---|
| 2344 | + ' Rules can be separated by ";".' ]
|
---|
| 2345 | );
|
---|
[6370] | 2346 | }
|
---|
| 2347 | }
|
---|
| 2348 | }
|
---|
| 2349 |
|
---|
| 2350 | return at;
|
---|
| 2351 | }
|
---|
[7046] | 2352 | // }}}
|
---|
[6370] | 2353 |
|
---|
[7046] | 2354 | // helper functions for sub parser {{{
|
---|
[7174] | 2355 |
|
---|
| 2356 | /* For given date, returns date moved to the start of the day with an offset specified in minutes. {{{
|
---|
| 2357 | * For example, if date is 2014-05-19_18:17:12, dateAtDayMinutes would
|
---|
| 2358 | * return 2014-05-19_02:00:00 for minutes=120.
|
---|
| 2359 | *
|
---|
| 2360 | * :param date: Date object.
|
---|
| 2361 | * :param minutes: Minutes used as offset starting from midnight of current day.
|
---|
| 2362 | * :returns: Moved date object.
|
---|
| 2363 | */
|
---|
[7046] | 2364 | function dateAtDayMinutes(date, minutes) {
|
---|
| 2365 | return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, minutes);
|
---|
| 2366 | }
|
---|
[7174] | 2367 | // }}}
|
---|
[7046] | 2368 |
|
---|
[7174] | 2369 | /* For given date, returns date moved to the specific day of week {{{
|
---|
| 2370 | *
|
---|
| 2371 | * :param date: Date object.
|
---|
| 2372 | * :param day: Integer number for day of week. Starting with zero (Sunday).
|
---|
| 2373 | * :returns: Moved date object.
|
---|
| 2374 | */
|
---|
[7046] | 2375 | function dateAtNextWeekday(date, day) {
|
---|
| 2376 | var delta = day - date.getDay();
|
---|
| 2377 | return new Date(date.getFullYear(), date.getMonth(), date.getDate() + delta + (delta < 0 ? 7 : 0));
|
---|
| 2378 | }
|
---|
[7174] | 2379 | // }}}
|
---|
[7046] | 2380 |
|
---|
[7174] | 2381 | /* Function to determine whether an array contains a value {{{
|
---|
| 2382 | * Source: http://stackoverflow.com/a/1181586
|
---|
| 2383 | *
|
---|
| 2384 | * :param needle: Element to find.
|
---|
| 2385 | * :returns: Index of element if present, if not present returns -1.
|
---|
| 2386 | */
|
---|
[7046] | 2387 | function indexOf(needle) {
|
---|
| 2388 | if(typeof Array.prototype.indexOf === 'function') {
|
---|
| 2389 | indexOf = Array.prototype.indexOf;
|
---|
| 2390 | } else {
|
---|
| 2391 | indexOf = function(needle) {
|
---|
| 2392 | var i = -1, index = -1;
|
---|
| 2393 | for(i = 0; i < this.length; i++) {
|
---|
| 2394 | if(this[i] === needle) {
|
---|
| 2395 | index = i;
|
---|
| 2396 | break;
|
---|
| 2397 | }
|
---|
| 2398 | }
|
---|
| 2399 | return index;
|
---|
| 2400 | };
|
---|
| 2401 | }
|
---|
| 2402 | return indexOf.call(this, needle);
|
---|
| 2403 | }
|
---|
[7174] | 2404 | // }}}
|
---|
[7046] | 2405 |
|
---|
[7174] | 2406 | /* Numeric list parser (1,2,3-4,-1) {{{
|
---|
| 2407 | * Used in weekday parser above.
|
---|
| 2408 | *
|
---|
| 2409 | * :param tokens: List of token objects.
|
---|
| 2410 | * :param at: Position where to start.
|
---|
| 2411 | * :param func: Function func(from, to, at).
|
---|
| 2412 | * :returns: Position at which the token does not belong to the list any more.
|
---|
| 2413 | */
|
---|
[7046] | 2414 | function parseNumRange(tokens, at, func) {
|
---|
[6370] | 2415 | for (; at < tokens.length; at++) {
|
---|
[7046] | 2416 | if (matchTokens(tokens, at, 'number', '-', 'number')) {
|
---|
| 2417 | // Number range
|
---|
| 2418 | func(tokens[at][0], tokens[at+2][0], at);
|
---|
| 2419 | at += 3;
|
---|
| 2420 | } else if (matchTokens(tokens, at, '-', 'number')) {
|
---|
| 2421 | // Negative number
|
---|
| 2422 | func(-tokens[at+1][0], -tokens[at+1][0], at);
|
---|
| 2423 | at += 2
|
---|
| 2424 | } else if (matchTokens(tokens, at, 'number')) {
|
---|
| 2425 | // Single number
|
---|
| 2426 | func(tokens[at][0], tokens[at][0], at);
|
---|
| 2427 | at++;
|
---|
| 2428 | } else {
|
---|
| 2429 | throw formatWarnErrorMessage(nblock, at + matchTokens(tokens, at, '-'),
|
---|
| 2430 | 'Unexpected token in number range: ' + tokens[at][1]);
|
---|
| 2431 | }
|
---|
| 2432 |
|
---|
| 2433 | if (!matchTokens(tokens, at, ','))
|
---|
| 2434 | break;
|
---|
| 2435 | }
|
---|
| 2436 |
|
---|
| 2437 | return at;
|
---|
| 2438 | }
|
---|
[7174] | 2439 | // }}}
|
---|
[7046] | 2440 |
|
---|
[7174] | 2441 | /* List parser for constrained weekdays in month range {{{
|
---|
| 2442 | * e.g. Su[-1] which selects the last Sunday of the month.
|
---|
| 2443 | *
|
---|
| 2444 | * :param tokens: List of token objects.
|
---|
| 2445 | * :param at: Position where to start.
|
---|
| 2446 | * :returns: Array:
|
---|
| 2447 | * 0. Constrained weekday number.
|
---|
| 2448 | * 1. Position at which the token does not belong to the list any more (after ']' token).
|
---|
| 2449 | */
|
---|
[7046] | 2450 | function getConstrainedWeekday(tokens, at) {
|
---|
| 2451 | var number = 0;
|
---|
| 2452 | var endat = parseNumRange(tokens, at, function(from, to, at) {
|
---|
| 2453 |
|
---|
| 2454 | // bad number
|
---|
| 2455 | if (from == 0 || from < -5 || from > 5)
|
---|
| 2456 | throw formatWarnErrorMessage(nblock, at,
|
---|
| 2457 | 'Number between -5 and 5 (except 0) expected');
|
---|
| 2458 |
|
---|
| 2459 | if (from == to) {
|
---|
| 2460 | if (number != 0)
|
---|
| 2461 | throw formatWarnErrorMessage(nblock, at,
|
---|
[7174] | 2462 | 'You can not use more than one constrained weekday in a month range');
|
---|
[7046] | 2463 | number = from;
|
---|
| 2464 | } else {
|
---|
| 2465 | throw formatWarnErrorMessage(nblock, at+2,
|
---|
| 2466 | 'You can not use a range of constrained weekdays in a month range');
|
---|
| 2467 | }
|
---|
| 2468 | });
|
---|
| 2469 |
|
---|
| 2470 | if (!matchTokens(tokens, endat, ']'))
|
---|
| 2471 | throw formatWarnErrorMessage(nblock, endat, '"]" expected.');
|
---|
| 2472 |
|
---|
| 2473 | return [ number, endat + 1 ];
|
---|
| 2474 | }
|
---|
[7174] | 2475 | // }}}
|
---|
[7046] | 2476 |
|
---|
| 2477 | // Check if period is ok. Period 0 or 1 don’t make much sense.
|
---|
[7174] | 2478 | /* List parser for constrained weekdays in month range {{{
|
---|
| 2479 | * e.g. Su[-1] which selects the last Sunday of the month.
|
---|
| 2480 | *
|
---|
| 2481 | * :param tokens: List of token objects.
|
---|
| 2482 | * :param at: Position where to start.
|
---|
| 2483 | * :returns: Array:
|
---|
| 2484 | * 0. Constrained weekday number.
|
---|
| 2485 | * 1. Position at which the token does not belong to the list any more (after ']' token).
|
---|
| 2486 | */
|
---|
[7046] | 2487 | function checkPeriod(at, period, period_type, parm_string) {
|
---|
| 2488 | if (done_with_warnings)
|
---|
| 2489 | return;
|
---|
| 2490 |
|
---|
| 2491 | if (period === 0) {
|
---|
| 2492 | throw formatWarnErrorMessage(nblock, at,
|
---|
| 2493 | 'You can not use '+ period_type +' ranges with period equals zero.');
|
---|
| 2494 | } else if (period === 1) {
|
---|
| 2495 | if (typeof parm_string == 'string' && parm_string == 'no_end_year')
|
---|
| 2496 | parsing_warnings.push([nblock, at,
|
---|
| 2497 | 'Please don’t use '+ period_type +' ranges with period equals one.'
|
---|
| 2498 | + ' If you want to express that a facility is open starting from a year without limit use "<year>+".']);
|
---|
| 2499 | else
|
---|
| 2500 | parsing_warnings.push([nblock, at,
|
---|
| 2501 | 'Please don’t use '+ period_type +' ranges with period equals one.']);
|
---|
| 2502 | }
|
---|
| 2503 | }
|
---|
| 2504 |
|
---|
| 2505 | function getDateForConstrainedWeekday(year, month, weekday, constrained_weekday, add_days) {
|
---|
| 2506 | var tmp_date = dateAtNextWeekday(
|
---|
| 2507 | new Date(year, month + (constrained_weekday[0] > 0 ? 0 : 1), 1), weekday);
|
---|
| 2508 |
|
---|
| 2509 | tmp_date.setDate(tmp_date.getDate() + (constrained_weekday[0] + (constrained_weekday[0] > 0 ? -1 : 0)) * 7);
|
---|
| 2510 |
|
---|
| 2511 | if (typeof add_days != 'undefined' && add_days[1])
|
---|
| 2512 | tmp_date.setDate(tmp_date.getDate() + add_days[0]);
|
---|
| 2513 |
|
---|
| 2514 | return tmp_date;
|
---|
| 2515 | }
|
---|
| 2516 |
|
---|
| 2517 | function formatWarnErrorMessage(nblock, at, message) {
|
---|
| 2518 | var pos = 0;
|
---|
| 2519 | if (nblock == -1) { // Usage of block index not required because we do have access to value.length.
|
---|
| 2520 | pos = value.length - at;
|
---|
| 2521 | } else { // Issue accrued at a later time, position in string needs to be reconstructed.
|
---|
| 2522 | if (typeof tokens[nblock][0][at] == 'undefined') {
|
---|
| 2523 | pos = value.length;
|
---|
| 2524 | if (typeof tokens[nblock][0][tokens[nblock][0].length-1] != 'undefined') {
|
---|
| 2525 | // pos -= tokens[nblock][0][tokens[nblock][0].length-1][2];
|
---|
| 2526 | console.warn("FIXME");
|
---|
| 2527 | }
|
---|
| 2528 | } else {
|
---|
| 2529 | pos = value.length;
|
---|
| 2530 | if (typeof tokens[nblock][0][at+1] != 'undefined') {
|
---|
| 2531 | pos -= tokens[nblock][0][at+1][2];
|
---|
| 2532 | } else if (typeof tokens[nblock][2] != 'undefined') {
|
---|
| 2533 | pos -= tokens[nblock][2];
|
---|
| 2534 | } else {
|
---|
| 2535 | }
|
---|
| 2536 | }
|
---|
| 2537 | }
|
---|
| 2538 | return value.substring(0, pos) + ' <--- (' + message + ')';
|
---|
| 2539 | }
|
---|
| 2540 |
|
---|
| 2541 | // check if date is valid
|
---|
| 2542 | function isValidDate(month, day, nblock, at) {
|
---|
| 2543 | // month == 0 is Jan
|
---|
| 2544 |
|
---|
| 2545 | // May use this instead. Does not say, what is wrong as good was implementation below.
|
---|
| 2546 | // var testDate = new Date(year, month, day);
|
---|
| 2547 | // if (testDate.getDate() != day || testDate.getMonth() != month || testDate.getFullYear() != year) {
|
---|
| 2548 | // console.error('date not valid');
|
---|
| 2549 | // }
|
---|
| 2550 |
|
---|
| 2551 | // https://en.wikipedia.org/wiki/Month#Julian_and_Gregorian_calendars
|
---|
| 2552 | if (day < 1 || day > 31)
|
---|
| 2553 | throw formatWarnErrorMessage(nblock, at, 'Day must be between 1 and 31.');
|
---|
| 2554 | if ((month==3 || month==5 || month==8 || month==10) && day==31)
|
---|
| 2555 | throw formatWarnErrorMessage(nblock, at, 'Month ' + months[month] + " doesn't have 31 days.!");
|
---|
| 2556 | if (month == 1 && day == 30)
|
---|
| 2557 | throw formatWarnErrorMessage(nblock, at, 'Month ' + months[1]+ " either has 28 or 29 days (leap years).");
|
---|
| 2558 | }
|
---|
| 2559 | // }}}
|
---|
| 2560 |
|
---|
| 2561 | // Time range parser (10:00-12:00,14:00-16:00) {{{
|
---|
| 2562 | //
|
---|
| 2563 | // extended_open_end: <time> - <time> +
|
---|
| 2564 | // at is here A (if extended_open_end is true)
|
---|
| 2565 | function parseTimeRange(tokens, at, selectors, extended_open_end) {
|
---|
| 2566 | for (; at < tokens.length; at++) {
|
---|
[6370] | 2567 | var has_time_var_calc = [], has_normal_time = []; // element 0: start time, 1: end time
|
---|
| 2568 | has_normal_time[0] = matchTokens(tokens, at, 'number', 'timesep', 'number');
|
---|
| 2569 | has_time_var_calc[0] = matchTokens(tokens, at, '(', 'timevar');
|
---|
| 2570 | if (has_normal_time[0] || matchTokens(tokens, at, 'timevar') || has_time_var_calc[0]) {
|
---|
| 2571 | // relying on the fact that always *one* of them is true
|
---|
| 2572 |
|
---|
[6489] | 2573 | var is_point_in_time = false; // default no time range
|
---|
| 2574 | var has_open_end = false; // default no open end
|
---|
| 2575 | var timevar_add = [ 0, 0 ];
|
---|
[7046] | 2576 | var timevar_string = []; // capture timevar string like 'sunrise' to calculate it for the current date.
|
---|
[6370] | 2577 |
|
---|
[6489] | 2578 | // minutes_from
|
---|
| 2579 | if (has_normal_time[0]) {
|
---|
[6370] | 2580 | var minutes_from = getMinutesByHoursMinutes(tokens, nblock, at+has_time_var_calc[0]);
|
---|
[6489] | 2581 | } else {
|
---|
| 2582 | timevar_string[0] = tokens[at+has_time_var_calc[0]][0];
|
---|
| 2583 | var minutes_from = word_value_replacement[timevar_string[0]];
|
---|
[6370] | 2584 |
|
---|
[6489] | 2585 | if (has_time_var_calc[0]) {
|
---|
| 2586 | timevar_add[0] = parseTimevarCalc(tokens, at);
|
---|
| 2587 | minutes_from += timevar_add[0];
|
---|
| 2588 | }
|
---|
[6370] | 2589 | }
|
---|
| 2590 |
|
---|
[6489] | 2591 | var at_end_time = at+(has_normal_time[0] ? 3 : (has_time_var_calc[0] ? 7 : 1))+1; // after '-'
|
---|
| 2592 | if (!matchTokens(tokens, at_end_time - 1, '-')) { // not time range
|
---|
| 2593 | if (matchTokens(tokens, at_end_time - 1, '+')) {
|
---|
[6370] | 2594 | has_open_end = true;
|
---|
| 2595 | } else {
|
---|
| 2596 | if (oh_mode == 0) {
|
---|
[7046] | 2597 | throw formatWarnErrorMessage(nblock, at+(
|
---|
| 2598 | has_normal_time[0] ? (
|
---|
| 2599 | typeof tokens[at+3] == 'object' ? 3 : 2
|
---|
| 2600 | ) : (
|
---|
| 2601 | has_time_var_calc[0] ? 2 : 1
|
---|
| 2602 | )
|
---|
| 2603 | ),
|
---|
[6370] | 2604 | 'hyphen (-) or open end (+) in time range '
|
---|
[6489] | 2605 | + (has_time_var_calc[0] ? 'calculation ' : '') + 'expected.'
|
---|
| 2606 | + ' For working with points in time, the mode for opening_hours.js has to be altered.'
|
---|
| 2607 | + ' Maybe wrong tag?');
|
---|
[6370] | 2608 | } else {
|
---|
| 2609 | var minutes_to = minutes_from + 1;
|
---|
| 2610 | is_point_in_time = true;
|
---|
| 2611 | }
|
---|
| 2612 | }
|
---|
| 2613 | }
|
---|
| 2614 |
|
---|
[6489] | 2615 | // minutes_to
|
---|
[6370] | 2616 | if (has_open_end) {
|
---|
| 2617 | if (minutes_from >= 22 * 60)
|
---|
[6489] | 2618 | var minutes_to = minutes_from + 8 * 60;
|
---|
[6370] | 2619 | else if (minutes_from >= 17 * 60)
|
---|
[6489] | 2620 | var minutes_to = minutes_from + 10 * 60;
|
---|
[6370] | 2621 | else
|
---|
| 2622 | var minutes_to = minutes_in_day;
|
---|
| 2623 | } else if (!is_point_in_time) {
|
---|
| 2624 | has_normal_time[1] = matchTokens(tokens, at_end_time, 'number', 'timesep', 'number');
|
---|
| 2625 | has_time_var_calc[1] = matchTokens(tokens, at_end_time, '(', 'timevar');
|
---|
| 2626 | if (!has_normal_time[1] && !matchTokens(tokens, at_end_time, 'timevar') && !has_time_var_calc[1]) {
|
---|
[6489] | 2627 | throw formatWarnErrorMessage(nblock, at_end_time, 'time range does not continue as expected');
|
---|
[6370] | 2628 | } else {
|
---|
[6489] | 2629 | if (has_normal_time[1]) {
|
---|
[6370] | 2630 | var minutes_to = getMinutesByHoursMinutes(tokens, nblock, at_end_time);
|
---|
[6489] | 2631 | } else {
|
---|
| 2632 | timevar_string[1] = tokens[at_end_time+has_time_var_calc[1]][0]
|
---|
| 2633 | var minutes_to = word_value_replacement[timevar_string[1]];
|
---|
| 2634 | }
|
---|
[6370] | 2635 |
|
---|
| 2636 | if (has_time_var_calc[1]) {
|
---|
| 2637 | timevar_add[1] = parseTimevarCalc(tokens, at_end_time);
|
---|
| 2638 | minutes_to += timevar_add[1];
|
---|
| 2639 | }
|
---|
[6489] | 2640 | }
|
---|
| 2641 | }
|
---|
[6370] | 2642 |
|
---|
[6489] | 2643 | at = at_end_time + (is_point_in_time ? -1 :
|
---|
| 2644 | (has_normal_time[1] ? 3 : (has_time_var_calc[1] ? 7 : !has_open_end))
|
---|
| 2645 | );
|
---|
| 2646 |
|
---|
| 2647 | if (matchTokens(tokens, at, '/', 'number')) {
|
---|
| 2648 | if (matchTokens(tokens, at + 2, 'timesep', 'number')) { // /hours:minutes
|
---|
| 2649 | var point_in_time_period = getMinutesByHoursMinutes(tokens, nblock, at + 1);
|
---|
| 2650 | at += 4;
|
---|
| 2651 | } else { // /minutes
|
---|
| 2652 | var point_in_time_period = tokens[at + 1][0];
|
---|
| 2653 | at += 2;
|
---|
| 2654 | if (matchTokens(tokens, at, 'timesep'))
|
---|
| 2655 | throw formatWarnErrorMessage(nblock, at,
|
---|
| 2656 | 'Time period does not continue as expected. Exampe "/01:30".');
|
---|
[6370] | 2657 | }
|
---|
[6489] | 2658 |
|
---|
| 2659 | if (oh_mode == 0)
|
---|
| 2660 | throw formatWarnErrorMessage(nblock, at - 1,
|
---|
| 2661 | 'opening_hours is running in "time range mode". Found point in time.');
|
---|
| 2662 |
|
---|
| 2663 | is_point_in_time = true;
|
---|
[7046] | 2664 | } else if (matchTokens(tokens, at, '+')) {
|
---|
| 2665 | parseTimeRange(tokens, at_end_time, selectors, true);
|
---|
| 2666 | at++;
|
---|
[6489] | 2667 | } else if (oh_mode == 1 && !is_point_in_time) {
|
---|
| 2668 | throw formatWarnErrorMessage(nblock, at_end_time,
|
---|
| 2669 | 'opening_hours is running in "points in time mode". Found time range.');
|
---|
[6370] | 2670 | }
|
---|
| 2671 |
|
---|
[6489] | 2672 | if (typeof lat != 'undefined') { // lon will also be defined (see above)
|
---|
| 2673 | if (!has_normal_time[0] || !(has_normal_time[1] || has_open_end || is_point_in_time) )
|
---|
| 2674 | week_stable = false;
|
---|
| 2675 | } else { // we can not calculate exact times so we use the already applied constants (word_value_replacement).
|
---|
| 2676 | timevar_string = [];
|
---|
| 2677 | }
|
---|
| 2678 |
|
---|
[6370] | 2679 | // normalize minutes into range
|
---|
[7046] | 2680 | if (!extended_open_end && minutes_from >= minutes_in_day)
|
---|
[6370] | 2681 | throw formatWarnErrorMessage(nblock, at_end_time - 1,
|
---|
| 2682 | 'Time range starts outside of the current day');
|
---|
| 2683 | if (minutes_to < minutes_from || ((has_normal_time[0] && has_normal_time[1]) && minutes_from == minutes_to))
|
---|
| 2684 | minutes_to += minutes_in_day;
|
---|
| 2685 | if (minutes_to > minutes_in_day * 2)
|
---|
[7046] | 2686 | throw formatWarnErrorMessage(nblock, at_end_time + (has_normal_time[1] ? 4 : (has_time_var_calc[1] ? 7 : 1)) - 2,
|
---|
[6370] | 2687 | 'Time spanning more than two midnights not supported');
|
---|
| 2688 |
|
---|
[6489] | 2689 | // this shortcut makes always-open range check faster
|
---|
| 2690 | if (!(minutes_from == 0 && minutes_to == minutes_in_day)) {
|
---|
| 2691 | if (minutes_to > minutes_in_day) { // has_normal_time[1] must be true
|
---|
| 2692 | selectors.time.push(function(minutes_from, minutes_to, timevar_string, timevar_add, has_open_end, is_point_in_time, point_in_time_period) { return function(date) {
|
---|
| 2693 | var ourminutes = date.getHours() * 60 + date.getMinutes();
|
---|
[6370] | 2694 |
|
---|
[6489] | 2695 | if (timevar_string[0]) {
|
---|
| 2696 | var date_from = eval('SunCalc.getTimes(date, lat, lon).' + timevar_string[0]);
|
---|
| 2697 | minutes_from = date_from.getHours() * 60 + date_from.getMinutes() + timevar_add[0];
|
---|
| 2698 | }
|
---|
| 2699 | if (timevar_string[1]) {
|
---|
| 2700 | var date_to = eval('SunCalc.getTimes(date, lat, lon).' + timevar_string[1]);
|
---|
| 2701 | minutes_to = date_to.getHours() * 60 + date_to.getMinutes() + timevar_add[1];
|
---|
| 2702 | minutes_to += minutes_in_day;
|
---|
| 2703 | // Needs to be added because it was added by
|
---|
| 2704 | // normal times: if (minutes_to < minutes_from)
|
---|
| 2705 | // above the selector construction.
|
---|
| 2706 | } else if (is_point_in_time && typeof point_in_time_period != 'number') {
|
---|
| 2707 | minutes_to = minutes_from + 1;
|
---|
| 2708 | }
|
---|
[6370] | 2709 |
|
---|
[6489] | 2710 | if (typeof point_in_time_period == 'number') {
|
---|
| 2711 | if (ourminutes < minutes_from) {
|
---|
| 2712 | return [false, dateAtDayMinutes(date, minutes_from)];
|
---|
| 2713 | } else if (ourminutes <= minutes_to) {
|
---|
| 2714 | for (var cur_min = minutes_from; ourminutes + point_in_time_period >= cur_min; cur_min += point_in_time_period) {
|
---|
| 2715 | if (cur_min == ourminutes) {
|
---|
| 2716 | return [true, dateAtDayMinutes(date, ourminutes + 1)];
|
---|
| 2717 | } else if (ourminutes < cur_min) {
|
---|
| 2718 | return [false, dateAtDayMinutes(date, cur_min)];
|
---|
| 2719 | }
|
---|
| 2720 | }
|
---|
| 2721 | }
|
---|
| 2722 | return [false, dateAtDayMinutes(date, minutes_in_day)];
|
---|
| 2723 | } else {
|
---|
| 2724 | if (ourminutes < minutes_from)
|
---|
| 2725 | return [false, dateAtDayMinutes(date, minutes_from)];
|
---|
| 2726 | else
|
---|
| 2727 | return [true, dateAtDayMinutes(date, minutes_to), has_open_end];
|
---|
| 2728 | }
|
---|
| 2729 | }}(minutes_from, minutes_to, timevar_string, timevar_add, has_open_end, is_point_in_time, point_in_time_period));
|
---|
[6370] | 2730 |
|
---|
[6489] | 2731 | selectors.wraptime.push(function(minutes_from, minutes_to, timevar_string, timevar_add, has_open_end, is_point_in_time, point_in_time_period) { return function(date) {
|
---|
| 2732 | var ourminutes = date.getHours() * 60 + date.getMinutes();
|
---|
[6370] | 2733 |
|
---|
[6489] | 2734 | if (timevar_string[0]) {
|
---|
| 2735 | var date_from = eval('SunCalc.getTimes(date, lat, lon).' + timevar_string[0]);
|
---|
| 2736 | minutes_from = date_from.getHours() * 60 + date_from.getMinutes() + timevar_add[0];
|
---|
| 2737 | }
|
---|
| 2738 | if (timevar_string[1]) {
|
---|
| 2739 | var date_to = eval('SunCalc.getTimes(date, lat, lon).' + timevar_string[1]);
|
---|
| 2740 | minutes_to = date_to.getHours() * 60 + date_to.getMinutes() + timevar_add[1];
|
---|
| 2741 | // minutes_in_day does not need to be added.
|
---|
| 2742 | // For normal times in it was added in: if (minutes_to < // minutes_from)
|
---|
| 2743 | // above the selector construction and
|
---|
| 2744 | // subtracted in the selector construction call
|
---|
| 2745 | // which returns the selector function.
|
---|
| 2746 | }
|
---|
[6370] | 2747 |
|
---|
[6489] | 2748 | if (typeof point_in_time_period == 'number') {
|
---|
| 2749 | if (ourminutes <= minutes_to) {
|
---|
| 2750 | for (var cur_min = 0; ourminutes + point_in_time_period >= cur_min; cur_min += point_in_time_period) {
|
---|
| 2751 | if (cur_min == ourminutes) {
|
---|
| 2752 | return [true, dateAtDayMinutes(date, ourminutes + 1)];
|
---|
| 2753 | } else if (ourminutes < cur_min) {
|
---|
| 2754 | return [false, dateAtDayMinutes(date, cur_min)];
|
---|
| 2755 | }
|
---|
| 2756 | }
|
---|
| 2757 | }
|
---|
| 2758 | } else {
|
---|
| 2759 | if (ourminutes < minutes_to)
|
---|
| 2760 | return [true, dateAtDayMinutes(date, minutes_to), has_open_end];
|
---|
| 2761 | }
|
---|
[6370] | 2762 | return [false, undefined];
|
---|
[6489] | 2763 | }}(minutes_from, minutes_to - minutes_in_day, timevar_string, timevar_add, has_open_end, is_point_in_time, point_in_time_period));
|
---|
| 2764 | } else {
|
---|
| 2765 | selectors.time.push(function(minutes_from, minutes_to, timevar_string, timevar_add, has_open_end, is_point_in_time, point_in_time_period) { return function(date) {
|
---|
| 2766 | var ourminutes = date.getHours() * 60 + date.getMinutes();
|
---|
[6370] | 2767 |
|
---|
[6489] | 2768 | if (timevar_string[0]) {
|
---|
| 2769 | var date_from = eval('SunCalc.getTimes(date, lat, lon).' + timevar_string[0]);
|
---|
| 2770 | minutes_from = date_from.getHours() * 60 + date_from.getMinutes() + timevar_add[0];
|
---|
| 2771 | }
|
---|
| 2772 | if (timevar_string[1]) {
|
---|
| 2773 | var date_to = eval('SunCalc.getTimes(date, lat, lon).' + timevar_string[1]);
|
---|
| 2774 | minutes_to = date_to.getHours() * 60 + date_to.getMinutes() + timevar_add[1];
|
---|
| 2775 | } else if (is_point_in_time && typeof point_in_time_period != 'number') {
|
---|
| 2776 | minutes_to = minutes_from + 1;
|
---|
| 2777 | }
|
---|
[6370] | 2778 |
|
---|
[6489] | 2779 | if (typeof point_in_time_period == 'number') {
|
---|
| 2780 | if (ourminutes < minutes_from) {
|
---|
| 2781 | return [false, dateAtDayMinutes(date, minutes_from)];
|
---|
| 2782 | } else if (ourminutes <= minutes_to) {
|
---|
| 2783 | for (var cur_min = minutes_from; ourminutes + point_in_time_period >= cur_min; cur_min += point_in_time_period) {
|
---|
| 2784 | if (cur_min == ourminutes) {
|
---|
| 2785 | return [true, dateAtDayMinutes(date, ourminutes + 1)];
|
---|
| 2786 | } else if (ourminutes < cur_min) {
|
---|
| 2787 | return [false, dateAtDayMinutes(date, cur_min)];
|
---|
| 2788 | }
|
---|
| 2789 | }
|
---|
| 2790 | }
|
---|
| 2791 | return [false, dateAtDayMinutes(date, minutes_in_day)];
|
---|
| 2792 | } else {
|
---|
| 2793 | if (ourminutes < minutes_from)
|
---|
| 2794 | return [false, dateAtDayMinutes(date, minutes_from)];
|
---|
| 2795 | else if (ourminutes < minutes_to)
|
---|
| 2796 | return [true, dateAtDayMinutes(date, minutes_to), has_open_end];
|
---|
| 2797 | else
|
---|
| 2798 | return [false, dateAtDayMinutes(date, minutes_from + minutes_in_day)];
|
---|
| 2799 | }
|
---|
| 2800 | }}(minutes_from, minutes_to, timevar_string, timevar_add, has_open_end, is_point_in_time, point_in_time_period));
|
---|
| 2801 | }
|
---|
[7046] | 2802 | } else {
|
---|
| 2803 | selectors.time.push(function(date) { return [true]; });
|
---|
[6370] | 2804 | }
|
---|
[7046] | 2805 |
|
---|
| 2806 | } else if (matchTokens(tokens, at, 'number', '-', 'number')) { // "Mo 09-18" (Please don’t use this) -> "Mo 09:00-18:00".
|
---|
[6420] | 2807 | var minutes_from = tokens[at][0] * 60;
|
---|
| 2808 | var minutes_to = tokens[at+2][0] * 60;
|
---|
| 2809 | if (!done_with_warnings)
|
---|
| 2810 | parsing_warnings.push([nblock, at + 2,
|
---|
| 2811 | 'Time range without minutes specified. Not very explicit! Please use this syntax instead e.g. "12:00-14:00".']);
|
---|
| 2812 |
|
---|
| 2813 | if (minutes_from >= minutes_in_day)
|
---|
| 2814 | throw formatWarnErrorMessage(nblock, at,
|
---|
| 2815 | 'Time range starts outside of the current day');
|
---|
| 2816 | if (minutes_to < minutes_from)
|
---|
| 2817 | minutes_to += minutes_in_day;
|
---|
| 2818 | if (minutes_to > minutes_in_day * 2)
|
---|
| 2819 | throw formatWarnErrorMessage(nblock, at + 2,
|
---|
| 2820 | 'Time spanning more than two midnights not supported');
|
---|
| 2821 |
|
---|
| 2822 | if (minutes_to > minutes_in_day) {
|
---|
| 2823 | selectors.time.push(function(minutes_from, minutes_to) { return function(date) {
|
---|
| 2824 | var ourminutes = date.getHours() * 60 + date.getMinutes();
|
---|
| 2825 |
|
---|
| 2826 | if (ourminutes < minutes_from)
|
---|
| 2827 | return [false, dateAtDayMinutes(date, minutes_from)];
|
---|
| 2828 | else
|
---|
| 2829 | return [true, dateAtDayMinutes(date, minutes_to)];
|
---|
| 2830 | }}(minutes_from, minutes_to));
|
---|
| 2831 |
|
---|
| 2832 | selectors.wraptime.push(function(minutes_from, minutes_to) { return function(date) {
|
---|
| 2833 | var ourminutes = date.getHours() * 60 + date.getMinutes();
|
---|
| 2834 |
|
---|
| 2835 | if (ourminutes < minutes_to)
|
---|
| 2836 | return [true, dateAtDayMinutes(date, minutes_to)];
|
---|
| 2837 | else
|
---|
| 2838 | return [false, undefined];
|
---|
| 2839 | }}(minutes_from, minutes_to - minutes_in_day));
|
---|
| 2840 | } else {
|
---|
| 2841 | selectors.time.push(function(minutes_from, minutes_to) { return function(date) {
|
---|
| 2842 | var ourminutes = date.getHours() * 60 + date.getMinutes();
|
---|
| 2843 |
|
---|
| 2844 | if (ourminutes < minutes_from)
|
---|
| 2845 | return [false, dateAtDayMinutes(date, minutes_from)];
|
---|
| 2846 | else if (ourminutes < minutes_to)
|
---|
| 2847 | return [true, dateAtDayMinutes(date, minutes_to), has_open_end];
|
---|
| 2848 | else
|
---|
| 2849 | return [false, dateAtDayMinutes(date, minutes_from + minutes_in_day)];
|
---|
| 2850 | }}(minutes_from, minutes_to));
|
---|
| 2851 | }
|
---|
| 2852 |
|
---|
| 2853 | at += 3;
|
---|
[6370] | 2854 | } else { // additional block
|
---|
| 2855 | if (matchTokens(tokens, at, '('))
|
---|
[7046] | 2856 | throw formatWarnErrorMessage(nblock, at, 'Missing variable time (e.g. sunrise) after: "' + tokens[at][1] + '"');
|
---|
[6370] | 2857 | if (matchTokens(tokens, at, 'number', 'timesep'))
|
---|
| 2858 | throw formatWarnErrorMessage(nblock, at+2, 'Missing minutes in time range after: "' + tokens[at+1][1] + '"');
|
---|
| 2859 | if (matchTokens(tokens, at, 'number'))
|
---|
| 2860 | throw formatWarnErrorMessage(nblock, at+2, 'Missing time seperator in time range after: "' + tokens[at][1] + '"');
|
---|
| 2861 | return [ at ];
|
---|
| 2862 | }
|
---|
| 2863 |
|
---|
| 2864 | if (!matchTokens(tokens, at, ','))
|
---|
| 2865 | break;
|
---|
| 2866 | }
|
---|
| 2867 |
|
---|
| 2868 | return at;
|
---|
| 2869 | }
|
---|
| 2870 |
|
---|
[7046] | 2871 | // get time in minutes from <hour>:<minute> {{{
|
---|
| 2872 | // Only used if throwing an error is wanted.
|
---|
| 2873 | function getMinutesByHoursMinutes(tokens, nblock, at) {
|
---|
| 2874 | if (tokens[at+2][0] > 59)
|
---|
| 2875 | throw formatWarnErrorMessage(nblock, at+2,
|
---|
| 2876 | 'Minutes are greater than 59.');
|
---|
| 2877 | return tokens[at][0] * 60 + tokens[at+2][0];
|
---|
[6370] | 2878 | }
|
---|
[7046] | 2879 | // }}}
|
---|
[6370] | 2880 |
|
---|
[7046] | 2881 | // get time in minutes from "(sunrise-01:30)" {{{
|
---|
| 2882 | // Extract the added or subtracted time from "(sunrise-01:30)"
|
---|
| 2883 | // returns time in minutes e.g. -90
|
---|
[6370] | 2884 | function parseTimevarCalc(tokens, at) {
|
---|
| 2885 | if (matchTokens(tokens, at+2, '+') || matchTokens(tokens, at+2, '-')) {
|
---|
| 2886 | if (matchTokens(tokens, at+3, 'number', 'timesep', 'number')) {
|
---|
| 2887 | if (matchTokens(tokens, at+6, ')')) {
|
---|
| 2888 | var add_or_subtract = tokens[at+2][0] == '+' ? '1' : '-1';
|
---|
[7046] | 2889 | var minutes = getMinutesByHoursMinutes(tokens, nblock, at+3) * add_or_subtract;
|
---|
[6489] | 2890 | if (minutes == 0)
|
---|
| 2891 | parsing_warnings.push([ nblock, at+5, 'Adding zero in a variable time calculation does not change the variable time.'
|
---|
| 2892 | + ' Please omit the calculation (example: "12:00-sunset").' ]
|
---|
| 2893 | );
|
---|
| 2894 | return minutes;
|
---|
[6370] | 2895 | } else {
|
---|
| 2896 | error = [ at+6, '. Missing ")".'];
|
---|
| 2897 | }
|
---|
| 2898 | } else {
|
---|
| 2899 | error = [ at+5, ' (time).'];
|
---|
| 2900 | }
|
---|
| 2901 | } else {
|
---|
| 2902 | error = [ at+2, '. "+" or "-" expected.'];
|
---|
| 2903 | }
|
---|
| 2904 |
|
---|
| 2905 | if (error)
|
---|
| 2906 | throw formatWarnErrorMessage(nblock, error[0],
|
---|
| 2907 | 'Calculcation with variable time is not in the right syntax' + error[1]);
|
---|
| 2908 | }
|
---|
[7046] | 2909 | // }}}
|
---|
| 2910 | // }}}
|
---|
[6370] | 2911 |
|
---|
[7046] | 2912 | // Weekday range parser (Mo,We-Fr,Sa[1-2,-1],PH) {{{
|
---|
[6370] | 2913 | function parseWeekdayRange(tokens, at, selectors) {
|
---|
| 2914 | for (; at < tokens.length; at++) {
|
---|
| 2915 | if (matchTokens(tokens, at, 'weekday', '[')) {
|
---|
| 2916 | // Conditional weekday (Mo[3])
|
---|
| 2917 | var numbers = [];
|
---|
| 2918 |
|
---|
| 2919 | // Get list of constraints
|
---|
| 2920 | var endat = parseNumRange(tokens, at+2, function(from, to, at) {
|
---|
| 2921 |
|
---|
| 2922 | // bad number
|
---|
| 2923 | if (from == 0 || from < -5 || from > 5)
|
---|
| 2924 | throw formatWarnErrorMessage(nblock, at,
|
---|
| 2925 | 'Number between -5 and 5 (except 0) expected');
|
---|
| 2926 |
|
---|
| 2927 | if (from == to) {
|
---|
| 2928 | numbers.push(from);
|
---|
| 2929 | } else if (from < to) {
|
---|
| 2930 | for (var i = from; i <= to; i++) {
|
---|
| 2931 | // bad number
|
---|
| 2932 | if (i == 0 || i < -5 || i > 5)
|
---|
| 2933 | throw formatWarnErrorMessage(nblock, at+2,
|
---|
| 2934 | 'Number between -5 and 5 (except 0) expected.');
|
---|
| 2935 |
|
---|
| 2936 | numbers.push(i);
|
---|
| 2937 | }
|
---|
| 2938 | } else {
|
---|
| 2939 | throw formatWarnErrorMessage(nblock, at+2,
|
---|
| 2940 | 'Bad range: ' + from + '-' + to);
|
---|
| 2941 | }
|
---|
| 2942 | });
|
---|
| 2943 |
|
---|
| 2944 | if (!matchTokens(tokens, endat, ']'))
|
---|
| 2945 | throw formatWarnErrorMessage(nblock, endat, '"]" or more numbers expected.');
|
---|
| 2946 |
|
---|
| 2947 | var add_days = getMoveDays(tokens, endat+1, 6, 'constrained weekdays');
|
---|
| 2948 | week_stable = false;
|
---|
| 2949 |
|
---|
| 2950 | // Create selector for each list element
|
---|
| 2951 | for (var nnumber = 0; nnumber < numbers.length; nnumber++) {
|
---|
| 2952 |
|
---|
| 2953 | selectors.weekday.push(function(weekday, number, add_days) { return function(date) {
|
---|
| 2954 | var date_num = getValueForDate(date, false); // Year not needed to distinguish.
|
---|
| 2955 | var start_of_this_month = new Date(date.getFullYear(), date.getMonth(), 1);
|
---|
| 2956 | var start_of_next_month = new Date(date.getFullYear(), date.getMonth() + 1, 1);
|
---|
| 2957 |
|
---|
| 2958 | var target_day_this_month;
|
---|
| 2959 |
|
---|
| 2960 | target_day_this_month = getDateForConstrainedWeekday(date.getFullYear(), date.getMonth(), weekday, [ number ]);
|
---|
| 2961 |
|
---|
| 2962 | var target_day_with_added_days_this_month = new Date(target_day_this_month.getFullYear(),
|
---|
| 2963 | target_day_this_month.getMonth(), target_day_this_month.getDate() + add_days);
|
---|
| 2964 |
|
---|
| 2965 | // The target day with added days can be before this month
|
---|
| 2966 | if (target_day_with_added_days_this_month.getTime() < start_of_this_month.getTime()) {
|
---|
| 2967 | // but in this case, the target day without the days added needs to be in this month
|
---|
| 2968 | if (target_day_this_month.getTime() >= start_of_this_month.getTime()) {
|
---|
| 2969 | // so we calculate it for the month
|
---|
| 2970 | // following this month and hope that the
|
---|
| 2971 | // target day will actually be this month.
|
---|
| 2972 |
|
---|
| 2973 | target_day_with_added_days_this_month = dateAtNextWeekday(
|
---|
| 2974 | new Date(date.getFullYear(), date.getMonth() + (number > 0 ? 0 : 1) + 1, 1), weekday);
|
---|
| 2975 | target_day_this_month.setDate(target_day_with_added_days_this_month.getDate()
|
---|
| 2976 | + (number + (number > 0 ? -1 : 0)) * 7 + add_days);
|
---|
| 2977 | } else {
|
---|
| 2978 | // Calculated target day is not inside this month
|
---|
| 2979 | // therefore the specified weekday (e.g. fifth Sunday)
|
---|
| 2980 | // does not exist this month. Try it next month.
|
---|
| 2981 | return [false, start_of_next_month];
|
---|
| 2982 | }
|
---|
| 2983 | } else if (target_day_with_added_days_this_month.getTime() >= start_of_next_month.getTime()) {
|
---|
| 2984 | // The target day is in the next month. If the target day without the added days is not in this month
|
---|
| 2985 | if (target_day_this_month.getTime() >= start_of_next_month.getTime())
|
---|
| 2986 | return [false, start_of_next_month];
|
---|
| 2987 | }
|
---|
| 2988 |
|
---|
| 2989 | if (add_days > 0) {
|
---|
| 2990 | var target_day_with_added_moved_days_this_month = dateAtNextWeekday(
|
---|
| 2991 | new Date(date.getFullYear(), date.getMonth() + (number > 0 ? 0 : 1) -1, 1), weekday);
|
---|
| 2992 | target_day_with_added_moved_days_this_month.setDate(target_day_with_added_moved_days_this_month.getDate()
|
---|
| 2993 | + (number + (number > 0 ? -1 : 0)) * 7 + add_days);
|
---|
| 2994 |
|
---|
| 2995 | if (date_num == getValueForDate(target_day_with_added_moved_days_this_month, false))
|
---|
| 2996 | return [true, dateAtDayMinutes(date, minutes_in_day)];
|
---|
| 2997 | } else if (add_days < 0) {
|
---|
| 2998 | var target_day_with_added_moved_days_this_month = dateAtNextWeekday(
|
---|
| 2999 | new Date(date.getFullYear(), date.getMonth() + (number > 0 ? 0 : 1) + 1, 1), weekday);
|
---|
| 3000 | target_day_with_added_moved_days_this_month.setDate(target_day_with_added_moved_days_this_month.getDate()
|
---|
| 3001 | + (number + (number > 0 ? -1 : 0)) * 7 + add_days);
|
---|
| 3002 |
|
---|
| 3003 | if (target_day_with_added_moved_days_this_month.getTime() >= start_of_next_month.getTime()) {
|
---|
| 3004 | if (target_day_with_added_days_this_month.getTime() >= start_of_next_month.getTime())
|
---|
| 3005 | return [false, target_day_with_added_moved_days_this_month];
|
---|
| 3006 | } else {
|
---|
| 3007 | if (target_day_with_added_days_this_month.getTime() < start_of_next_month.getTime()
|
---|
| 3008 | && getValueForDate(target_day_with_added_days_this_month, false) == date_num)
|
---|
| 3009 | return [true, dateAtDayMinutes(date, minutes_in_day)];
|
---|
| 3010 |
|
---|
| 3011 | target_day_with_added_days_this_month = target_day_with_added_moved_days_this_month;
|
---|
| 3012 | }
|
---|
| 3013 | }
|
---|
| 3014 |
|
---|
| 3015 | // we hit the target day
|
---|
| 3016 | if (date.getDate() == target_day_with_added_days_this_month.getDate()) {
|
---|
| 3017 | return [true, dateAtDayMinutes(date, minutes_in_day)];
|
---|
| 3018 | }
|
---|
| 3019 |
|
---|
| 3020 | // we're before target day
|
---|
| 3021 | if (date.getDate() < target_day_with_added_days_this_month.getDate()) {
|
---|
| 3022 | return [false, target_day_with_added_days_this_month];
|
---|
| 3023 | }
|
---|
| 3024 |
|
---|
| 3025 | // we're after target day, set check date to next month
|
---|
| 3026 | return [false, start_of_next_month];
|
---|
| 3027 | }}(tokens[at][0], numbers[nnumber], add_days[0]));
|
---|
| 3028 | }
|
---|
| 3029 |
|
---|
| 3030 | at = endat + 1 + add_days[1];
|
---|
| 3031 | } else if (matchTokens(tokens, at, 'weekday')) {
|
---|
| 3032 | // Single weekday (Mo) or weekday range (Mo-Fr)
|
---|
| 3033 | var is_range = matchTokens(tokens, at+1, '-', 'weekday');
|
---|
| 3034 |
|
---|
| 3035 | var weekday_from = tokens[at][0];
|
---|
| 3036 | var weekday_to = is_range ? tokens[at+2][0] : weekday_from;
|
---|
| 3037 |
|
---|
| 3038 | var inside = true;
|
---|
| 3039 |
|
---|
| 3040 | // handle reversed range
|
---|
| 3041 | if (weekday_to < weekday_from) {
|
---|
| 3042 | var tmp = weekday_to;
|
---|
| 3043 | weekday_to = weekday_from - 1;
|
---|
| 3044 | weekday_from = tmp + 1;
|
---|
| 3045 | inside = false;
|
---|
| 3046 | }
|
---|
| 3047 |
|
---|
| 3048 | if (weekday_to < weekday_from) { // handle full range
|
---|
[7046] | 3049 | selectors.weekday.push(function(date) { return [true]; });
|
---|
[6370] | 3050 | // Not needed. If there is no selector it automatically matches everything.
|
---|
[7046] | 3051 | // WRONG: This only works if there is no other selector in this selector group ...
|
---|
[6370] | 3052 | } else {
|
---|
| 3053 | selectors.weekday.push(function(weekday_from, weekday_to, inside) { return function(date) {
|
---|
| 3054 | var ourweekday = date.getDay();
|
---|
| 3055 |
|
---|
| 3056 | if (ourweekday < weekday_from || ourweekday > weekday_to) {
|
---|
| 3057 | return [!inside, dateAtNextWeekday(date, weekday_from)];
|
---|
| 3058 | } else {
|
---|
| 3059 | return [inside, dateAtNextWeekday(date, weekday_to + 1)];
|
---|
| 3060 | }
|
---|
| 3061 | }}(weekday_from, weekday_to, inside));
|
---|
| 3062 | }
|
---|
| 3063 |
|
---|
| 3064 | at += is_range ? 3 : 1;
|
---|
| 3065 | } else if (matchTokens(tokens, at, 'holiday')) {
|
---|
| 3066 | week_stable = false;
|
---|
| 3067 | return parseHoliday(tokens, at, selectors, true);
|
---|
| 3068 | } else {
|
---|
| 3069 | throw formatWarnErrorMessage(nblock, at, 'Unexpected token in weekday range: ' + tokens[at][1]);
|
---|
| 3070 | }
|
---|
| 3071 |
|
---|
| 3072 | if (!matchTokens(tokens, at, ','))
|
---|
| 3073 | break;
|
---|
| 3074 | }
|
---|
| 3075 |
|
---|
[6489] | 3076 | if (typeof used_subparsers['weekdays'] != 'object')
|
---|
| 3077 | used_subparsers['weekdays'] = [ at ];
|
---|
[6370] | 3078 | else
|
---|
[6489] | 3079 | used_subparsers['weekdays'].push(at);
|
---|
[6370] | 3080 |
|
---|
| 3081 | return at;
|
---|
| 3082 | }
|
---|
| 3083 |
|
---|
| 3084 | function getMoveDays(tokens, at, max_differ, name) {
|
---|
| 3085 | var add_days = [ 0, 0 ]; // [ 'add days', 'how many tokens' ]
|
---|
| 3086 | add_days[0] = matchTokens(tokens, at, '+') || (matchTokens(tokens, at, '-') ? -1 : 0);
|
---|
| 3087 | if (add_days[0] != 0 && matchTokens(tokens, at+1, 'number', 'calcday')) {
|
---|
| 3088 | // continues with '+ 5 days' or something like that
|
---|
| 3089 | if (tokens[at+1][0] > max_differ)
|
---|
| 3090 | throw formatWarnErrorMessage(nblock, at+2,
|
---|
| 3091 | 'There should be no reason to differ more than ' + max_differ + ' days from a ' + name + '. If so tell us …');
|
---|
| 3092 | add_days[0] *= tokens[at+1][0];
|
---|
| 3093 | if (add_days[0] == 0 && !done_with_warnings)
|
---|
| 3094 | parsing_warnings.push([ nblock, at+2, 'Adding 0 does not change the date. Please omit this.' ]);
|
---|
| 3095 | add_days[1] = 3;
|
---|
| 3096 | } else {
|
---|
| 3097 | add_days[0] = 0;
|
---|
| 3098 | }
|
---|
| 3099 | return add_days;
|
---|
| 3100 | }
|
---|
[7046] | 3101 | // }}}
|
---|
[6370] | 3102 |
|
---|
[7046] | 3103 | // Holiday parser for public and school holidays (PH,SH) {{{
|
---|
[6370] | 3104 | // push_to_weekday will push the selector into the weekday selector array which has the desired side effect of working in conjunction with the weekday selectors (either the holiday match or the weekday), which is the normal and expected behavior.
|
---|
| 3105 | function parseHoliday(tokens, at, selectors, push_to_weekday) {
|
---|
| 3106 | for (; at < tokens.length; at++) {
|
---|
| 3107 | if (matchTokens(tokens, at, 'holiday')) {
|
---|
| 3108 | if (tokens[at][0] == 'PH') {
|
---|
| 3109 | var applying_holidays = getMatchingHoliday(tokens[at][0]);
|
---|
| 3110 |
|
---|
| 3111 | // Only allow moving one day in the past or in the future.
|
---|
| 3112 | // This makes implementation easier because only one holiday is assumed to be moved to the next year.
|
---|
| 3113 | var add_days = getMoveDays(tokens, at+1, 1, 'public holiday');
|
---|
| 3114 |
|
---|
| 3115 | var selector = function(applying_holidays, add_days) { return function(date) {
|
---|
| 3116 |
|
---|
| 3117 | var holidays = getApplyingHolidaysForYear(applying_holidays, date.getFullYear(), add_days);
|
---|
| 3118 | // Needs to be calculated each time because of movable days.
|
---|
| 3119 |
|
---|
| 3120 | var date_num = getValueForDate(date, true);
|
---|
| 3121 |
|
---|
| 3122 | for (var i = 0; i < holidays.length; i++) {
|
---|
| 3123 | var next_holiday_date_num = getValueForDate(holidays[i][0], true);
|
---|
| 3124 |
|
---|
| 3125 | if (date_num < next_holiday_date_num) {
|
---|
| 3126 |
|
---|
| 3127 | if (add_days[0] > 0) {
|
---|
| 3128 | // Calculate the last holiday from previous year to tested against it.
|
---|
| 3129 | var holidays_last_year = getApplyingHolidaysForYear(applying_holidays, date.getFullYear() - 1, add_days);
|
---|
| 3130 | var last_holiday_last_year = holidays_last_year[holidays_last_year.length - 1];
|
---|
| 3131 | var last_holiday_last_year_num = getValueForDate(last_holiday_last_year[0], true);
|
---|
| 3132 |
|
---|
| 3133 | if (date_num < last_holiday_last_year_num ) {
|
---|
| 3134 | return [ false, last_holiday_last_year[0] ];
|
---|
| 3135 | } else if (date_num == last_holiday_last_year_num) {
|
---|
| 3136 | return [true, dateAtDayMinutes(last_holiday_last_year[0], minutes_in_day),
|
---|
| 3137 | 'Day after ' +last_holiday_last_year[1] ];
|
---|
| 3138 | }
|
---|
| 3139 | }
|
---|
| 3140 |
|
---|
| 3141 | return [ false, holidays[i][0] ];
|
---|
| 3142 | } else if (date_num == next_holiday_date_num) {
|
---|
| 3143 | return [true, new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1),
|
---|
| 3144 | (add_days[0] > 0 ? 'Day after ' : (add_days[0] < 0 ? 'Day before ' : '')) + holidays[i][1] ];
|
---|
| 3145 | }
|
---|
| 3146 | }
|
---|
| 3147 |
|
---|
| 3148 | if (add_days[0] < 0) {
|
---|
| 3149 | // Calculate the first holiday from next year to tested against it.
|
---|
| 3150 | var holidays_next_year = getApplyingHolidaysForYear(applying_holidays, date.getFullYear() + 1, add_days);
|
---|
| 3151 | var first_holidays_next_year = holidays_next_year[0];
|
---|
| 3152 | var first_holidays_next_year_num = getValueForDate(first_holidays_next_year[0], true);
|
---|
| 3153 | if (date_num == first_holidays_next_year_num) {
|
---|
| 3154 | return [true, dateAtDayMinutes(first_holidays_next_year[0], minutes_in_day),
|
---|
| 3155 | 'Day before ' + first_holidays_next_year[1] ];
|
---|
| 3156 | }
|
---|
| 3157 | }
|
---|
| 3158 |
|
---|
| 3159 | // continue next year
|
---|
| 3160 | return [ false, new Date(holidays[0][0].getFullYear() + 1,
|
---|
| 3161 | holidays[0][0].getMonth(),
|
---|
| 3162 | holidays[0][0].getDate()) ];
|
---|
| 3163 |
|
---|
| 3164 | }}(applying_holidays, add_days);
|
---|
| 3165 |
|
---|
| 3166 | if (push_to_weekday)
|
---|
| 3167 | selectors.weekday.push(selector);
|
---|
| 3168 | else
|
---|
| 3169 | selectors.holiday.push(selector);
|
---|
| 3170 |
|
---|
| 3171 | at += 1 + add_days[1];
|
---|
| 3172 | } else if (tokens[at][0] == 'SH') {
|
---|
| 3173 | var applying_holidays = getMatchingHoliday(tokens[at][0]);
|
---|
| 3174 |
|
---|
| 3175 | var holidays = []; // needs to be sorted each time because of movable days
|
---|
| 3176 |
|
---|
| 3177 | var selector = function(applying_holidays) { return function(date) {
|
---|
| 3178 | var date_num = getValueForDate(date);
|
---|
| 3179 |
|
---|
| 3180 | // Iterate over holiday array containing the different holiday ranges.
|
---|
| 3181 | for (var i = 0; i < applying_holidays.length; i++) {
|
---|
| 3182 |
|
---|
| 3183 | var holiday = getSHForYear(applying_holidays[i], date.getFullYear());
|
---|
| 3184 |
|
---|
| 3185 | for (var h = 0; h < holiday.length; h+=4) {
|
---|
| 3186 | var holiday_to_plus = new Date(date.getFullYear(), holiday[2+h] - 1, holiday[3+h] + 1);
|
---|
| 3187 | var holiday_from = (holiday[0+h] - 1) * 100 + holiday[1+h];
|
---|
| 3188 | var holiday_to = (holiday[2+h] - 1) * 100 + holiday[3+h];
|
---|
| 3189 | holiday_to_plus = getValueForDate(holiday_to_plus);
|
---|
| 3190 |
|
---|
| 3191 | var holiday_ends_next_year = holiday_to < holiday_from;
|
---|
| 3192 |
|
---|
| 3193 | if (date_num < holiday_from) { // date is before selected holiday
|
---|
| 3194 |
|
---|
| 3195 | // check if we are in the holidays from the last year spanning into this year
|
---|
| 3196 | var last_year_holiday = getSHForYear(applying_holidays[applying_holidays.length - 1], date.getFullYear() - 1, false);
|
---|
| 3197 | if (typeof last_year_holiday != 'undefined') {
|
---|
| 3198 | var last_year_holiday_from = (last_year_holiday[last_year_holiday.length - 4] - 1) * 100
|
---|
| 3199 | + last_year_holiday[last_year_holiday.length - 3]; // e.g. 1125
|
---|
| 3200 | var last_year_holiday_to = (last_year_holiday[last_year_holiday.length - 2] - 1) * 100
|
---|
| 3201 | + last_year_holiday[last_year_holiday.length - 1]; // e.g. 0005
|
---|
| 3202 |
|
---|
| 3203 | if (last_year_holiday_to < last_year_holiday_from && date_num < last_year_holiday_to)
|
---|
| 3204 | return [ true, new Date(date.getFullYear(),
|
---|
| 3205 | last_year_holiday[last_year_holiday.length - 2] - 1,
|
---|
| 3206 | last_year_holiday[last_year_holiday.length - 1] + 1),
|
---|
| 3207 | applying_holidays[applying_holidays.length - 1].name ];
|
---|
| 3208 | else
|
---|
| 3209 | return [ false, new Date(date.getFullYear(), holiday[0+h] - 1, holiday[1+h]) ];
|
---|
| 3210 | } else { // school holidays for last year are not defined.
|
---|
| 3211 | return [ false, new Date(date.getFullYear(), holiday[0+h] - 1, holiday[1+h]) ];
|
---|
| 3212 | }
|
---|
| 3213 | } else if (holiday_from <= date_num && (date_num < holiday_to_plus || holiday_ends_next_year)) {
|
---|
| 3214 | return [ true, new Date(date.getFullYear() + holiday_ends_next_year, holiday[2+h] - 1, holiday[3+h] + 1),
|
---|
| 3215 | applying_holidays[i].name ];
|
---|
| 3216 | } else if (holiday_to_plus == date_num) { // selected holiday end is equal to month and day
|
---|
| 3217 | if (h + 4 < holiday.length) { // next holiday is next date range of the same holidays
|
---|
| 3218 | h += 4;
|
---|
| 3219 | return [ false, new Date(date.getFullYear(), holiday[0+h] - 1, holiday[1+h]) ];
|
---|
| 3220 | } else {
|
---|
| 3221 | if (i + 1 == applying_holidays.length) { // last holidays are handled, continue all over again
|
---|
| 3222 | var holiday = getSHForYear(applying_holidays[0], date.getFullYear() + 1);
|
---|
| 3223 | return [ false, new Date(date.getFullYear() + !holiday_ends_next_year, holiday[0+h] - 1, holiday[1+h]) ];
|
---|
| 3224 | } else { // return the start of the next holidays
|
---|
| 3225 | var holiday = getSHForYear(applying_holidays[i+1], date.getFullYear());
|
---|
| 3226 | return [ false, new Date(date.getFullYear(), holiday[0] - 1, holiday[1]) ];
|
---|
| 3227 | }
|
---|
| 3228 | }
|
---|
| 3229 | }
|
---|
| 3230 | }
|
---|
| 3231 | }
|
---|
| 3232 | return [ false ];
|
---|
| 3233 | }}(applying_holidays);
|
---|
| 3234 |
|
---|
| 3235 | if (push_to_weekday)
|
---|
| 3236 | selectors.weekday.push(selector);
|
---|
| 3237 | else
|
---|
| 3238 | selectors.holiday.push(selector);
|
---|
| 3239 | at += 1;
|
---|
| 3240 | }
|
---|
| 3241 | } else if (matchTokens(tokens, at, 'weekday')) {
|
---|
| 3242 | return parseWeekdayRange(tokens, at, selectors);
|
---|
| 3243 | } else {
|
---|
| 3244 | throw formatWarnErrorMessage(nblock, at, 'Unexpected token (school holiday parser): ' + tokens[at][1]);
|
---|
| 3245 | }
|
---|
| 3246 |
|
---|
| 3247 | if (!matchTokens(tokens, at, ','))
|
---|
| 3248 | break;
|
---|
| 3249 | }
|
---|
| 3250 |
|
---|
| 3251 | return at;
|
---|
| 3252 | }
|
---|
| 3253 |
|
---|
[7046] | 3254 | // Helpers for holiday parsers {{{
|
---|
[6370] | 3255 | // Returns a number for a date which can then be used to compare just the dates (without the time).
|
---|
| 3256 | // This is necessary because a selector could be called for the middle of the day and we need to tell if it matches that day.
|
---|
| 3257 | // Example: Returns 20150015 for Jan 01 2015
|
---|
| 3258 | function getValueForDate(date, include_year) {
|
---|
| 3259 | // Implicit because undefined evaluates to false
|
---|
| 3260 | // include_year = typeof include_year != 'undefined' ? include_year : false;
|
---|
| 3261 |
|
---|
| 3262 | return (include_year ? date.getFullYear() * 10000 : 0) + date.getMonth() * 100 + date.getDate();
|
---|
| 3263 | }
|
---|
| 3264 |
|
---|
| 3265 | // return the school holiday definition e.g. [ 5, 25, /* to */ 6, 5 ],
|
---|
| 3266 | // for the specified year
|
---|
| 3267 | function getSHForYear(SH_hash, year, fatal) {
|
---|
| 3268 | if (typeof fatal == 'undefined')
|
---|
| 3269 | fatal = true;
|
---|
| 3270 |
|
---|
| 3271 | var holiday = SH_hash[year];
|
---|
| 3272 | if (typeof holiday == 'undefined') {
|
---|
| 3273 | holiday = SH_hash['default']; // applies for any year without explicit definition
|
---|
| 3274 | if (typeof holiday == 'undefined') {
|
---|
| 3275 | if (fatal) {
|
---|
| 3276 | throw 'School holiday ' + SH_hash.name + ' has no definition for the year ' + year + '.';
|
---|
| 3277 | } else {
|
---|
| 3278 | return undefined;
|
---|
| 3279 | }
|
---|
| 3280 | }
|
---|
| 3281 | }
|
---|
| 3282 | return holiday;
|
---|
| 3283 | }
|
---|
| 3284 |
|
---|
| 3285 | // Return closed holiday definition available.
|
---|
| 3286 | // First try to get the state, if missing get the country wide holidays
|
---|
| 3287 | // (which can be limited to some states).
|
---|
| 3288 | function getMatchingHoliday(type_of_holidays) {
|
---|
| 3289 | if (typeof location_cc != 'undefined') {
|
---|
| 3290 | if (holidays.hasOwnProperty(location_cc)) {
|
---|
| 3291 | if (typeof location_state != 'undefined') {
|
---|
| 3292 | if (holidays[location_cc][location_state]
|
---|
| 3293 | && holidays[location_cc][location_state][type_of_holidays]) {
|
---|
| 3294 | // if holidays for the state are specified use it
|
---|
| 3295 | // and ignore lesser specific ones (for the country)
|
---|
| 3296 | return holidays[location_cc][location_state][type_of_holidays];
|
---|
| 3297 | } else if (holidays[location_cc][type_of_holidays]) {
|
---|
| 3298 | // holidays are only defined country wide
|
---|
| 3299 | matching_holiday = {}; // holidays in the country wide scope can be limited to certain states
|
---|
| 3300 | for (var holiday_name in holidays[location_cc][type_of_holidays]) {
|
---|
| 3301 | if (typeof holidays[location_cc][type_of_holidays][holiday_name][2] === 'object') {
|
---|
| 3302 | if (-1 != indexOf.call(holidays[location_cc][type_of_holidays][holiday_name][2], location_state))
|
---|
| 3303 | matching_holiday[holiday_name] = holidays[location_cc][type_of_holidays][holiday_name];
|
---|
| 3304 | } else {
|
---|
| 3305 | matching_holiday[holiday_name] = holidays[location_cc][type_of_holidays][holiday_name];
|
---|
| 3306 | }
|
---|
| 3307 | }
|
---|
| 3308 | if (Object.keys(matching_holiday).length == 0)
|
---|
| 3309 | throw 'There are no holidays ' + type_of_holidays + ' defined for country ' + location_cc + '.'
|
---|
| 3310 | + ' Please add them: https://github.com/ypid/opening_hours.js ';
|
---|
| 3311 | return matching_holiday;
|
---|
| 3312 | } else {
|
---|
| 3313 | throw 'Holidays ' + type_of_holidays + ' are not defined for country ' + location_cc
|
---|
| 3314 | + ' and state ' + location_state + '.'
|
---|
| 3315 | + ' Please add them.';
|
---|
| 3316 | }
|
---|
| 3317 | }
|
---|
| 3318 | } else {
|
---|
| 3319 | throw 'No holidays are defined for country ' + location_cc + '. Please add them: https://github.com/ypid/opening_hours.js ';
|
---|
| 3320 | }
|
---|
| 3321 | } else { // we have no idea which holidays do apply because the country code was not provided
|
---|
| 3322 | throw 'Country code missing which is needed to select the correct holidays (see README how to provide it)'
|
---|
| 3323 | }
|
---|
| 3324 | }
|
---|
| 3325 |
|
---|
| 3326 | function getMovableEventsForYear(Y) {
|
---|
| 3327 | // calculate easter
|
---|
| 3328 | var C = Math.floor(Y/100);
|
---|
| 3329 | var N = Y - 19*Math.floor(Y/19);
|
---|
| 3330 | var K = Math.floor((C - 17)/25);
|
---|
| 3331 | var I = C - Math.floor(C/4) - Math.floor((C - K)/3) + 19*N + 15;
|
---|
| 3332 | I = I - 30*Math.floor((I/30));
|
---|
| 3333 | I = I - Math.floor(I/28)*(1 - Math.floor(I/28)*Math.floor(29/(I + 1))*Math.floor((21 - N)/11));
|
---|
| 3334 | var J = Y + Math.floor(Y/4) + I + 2 - C + Math.floor(C/4);
|
---|
| 3335 | J = J - 7*Math.floor(J/7);
|
---|
| 3336 | var L = I - J;
|
---|
| 3337 | var M = 3 + Math.floor((L + 40)/44);
|
---|
| 3338 | var D = L + 28 - 31*Math.floor(M/4);
|
---|
| 3339 |
|
---|
[7046] | 3340 | // calculate orthodox easter
|
---|
| 3341 | var oA = Y % 4;
|
---|
| 3342 | var oB = Y % 7;
|
---|
| 3343 | var oC = Y % 19;
|
---|
| 3344 | var oD = (19*oC + 15) % 30;
|
---|
| 3345 | var oE = (2*oA+4*oB - oD + 34) % 7;
|
---|
| 3346 | var oF = oD+oE
|
---|
| 3347 |
|
---|
| 3348 | if (oF < 9) {oDate = new Date(Y, 4-1, oF+4);}
|
---|
| 3349 | else {if ((oF+4)<31) {oDate = new Date(Y, 4-1, oF+4);}
|
---|
| 3350 | else {oDate = new Date(Y, 5-1, oF-26);}}
|
---|
| 3351 |
|
---|
| 3352 | // calculate last Sunday in February
|
---|
| 3353 | var lastFebruaryDay = new Date(Y, 2, 0);
|
---|
| 3354 | var lastFebruarySunday = lastFebruaryDay.getDate() - lastFebruaryDay.getDay();
|
---|
| 3355 |
|
---|
| 3356 | // calculate Victoria Day. last Monday before or on May 24
|
---|
| 3357 | var may_24 = new Date(Y, 4, 24);
|
---|
| 3358 | var victoriaDay = 24 - ((6 + may_24.getDay()) % 7);
|
---|
| 3359 |
|
---|
| 3360 | // calculate Canada Day. July 1st unless 1st is on Sunday, then July 2.
|
---|
| 3361 | var july_1 = new Date(Y, 6, 1);
|
---|
| 3362 | var canadaDay = july_1.getDay() === 0 ? 2 : 1;
|
---|
| 3363 |
|
---|
| 3364 | // calculate first Monday for each month
|
---|
| 3365 | var firstMondays = {};
|
---|
| 3366 | for (var i = 0; i < 12; i++) {
|
---|
| 3367 | var first = new Date(Y, i, 1);
|
---|
| 3368 | var firstMonday = 1 + ((8 - first.getDay()) % 7);
|
---|
| 3369 | firstMondays[i] = firstMonday;
|
---|
| 3370 | };
|
---|
| 3371 |
|
---|
[6370] | 3372 | return {
|
---|
[7046] | 3373 | 'firstFebruaryMonday': new Date(Y, 1, firstMondays[1]),
|
---|
| 3374 | 'lastFebruarySunday': new Date(Y, 1, lastFebruarySunday),
|
---|
[6370] | 3375 | 'easter': new Date(Y, M - 1, D),
|
---|
[7046] | 3376 | 'victoriaDay': new Date(Y, 4, victoriaDay),
|
---|
| 3377 | 'canadaDay': new Date(Y, 6, canadaDay),
|
---|
| 3378 | 'firstAugustMonday': new Date(Y, 7, firstMondays[7]),
|
---|
| 3379 | 'firstSeptemberMonday': new Date(Y, 8, firstMondays[8]),
|
---|
| 3380 | 'firstOctoberMonday': new Date(Y, 9, firstMondays[9]),
|
---|
| 3381 | 'orthodox easter' : oDate,
|
---|
[6370] | 3382 | };
|
---|
| 3383 | }
|
---|
| 3384 |
|
---|
| 3385 | function getApplyingHolidaysForYear(applying_holidays, year, add_days) {
|
---|
| 3386 | var movableDays = getMovableEventsForYear(year);
|
---|
| 3387 |
|
---|
| 3388 | var sorted_holidays = [];
|
---|
| 3389 |
|
---|
| 3390 | for (var holiday_name in applying_holidays) {
|
---|
| 3391 | if (typeof applying_holidays[holiday_name][0] == 'string') {
|
---|
| 3392 | var selected_movableDay = movableDays[applying_holidays[holiday_name][0]];
|
---|
| 3393 | if (!selected_movableDay)
|
---|
| 3394 | throw 'Movable day ' + applying_holidays[holiday_name][0] + ' can not not be calculated.'
|
---|
| 3395 | + ' Please add the formula how to calculate it.';
|
---|
| 3396 | var next_holiday = new Date(selected_movableDay.getFullYear(),
|
---|
| 3397 | selected_movableDay.getMonth(),
|
---|
| 3398 | selected_movableDay.getDate()
|
---|
| 3399 | + applying_holidays[holiday_name][1]
|
---|
| 3400 | );
|
---|
| 3401 | if (year != next_holiday.getFullYear())
|
---|
| 3402 | throw 'The movable day ' + applying_holidays[holiday_name][0] + ' plus '
|
---|
| 3403 | + applying_holidays[holiday_name][1]
|
---|
| 3404 | + ' days is not in the year of the movable day anymore. Currently not supported.';
|
---|
| 3405 | } else {
|
---|
| 3406 | var next_holiday = new Date(year,
|
---|
| 3407 | applying_holidays[holiday_name][0] - 1,
|
---|
| 3408 | applying_holidays[holiday_name][1]
|
---|
| 3409 | );
|
---|
| 3410 | }
|
---|
| 3411 | if (add_days[0])
|
---|
| 3412 | next_holiday.setDate(next_holiday.getDate() + add_days[0]);
|
---|
| 3413 |
|
---|
| 3414 | sorted_holidays.push([ next_holiday, holiday_name ]);
|
---|
| 3415 | }
|
---|
| 3416 |
|
---|
| 3417 | sorted_holidays = sorted_holidays.sort(function(a,b){
|
---|
| 3418 | if (a[0].getTime() < b[0].getTime()) return -1;
|
---|
| 3419 | if (a[0].getTime() > b[0].getTime()) return 1;
|
---|
| 3420 | return 0;
|
---|
| 3421 | });
|
---|
| 3422 |
|
---|
| 3423 | return sorted_holidays;
|
---|
| 3424 | }
|
---|
[7046] | 3425 | // }}}
|
---|
| 3426 | // }}}
|
---|
[6370] | 3427 |
|
---|
[7046] | 3428 | // Year range parser (2013,2016-2018,2020/2) {{{
|
---|
[6370] | 3429 | function parseYearRange(tokens, at) {
|
---|
| 3430 | for (; at < tokens.length; at++) {
|
---|
| 3431 | if (matchTokens(tokens, at, 'year')) {
|
---|
| 3432 | var is_range = false, has_period = false;
|
---|
| 3433 | if (matchTokens(tokens, at+1, '-', 'year', '/', 'number')) {
|
---|
| 3434 | var is_range = true;
|
---|
| 3435 | var has_period = true;
|
---|
[7046] | 3436 | var period = parseInt(tokens[at+4][0]);
|
---|
| 3437 | checkPeriod(at+4, period, 'year');
|
---|
[6370] | 3438 | } else {
|
---|
| 3439 | var is_range = matchTokens(tokens, at+1, '-', 'year');
|
---|
| 3440 | var has_period = matchTokens(tokens, at+1, '/', 'number');
|
---|
[7046] | 3441 | if (has_period) {
|
---|
| 3442 | var period = parseInt(tokens[at+2][0]);
|
---|
| 3443 | checkPeriod(at+2, period, 'year', 'no_end_year');
|
---|
| 3444 | } else if (matchTokens(tokens, at+1, '+')) {
|
---|
| 3445 | var period = 1;
|
---|
| 3446 | has_period = 2;
|
---|
| 3447 | }
|
---|
[6370] | 3448 | }
|
---|
| 3449 |
|
---|
[7046] | 3450 | var year_from = parseInt(tokens[at][0]);
|
---|
| 3451 | // error checking {{{
|
---|
| 3452 | if (is_range && tokens[at+2][0] <= year_from) {
|
---|
[6370] | 3453 | // handle reversed range
|
---|
[7046] | 3454 | if (tokens[at+2][0] == year_from)
|
---|
| 3455 | throw formatWarnErrorMessage(nblock, at,
|
---|
| 3456 | 'A year range in which the start year is equal to the end year does not make sense.'
|
---|
| 3457 | + ' Please remove the end year. E.g. "' + year_from + ' May 23"');
|
---|
| 3458 | else
|
---|
| 3459 | throw formatWarnErrorMessage(nblock, at,
|
---|
| 3460 | 'A year range in which the start year is greater than the end year does not make sense.'
|
---|
| 3461 | + ' Please turn it over.');
|
---|
[6370] | 3462 | }
|
---|
[7046] | 3463 | // }}}
|
---|
[6370] | 3464 |
|
---|
[7046] | 3465 | selectors.year.push(function(tokens, at, year_from, is_range, has_period, period) { return function(date) {
|
---|
| 3466 | var ouryear = date.getFullYear();
|
---|
| 3467 | var year_to = is_range ? parseInt(tokens[at+2][0]) : year_from;
|
---|
| 3468 |
|
---|
[6370] | 3469 | if (ouryear < year_from ){
|
---|
| 3470 | return [false, new Date(year_from, 0, 1)];
|
---|
| 3471 | } else if (has_period) {
|
---|
| 3472 | if (year_from <= ouryear) {
|
---|
[7046] | 3473 | if (is_range && year_to < ouryear)
|
---|
| 3474 | return [false];
|
---|
[6370] | 3475 | if (period > 0) {
|
---|
| 3476 | if ((ouryear - year_from) % period == 0) {
|
---|
| 3477 | return [true, new Date(ouryear + 1, 0, 1)];
|
---|
| 3478 | } else {
|
---|
| 3479 | return [false, new Date(ouryear + period - 1, 0, 1)];
|
---|
| 3480 | }
|
---|
| 3481 | }
|
---|
| 3482 | }
|
---|
| 3483 | } else if (is_range) {
|
---|
[7046] | 3484 | if (ouryear <= year_to)
|
---|
[6370] | 3485 | return [true, new Date(year_to + 1, 0, 1)];
|
---|
| 3486 | } else if (ouryear == year_from) {
|
---|
| 3487 | return [true];
|
---|
| 3488 | }
|
---|
| 3489 |
|
---|
| 3490 | return [false];
|
---|
| 3491 |
|
---|
[7046] | 3492 | }}(tokens, at, year_from, is_range, has_period, period));
|
---|
[6370] | 3493 |
|
---|
[7046] | 3494 | at += 1 + (is_range ? 2 : 0) + (has_period ? (has_period == 2 ? 1 : 2) : 0);
|
---|
[6370] | 3495 | } else {
|
---|
| 3496 | throw formatWarnErrorMessage(nblock, at, 'Unexpected token in year range: ' + tokens[at][1]);
|
---|
| 3497 | }
|
---|
| 3498 |
|
---|
| 3499 | if (!matchTokens(tokens, at, ','))
|
---|
| 3500 | break;
|
---|
| 3501 | }
|
---|
| 3502 |
|
---|
[6489] | 3503 | if (typeof used_subparsers['year ranges'] != 'object')
|
---|
| 3504 | used_subparsers['year ranges'] = [ at ];
|
---|
[6370] | 3505 | else
|
---|
[6489] | 3506 | used_subparsers['year ranges'].push(at);
|
---|
[6370] | 3507 |
|
---|
| 3508 | return at;
|
---|
| 3509 | }
|
---|
[7046] | 3510 | // }}}
|
---|
[6370] | 3511 |
|
---|
[7046] | 3512 | // Week range parser (week 11-20, week 1-53/2) {{{
|
---|
[6370] | 3513 | function parseWeekRange(tokens, at) {
|
---|
| 3514 | for (; at < tokens.length; at++) {
|
---|
| 3515 | if (matchTokens(tokens, at, 'number')) {
|
---|
| 3516 | var is_range = matchTokens(tokens, at+1, '-', 'number'), has_period = false;
|
---|
| 3517 | if (is_range) {
|
---|
| 3518 | has_period = matchTokens(tokens, at+3, '/', 'number');
|
---|
| 3519 | // if (week_stable) {
|
---|
| 3520 | // if (tokens[at][0] == 1 && tokens[at+2][0] >) // Maximum?
|
---|
| 3521 | // week_stable = true;
|
---|
| 3522 | // else
|
---|
| 3523 | // week_stable = false;
|
---|
| 3524 | // } else {
|
---|
| 3525 | // week_stable = false;
|
---|
| 3526 | // }
|
---|
| 3527 | }
|
---|
| 3528 |
|
---|
| 3529 | selectors.week.push(function(tokens, at, is_range, has_period) { return function(date) {
|
---|
| 3530 | var ourweek = Math.floor((date - dateAtWeek(date, 0)) / msec_in_week);
|
---|
| 3531 |
|
---|
| 3532 | var week_from = tokens[at][0] - 1;
|
---|
| 3533 | var week_to = is_range ? tokens[at+2][0] - 1 : week_from;
|
---|
| 3534 |
|
---|
| 3535 | var start_of_next_year = new Date(date.getFullYear() + 1, 0, 1);
|
---|
| 3536 |
|
---|
| 3537 | // before range
|
---|
| 3538 | if (ourweek < week_from)
|
---|
| 3539 | return [false, getMinDate(dateAtWeek(date, week_from), start_of_next_year)];
|
---|
| 3540 |
|
---|
| 3541 | // we're after range, set check date to next year
|
---|
| 3542 | if (ourweek > week_to)
|
---|
| 3543 | return [false, start_of_next_year];
|
---|
| 3544 |
|
---|
| 3545 | // we're in range
|
---|
| 3546 | var period;
|
---|
| 3547 | if (has_period) {
|
---|
| 3548 | var period = tokens[at+4][0];
|
---|
| 3549 | if (period > 1) {
|
---|
| 3550 | var in_period = (ourweek - week_from) % period == 0;
|
---|
| 3551 | if (in_period)
|
---|
| 3552 | return [true, getMinDate(dateAtWeek(date, ourweek + 1), start_of_next_year)];
|
---|
| 3553 | else
|
---|
| 3554 | return [false, getMinDate(dateAtWeek(date, ourweek + period - 1), start_of_next_year)];
|
---|
| 3555 | }
|
---|
| 3556 | }
|
---|
| 3557 |
|
---|
| 3558 | return [true, getMinDate(dateAtWeek(date, week_to + 1), start_of_next_year)];
|
---|
| 3559 | }}(tokens, at, is_range, has_period));
|
---|
| 3560 |
|
---|
| 3561 | at += 1 + (is_range ? 2 : 0) + (has_period ? 2 : 0);
|
---|
| 3562 | } else {
|
---|
| 3563 | throw formatWarnErrorMessage(nblock, at, 'Unexpected token in week range: ' + tokens[at][1]);
|
---|
| 3564 | }
|
---|
| 3565 |
|
---|
| 3566 | if (!matchTokens(tokens, at, ','))
|
---|
| 3567 | break;
|
---|
[6420] | 3568 |
|
---|
| 3569 | if (!matchTokens(tokens, at+1, 'number')) {
|
---|
| 3570 | at++; // we don‘t need the comma in parseGroup
|
---|
| 3571 | break;
|
---|
| 3572 | }
|
---|
[6370] | 3573 | }
|
---|
| 3574 |
|
---|
[6489] | 3575 | if (typeof used_subparsers['week ranges'] != 'object')
|
---|
| 3576 | used_subparsers['week ranges'] = [ at ];
|
---|
[6370] | 3577 | else
|
---|
[6489] | 3578 | used_subparsers['week ranges'].push;
|
---|
[6370] | 3579 |
|
---|
| 3580 | return at;
|
---|
| 3581 | }
|
---|
| 3582 |
|
---|
| 3583 | function dateAtWeek(date, week) {
|
---|
| 3584 | var tmpdate = new Date(date.getFullYear(), 0, 1);
|
---|
| 3585 | tmpdate.setDate(1 - (tmpdate.getDay() + 6) % 7 + week * 7); // start of week n where week starts on Monday
|
---|
| 3586 | return tmpdate;
|
---|
| 3587 | }
|
---|
| 3588 |
|
---|
| 3589 | function getMinDate(date /*, ...*/) {
|
---|
| 3590 | for (var i = 1; i < arguments.length; i++)
|
---|
| 3591 | if (arguments[i].getTime() < date.getTime())
|
---|
| 3592 | date = arguments[i];
|
---|
| 3593 | return date;
|
---|
| 3594 | }
|
---|
[7046] | 3595 | // }}}
|
---|
[6370] | 3596 |
|
---|
[7046] | 3597 | // Month range parser (Jan,Feb-Mar) {{{
|
---|
| 3598 | // push_to_monthday will push the selector into the monthday selector array which has the desired side effect of working in conjunction with the monthday selectors (either the month match or the monthday).
|
---|
| 3599 | function parseMonthRange(tokens, at, push_to_monthday) {
|
---|
[6370] | 3600 | for (; at < tokens.length; at++) {
|
---|
[7046] | 3601 | // Use parseMonthdayRange if '<month> <daynum>' and not '<month> <hour>:<minute>'
|
---|
| 3602 | if (matchTokens(tokens, at, 'month', 'number') && !matchTokens(tokens, at+2, 'timesep', 'number')) {
|
---|
| 3603 | return parseMonthdayRange(tokens, at, nblock, true);
|
---|
| 3604 | } else if (matchTokens(tokens, at, 'month')) {
|
---|
[6370] | 3605 | // Single month (Jan) or month range (Feb-Mar)
|
---|
| 3606 | var is_range = matchTokens(tokens, at+1, '-', 'month');
|
---|
| 3607 |
|
---|
| 3608 | if (is_range && week_stable) {
|
---|
| 3609 | var month_from = tokens[at][0];
|
---|
| 3610 | var month_to = tokens[at+2][0];
|
---|
| 3611 | if (month_from == (month_to + 1) % 12)
|
---|
| 3612 | week_stable = true;
|
---|
| 3613 | else
|
---|
| 3614 | week_stable = false;
|
---|
| 3615 | } else {
|
---|
| 3616 | week_stable = false;
|
---|
| 3617 | }
|
---|
| 3618 |
|
---|
[7046] | 3619 | var selector = function(tokens, at, is_range) { return function(date) {
|
---|
[6370] | 3620 | var ourmonth = date.getMonth();
|
---|
| 3621 | var month_from = tokens[at][0];
|
---|
| 3622 | var month_to = is_range ? tokens[at+2][0] : month_from;
|
---|
| 3623 |
|
---|
| 3624 | var inside = true;
|
---|
| 3625 |
|
---|
| 3626 | // handle reversed range
|
---|
| 3627 | if (month_to < month_from) {
|
---|
| 3628 | var tmp = month_to;
|
---|
| 3629 | month_to = month_from - 1;
|
---|
| 3630 | month_from = tmp + 1;
|
---|
| 3631 | inside = false;
|
---|
| 3632 | }
|
---|
| 3633 |
|
---|
| 3634 | // handle full range
|
---|
| 3635 | if (month_to < month_from)
|
---|
| 3636 | return [!inside];
|
---|
| 3637 |
|
---|
| 3638 | if (ourmonth < month_from || ourmonth > month_to) {
|
---|
| 3639 | return [!inside, dateAtNextMonth(date, month_from)];
|
---|
| 3640 | } else {
|
---|
| 3641 | return [inside, dateAtNextMonth(date, month_to + 1)];
|
---|
| 3642 | }
|
---|
[7046] | 3643 | }}(tokens, at, is_range);
|
---|
[6370] | 3644 |
|
---|
[7046] | 3645 | if (push_to_monthday === true)
|
---|
| 3646 | selectors.monthday.push(selector);
|
---|
| 3647 | else
|
---|
| 3648 | selectors.month.push(selector);
|
---|
| 3649 |
|
---|
[6370] | 3650 | at += is_range ? 3 : 1;
|
---|
| 3651 | } else {
|
---|
| 3652 | throw formatWarnErrorMessage(nblock, at, 'Unexpected token in month range: ' + tokens[at][1]);
|
---|
| 3653 | }
|
---|
| 3654 |
|
---|
| 3655 | if (!matchTokens(tokens, at, ','))
|
---|
| 3656 | break;
|
---|
| 3657 | }
|
---|
| 3658 |
|
---|
[6489] | 3659 | if (typeof used_subparsers['months'] != 'object')
|
---|
| 3660 | used_subparsers['months'] = [ at ];
|
---|
[6370] | 3661 | else
|
---|
[6489] | 3662 | used_subparsers['months'].push(at);
|
---|
[6370] | 3663 |
|
---|
| 3664 | return at;
|
---|
| 3665 | }
|
---|
| 3666 |
|
---|
| 3667 | function dateAtNextMonth(date, month) {
|
---|
| 3668 | return new Date(date.getFullYear(), month < date.getMonth() ? month + 12 : month);
|
---|
| 3669 | }
|
---|
[7046] | 3670 | // }}}
|
---|
[6370] | 3671 |
|
---|
[7046] | 3672 | // Month day range parser (Jan 26-31; Jan 26-Feb 26) {{{
|
---|
| 3673 | // push_to_month will push the selector into the month selector array which has the desired side effect of working in conjunction with the month selectors (either the month match or the monthday).
|
---|
| 3674 | function parseMonthdayRange(tokens, at, nblock, push_to_month) {
|
---|
[6370] | 3675 | for (; at < tokens.length; at++) {
|
---|
| 3676 | var has_year = [], has_month = [], has_event = [], has_calc = [], has_constrained_weekday = [], has_calc = [];
|
---|
| 3677 | has_year[0] = matchTokens(tokens, at, 'year');
|
---|
| 3678 | has_month[0] = matchTokens(tokens, at+has_year[0], 'month', 'number');
|
---|
| 3679 | has_event[0] = matchTokens(tokens, at+has_year[0], 'event');
|
---|
| 3680 | if (has_event[0])
|
---|
| 3681 | has_calc[0] = getMoveDays(tokens, at+has_year[0]+1, 200, 'event like easter');
|
---|
| 3682 |
|
---|
| 3683 | if (matchTokens(tokens, at+has_year[0], 'month', 'weekday', '[')) {
|
---|
| 3684 | has_constrained_weekday[0] = getConstrainedWeekday(tokens, at+has_year[0]+3);
|
---|
| 3685 | has_calc[0] = getMoveDays(tokens, has_constrained_weekday[0][1], 6, 'constrained weekdays');
|
---|
| 3686 | var at_range_sep = has_constrained_weekday[0][1] + (typeof has_calc[0] != 'undefined' && has_calc[0][1] ? 3 : 0);
|
---|
| 3687 | } else {
|
---|
| 3688 | var at_range_sep = at+has_year[0]
|
---|
| 3689 | + (has_event[0]
|
---|
| 3690 | ? (typeof has_calc[0] != 'undefined' && has_calc[0][1] ? 4 : 1)
|
---|
| 3691 | : 2);
|
---|
| 3692 | }
|
---|
| 3693 |
|
---|
| 3694 | if ((has_month[0] || has_event[0] || has_constrained_weekday[0]) && matchTokens(tokens, at_range_sep, '-')) {
|
---|
| 3695 | has_year[1] = matchTokens(tokens, at_range_sep+1, 'year');
|
---|
| 3696 | var at_sec_event_or_month = at_range_sep+1+has_year[1];
|
---|
| 3697 | has_month[1] = matchTokens(tokens, at_sec_event_or_month, 'month', 'number');
|
---|
| 3698 | if (!has_month[1]) {
|
---|
| 3699 | has_event[1] = matchTokens(tokens, at_sec_event_or_month, 'event');
|
---|
| 3700 | if (has_event[1]) {
|
---|
| 3701 | has_calc[1] = getMoveDays(tokens, at_sec_event_or_month+1, 366, 'event like easter');
|
---|
| 3702 | } else if (matchTokens(tokens, at_sec_event_or_month, 'month', 'weekday', '[')) {
|
---|
| 3703 | has_constrained_weekday[1] = getConstrainedWeekday(tokens, at_sec_event_or_month+3);
|
---|
| 3704 | has_calc[1] = getMoveDays(tokens, has_constrained_weekday[1][1], 6, 'constrained weekdays');
|
---|
| 3705 | }
|
---|
| 3706 | }
|
---|
| 3707 | }
|
---|
| 3708 |
|
---|
[7046] | 3709 | // monthday range like Jan 26-Feb 26 {{{
|
---|
[6370] | 3710 | if (has_year[0] == has_year[1] && (has_month[1] || has_event[1] || has_constrained_weekday[1])) {
|
---|
| 3711 |
|
---|
[7046] | 3712 | if (has_month[0])
|
---|
| 3713 | isValidDate(tokens[at+has_year[0]][0], tokens[at+has_year[0]+1][0], nblock, at+has_year[0]+1);
|
---|
| 3714 | if (has_month[1])
|
---|
| 3715 | isValidDate(tokens[at_sec_event_or_month][0], tokens[at_sec_event_or_month+1][0], nblock, at+has_year[0]+1);
|
---|
| 3716 |
|
---|
| 3717 | var selector = function(tokens, at, nblock, has_year, has_event, has_calc, at_sec_event_or_month, has_constrained_weekday) { return function(date) {
|
---|
[6370] | 3718 | var start_of_next_year = new Date(date.getFullYear() + 1, 0, 1);
|
---|
| 3719 |
|
---|
| 3720 | if (has_event[0]) {
|
---|
| 3721 | var movableDays = getMovableEventsForYear(has_year[0] ? parseInt(tokens[at][0]) : date.getFullYear());
|
---|
| 3722 | var from_date = movableDays[tokens[at+has_year[0]][0]];
|
---|
| 3723 |
|
---|
| 3724 | if (typeof has_calc[0] != 'undefined' && has_calc[0][1]) {
|
---|
| 3725 | var from_year_before_calc = from_date.getFullYear();
|
---|
| 3726 | from_date.setDate(from_date.getDate() + has_calc[0][0]);
|
---|
| 3727 | if (from_year_before_calc != from_date.getFullYear())
|
---|
| 3728 | throw formatWarnErrorMessage(nblock, at+has_year[0]+has_calc[0][1]*3,
|
---|
| 3729 | 'The movable day ' + tokens[at+has_year[0]][0] + ' plus ' + has_calc[0][0]
|
---|
| 3730 | + ' days is not in the year of the movable day anymore. Currently not supported.');
|
---|
| 3731 | }
|
---|
| 3732 | } else if (has_constrained_weekday[0]) {
|
---|
| 3733 | var from_date = getDateForConstrainedWeekday((has_year[0] ? tokens[at][0] : date.getFullYear()), // year
|
---|
| 3734 | tokens[at+has_year[0]][0], // month
|
---|
| 3735 | tokens[at+has_year[0]+1][0], // weekday
|
---|
| 3736 | has_constrained_weekday[0],
|
---|
| 3737 | has_calc[0]);
|
---|
| 3738 | // var from_date_without_calc = getDateForConstrainedWeekday((has_year[0] ? tokens[at][0] : date.getFullYear()), // year
|
---|
| 3739 | // tokens[at+has_year[0]][0], // month
|
---|
| 3740 | // tokens[at+has_year[0]+1][0], // weekday
|
---|
| 3741 | // has_constrained_weekday[0],
|
---|
| 3742 | // [ 0, 0 ]);
|
---|
| 3743 | // if (from_date_without_calc.getFullYear() != from_date.getFullYear())
|
---|
| 3744 | // throw formatWarnErrorMessage(nblock, at+has_year[0]+has_calc[0][1],
|
---|
| 3745 | // 'The constrained ' + weekdays[tokens[at+has_year[0]+1][0]] + ' plus ' + has_calc[0][0]
|
---|
| 3746 | // + ' days is not in the year of the movable day anymore. Currently not supported.');
|
---|
| 3747 | } else {
|
---|
| 3748 | var from_date = new Date((has_year[0] ? tokens[at][0] : date.getFullYear()),
|
---|
| 3749 | tokens[at+has_year[0]][0], tokens[at+has_year[0]+1][0]);
|
---|
| 3750 | }
|
---|
| 3751 |
|
---|
| 3752 | if (has_event[1]) {
|
---|
| 3753 | var movableDays = getMovableEventsForYear(has_year[1]
|
---|
| 3754 | ? parseInt(tokens[at_sec_event_or_month-1][0])
|
---|
| 3755 | : date.getFullYear());
|
---|
| 3756 | var to_date = movableDays[tokens[at_sec_event_or_month][0]];
|
---|
| 3757 |
|
---|
| 3758 | if (typeof has_calc[1] != 'undefined' && has_calc[1][1]) {
|
---|
| 3759 | var to_year_before_calc = to_date.getFullYear();
|
---|
| 3760 | to_date.setDate(to_date.getDate() + has_calc[1][0]);
|
---|
| 3761 | if (to_year_before_calc != to_date.getFullYear())
|
---|
| 3762 | throw formatWarnErrorMessage(nblock, at_sec_event_or_month+has_calc[1][1],
|
---|
| 3763 | 'The movable day ' + tokens[at_sec_event_or_month][0] + ' plus ' + has_calc[1][0]
|
---|
| 3764 | + ' days is not in the year of the movable day anymore. Currently not supported.');
|
---|
| 3765 | }
|
---|
| 3766 | } else if (has_constrained_weekday[1]) {
|
---|
| 3767 | var to_date = getDateForConstrainedWeekday((has_year[1] ? tokens[at_sec_event_or_month-1][0] : date.getFullYear()), // year
|
---|
| 3768 | tokens[at_sec_event_or_month][0], // month
|
---|
| 3769 | tokens[at_sec_event_or_month+1][0], // weekday
|
---|
| 3770 | has_constrained_weekday[1],
|
---|
| 3771 | has_calc[1]);
|
---|
| 3772 | } else {
|
---|
| 3773 | var to_date = new Date((has_year[1] ? tokens[at_sec_event_or_month-1][0] : date.getFullYear()),
|
---|
| 3774 | tokens[at_sec_event_or_month][0], tokens[at_sec_event_or_month+1][0] + 1);
|
---|
| 3775 | }
|
---|
| 3776 |
|
---|
| 3777 | var inside = true;
|
---|
| 3778 |
|
---|
| 3779 | if (to_date < from_date) {
|
---|
| 3780 | var tmp = to_date;
|
---|
| 3781 | to_date = from_date;
|
---|
| 3782 | from_date = tmp;
|
---|
| 3783 | inside = false;
|
---|
| 3784 | }
|
---|
| 3785 |
|
---|
| 3786 | if (date.getTime() < from_date.getTime()) {
|
---|
| 3787 | return [!inside, from_date];
|
---|
| 3788 | } else if (date.getTime() < to_date.getTime()) {
|
---|
| 3789 | return [inside, to_date];
|
---|
| 3790 | } else {
|
---|
| 3791 | if (has_year[0]) {
|
---|
| 3792 | return [!inside];
|
---|
| 3793 | } else {
|
---|
| 3794 | // // back matching, if from_date is moved to last year
|
---|
| 3795 | // var from_date_next_year = getDateForConstrainedWeekday(date.getFullYear() + 1, // year
|
---|
| 3796 | // tokens[at+has_year[0]][0], // month
|
---|
| 3797 | // tokens[at+has_year[0]+1][0], // weekday
|
---|
| 3798 | // has_constrained_weekday[0],
|
---|
| 3799 | // has_calc[0]);
|
---|
| 3800 | // if (date.getFullYear() == from_date_next_year.getFullYear()) {
|
---|
| 3801 | // if (date.getTime() < from_date_next_year.getTime()) {
|
---|
| 3802 | // return [!inside, from_date_next_year];
|
---|
| 3803 | // }
|
---|
| 3804 | // }
|
---|
| 3805 |
|
---|
| 3806 | return [!inside, start_of_next_year];
|
---|
| 3807 | }
|
---|
| 3808 | }
|
---|
[7046] | 3809 | }}(tokens, at, nblock, has_year, has_event, has_calc, at_sec_event_or_month, has_constrained_weekday);
|
---|
[6370] | 3810 |
|
---|
[7046] | 3811 | if (push_to_month === true)
|
---|
| 3812 | selectors.month.push(selector);
|
---|
| 3813 | else
|
---|
| 3814 | selectors.monthday.push(selector);
|
---|
| 3815 |
|
---|
[6370] | 3816 | at = (has_constrained_weekday[1]
|
---|
| 3817 | ? has_constrained_weekday[1][1]
|
---|
| 3818 | : at_sec_event_or_month + (has_event[1] ? 1 : 2))
|
---|
| 3819 | + (typeof has_calc[1] != 'undefined' ? has_calc[1][1] : 0);
|
---|
| 3820 |
|
---|
[7046] | 3821 | // }}}
|
---|
| 3822 | // Monthday range like Jan 26-31 {{{
|
---|
[6370] | 3823 | } else if (has_month[0]) {
|
---|
| 3824 |
|
---|
[7046] | 3825 | has_year = has_year[0];
|
---|
| 3826 | var year = tokens[at][0]; // Could be month if has no year. Tested later.
|
---|
| 3827 | var month = tokens[at+has_year][0];
|
---|
[6370] | 3828 |
|
---|
[7046] | 3829 | var first_round = true;
|
---|
[6370] | 3830 |
|
---|
[7046] | 3831 | do {
|
---|
| 3832 | var range_from = tokens[at+1 + has_year][0];
|
---|
| 3833 | var is_range = matchTokens(tokens, at+2+has_year, '-', 'number');
|
---|
| 3834 | var period = undefined;
|
---|
| 3835 | var range_to = tokens[at+has_year+(is_range ? 3 : 1)][0] + 1;
|
---|
| 3836 | if (is_range && matchTokens(tokens, at+has_year+4, '/', 'number')) {
|
---|
| 3837 | period = tokens[at+has_year+5][0];
|
---|
| 3838 | checkPeriod(at+has_year+5, period, 'day');
|
---|
| 3839 | }
|
---|
[6370] | 3840 |
|
---|
[7046] | 3841 | if (first_round) {
|
---|
| 3842 | var at_timesep_if_monthRange = at + has_year + 1 // at month number
|
---|
| 3843 | + (is_range ? 2 : 0) + (period ? 2 : 0)
|
---|
| 3844 | + !(is_range || period); // if not range nor has period, add one
|
---|
[6370] | 3845 |
|
---|
[7046] | 3846 | // Check for '<month> <timespan>'
|
---|
| 3847 | if (matchTokens(tokens, at_timesep_if_monthRange, 'timesep', 'number')
|
---|
| 3848 | && (matchTokens(tokens, at_timesep_if_monthRange+2, '+')
|
---|
| 3849 | || matchTokens(tokens, at_timesep_if_monthRange+2, '-')
|
---|
| 3850 | || oh_mode != 0))
|
---|
| 3851 | return parseMonthRange(tokens, at);
|
---|
| 3852 | }
|
---|
[6370] | 3853 |
|
---|
[7046] | 3854 | // error checking {{{
|
---|
| 3855 | if (range_to < range_from)
|
---|
| 3856 | throw formatWarnErrorMessage(nblock, at+has_year+3,
|
---|
| 3857 | 'Range in wrong order. From day is greater than to day.');
|
---|
| 3858 | isValidDate(month, range_from, nblock, at+1 + has_year);
|
---|
| 3859 | isValidDate(month, range_to - 1 /* added previously */,
|
---|
| 3860 | nblock, at+has_year+(is_range ? 3 : 1));
|
---|
| 3861 | // }}}
|
---|
[6370] | 3862 |
|
---|
[7046] | 3863 | var selector = function(year, has_year, month, range_from, range_to, period) { return function(date) {
|
---|
| 3864 | var start_of_next_year = new Date(date.getFullYear() + 1, 0, 1);
|
---|
[6370] | 3865 |
|
---|
[7046] | 3866 | var from_date = new Date(has_year ? year : date.getFullYear(),
|
---|
| 3867 | month, range_from);
|
---|
| 3868 | if (month == 1 && range_from != from_date.getDate()) // Only on leap years does this day exist.
|
---|
| 3869 | return [false]; // If day 29 does not exist,
|
---|
| 3870 | // then the date object adds one day to date
|
---|
| 3871 | // and this selector should not match.
|
---|
| 3872 | var to_date = new Date(from_date.getFullYear(),
|
---|
| 3873 | month, range_to);
|
---|
| 3874 | if (month == 1 && is_range && range_to != to_date.getDate()) // Only on leap years does this day exist.
|
---|
| 3875 | return [false];
|
---|
| 3876 |
|
---|
| 3877 | if (date.getTime() < from_date.getTime())
|
---|
| 3878 | return [false, from_date];
|
---|
| 3879 | else if (date.getTime() >= to_date.getTime())
|
---|
| 3880 | return [false, start_of_next_year];
|
---|
| 3881 | else if (!period)
|
---|
| 3882 | return [true, to_date];
|
---|
| 3883 |
|
---|
| 3884 | var nday = Math.floor((date.getTime() - from_date.getTime()) / msec_in_day);
|
---|
| 3885 | var in_period = nday % period;
|
---|
| 3886 |
|
---|
| 3887 | if (in_period == 0)
|
---|
| 3888 | return [true, new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1)];
|
---|
| 3889 | else
|
---|
| 3890 | return [false, new Date(date.getFullYear(), date.getMonth(), date.getDate() + period - in_period)];
|
---|
| 3891 |
|
---|
| 3892 | }}(year, has_year, month, range_from, range_to, period);
|
---|
| 3893 |
|
---|
| 3894 | if (push_to_month === true)
|
---|
| 3895 | selectors.month.push(selector);
|
---|
[6370] | 3896 | else
|
---|
[7046] | 3897 | selectors.monthday.push(selector);
|
---|
[6420] | 3898 |
|
---|
[7046] | 3899 | at += 2 + has_year + (is_range ? 2 : 0) + (period ? 2 : 0);
|
---|
[6370] | 3900 |
|
---|
[7046] | 3901 | first_round = false;
|
---|
| 3902 | }
|
---|
| 3903 | while (matchTokens(tokens, at, ',', 'number'))
|
---|
[6370] | 3904 |
|
---|
[7046] | 3905 |
|
---|
| 3906 | // }}}
|
---|
| 3907 | // Only event like easter {{{
|
---|
[6370] | 3908 | } else if (has_event[0]) {
|
---|
| 3909 |
|
---|
[7046] | 3910 | var selector = function(tokens, at, nblock, has_year, add_days) { return function(date) {
|
---|
[6370] | 3911 |
|
---|
| 3912 | // console.log('enter selector with date: ' + date);
|
---|
| 3913 | var movableDays = getMovableEventsForYear((has_year ? tokens[at][0] : date.getFullYear()));
|
---|
| 3914 | var event_date = movableDays[tokens[at+has_year][0]];
|
---|
| 3915 | if (!event_date)
|
---|
| 3916 | throw 'Movable day ' + tokens[at+has_year][0] + ' can not not be calculated.'
|
---|
| 3917 | + ' Please add the formula how to calculate it.';
|
---|
| 3918 |
|
---|
| 3919 | if (add_days[0]) {
|
---|
| 3920 | event_date.setDate(event_date.getDate() + add_days[0]);
|
---|
| 3921 | if (date.getFullYear() != event_date.getFullYear())
|
---|
| 3922 | throw formatWarnErrorMessage(nblock, at+has_year+add_days[1], 'The movable day ' + tokens[at+has_year][0] + ' plus '
|
---|
| 3923 | + add_days[0]
|
---|
| 3924 | + ' days is not in the year of the movable day anymore. Currently not supported.');
|
---|
| 3925 | }
|
---|
| 3926 |
|
---|
| 3927 | if (date.getTime() < event_date.getTime())
|
---|
| 3928 | return [false, event_date];
|
---|
| 3929 | // else if (date.getTime() < event_date.getTime() + msec_in_day) // does not work because of daylight saving times
|
---|
| 3930 | else if (event_date.getMonth() * 100 + event_date.getDate() == date.getMonth() * 100 + date.getDate())
|
---|
| 3931 | return [true, new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1)];
|
---|
| 3932 | else
|
---|
| 3933 | return [false, new Date(date.getFullYear() + 1, 0, 1)];
|
---|
| 3934 |
|
---|
[7046] | 3935 | }}(tokens, at, nblock, has_year[0], has_calc[0]);
|
---|
[6370] | 3936 |
|
---|
[7046] | 3937 | if (push_to_month === true)
|
---|
| 3938 | selectors.month.push(selector);
|
---|
| 3939 | else
|
---|
| 3940 | selectors.monthday.push(selector);
|
---|
| 3941 |
|
---|
[6370] | 3942 | at += has_year[0] + has_event[0] + (typeof has_calc[0][1] != 'undefined' && has_calc[0][1] ? 3 : 0);
|
---|
[7046] | 3943 | // }}}
|
---|
[6370] | 3944 | } else if (has_constrained_weekday[0]) {
|
---|
| 3945 | at = parseMonthRange(tokens, at);
|
---|
| 3946 | } else if (matchTokens(tokens, at, 'month')) {
|
---|
[7046] | 3947 | return parseMonthRange(tokens, at, true);
|
---|
[6370] | 3948 | } else {
|
---|
| 3949 | // throw 'Unexpected token in monthday range: "' + tokens[at] + '"';
|
---|
| 3950 | return at;
|
---|
| 3951 | }
|
---|
| 3952 |
|
---|
| 3953 | if (!matchTokens(tokens, at, ','))
|
---|
| 3954 | break;
|
---|
| 3955 | }
|
---|
| 3956 |
|
---|
[6489] | 3957 | if (typeof used_subparsers['monthday ranges'] != 'object')
|
---|
| 3958 | used_subparsers['monhday ranges'] = [ at ];
|
---|
[6370] | 3959 | else
|
---|
[6489] | 3960 | used_subparsers['monhday ranges'].push(at);
|
---|
[6370] | 3961 |
|
---|
| 3962 | return at;
|
---|
| 3963 | }
|
---|
[7046] | 3964 | // }}}
|
---|
[6370] | 3965 |
|
---|
[7046] | 3966 | // Main selector traversal function (return state array for date) {{{
|
---|
[6370] | 3967 | this.getStatePair = function(date) {
|
---|
| 3968 | var resultstate = false;
|
---|
| 3969 | var changedate;
|
---|
| 3970 | var unknown = false;
|
---|
[6489] | 3971 | var comment;
|
---|
[6370] | 3972 | var match_block;
|
---|
| 3973 |
|
---|
| 3974 | var date_matching_blocks = [];
|
---|
| 3975 |
|
---|
| 3976 | for (var nblock = 0; nblock < blocks.length; nblock++) {
|
---|
| 3977 | var matching_date_block = true;
|
---|
| 3978 | // console.log(nblock, 'length', blocks[nblock].date.length);
|
---|
| 3979 |
|
---|
| 3980 | // Try each date selector type
|
---|
| 3981 | for (var ndateselector = 0; ndateselector < blocks[nblock].date.length; ndateselector++) {
|
---|
| 3982 | var dateselectors = blocks[nblock].date[ndateselector];
|
---|
| 3983 | // console.log(nblock, ndateselector);
|
---|
| 3984 |
|
---|
| 3985 | var has_matching_selector = false;
|
---|
| 3986 | for (var datesel = 0; datesel < dateselectors.length; datesel++) {
|
---|
| 3987 | var res = dateselectors[datesel](date);
|
---|
| 3988 | if (res[0]) {
|
---|
| 3989 | has_matching_selector = true;
|
---|
| 3990 |
|
---|
| 3991 | if (typeof res[2] == 'string') { // holiday name
|
---|
| 3992 | comment = [ res[2] ];
|
---|
| 3993 | }
|
---|
| 3994 |
|
---|
| 3995 | }
|
---|
| 3996 | if (typeof changedate === 'undefined' || (typeof res[1] !== 'undefined' && res[1].getTime() < changedate.getTime()))
|
---|
| 3997 | changedate = res[1];
|
---|
| 3998 | }
|
---|
| 3999 |
|
---|
| 4000 | if (!has_matching_selector) {
|
---|
| 4001 | matching_date_block = false;
|
---|
| 4002 | // We can ignore other date selectors, as the state won't change
|
---|
| 4003 | // anyway until THIS selector matches (due to conjunction of date
|
---|
| 4004 | // selectors of different types).
|
---|
| 4005 | // This is also an optimization, if widest date selector types
|
---|
| 4006 | // are checked first.
|
---|
| 4007 | break;
|
---|
| 4008 | }
|
---|
| 4009 |
|
---|
| 4010 | }
|
---|
| 4011 |
|
---|
| 4012 | if (matching_date_block) {
|
---|
| 4013 | // The following lines implement date overwriting logic (e.g. for
|
---|
| 4014 | // "Mo-Fr 10:00-20:00; We 10:00-16:00", We block overrides Mo-Fr block.
|
---|
| 4015 | //
|
---|
| 4016 | // This is the only way to be consistent. I thought about ("22:00-02:00; Tu 12:00-14:00") letting Th override 22:00-02:00 partly:
|
---|
| 4017 | // Like: Th 00:00-02:00,12:00-14:00 but this would result in including 22:00-00:00 for Th which is probably not what you want.
|
---|
| 4018 | if (blocks[nblock].date.length > 0 && (blocks[nblock].meaning || blocks[nblock].unknown)
|
---|
| 4019 | && !blocks[nblock].wrapped && !blocks[nblock].additional && !blocks[nblock].fallback) {
|
---|
| 4020 | // var old_date_matching_blocks = date_matching_blocks;
|
---|
| 4021 | date_matching_blocks = [];
|
---|
| 4022 | // for (var nblock = 0; nblock < old_date_matching_blocks.length; nblock++) {
|
---|
| 4023 | // if (!blocks[old_date_matching_blocks[nblock]].wrapped)
|
---|
| 4024 | // date_matching_blocks.push(nblock);
|
---|
| 4025 | // }
|
---|
| 4026 | }
|
---|
| 4027 | date_matching_blocks.push(nblock);
|
---|
| 4028 | }
|
---|
| 4029 | }
|
---|
| 4030 |
|
---|
| 4031 | block:
|
---|
| 4032 | for (var nblock = 0; nblock < date_matching_blocks.length; nblock++) {
|
---|
| 4033 | var block = date_matching_blocks[nblock];
|
---|
| 4034 |
|
---|
| 4035 | // console.log('Processing block ' + block + ':\t' + blocks[block].comment + ' with date', date,
|
---|
| 4036 | // 'and', blocks[block].time.length, 'time selectors');
|
---|
| 4037 |
|
---|
| 4038 | // there is no time specified, state applies to the whole day
|
---|
| 4039 | if (blocks[block].time.length == 0) {
|
---|
| 4040 | // console.log('there is no time', date);
|
---|
| 4041 | if (!blocks[block].fallback || (blocks[block].fallback && !(resultstate || unknown))) {
|
---|
| 4042 | resultstate = blocks[block].meaning;
|
---|
| 4043 | unknown = blocks[block].unknown;
|
---|
| 4044 | match_block = block;
|
---|
| 4045 |
|
---|
| 4046 | if (typeof blocks[block].comment != 'undefined')
|
---|
| 4047 | comment = blocks[block].comment;
|
---|
| 4048 | else if (typeof comment == 'object') // holiday name
|
---|
| 4049 | comment = comment[0];
|
---|
| 4050 |
|
---|
| 4051 | if (blocks[block].fallback)
|
---|
| 4052 | break block; // fallback block matched, no need for checking the rest
|
---|
| 4053 | }
|
---|
| 4054 | }
|
---|
| 4055 |
|
---|
| 4056 | for (var timesel = 0; timesel < blocks[block].time.length; timesel++) {
|
---|
| 4057 | var res = blocks[block].time[timesel](date);
|
---|
| 4058 |
|
---|
| 4059 | // console.log('res:', res);
|
---|
| 4060 | if (res[0]) {
|
---|
| 4061 | if (!blocks[block].fallback || (blocks[block].fallback && !(resultstate || unknown))) {
|
---|
| 4062 | resultstate = blocks[block].meaning;
|
---|
| 4063 | unknown = blocks[block].unknown;
|
---|
| 4064 | match_block = block;
|
---|
| 4065 |
|
---|
[7046] | 4066 | if (typeof blocks[block].comment == 'string') // only use comment if one is specified
|
---|
[6370] | 4067 | comment = blocks[block].comment;
|
---|
| 4068 | else if (typeof comment == 'object') // holiday name
|
---|
| 4069 | comment = comment[0];
|
---|
| 4070 | else if (comment === 'Specified as open end. Closing time was guessed.')
|
---|
| 4071 | comment = blocks[block].comment;
|
---|
| 4072 |
|
---|
| 4073 | // open end
|
---|
| 4074 | if (typeof res[2] == 'boolean' && res[2] && (resultstate || unknown)) {
|
---|
| 4075 | if (typeof comment == 'undefined')
|
---|
| 4076 | comment = 'Specified as open end. Closing time was guessed.';
|
---|
| 4077 | resultstate = false;
|
---|
| 4078 | unknown = true;
|
---|
| 4079 | }
|
---|
| 4080 |
|
---|
| 4081 | if (blocks[block].fallback) {
|
---|
| 4082 | if (typeof changedate === 'undefined' || (typeof res[1] !== 'undefined' && res[1] < changedate))
|
---|
| 4083 | changedate = res[1];
|
---|
| 4084 |
|
---|
[7046] | 4085 | // break block; // Fallback block matched, no need for checking the rest.
|
---|
| 4086 | // WRONG: What if 'off' is used after fallback block.
|
---|
[6370] | 4087 | }
|
---|
| 4088 | }
|
---|
| 4089 | }
|
---|
| 4090 | if (typeof changedate === 'undefined' || (typeof res[1] !== 'undefined' && res[1] < changedate))
|
---|
| 4091 | changedate = res[1];
|
---|
| 4092 | }
|
---|
| 4093 | }
|
---|
| 4094 |
|
---|
| 4095 | // console.log('changedate', changedate, resultstate, comment, match_block);
|
---|
| 4096 | return [ resultstate, changedate, unknown, comment, match_block ];
|
---|
| 4097 | }
|
---|
[7046] | 4098 | // }}}
|
---|
[6370] | 4099 |
|
---|
[7174] | 4100 | // Generate prettified value based on tokens {{{
|
---|
[6370] | 4101 | function prettifySelector(tokens, at, last_at, conf, used_parseTimeRange) {
|
---|
| 4102 | var value = '';
|
---|
| 4103 | var start_at = at;
|
---|
| 4104 | while (at < last_at) {
|
---|
[6420] | 4105 | if (matchTokens(tokens, at, 'weekday')) { // FIXME
|
---|
[6370] | 4106 | if (!conf.leave_weekday_sep_one_day_betw
|
---|
| 4107 | && at - start_at > 1 && (matchTokens(tokens, at-1, ',') || matchTokens(tokens, at-1, '-'))
|
---|
| 4108 | && matchTokens(tokens, at-2, 'weekday')
|
---|
| 4109 | && tokens[at][0] == (tokens[at-2][0] + 1) % 7) {
|
---|
| 4110 | value = value.substring(0, value.length - 1) + conf.sep_one_day_between;
|
---|
| 4111 | }
|
---|
| 4112 | value += weekdays[tokens[at][0]];
|
---|
[7174] | 4113 | } else if (at - start_at > 0 // e.g. '09:0' -> '09:00'
|
---|
| 4114 | && used_parseTimeRange > 0
|
---|
| 4115 | && matchTokens(tokens, at-1, 'timesep')
|
---|
| 4116 | && matchTokens(tokens, at, 'number')) {
|
---|
[6370] | 4117 | value += (tokens[at][0] < 10 ? '0' : '') + tokens[at][0].toString();
|
---|
[7174] | 4118 | } else if (used_parseTimeRange > 0 // e.g. '9:00' -> ' 09:00'
|
---|
| 4119 | && conf.leading_zero_hour
|
---|
| 4120 | && at != tokens.length
|
---|
[6420] | 4121 | && matchTokens(tokens, at, 'number')
|
---|
[7174] | 4122 | && matchTokens(tokens, at+1, 'timesep')) {
|
---|
| 4123 | value += (
|
---|
| 4124 | tokens[at][0] < 10 ?
|
---|
| 4125 | (tokens[at][0] == 0 && conf.one_zero_if_hour_zero ?
|
---|
| 4126 | '' : '0') :
|
---|
| 4127 | '') + tokens[at][0].toString();
|
---|
| 4128 | } else if (used_parseTimeRange > 0 // e.g. '9-18' -> '09:00-18:00'
|
---|
| 4129 | && at + 2 < last_at
|
---|
[6420] | 4130 | && matchTokens(tokens, at, 'number')
|
---|
| 4131 | && matchTokens(tokens, at+1, '-')
|
---|
[7174] | 4132 | && matchTokens(tokens, at+2, 'number')) {
|
---|
| 4133 | value += (tokens[at][0] < 10 ?
|
---|
| 4134 | (tokens[at][0] == 0 && conf.one_zero_if_hour_zero ? '' : '0')
|
---|
| 4135 | : '') + tokens[at][0].toString();
|
---|
| 4136 | value += ':00-'
|
---|
| 4137 | + (tokens[at+2][0] < 10 ? '0' : '') + tokens[at+2][0].toString()
|
---|
| 4138 | + ':00';
|
---|
[6489] | 4139 | at += 2;
|
---|
[6370] | 4140 | } else if (matchTokens(tokens, at, 'comment')) {
|
---|
| 4141 | value += '"' + tokens[at][0].toString() + '"';
|
---|
| 4142 | } else if (matchTokens(tokens, at, 'closed')) {
|
---|
| 4143 | value += (conf.leave_off_closed ? tokens[at][0] : conf.keyword_for_off_closed);
|
---|
| 4144 | } else if (at - start_at > 0 && matchTokens(tokens, at, 'number')
|
---|
| 4145 | && (matchTokens(tokens, at-1, 'month')
|
---|
| 4146 | || matchTokens(tokens, at-1, 'week')
|
---|
| 4147 | )) {
|
---|
| 4148 | value += ' ' + tokens[at][0];
|
---|
| 4149 | } else if (at - start_at > 0 && matchTokens(tokens, at, 'month')
|
---|
| 4150 | && matchTokens(tokens, at-1, 'year')) {
|
---|
| 4151 | value += ' ' + months[[tokens[at][0]]];
|
---|
| 4152 | } else if (at - start_at > 0 && matchTokens(tokens, at, 'event')
|
---|
| 4153 | && matchTokens(tokens, at-1, 'year')) {
|
---|
| 4154 | value += ' ' + tokens[at][0];
|
---|
| 4155 | } else if (matchTokens(tokens, at, 'month')) {
|
---|
| 4156 | value += months[[tokens[at][0]]];
|
---|
| 4157 | if (at + 1 < last_at && matchTokens(tokens, at+1, 'weekday'))
|
---|
[6420] | 4158 | value += ' ';
|
---|
[6370] | 4159 | } else if (at + 2 < last_at
|
---|
| 4160 | && (matchTokens(tokens, at, '-') || matchTokens(tokens, at, '+'))
|
---|
| 4161 | && matchTokens(tokens, at+1, 'number', 'calcday')) {
|
---|
| 4162 | value += ' ' + tokens[at][0] + tokens[at+1][0] + ' day' + (Math.abs(tokens[at+1][0]) == 1 ? '' : 's');
|
---|
| 4163 | at += 2;
|
---|
| 4164 | } else {
|
---|
| 4165 | // if (matchTokens(tokens, at, 'open') || matchTokens(tokens, at, 'unknown'))
|
---|
| 4166 | // value += ' ';
|
---|
| 4167 |
|
---|
| 4168 | value += tokens[at][0].toString();
|
---|
| 4169 | }
|
---|
| 4170 | at++;
|
---|
| 4171 | }
|
---|
| 4172 | return value + ' ';
|
---|
| 4173 | }
|
---|
[7046] | 4174 | // }}}
|
---|
[6370] | 4175 |
|
---|
| 4176 | //======================================================================
|
---|
[7046] | 4177 | // Public interface {{{
|
---|
[6370] | 4178 | // All functions below are considered public.
|
---|
| 4179 | //======================================================================
|
---|
| 4180 |
|
---|
| 4181 | //======================================================================
|
---|
[7046] | 4182 | // Iterator interface {{{
|
---|
[6370] | 4183 | //======================================================================
|
---|
| 4184 | this.getIterator = function(date) {
|
---|
| 4185 | return new function(oh) {
|
---|
| 4186 | if (typeof date === 'undefined')
|
---|
| 4187 | date = new Date();
|
---|
| 4188 |
|
---|
| 4189 | var prevstate = [ undefined, date, undefined, undefined, undefined ];
|
---|
| 4190 | var state = oh.getStatePair(date);
|
---|
| 4191 |
|
---|
| 4192 | this.setDate = function(date) {
|
---|
| 4193 | if (typeof date != 'object')
|
---|
| 4194 | throw 'Date as parameter needed.';
|
---|
| 4195 |
|
---|
| 4196 | prevstate = [ undefined, date, undefined, undefined, undefined ];
|
---|
| 4197 | state = oh.getStatePair(date);
|
---|
| 4198 | }
|
---|
| 4199 |
|
---|
| 4200 | this.getDate = function() {
|
---|
| 4201 | return prevstate[1];
|
---|
| 4202 | }
|
---|
| 4203 |
|
---|
| 4204 | this.getState = function() {
|
---|
| 4205 | return state[0];
|
---|
| 4206 | }
|
---|
| 4207 |
|
---|
| 4208 | this.getUnknown = function() {
|
---|
| 4209 | return state[2];
|
---|
| 4210 | }
|
---|
| 4211 |
|
---|
| 4212 | this.getStateString = function(past) {
|
---|
| 4213 | return (state[0] ? 'open' : (state[2] ? 'unknown' : (past ? 'closed' : 'close')));
|
---|
| 4214 | }
|
---|
| 4215 |
|
---|
| 4216 | this.getComment = function() {
|
---|
| 4217 | return state[3];
|
---|
| 4218 | }
|
---|
| 4219 |
|
---|
| 4220 | this.getMatchingRule = function(user_conf) {
|
---|
| 4221 | if (typeof state[4] == 'undefined')
|
---|
| 4222 | return undefined;
|
---|
| 4223 |
|
---|
| 4224 | if (typeof user_conf != 'object')
|
---|
| 4225 | var user_conf = {};
|
---|
| 4226 | for (key in default_prettify_conf) {
|
---|
[6489] | 4227 | if (typeof user_conf[key] == 'undefined')
|
---|
[6370] | 4228 | user_conf[key] = default_prettify_conf[key];
|
---|
| 4229 | }
|
---|
| 4230 |
|
---|
| 4231 | var really_done_with_warnings = done_with_warnings; // getWarnings can be called later.
|
---|
| 4232 | done_with_warnings = true;
|
---|
| 4233 | prettified_value = '';
|
---|
| 4234 | var selectors = { // Not really needed. This whole thing is only necessary because of the token used for additional blocks.
|
---|
| 4235 | time: [], weekday: [], holiday: [], week: [], month: [], monthday: [], year: [], wraptime: [],
|
---|
| 4236 |
|
---|
| 4237 | fallback: false, // does not matter
|
---|
| 4238 | additional: false,
|
---|
| 4239 | meaning: true,
|
---|
| 4240 | unknown: false,
|
---|
| 4241 | comment: undefined,
|
---|
| 4242 | };
|
---|
| 4243 |
|
---|
[6489] | 4244 | // token block index used to build the selectors for this block.
|
---|
| 4245 | var token_block = blocks[state[4]].build_from_token_block;
|
---|
| 4246 | parseGroup(tokens[token_block[0]][0], token_block[1], selectors, state[4], user_conf);
|
---|
[6370] | 4247 |
|
---|
[6489] | 4248 | if (prettified_value[prettified_value.length - 1] == ',')
|
---|
| 4249 | prettified_value = prettified_value.substr(0, prettified_value.length - 1);
|
---|
| 4250 |
|
---|
[6370] | 4251 | done_with_warnings = really_done_with_warnings;
|
---|
| 4252 |
|
---|
| 4253 | return prettified_value;
|
---|
| 4254 | }
|
---|
| 4255 |
|
---|
| 4256 | this.advance = function(datelimit) {
|
---|
| 4257 | if (typeof datelimit === 'undefined')
|
---|
| 4258 | datelimit = new Date(prevstate[1].getTime() + msec_in_day * 366 * 5);
|
---|
| 4259 | else if (datelimit.getTime() <= prevstate[1].getTime())
|
---|
| 4260 | return false; // The limit for advance needs to be after the current time.
|
---|
| 4261 |
|
---|
| 4262 | do {
|
---|
| 4263 | // open range, we won't be able to advance
|
---|
| 4264 | if (typeof state[1] === 'undefined')
|
---|
| 4265 | return false;
|
---|
| 4266 |
|
---|
| 4267 | // console.log('\n' + 'previous check time:', prevstate[1]
|
---|
| 4268 | // + ', current check time:',
|
---|
| 4269 | // // (state[1].getHours() < 10 ? '0' : '') + state[1].getHours() +
|
---|
| 4270 | // // ':'+(state[1].getMinutes() < 10 ? '0' : '')+ state[1].getMinutes(), state[1].getDate(),
|
---|
| 4271 | // state[1],
|
---|
| 4272 | // (state[0] ? 'open' : (state[2] ? 'unknown' : 'closed')) + ', comment:', state[3]);
|
---|
| 4273 |
|
---|
| 4274 | // We're going backwards or staying at place.
|
---|
| 4275 | // This always indicates coding error in a selector code.
|
---|
| 4276 | if (state[1].getTime() <= prevstate[1].getTime())
|
---|
| 4277 | throw 'Fatal: infinite loop in nextChange';
|
---|
| 4278 |
|
---|
| 4279 | // don't advance beyond limits (same as open range)
|
---|
| 4280 | if (state[1].getTime() >= datelimit.getTime())
|
---|
| 4281 | return false;
|
---|
| 4282 |
|
---|
| 4283 | // do advance
|
---|
| 4284 | prevstate = state;
|
---|
| 4285 | state = oh.getStatePair(prevstate[1]);
|
---|
| 4286 | } while (state[0] === prevstate[0] && state[2] === prevstate[2] && state[3] === prevstate[3]);
|
---|
| 4287 | return true;
|
---|
| 4288 | }
|
---|
| 4289 | }(this);
|
---|
| 4290 | }
|
---|
[7046] | 4291 | // }}}
|
---|
[6370] | 4292 |
|
---|
[7046] | 4293 | // Simple API {{{
|
---|
| 4294 |
|
---|
| 4295 | // Get parse warnings.
|
---|
| 4296 | // Returns an empty string if there are no warnings.
|
---|
[6370] | 4297 | this.getWarnings = function() {
|
---|
| 4298 | var it = this.getIterator();
|
---|
| 4299 | return getWarnings(it);
|
---|
| 4300 | }
|
---|
| 4301 |
|
---|
[7046] | 4302 | // Get a nicely formated value.
|
---|
[6370] | 4303 | this.prettifyValue = function(user_conf) {
|
---|
| 4304 | if (typeof user_conf != 'object')
|
---|
| 4305 | var user_conf = {};
|
---|
| 4306 |
|
---|
| 4307 | for (key in default_prettify_conf) {
|
---|
| 4308 | if (typeof user_conf[key] == 'undefined')
|
---|
| 4309 | user_conf[key] = default_prettify_conf[key];
|
---|
| 4310 | }
|
---|
| 4311 |
|
---|
| 4312 | var really_done_with_warnings = done_with_warnings; // getWarnings can be called later.
|
---|
| 4313 | done_with_warnings = true;
|
---|
| 4314 |
|
---|
| 4315 | prettified_value = '';
|
---|
| 4316 | for (var nblock = 0; nblock < tokens.length; nblock++) {
|
---|
| 4317 | if (tokens[nblock][0].length == 0) continue;
|
---|
| 4318 | // Block does contain nothing useful e.g. second block of '10:00-12:00;' (empty) which needs to be handled.
|
---|
| 4319 |
|
---|
| 4320 | if (nblock != 0)
|
---|
| 4321 | prettified_value += (tokens[nblock][1]
|
---|
| 4322 | ? user_conf.block_sep_string + '|| '
|
---|
| 4323 | : (user_conf.print_semicolon ? ';' : '') + user_conf.block_sep_string);
|
---|
| 4324 |
|
---|
| 4325 | var continue_at = 0;
|
---|
| 4326 | do {
|
---|
| 4327 | if (continue_at == tokens[nblock][0].length) break;
|
---|
| 4328 | // Block does contain nothing useful e.g. second block of '10:00-12:00,' (empty) which needs to be handled.
|
---|
| 4329 |
|
---|
| 4330 | var selectors = { // Not really needed. This whole thing is only necessary because of the token used for additional blocks.
|
---|
| 4331 | time: [], weekday: [], holiday: [], week: [], month: [], monthday: [], year: [], wraptime: [],
|
---|
| 4332 |
|
---|
| 4333 | fallback: tokens[nblock][1],
|
---|
| 4334 | additional: continue_at ? true : false,
|
---|
| 4335 | meaning: true,
|
---|
| 4336 | unknown: false,
|
---|
| 4337 | comment: undefined,
|
---|
| 4338 | };
|
---|
| 4339 |
|
---|
| 4340 | continue_at = parseGroup(tokens[nblock][0], continue_at, selectors, nblock, user_conf);
|
---|
| 4341 |
|
---|
| 4342 | if (typeof continue_at == 'object') {
|
---|
| 4343 | continue_at = continue_at[0];
|
---|
| 4344 | prettified_value += user_conf.block_sep_string;
|
---|
| 4345 | } else {
|
---|
| 4346 | continue_at = 0;
|
---|
| 4347 | }
|
---|
| 4348 |
|
---|
| 4349 | } while (continue_at)
|
---|
| 4350 | }
|
---|
| 4351 |
|
---|
| 4352 | done_with_warnings = really_done_with_warnings;
|
---|
| 4353 |
|
---|
| 4354 | return prettified_value;
|
---|
| 4355 | }
|
---|
| 4356 |
|
---|
[7046] | 4357 | // Check whether facility is `open' on the given date (or now).
|
---|
[6370] | 4358 | this.getState = function(date) {
|
---|
| 4359 | var it = this.getIterator(date);
|
---|
| 4360 | return it.getState();
|
---|
| 4361 | }
|
---|
| 4362 |
|
---|
| 4363 | // If the state of a amenity is conditional. Conditions can be expressed in comments.
|
---|
| 4364 | // True will only be returned if the state is false as the getState only
|
---|
| 4365 | // returns true if the amenity is really open. So you may want to check
|
---|
[7046] | 4366 | // the result of getUnknown if getState returned false.
|
---|
[6370] | 4367 | this.getUnknown = function(date) {
|
---|
| 4368 | var it = this.getIterator(date);
|
---|
| 4369 | return it.getUnknown();
|
---|
| 4370 | }
|
---|
| 4371 |
|
---|
| 4372 | // Return state string. Either 'open', 'unknown' or 'closed'.
|
---|
| 4373 | this.getStateString = function(date, past) {
|
---|
| 4374 | var it = this.getIterator(date);
|
---|
| 4375 | return it.getStateString(past);
|
---|
| 4376 | }
|
---|
| 4377 |
|
---|
| 4378 | // Returns the comment.
|
---|
[7046] | 4379 | // If no comment is specified this function will return undefined.
|
---|
[6370] | 4380 | this.getComment = function(date) {
|
---|
| 4381 | var it = this.getIterator(date);
|
---|
| 4382 | return it.getComment();
|
---|
| 4383 | }
|
---|
| 4384 |
|
---|
[7046] | 4385 | // Return the block which matched thus deterrents the current state.
|
---|
[6370] | 4386 | this.getMatchingRule = function(date) {
|
---|
| 4387 | var it = this.getIterator(date);
|
---|
| 4388 | return it.getMatchingRule();
|
---|
| 4389 | }
|
---|
| 4390 |
|
---|
[7046] | 4391 | // Returns time of next status change.
|
---|
[6370] | 4392 | this.getNextChange = function(date, maxdate) {
|
---|
| 4393 | var it = this.getIterator(date);
|
---|
| 4394 | if (!it.advance(maxdate))
|
---|
| 4395 | return undefined;
|
---|
| 4396 | return it.getDate();
|
---|
| 4397 | }
|
---|
| 4398 |
|
---|
[7046] | 4399 | // Checks whether open intervals are same for every week.
|
---|
| 4400 | this.isWeekStable = function() {
|
---|
| 4401 | return week_stable;
|
---|
| 4402 | }
|
---|
| 4403 | // }}}
|
---|
| 4404 |
|
---|
| 4405 | // High-level API {{{
|
---|
| 4406 |
|
---|
[6370] | 4407 | // return array of open intervals between two dates
|
---|
| 4408 | this.getOpenIntervals = function(from, to) {
|
---|
| 4409 | var res = [];
|
---|
| 4410 |
|
---|
| 4411 | var it = this.getIterator(from);
|
---|
| 4412 |
|
---|
| 4413 | if (it.getState() || it.getUnknown())
|
---|
| 4414 | res.push([from, undefined, it.getUnknown(), it.getComment()]);
|
---|
| 4415 |
|
---|
| 4416 | while (it.advance(to)) {
|
---|
| 4417 | if (it.getState() || it.getUnknown()) {
|
---|
| 4418 | if (res.length != 0 && typeof res[res.length - 1][1] == 'undefined') {
|
---|
| 4419 | // last state was also open or unknown
|
---|
| 4420 | res[res.length - 1][1] = it.getDate();
|
---|
| 4421 | }
|
---|
| 4422 | res.push([it.getDate(), undefined, it.getUnknown(), it.getComment()]);
|
---|
| 4423 | } else {
|
---|
| 4424 | if (res.length != 0 && typeof res[res.length - 1][1] == 'undefined') {
|
---|
| 4425 | // only use the first time as closing/change time and ignore closing times which might follow
|
---|
| 4426 | res[res.length - 1][1] = it.getDate();
|
---|
| 4427 | }
|
---|
| 4428 | }
|
---|
| 4429 | }
|
---|
| 4430 |
|
---|
| 4431 | if (res.length > 0 && typeof res[res.length - 1][1] === 'undefined')
|
---|
| 4432 | res[res.length - 1][1] = to;
|
---|
| 4433 |
|
---|
| 4434 | return res;
|
---|
| 4435 | }
|
---|
| 4436 |
|
---|
| 4437 | // return total number of milliseconds a facility is open within a given date range
|
---|
| 4438 | this.getOpenDuration = function(from, to) {
|
---|
| 4439 | // console.log('-----------');
|
---|
| 4440 |
|
---|
| 4441 | var open = 0;
|
---|
| 4442 | var unknown = 0;
|
---|
| 4443 |
|
---|
| 4444 | var it = this.getIterator(from);
|
---|
| 4445 | var prevdate = (it.getState() || it.getUnknown()) ? from : undefined;
|
---|
| 4446 | var prevstate = it.getState();
|
---|
| 4447 | var prevunknown = it.getUnknown();
|
---|
| 4448 |
|
---|
| 4449 | while (it.advance(to)) {
|
---|
| 4450 | if (it.getState() || it.getUnknown()) {
|
---|
| 4451 |
|
---|
| 4452 | if (typeof prevdate !== 'undefined') {
|
---|
| 4453 | // last state was also open or unknown
|
---|
| 4454 | if (prevunknown) //
|
---|
| 4455 | unknown += it.getDate().getTime() - prevdate.getTime();
|
---|
| 4456 | else if (prevstate)
|
---|
| 4457 | open += it.getDate().getTime() - prevdate.getTime();
|
---|
| 4458 | }
|
---|
| 4459 |
|
---|
| 4460 | prevdate = it.getDate();
|
---|
| 4461 | prevstate = it.getState();
|
---|
| 4462 | prevunknown = it.getUnknown();
|
---|
| 4463 | // console.log('if', prevdate, open / (1000 * 60 * 60), unknown / (1000 * 60 * 60));
|
---|
| 4464 | } else {
|
---|
| 4465 | // console.log('else', prevdate);
|
---|
| 4466 | if (typeof prevdate !== 'undefined') {
|
---|
| 4467 | if (prevunknown)
|
---|
| 4468 | unknown += it.getDate().getTime() - prevdate.getTime();
|
---|
| 4469 | else
|
---|
| 4470 | open += it.getDate().getTime() - prevdate.getTime();
|
---|
| 4471 | prevdate = undefined;
|
---|
| 4472 | }
|
---|
| 4473 | }
|
---|
| 4474 | }
|
---|
| 4475 |
|
---|
| 4476 | if (typeof prevdate !== 'undefined') {
|
---|
| 4477 | if (prevunknown)
|
---|
| 4478 | unknown += to.getTime() - prevdate.getTime();
|
---|
| 4479 | else
|
---|
| 4480 | open += to.getTime() - prevdate.getTime();
|
---|
| 4481 | }
|
---|
| 4482 |
|
---|
| 4483 | return [ open, unknown ];
|
---|
| 4484 | }
|
---|
[7046] | 4485 | // }}}
|
---|
| 4486 | // }}}
|
---|
[6370] | 4487 | }
|
---|
[7174] | 4488 | }));
|
---|
| 4489 | // vim: set ts=4 sw=4 tw=0 noet foldmarker={{{,}}} foldlevel=0 foldmethod=marker :
|
---|