(function (root, factory) { // constants (holidays, error correction) {{{ // holidays {{{ var holidays = { 'fr': { 'PH': { // http://fr.wikipedia.org/wiki/F%C3%AAtes_et_jours_f%C3%A9ri%C3%A9s_en_France "Jour de l'an" : [ 1, 1 ], "Vendredi saint" : [ 'easter', -2, [ 'Moselle', 'Bas-Rhin', 'Haut-Rhin', 'Guadeloupe', 'Martinique', 'Polynésie française' ] ], "Lundi de Pâques" : [ 'easter', 1 ], "Saint-Pierre-Chanel" : [ 4, 28, [ 'Wallis-et-Futuna' ] ], "Fête du Travail" : [ 5, 1 ], "Fête de la Victoire" : [ 5, 8 ], "Abolition de l'esclavage" : [ 5, 22, [ 'Martinique' ] ], "Abolition de l'esclavage" : [ 5, 27, [ 'Guadeloupe' ] ], "Jeudi de l'Ascension" : [ 'easter', 39 ], "Lundi de Pentecôte" : [ 'easter', 50 ], "Abolition de l'esclavage" : [ 6, 10, [ 'Guyane' ] ], "Fête de l'autonomie" : [ 6, 29, [ 'Polynésie française' ] ], "Fête nationale" : [ 7, 14 ], "Fête Victor Schoelcher" : [ 7, 21, [ 'Guadeloupe', 'Martinique' ] ], "Fête du Territoire" : [ 7, 29, [ 'Wallis-et-Futuna' ] ], "Assomption" : [ 8, 15 ], "Fête de la citoyenneté" : [ 9, 24, [ 'Nouvelle-Calédonie' ] ], "Toussaint" : [ 11, 1 ], "Armistice" : [ 11, 11 ], "Abolition de l'esclavage" : [ 12, 20, [ 'Réunion' ] ], "Noël" : [ 12, 25 ], "Saint-Étienne " : [ 12, 26, [ 'Moselle', 'Bas-Rhin', 'Haut-Rhin' ] ] } }, 'de': { 'PH': { // http://de.wikipedia.org/wiki/Feiertage_in_Deutschland 'Neujahrstag' : [ 1, 1 ], // month 1, day 1, whole Germany 'Heilige Drei Könige' : [ 1, 6, [ 'Baden-Württemberg', 'Bayern', 'Sachsen-Anhalt'] ], // only in the specified states 'Tag der Arbeit' : [ 5, 1 ], // whole Germany 'Karfreitag' : [ 'easter', -2 ], // two days before easter 'Ostersonntag' : [ 'easter', 0, [ 'Brandenburg'] ], 'Ostermontag' : [ 'easter', 1 ], 'Christi Himmelfahrt' : [ 'easter', 39 ], 'Pfingstsonntag' : [ 'easter', 49, [ 'Brandenburg'] ], 'Pfingstmontag' : [ 'easter', 50 ], 'Fronleichnam' : [ 'easter', 60, [ 'Baden-Württemberg', 'Bayern', 'Hessen', 'Nordrhein-Westfalen', 'Rheinland-Pfalz', 'Saarland' ] ], 'Mariä Himmelfahrt' : [ 8, 15, [ 'Saarland'] ], 'Tag der Deutschen Einheit' : [ 10, 3 ], 'Reformationstag' : [ 10, 31, [ 'Brandenburg', 'Mecklenburg-Vorpommern', 'Sachsen', 'Sachsen-Anhalt', 'Thüringen'] ], 'Allerheiligen' : [ 11, 1, [ 'Baden-Württemberg', 'Bayern', 'Nordrhein-Westfalen', 'Rheinland-Pfalz', 'Saarland' ] ], '1. Weihnachtstag' : [ 12, 25 ], '2. Weihnachtstag' : [ 12, 26 ], // 'Silvester' : [ 12, 31 ], // for testing }, 'Baden-Württemberg': { // does only apply in Baden-Württemberg // This more specific rule set overwrites the country wide one (they are just ignored). // You may use this instead of the country wide with some // additional holidays for some states, if one state // totally disagrees about how to do public holidays … // 'PH': { // '2. Weihnachtstag' : [ 12, 26 ], // }, // school holiday normally variate between states 'SH': [ // generated by convert_ical_to_json // You may can adjust this script to use other resources (for other countries) too. { name: 'Osterferien', 2005: [ 3, 24, /* to */ 3, 24, 3, 29, /* to */ 4, 2 ], 2006: [ 4, 18, /* to */ 4, 22 ], 2007: [ 4, 2, /* to */ 4, 14 ], 2008: [ 3, 17, /* to */ 3, 28 ], 2009: [ 4, 9, /* to */ 4, 9, 4, 14, /* to */ 4, 17 ], 2010: [ 4, 1, /* to */ 4, 1, 4, 6, /* to */ 4, 10 ], 2011: [ 4, 21, /* to */ 4, 21, 4, 26, /* to */ 4, 30 ], 2012: [ 4, 2, /* to */ 4, 13 ], 2013: [ 3, 25, /* to */ 4, 5 ], 2014: [ 4, 14, /* to */ 4, 25 ], 2015: [ 3, 30, /* to */ 4, 10 ], 2016: [ 3, 29, /* to */ 4, 2 ], 2017: [ 4, 10, /* to */ 4, 21 ], }, { name: 'Pfingstferien', 2005: [ 5, 17, /* to */ 5, 28 ], 2006: [ 5, 29, /* to */ 6, 10 ], 2007: [ 5, 29, /* to */ 6, 9 ], 2008: [ 5, 13, /* to */ 5, 23 ], 2009: [ 5, 25, /* to */ 6, 6 ], 2010: [ 5, 25, /* to */ 6, 5 ], 2011: [ 6, 14, /* to */ 6, 25 ], 2012: [ 5, 29, /* to */ 6, 9 ], 2013: [ 5, 21, /* to */ 6, 1 ], 2014: [ 6, 10, /* to */ 6, 21 ], 2015: [ 5, 26, /* to */ 6, 6 ], 2016: [ 5, 17, /* to */ 5, 28 ], 2017: [ 6, 6, /* to */ 6, 16 ], }, { name: 'Sommerferien', 2005: [ 7, 28, /* to */ 9, 10 ], 2006: [ 8, 3, /* to */ 9, 16 ], 2007: [ 7, 26, /* to */ 9, 8 ], 2008: [ 7, 24, /* to */ 9, 6 ], 2009: [ 7, 30, /* to */ 9, 12 ], 2010: [ 7, 29, /* to */ 9, 11 ], 2011: [ 7, 28, /* to */ 9, 10 ], 2012: [ 7, 26, /* to */ 9, 8 ], 2013: [ 7, 25, /* to */ 9, 7 ], 2014: [ 7, 31, /* to */ 9, 13 ], 2015: [ 7, 30, /* to */ 9, 12 ], 2016: [ 7, 28, /* to */ 9, 10 ], 2017: [ 7, 27, /* to */ 9, 9 ], }, { name: 'Herbstferien', 2005: [ 11, 2, /* to */ 11, 4 ], 2006: [ 10, 30, /* to */ 11, 3 ], 2007: [ 10, 29, /* to */ 11, 3 ], 2008: [ 10, 27, /* to */ 10, 31 ], 2009: [ 10, 26, /* to */ 10, 31 ], 2010: [ 11, 2, /* to */ 11, 6 ], 2011: [ 10, 31, /* to */ 10, 31, 11, 2, /* to */ 11, 4 ], 2012: [ 10, 29, /* to */ 11, 2 ], 2013: [ 10, 28, /* to */ 10, 30 ], 2014: [ 10, 27, /* to */ 10, 30 ], 2015: [ 11, 2, /* to */ 11, 6 ], 2016: [ 11, 2, /* to */ 11, 4 ], }, { name: 'Weihnachtsferien', 2005: [ 12, 22, /* to */ 1, 5 ], 2006: [ 12, 27, /* to */ 1, 5 ], 2007: [ 12, 24, /* to */ 1, 5 ], 2008: [ 12, 22, /* to */ 1, 10 ], 2009: [ 12, 23, /* to */ 1, 9 ], 2010: [ 12, 23, /* to */ 1, 8 ], 2011: [ 12, 23, /* to */ 1, 5 ], 2012: [ 12, 24, /* to */ 1, 5 ], 2013: [ 12, 23, /* to */ 1, 4 ], 2014: [ 12, 22, /* to */ 1, 5 ], 2015: [ 12, 23, /* to */ 1, 9 ], 2016: [ 12, 23, /* to */ 1, 7 ], }, ], }, 'Mecklenburg-Vorpommern': { 'SH': [ { name: 'Winterferien', 2010: [ 2, 6, /* to */ 2, 20 ], 2011: [ 2, 7, /* to */ 2, 19 ], 2012: [ 2, 6, /* to */ 2, 17 ], 2013: [ 2, 4, /* to */ 2, 15 ], 2014: [ 2, 3, /* to */ 2, 15 ], 2015: [ 2, 2, /* to */ 2, 14 ], 2016: [ 2, 1, /* to */ 2, 13 ], 2017: [ 2, 6, /* to */ 2, 18 ], }, { name: 'Osterferien', 2010: [ 3, 29, /* to */ 4, 7 ], 2011: [ 4, 16, /* to */ 4, 27 ], 2012: [ 4, 2, /* to */ 4, 11 ], 2013: [ 3, 25, /* to */ 4, 3 ], 2014: [ 4, 14, /* to */ 4, 23 ], 2015: [ 3, 30, /* to */ 4, 8 ], 2016: [ 3, 21, /* to */ 3, 30 ], 2017: [ 4, 10, /* to */ 4, 19 ], }, { name: 'Pfingstferien', 2010: [ 5, 21, /* to */ 5, 22 ], 2011: [ 6, 10, /* to */ 6, 14 ], 2012: [ 5, 25, /* to */ 5, 29 ], 2013: [ 5, 17, /* to */ 5, 21 ], 2014: [ 6, 6, /* to */ 6, 10 ], 2015: [ 5, 22, /* to */ 5, 26 ], 2016: [ 5, 14, /* to */ 5, 17 ], 2017: [ 6, 2, /* to */ 6, 6 ], }, { name: 'Sommerferien', 2010: [ 7, 12, /* to */ 8, 21 ], 2011: [ 7, 4, /* to */ 8, 13 ], 2012: [ 6, 23, /* to */ 8, 4 ], 2013: [ 6, 22, /* to */ 8, 3 ], 2014: [ 7, 14, /* to */ 8, 23 ], 2015: [ 7, 20, /* to */ 8, 29 ], 2016: [ 7, 25, /* to */ 9, 3 ], 2017: [ 7, 24, /* to */ 9, 2 ], }, { name: 'Herbstferien', 2010: [ 10, 18, /* to */ 10, 23 ], 2011: [ 10, 17, /* to */ 10, 21 ], 2012: [ 10, 1, /* to */ 10, 5 ], 2013: [ 10, 14, /* to */ 10, 19 ], 2014: [ 10, 20, /* to */ 10, 25 ], 2015: [ 10, 24, /* to */ 10, 30 ], 2016: [ 10, 24, /* to */ 10, 28 ], }, { name: 'Weihnachtsferien', 2010: [ 12, 23, /* to */ 12, 31 ], 2011: [ 12, 23, /* to */ 1, 3 ], 2012: [ 12, 21, /* to */ 1, 4 ], 2013: [ 12, 23, /* to */ 1, 3 ], 2014: [ 12, 22, /* to */ 1, 2 ], 2015: [ 12, 21, /* to */ 1, 2 ], 2016: [ 12, 22, /* to */ 1, 2 ], }, ], }, 'Hessen': { 'SH': [ { name: 'Osterferien', 2010: [ 3, 29, /* to */ 4, 10 ], 2011: [ 4, 18, /* to */ 4, 30 ], 2012: [ 4, 2, /* to */ 4, 14 ], 2013: [ 3, 25, /* to */ 4, 6 ], 2014: [ 4, 14, /* to */ 4, 26 ], 2015: [ 3, 30, /* to */ 4, 11 ], 2016: [ 3, 29, /* to */ 4, 9 ], 2017: [ 4, 3, /* to */ 4, 15 ], 2018: [ 3, 26, /* to */ 4, 7 ], }, { name: 'Sommerferien', 2010: [ 7, 5, /* to */ 8, 14 ], 2011: [ 6, 27, /* to */ 8, 5 ], 2012: [ 7, 2, /* to */ 8, 10 ], 2013: [ 7, 8, /* to */ 8, 16 ], 2014: [ 7, 28, /* to */ 9, 5 ], 2015: [ 7, 27, /* to */ 9, 5 ], 2016: [ 7, 18, /* to */ 8, 26 ], 2017: [ 7, 3, /* to */ 8, 11 ], }, { name: 'Herbstferien', 2010: [ 10, 11, /* to */ 10, 22 ], 2011: [ 10, 10, /* to */ 10, 22 ], 2012: [ 10, 15, /* to */ 10, 27 ], 2013: [ 10, 14, /* to */ 10, 26 ], 2014: [ 10, 20, /* to */ 11, 1 ], 2015: [ 10, 19, /* to */ 10, 31 ], 2016: [ 10, 17, /* to */ 10, 29 ], 2017: [ 10, 9, /* to */ 10, 21 ], }, { name: 'Weihnachtsferien', 2010: [ 12, 20, /* to */ 1, 7 ], 2011: [ 12, 21, /* to */ 1, 6 ], 2012: [ 12, 24, /* to */ 1, 12 ], 2013: [ 12, 23, /* to */ 1, 11 ], 2014: [ 12, 22, /* to */ 1, 10 ], 2015: [ 12, 23, /* to */ 1, 9 ], 2016: [ 12, 22, /* to */ 1, 7 ], 2017: [ 12, 24, /* to */ 1, 13 ], }, ], }, 'Schleswig-Holstein': { 'SH': [ { name: 'Osterferien', 2010: [ 4, 3, /* to */ 4, 17 ], 2011: [ 4, 15, /* to */ 4, 30 ], 2012: [ 3, 30, /* to */ 4, 13 ], 2013: [ 3, 25, /* to */ 4, 9 ], 2014: [ 4, 16, /* to */ 5, 2 ], 2015: [ 4, 1, /* to */ 4, 17 ], 2016: [ 3, 24, /* to */ 4, 9 ], 2017: [ 4, 7, /* to */ 4, 21 ], }, { name: 'Sommerferien', 2010: [ 7, 12, /* to */ 8, 21 ], 2011: [ 7, 4, /* to */ 8, 13 ], 2012: [ 6, 25, /* to */ 8, 4 ], 2013: [ 6, 24, /* to */ 8, 3 ], 2014: [ 7, 14, /* to */ 8, 23 ], 2015: [ 7, 20, /* to */ 8, 29 ], 2016: [ 7, 25, /* to */ 9, 3 ], 2017: [ 7, 24, /* to */ 9, 2 ], }, { name: 'Pfingstferien', 2011: [ 6, 3, /* to */ 6, 4 ], 2012: [ 5, 18, /* to */ 5, 18 ], 2013: [ 5, 10, /* to */ 5, 10 ], 2014: [ 5, 30, /* to */ 5, 30 ], 2015: [ 5, 15, /* to */ 5, 15 ], 2016: [ 5, 6, /* to */ 5, 6 ], 2017: [ 5, 26, /* to */ 5, 26 ], }, { name: 'Herbstferien', 2010: [ 10, 11, /* to */ 10, 23 ], 2011: [ 10, 10, /* to */ 10, 22 ], 2012: [ 10, 4, /* to */ 10, 19 ], 2013: [ 10, 4, /* to */ 10, 18 ], 2014: [ 10, 13, /* to */ 10, 25 ], 2015: [ 10, 19, /* to */ 10, 31 ], 2016: [ 10, 17, /* to */ 10, 29 ], }, { name: 'Weihnachtsferien', 2010: [ 12, 23, /* to */ 1, 7 ], 2011: [ 12, 23, /* to */ 1, 6 ], 2012: [ 12, 24, /* to */ 1, 5 ], 2013: [ 12, 23, /* to */ 1, 6 ], 2014: [ 12, 22, /* to */ 1, 6 ], 2015: [ 12, 21, /* to */ 1, 6 ], 2016: [ 12, 23, /* to */ 1, 6 ], }, ], }, 'Berlin': { 'SH': [ { name: 'Winterferien', 2010: [ 2, 1, /* to */ 2, 6 ], 2011: [ 1, 31, /* to */ 2, 5 ], 2012: [ 1, 30, /* to */ 2, 4 ], 2013: [ 2, 4, /* to */ 2, 9 ], 2014: [ 2, 3, /* to */ 2, 8 ], 2015: [ 2, 2, /* to */ 2, 7 ], 2016: [ 2, 1, /* to */ 2, 6 ], 2017: [ 1, 30, /* to */ 2, 4 ], }, { name: 'Osterferien', 2010: [ 3, 31, /* to */ 4, 10 ], 2011: [ 4, 18, /* to */ 4, 30 ], 2012: [ 4, 2, /* to */ 4, 14, 4, 30, /* to */ 4, 30 ], 2013: [ 3, 25, /* to */ 4, 6 ], 2014: [ 4, 14, /* to */ 4, 26, 5, 2, /* to */ 5, 2 ], 2015: [ 3, 30, /* to */ 4, 11 ], 2016: [ 3, 21, /* to */ 4, 2 ], 2017: [ 4, 10, /* to */ 4, 22 ], }, { name: 'Pfingstferien', 2010: [ 5, 14, /* to */ 5, 14, 5, 25, /* to */ 5, 25 ], 2011: [ 6, 3, /* to */ 6, 3 ], 2012: [ 5, 18, /* to */ 5, 18 ], 2013: [ 5, 10, /* to */ 5, 10, 5, 21, /* to */ 5, 21 ], 2014: [ 5, 30, /* to */ 5, 30 ], 2015: [ 5, 15, /* to */ 5, 15 ], 2016: [ 5, 6, /* to */ 5, 6, 5, 17, /* to */ 5, 17 ], 2017: [ 5, 26, /* to */ 5, 26 ], }, { name: 'Sommerferien', 2010: [ 7, 7, /* to */ 8, 21 ], 2011: [ 6, 29, /* to */ 8, 12 ], 2012: [ 6, 20, /* to */ 8, 3 ], 2013: [ 6, 19, /* to */ 8, 2 ], 2014: [ 7, 9, /* to */ 8, 22 ], 2015: [ 7, 15, /* to */ 8, 28 ], 2016: [ 7, 20, /* to */ 9, 2 ], 2017: [ 7, 19, /* to */ 9, 1 ], }, { name: 'Herbstferien', 2010: [ 10, 11, /* to */ 10, 23 ], 2011: [ 10, 4, /* to */ 10, 14 ], 2012: [ 10, 1, /* to */ 10, 13 ], 2013: [ 9, 30, /* to */ 10, 12 ], 2014: [ 10, 20, /* to */ 11, 1 ], 2015: [ 10, 19, /* to */ 10, 31 ], 2016: [ 10, 17, /* to */ 10, 28 ], }, { name: 'Weihnachtsferien', 2010: [ 12, 23, /* to */ 1, 1 ], 2011: [ 12, 23, /* to */ 1, 3 ], 2012: [ 12, 24, /* to */ 1, 4 ], 2013: [ 12, 23, /* to */ 1, 3 ], 2014: [ 12, 22, /* to */ 1, 2 ], 2015: [ 12, 23, /* to */ 1, 2 ], 2016: [ 12, 23, /* to */ 1, 3 ], }, ], }, 'Saarland': { 'SH': [ { name: 'Winterferien', 2010: [ 2, 15, /* to */ 2, 20 ], 2011: [ 3, 7, /* to */ 3, 12 ], 2012: [ 2, 20, /* to */ 2, 25 ], 2013: [ 2, 11, /* to */ 2, 16 ], 2014: [ 3, 3, /* to */ 3, 8 ], 2015: [ 2, 16, /* to */ 2, 21 ], }, { name: 'Osterferien', 2010: [ 3, 29, /* to */ 4, 10 ], 2011: [ 4, 18, /* to */ 4, 30 ], 2012: [ 4, 2, /* to */ 4, 14 ], 2013: [ 3, 25, /* to */ 4, 6 ], 2014: [ 4, 14, /* to */ 4, 26 ], 2015: [ 3, 30, /* to */ 4, 11 ], }, { name: 'Sommerferien', 2010: [ 7, 5, /* to */ 8, 14 ], 2011: [ 6, 24, /* to */ 8, 6 ], 2012: [ 7, 2, /* to */ 8, 14 ], 2013: [ 7, 8, /* to */ 8, 17 ], 2014: [ 7, 28, /* to */ 9, 6 ], 2015: [ 7, 27, /* to */ 9, 4 ], 2016: [ 7, 18, /* to */ 8, 26 ], 2017: [ 7, 3, /* to */ 8, 14 ], }, { name: 'Herbstferien', 2010: [ 10, 11, /* to */ 10, 23 ], 2011: [ 10, 4, /* to */ 10, 15 ], 2012: [ 10, 22, /* to */ 11, 3 ], 2013: [ 10, 21, /* to */ 11, 2 ], 2014: [ 10, 20, /* to */ 10, 31 ], }, { name: 'Weihnachtsferien', 2010: [ 12, 20, /* to */ 1, 1 ], 2011: [ 12, 23, /* to */ 1, 4 ], 2012: [ 12, 24, /* to */ 1, 5 ], 2013: [ 12, 20, /* to */ 1, 4 ], 2014: [ 12, 22, /* to */ 1, 7 ], }, ], }, 'Bremen': { 'SH': [ { name: 'Winterferien', 2010: [ 2, 1, /* to */ 2, 2 ], 2011: [ 1, 31, /* to */ 2, 1 ], 2012: [ 1, 30, /* to */ 1, 31 ], 2013: [ 1, 31, /* to */ 2, 1 ], 2014: [ 1, 30, /* to */ 1, 31 ], 2015: [ 2, 2, /* to */ 2, 3 ], 2016: [ 1, 28, /* to */ 1, 29 ], 2017: [ 1, 30, /* to */ 1, 31 ], }, { name: 'Osterferien', 2010: [ 3, 19, /* to */ 4, 6 ], 2011: [ 4, 16, /* to */ 4, 30 ], 2012: [ 3, 26, /* to */ 4, 11, 4, 30, /* to */ 4, 30 ], 2013: [ 3, 16, /* to */ 4, 2 ], 2014: [ 4, 3, /* to */ 4, 22, 5, 2, /* to */ 5, 2 ], 2015: [ 3, 25, /* to */ 4, 10 ], 2016: [ 3, 18, /* to */ 4, 2 ], 2017: [ 4, 10, /* to */ 4, 22 ], }, { name: 'Pfingstferien', 2010: [ 5, 14, /* to */ 5, 14, 5, 25, /* to */ 5, 25 ], 2011: [ 6, 3, /* to */ 6, 3, 6, 14, /* to */ 6, 14 ], 2012: [ 5, 18, /* to */ 5, 18, 5, 29, /* to */ 5, 29 ], 2013: [ 5, 10, /* to */ 5, 10, 5, 21, /* to */ 5, 21 ], 2014: [ 5, 30, /* to */ 5, 30, 6, 10, /* to */ 6, 10 ], 2015: [ 5, 15, /* to */ 5, 15, 5, 26, /* to */ 5, 26 ], 2016: [ 5, 6, /* to */ 5, 6, 5, 17, /* to */ 5, 17 ], 2017: [ 5, 26, /* to */ 5, 26, 6, 6, /* to */ 6, 6 ], }, { name: 'Sommerferien', 2010: [ 6, 24, /* to */ 8, 4 ], 2011: [ 7, 7, /* to */ 8, 17 ], 2012: [ 7, 23, /* to */ 8, 31 ], 2013: [ 6, 27, /* to */ 8, 7 ], 2014: [ 7, 31, /* to */ 9, 10 ], 2015: [ 7, 23, /* to */ 9, 2 ], 2016: [ 6, 23, /* to */ 8, 3 ], 2017: [ 6, 22, /* to */ 8, 2 ], }, { name: 'Herbstferien', 2010: [ 10, 9, /* to */ 10, 23 ], 2011: [ 10, 17, /* to */ 10, 29 ], 2012: [ 10, 22, /* to */ 11, 3 ], 2013: [ 10, 4, /* to */ 10, 18 ], 2014: [ 10, 27, /* to */ 11, 8 ], 2015: [ 10, 19, /* to */ 10, 31 ], 2016: [ 10, 4, /* to */ 10, 15 ], }, { name: 'Weihnachtsferien', 2010: [ 12, 22, /* to */ 1, 5 ], 2011: [ 12, 23, /* to */ 1, 4 ], 2012: [ 12, 24, /* to */ 1, 5 ], 2013: [ 12, 23, /* to */ 1, 3 ], 2014: [ 12, 22, /* to */ 1, 5 ], 2015: [ 12, 23, /* to */ 1, 6 ], 2016: [ 12, 21, /* to */ 1, 6 ], }, ], }, 'Bayern': { 'SH': [ { name: 'Winterferien', 2010: [ 2, 15, /* to */ 2, 20 ], 2011: [ 3, 7, /* to */ 3, 11 ], 2012: [ 2, 20, /* to */ 2, 24 ], 2013: [ 2, 11, /* to */ 2, 15 ], 2014: [ 3, 3, /* to */ 3, 7 ], 2015: [ 2, 16, /* to */ 2, 20 ], 2016: [ 2, 8, /* to */ 2, 12 ], 2017: [ 2, 27, /* to */ 3, 3 ], }, { name: 'Osterferien', 2010: [ 3, 29, /* to */ 4, 10 ], 2011: [ 4, 18, /* to */ 4, 30 ], 2012: [ 4, 2, /* to */ 4, 14 ], 2013: [ 3, 25, /* to */ 4, 6 ], 2014: [ 4, 14, /* to */ 4, 26 ], 2015: [ 3, 30, /* to */ 4, 11 ], 2016: [ 3, 21, /* to */ 4, 1 ], 2017: [ 4, 10, /* to */ 4, 22 ], }, { name: 'Pfingstferien', 2010: [ 5, 25, /* to */ 6, 5 ], 2011: [ 6, 14, /* to */ 6, 25 ], 2012: [ 5, 29, /* to */ 6, 9 ], 2013: [ 5, 21, /* to */ 5, 31 ], 2014: [ 6, 10, /* to */ 6, 21 ], 2015: [ 5, 26, /* to */ 6, 5 ], 2016: [ 5, 17, /* to */ 5, 28 ], 2017: [ 6, 6, /* to */ 6, 16 ], }, { name: 'Sommerferien', 2010: [ 8, 2, /* to */ 9, 13 ], 2011: [ 7, 30, /* to */ 9, 12 ], 2012: [ 8, 1, /* to */ 9, 12 ], 2013: [ 7, 31, /* to */ 9, 11 ], 2014: [ 7, 30, /* to */ 9, 15 ], 2015: [ 8, 1, /* to */ 9, 14 ], 2016: [ 7, 30, /* to */ 9, 12 ], 2017: [ 7, 29, /* to */ 9, 11 ], }, { name: 'Herbstferien', 2010: [ 11, 2, /* to */ 11, 5 ], 2011: [ 10, 31, /* to */ 11, 5 ], 2012: [ 10, 29, /* to */ 11, 3 ], 2013: [ 10, 28, /* to */ 10, 31 ], 2014: [ 10, 27, /* to */ 10, 31 ], 2015: [ 11, 2, /* to */ 11, 7 ], 2016: [ 10, 31, /* to */ 11, 4 ], }, { name: 'Weihnachtsferien', 2010: [ 12, 24, /* to */ 1, 7 ], 2011: [ 12, 27, /* to */ 1, 5 ], 2012: [ 12, 24, /* to */ 1, 5 ], 2013: [ 12, 23, /* to */ 1, 4 ], 2014: [ 12, 24, /* to */ 1, 5 ], 2015: [ 12, 24, /* to */ 1, 5 ], 2016: [ 12, 24, /* to */ 1, 5 ], }, ], }, 'Niedersachsen': { 'SH': [ { name: 'Winterferien', 2010: [ 2, 1, /* to */ 2, 2 ], 2011: [ 1, 31, /* to */ 2, 1 ], 2012: [ 1, 30, /* to */ 1, 31 ], 2013: [ 1, 31, /* to */ 2, 1 ], 2014: [ 1, 30, /* to */ 1, 31 ], 2015: [ 2, 2, /* to */ 2, 3 ], 2016: [ 1, 28, /* to */ 1, 29 ], 2017: [ 1, 30, /* to */ 1, 31 ], }, { name: 'Osterferien', 2010: [ 3, 19, /* to */ 4, 6 ], 2011: [ 4, 16, /* to */ 4, 30 ], 2012: [ 3, 26, /* to */ 4, 11, 4, 30, /* to */ 4, 30 ], 2013: [ 3, 16, /* to */ 4, 2 ], 2014: [ 4, 3, /* to */ 4, 22, 5, 2, /* to */ 5, 2 ], 2015: [ 3, 25, /* to */ 4, 10 ], 2016: [ 3, 18, /* to */ 4, 2 ], 2017: [ 4, 10, /* to */ 4, 22 ], }, { name: 'Pfingstferien', 2010: [ 5, 14, /* to */ 5, 14, 5, 25, /* to */ 5, 25 ], 2011: [ 6, 3, /* to */ 6, 3, 6, 14, /* to */ 6, 14 ], 2012: [ 5, 18, /* to */ 5, 18, 5, 29, /* to */ 5, 29 ], 2013: [ 5, 10, /* to */ 5, 10, 5, 21, /* to */ 5, 21 ], 2014: [ 5, 30, /* to */ 5, 30, 6, 10, /* to */ 6, 10 ], 2015: [ 5, 15, /* to */ 5, 15, 5, 26, /* to */ 5, 26 ], 2016: [ 5, 6, /* to */ 5, 6, 5, 17, /* to */ 5, 17 ], 2017: [ 5, 26, /* to */ 5, 26, 6, 6, /* to */ 6, 6 ], }, { name: 'Sommerferien', 2010: [ 6, 24, /* to */ 8, 4 ], 2011: [ 7, 7, /* to */ 8, 17 ], 2012: [ 7, 23, /* to */ 8, 31 ], 2013: [ 6, 27, /* to */ 8, 7 ], 2014: [ 7, 31, /* to */ 9, 10 ], 2015: [ 7, 23, /* to */ 9, 2 ], 2016: [ 6, 23, /* to */ 8, 3 ], 2017: [ 6, 22, /* to */ 8, 2 ], }, { name: 'Herbstferien', 2010: [ 10, 9, /* to */ 10, 23 ], 2011: [ 10, 17, /* to */ 10, 29 ], 2012: [ 10, 22, /* to */ 11, 3 ], 2013: [ 10, 4, /* to */ 10, 18 ], 2014: [ 10, 27, /* to */ 11, 8 ], 2015: [ 10, 19, /* to */ 10, 31 ], 2016: [ 10, 4, /* to */ 10, 15 ], }, { name: 'Weihnachtsferien', 2010: [ 12, 22, /* to */ 1, 5 ], 2011: [ 12, 23, /* to */ 1, 4 ], 2012: [ 12, 24, /* to */ 1, 5 ], 2013: [ 12, 23, /* to */ 1, 3 ], 2014: [ 12, 22, /* to */ 1, 5 ], 2015: [ 12, 23, /* to */ 1, 6 ], 2016: [ 12, 21, /* to */ 1, 6 ], }, ], }, 'Nordrhein-Westfalen': { 'SH': [ { name: 'Osterferien', 2010: [ 3, 27, /* to */ 4, 10 ], 2011: [ 4, 18, /* to */ 4, 30 ], 2012: [ 4, 2, /* to */ 4, 14 ], 2013: [ 3, 25, /* to */ 4, 6 ], 2014: [ 4, 14, /* to */ 4, 26 ], 2015: [ 3, 30, /* to */ 4, 11 ], 2016: [ 3, 21, /* to */ 4, 2 ], 2017: [ 4, 10, /* to */ 4, 22 ], }, { name: 'Pfingstferien', 2010: [ 5, 25, /* to */ 5, 25 ], 2012: [ 5, 29, /* to */ 5, 29 ], 2013: [ 5, 21, /* to */ 5, 21 ], 2014: [ 6, 10, /* to */ 6, 10 ], 2015: [ 5, 26, /* to */ 5, 26 ], 2016: [ 5, 17, /* to */ 5, 17 ], 2017: [ 6, 6, /* to */ 6, 6 ], }, { name: 'Sommerferien', 2010: [ 7, 15, /* to */ 8, 27 ], 2011: [ 7, 25, /* to */ 9, 6 ], 2012: [ 7, 9, /* to */ 8, 21 ], 2013: [ 7, 22, /* to */ 9, 3 ], 2014: [ 7, 7, /* to */ 8, 19 ], 2015: [ 6, 29, /* to */ 8, 11 ], 2016: [ 7, 11, /* to */ 8, 23 ], 2017: [ 7, 17, /* to */ 8, 29 ], }, { name: 'Herbstferien', 2010: [ 10, 11, /* to */ 10, 23 ], 2011: [ 10, 24, /* to */ 11, 5 ], 2012: [ 10, 8, /* to */ 10, 20 ], 2013: [ 10, 21, /* to */ 11, 2 ], 2014: [ 10, 6, /* to */ 10, 18 ], 2015: [ 10, 5, /* to */ 10, 17 ], 2016: [ 10, 10, /* to */ 10, 21 ], }, { name: 'Weihnachtsferien', 2010: [ 12, 24, /* to */ 1, 8 ], 2011: [ 12, 23, /* to */ 1, 6 ], 2012: [ 12, 21, /* to */ 1, 4 ], 2013: [ 12, 23, /* to */ 1, 7 ], 2014: [ 12, 22, /* to */ 1, 6 ], 2015: [ 12, 23, /* to */ 1, 6 ], 2016: [ 12, 23, /* to */ 1, 6 ], }, ], }, 'Sachsen': { 'SH': [ { name: 'Winterferien', 2010: [ 2, 8, /* to */ 2, 20 ], 2011: [ 2, 12, /* to */ 2, 26 ], 2012: [ 2, 13, /* to */ 2, 25 ], 2013: [ 2, 4, /* to */ 2, 15 ], 2014: [ 2, 17, /* to */ 3, 1 ], 2015: [ 2, 9, /* to */ 2, 21 ], 2016: [ 2, 8, /* to */ 2, 20 ], 2017: [ 2, 13, /* to */ 2, 24 ], }, { name: 'Osterferien', 2010: [ 4, 1, /* to */ 4, 10 ], 2011: [ 4, 22, /* to */ 4, 30 ], 2012: [ 4, 6, /* to */ 4, 14 ], 2013: [ 3, 29, /* to */ 4, 6 ], 2014: [ 4, 18, /* to */ 4, 26 ], 2015: [ 4, 2, /* to */ 4, 11 ], 2016: [ 3, 25, /* to */ 4, 2 ], 2017: [ 4, 13, /* to */ 4, 22 ], }, { name: 'Pfingstferien', 2010: [ 5, 14, /* to */ 5, 14 ], 2011: [ 6, 3, /* to */ 6, 3 ], 2012: [ 5, 18, /* to */ 5, 18 ], 2013: [ 5, 10, /* to */ 5, 10, 5, 18, /* to */ 5, 22 ], 2014: [ 5, 30, /* to */ 5, 30 ], 2015: [ 5, 15, /* to */ 5, 15 ], 2016: [ 5, 6, /* to */ 5, 6 ], 2017: [ 5, 26, /* to */ 5, 26 ], }, { name: 'Sommerferien', 2010: [ 6, 28, /* to */ 8, 6 ], 2011: [ 7, 11, /* to */ 8, 19 ], 2012: [ 7, 23, /* to */ 8, 31 ], 2013: [ 7, 15, /* to */ 8, 23 ], 2014: [ 7, 21, /* to */ 8, 29 ], 2015: [ 7, 13, /* to */ 8, 21 ], 2016: [ 6, 27, /* to */ 8, 5 ], 2017: [ 6, 26, /* to */ 8, 4 ], }, { name: 'Herbstferien', 2010: [ 10, 4, /* to */ 10, 16 ], 2011: [ 10, 17, /* to */ 10, 28 ], 2012: [ 10, 22, /* to */ 11, 2 ], 2013: [ 10, 21, /* to */ 11, 1 ], 2014: [ 10, 20, /* to */ 10, 31 ], 2015: [ 10, 12, /* to */ 10, 24 ], 2016: [ 10, 3, /* to */ 10, 15 ], }, { name: 'Weihnachtsferien', 2010: [ 12, 23, /* to */ 1, 1 ], 2011: [ 12, 23, /* to */ 1, 2 ], 2012: [ 12, 22, /* to */ 1, 2 ], 2013: [ 12, 21, /* to */ 1, 3 ], 2014: [ 12, 22, /* to */ 1, 3 ], 2015: [ 12, 21, /* to */ 1, 2 ], 2016: [ 12, 23, /* to */ 1, 2 ], }, ], }, 'Thüringen': { 'SH': [ { name: 'Winterferien', 2010: [ 2, 1, /* to */ 2, 6 ], 2011: [ 1, 31, /* to */ 2, 5 ], 2012: [ 2, 6, /* to */ 2, 11 ], 2013: [ 2, 18, /* to */ 2, 23 ], 2014: [ 2, 17, /* to */ 2, 22 ], 2015: [ 2, 2, /* to */ 2, 7 ], 2016: [ 2, 1, /* to */ 2, 6 ], 2017: [ 2, 6, /* to */ 2, 11 ], }, { name: 'Osterferien', 2010: [ 3, 29, /* to */ 4, 9 ], 2011: [ 4, 18, /* to */ 4, 30 ], 2012: [ 4, 2, /* to */ 4, 13 ], 2013: [ 3, 25, /* to */ 4, 6 ], 2014: [ 4, 19, /* to */ 5, 2 ], 2015: [ 3, 30, /* to */ 4, 11 ], 2016: [ 3, 24, /* to */ 4, 2 ], 2017: [ 4, 10, /* to */ 4, 21 ], }, { name: 'Sommerferien', 2010: [ 6, 24, /* to */ 8, 4 ], 2011: [ 7, 11, /* to */ 8, 19 ], 2012: [ 7, 23, /* to */ 8, 31 ], 2013: [ 7, 15, /* to */ 8, 23 ], 2014: [ 7, 21, /* to */ 8, 29 ], 2015: [ 7, 13, /* to */ 8, 21 ], 2016: [ 6, 27, /* to */ 8, 10 ], 2017: [ 6, 26, /* to */ 8, 9 ], }, { name: 'Pfingstferien', 2011: [ 6, 11, /* to */ 6, 14 ], 2012: [ 5, 25, /* to */ 5, 29 ], 2013: [ 5, 10, /* to */ 5, 10 ], 2014: [ 5, 30, /* to */ 5, 30 ], 2015: [ 5, 15, /* to */ 5, 15 ], 2016: [ 5, 6, /* to */ 5, 6 ], 2017: [ 5, 26, /* to */ 5, 26 ], }, { name: 'Herbstferien', 2010: [ 10, 9, /* to */ 10, 23 ], 2011: [ 10, 17, /* to */ 10, 28 ], 2012: [ 10, 22, /* to */ 11, 3 ], 2013: [ 10, 21, /* to */ 11, 2 ], 2014: [ 10, 6, /* to */ 10, 18 ], 2015: [ 10, 5, /* to */ 10, 17 ], 2016: [ 10, 10, /* to */ 10, 22 ], }, { name: 'Weihnachtsferien', 2010: [ 12, 23, /* to */ 1, 1 ], 2011: [ 12, 23, /* to */ 1, 1 ], 2012: [ 12, 24, /* to */ 1, 5 ], 2013: [ 12, 23, /* to */ 1, 4 ], 2014: [ 12, 22, /* to */ 1, 3 ], 2015: [ 12, 23, /* to */ 1, 2 ], 2016: [ 12, 23, /* to */ 12, 31 ], }, ], }, 'Hamburg': { 'SH': [ { name: 'Winterferien', 2010: [ 1, 29, /* to */ 1, 29 ], 2011: [ 1, 31, /* to */ 1, 31 ], 2012: [ 1, 30, /* to */ 1, 30 ], 2013: [ 2, 1, /* to */ 2, 1 ], 2014: [ 1, 31, /* to */ 1, 31 ], 2015: [ 1, 30, /* to */ 1, 30 ], 2016: [ 1, 29, /* to */ 1, 29 ], 2017: [ 1, 30, /* to */ 1, 30 ], }, { name: 'Osterferien', 2010: [ 3, 8, /* to */ 3, 20 ], 2011: [ 3, 7, /* to */ 3, 18 ], 2012: [ 3, 5, /* to */ 3, 16 ], 2013: [ 3, 4, /* to */ 3, 15 ], 2014: [ 3, 3, /* to */ 3, 14 ], 2015: [ 3, 2, /* to */ 3, 13 ], 2016: [ 3, 7, /* to */ 3, 18 ], 2017: [ 3, 6, /* to */ 3, 17 ], }, { name: 'Pfingstferien', 2010: [ 5, 14, /* to */ 5, 22 ], 2011: [ 4, 26, /* to */ 4, 29, 6, 3, /* to */ 6, 3 ], 2012: [ 4, 30, /* to */ 5, 4, 5, 18, /* to */ 5, 18 ], 2013: [ 5, 2, /* to */ 5, 10 ], 2014: [ 4, 28, /* to */ 5, 2, 5, 30, /* to */ 5, 30 ], 2015: [ 5, 11, /* to */ 5, 15 ], 2016: [ 5, 6, /* to */ 5, 6, 5, 17, /* to */ 5, 20 ], 2017: [ 5, 22, /* to */ 5, 26 ], }, { name: 'Sommerferien', 2010: [ 7, 8, /* to */ 8, 18 ], 2011: [ 6, 30, /* to */ 8, 10 ], 2012: [ 6, 21, /* to */ 8, 1 ], 2013: [ 6, 20, /* to */ 7, 31 ], 2014: [ 7, 10, /* to */ 8, 20 ], 2015: [ 7, 16, /* to */ 8, 26 ], 2016: [ 7, 21, /* to */ 8, 31 ], 2017: [ 7, 20, /* to */ 8, 30 ], }, { name: 'Herbstferien', 2010: [ 10, 4, /* to */ 10, 15 ], 2011: [ 10, 4, /* to */ 10, 14 ], 2012: [ 10, 1, /* to */ 10, 12 ], 2013: [ 9, 30, /* to */ 10, 11 ], 2014: [ 10, 13, /* to */ 10, 24 ], 2015: [ 10, 19, /* to */ 10, 30 ], 2016: [ 10, 17, /* to */ 10, 28 ], }, { name: 'Weihnachtsferien', 2010: [ 12, 23, /* to */ 1, 3 ], 2011: [ 12, 27, /* to */ 1, 6 ], 2012: [ 12, 21, /* to */ 1, 4 ], 2013: [ 12, 19, /* to */ 1, 3 ], 2014: [ 12, 22, /* to */ 1, 6 ], 2015: [ 12, 21, /* to */ 1, 1 ], 2016: [ 12, 27, /* to */ 1, 6 ], }, ], }, 'Sachsen-Anhalt': { 'SH': [ { name: 'Winterferien', 2010: [ 2, 8, /* to */ 2, 13 ], 2011: [ 2, 5, /* to */ 2, 12 ], 2012: [ 2, 4, /* to */ 2, 11 ], 2013: [ 2, 1, /* to */ 2, 8 ], 2014: [ 2, 1, /* to */ 2, 12 ], 2015: [ 2, 2, /* to */ 2, 14 ], 2016: [ 2, 1, /* to */ 2, 10 ], 2017: [ 2, 4, /* to */ 2, 11 ], }, { name: 'Osterferien', 2010: [ 3, 29, /* to */ 4, 9 ], 2011: [ 4, 18, /* to */ 4, 27 ], 2012: [ 4, 2, /* to */ 4, 7 ], 2013: [ 3, 25, /* to */ 3, 30 ], 2014: [ 4, 14, /* to */ 4, 17 ], 2015: [ 4, 2, /* to */ 4, 2 ], 2016: [ 3, 24, /* to */ 3, 24 ], 2017: [ 4, 10, /* to */ 4, 13 ], }, { name: 'Pfingstferien', 2010: [ 5, 14, /* to */ 5, 22 ], 2011: [ 6, 14, /* to */ 6, 18 ], 2012: [ 5, 18, /* to */ 5, 25 ], 2013: [ 5, 10, /* to */ 5, 18 ], 2014: [ 5, 30, /* to */ 6, 7 ], 2015: [ 5, 15, /* to */ 5, 23 ], 2016: [ 5, 6, /* to */ 5, 14 ], 2017: [ 5, 26, /* to */ 5, 26 ], }, { name: 'Sommerferien', 2010: [ 6, 24, /* to */ 8, 4 ], 2011: [ 7, 11, /* to */ 8, 24 ], 2012: [ 7, 23, /* to */ 9, 5 ], 2013: [ 7, 15, /* to */ 8, 28 ], 2014: [ 7, 21, /* to */ 9, 3 ], 2015: [ 7, 13, /* to */ 8, 26 ], 2016: [ 6, 27, /* to */ 8, 10 ], 2017: [ 6, 26, /* to */ 8, 9 ], }, { name: 'Herbstferien', 2010: [ 10, 18, /* to */ 10, 23 ], 2011: [ 10, 17, /* to */ 10, 22 ], 2012: [ 10, 29, /* to */ 11, 2 ], 2013: [ 10, 21, /* to */ 10, 25 ], 2014: [ 10, 27, /* to */ 10, 30 ], 2015: [ 10, 17, /* to */ 10, 24 ], 2016: [ 10, 4, /* to */ 10, 15 ], }, { name: 'Weihnachtsferien', 2010: [ 12, 22, /* to */ 1, 5 ], 2011: [ 12, 22, /* to */ 1, 7 ], 2012: [ 12, 19, /* to */ 1, 4 ], 2013: [ 12, 21, /* to */ 1, 3 ], 2014: [ 12, 22, /* to */ 1, 5 ], 2015: [ 12, 21, /* to */ 1, 5 ], 2016: [ 12, 19, /* to */ 1, 2 ], }, ], }, 'Rheinland-Pfalz': { 'SH': [ { name: 'Osterferien', 2010: [ 3, 26, /* to */ 4, 9 ], 2011: [ 4, 18, /* to */ 4, 29 ], 2012: [ 3, 29, /* to */ 4, 13 ], 2013: [ 3, 20, /* to */ 4, 5 ], 2014: [ 4, 11, /* to */ 4, 25 ], 2015: [ 3, 26, /* to */ 4, 10 ], 2016: [ 3, 18, /* to */ 4, 1 ], 2017: [ 4, 10, /* to */ 4, 21 ], }, { name: 'Sommerferien', 2010: [ 7, 5, /* to */ 8, 13 ], 2011: [ 6, 27, /* to */ 8, 5 ], 2012: [ 7, 2, /* to */ 8, 10 ], 2013: [ 7, 8, /* to */ 8, 16 ], 2014: [ 7, 28, /* to */ 9, 5 ], 2015: [ 7, 27, /* to */ 9, 4 ], 2016: [ 7, 18, /* to */ 8, 26 ], 2017: [ 7, 3, /* to */ 8, 11 ], }, { name: 'Herbstferien', 2010: [ 10, 11, /* to */ 10, 22 ], 2011: [ 10, 4, /* to */ 10, 14 ], 2012: [ 10, 1, /* to */ 10, 12 ], 2013: [ 10, 4, /* to */ 10, 18 ], 2014: [ 10, 20, /* to */ 10, 31 ], 2015: [ 10, 19, /* to */ 10, 30 ], 2016: [ 10, 10, /* to */ 10, 21 ], }, { name: 'Weihnachtsferien', 2010: [ 12, 23, /* to */ 1, 7 ], 2011: [ 12, 22, /* to */ 1, 6 ], 2012: [ 12, 20, /* to */ 1, 4 ], 2013: [ 12, 23, /* to */ 1, 7 ], 2014: [ 12, 22, /* to */ 1, 7 ], 2015: [ 12, 23, /* to */ 1, 8 ], 2016: [ 12, 22, /* to */ 1, 6 ], }, ], }, 'Brandenburg': { 'SH': [ { name: 'Winterferien', 2010: [ 2, 1, /* to */ 2, 6 ], 2011: [ 1, 31, /* to */ 2, 5 ], 2012: [ 1, 30, /* to */ 2, 4 ], 2013: [ 2, 4, /* to */ 2, 9 ], 2014: [ 2, 3, /* to */ 2, 8 ], 2015: [ 2, 2, /* to */ 2, 7 ], 2016: [ 2, 1, /* to */ 2, 6 ], 2017: [ 1, 30, /* to */ 2, 4 ], }, { name: 'Osterferien', 2010: [ 3, 31, /* to */ 4, 10 ], 2011: [ 4, 20, /* to */ 4, 30 ], 2012: [ 4, 4, /* to */ 4, 14, 4, 30, /* to */ 4, 30 ], 2013: [ 3, 27, /* to */ 4, 6 ], 2014: [ 4, 16, /* to */ 4, 26, 5, 2, /* to */ 5, 2 ], 2015: [ 4, 1, /* to */ 4, 11 ], 2016: [ 3, 23, /* to */ 4, 2 ], 2017: [ 4, 12, /* to */ 4, 22 ], }, { name: 'Pfingstferien', 2010: [ 5, 14, /* to */ 5, 14 ], 2011: [ 6, 3, /* to */ 6, 3 ], 2012: [ 5, 18, /* to */ 5, 18 ], 2013: [ 5, 10, /* to */ 5, 10 ], 2014: [ 5, 30, /* to */ 5, 30 ], 2015: [ 5, 15, /* to */ 5, 15 ], 2016: [ 5, 6, /* to */ 5, 6, 5, 17, /* to */ 5, 17 ], 2017: [ 5, 26, /* to */ 5, 26 ], }, { name: 'Sommerferien', 2010: [ 7, 8, /* to */ 8, 21 ], 2011: [ 6, 30, /* to */ 8, 13 ], 2012: [ 6, 21, /* to */ 8, 3 ], 2013: [ 6, 20, /* to */ 8, 2 ], 2014: [ 7, 10, /* to */ 8, 22 ], 2015: [ 7, 16, /* to */ 8, 28 ], 2016: [ 7, 21, /* to */ 9, 3 ], 2017: [ 7, 20, /* to */ 9, 1 ], }, { name: 'Herbstferien', 2010: [ 10, 11, /* to */ 10, 23 ], 2011: [ 10, 4, /* to */ 10, 14 ], 2012: [ 10, 1, /* to */ 10, 13 ], 2013: [ 9, 30, /* to */ 10, 12, 11, 1, /* to */ 11, 1 ], 2014: [ 10, 20, /* to */ 11, 1 ], 2015: [ 10, 19, /* to */ 10, 30 ], 2016: [ 10, 17, /* to */ 10, 28 ], }, { name: 'Weihnachtsferien', 2010: [ 12, 23, /* to */ 1, 1 ], 2011: [ 12, 23, /* to */ 1, 3 ], 2012: [ 12, 24, /* to */ 1, 4 ], 2013: [ 12, 23, /* to */ 1, 3 ], 2014: [ 12, 22, /* to */ 1, 2 ], 2015: [ 12, 23, /* to */ 1, 2 ], 2016: [ 12, 23, /* to */ 1, 3 ], }, ], }, }, 'at': { 'PH': { // http://de.wikipedia.org/wiki/Feiertage_in_%C3%96sterreich 'Neujahrstag' : [ 1, 1 ], 'Heilige Drei Könige' : [ 1, 6 ], // 'Josef' : [ 3, 19, [ 'Kärnten', 'Steiermark', 'Tirol', 'Vorarlberg' ] ], // 'Karfreitag' : [ 'easter', -2 ], 'Ostermontag' : [ 'easter', 1 ], 'Staatsfeiertag' : [ 5, 1 ], // 'Florian' : [ 5, 4, [ 'Oberösterreich' ] ], 'Christi Himmelfahrt' : [ 'easter', 39 ], 'Pfingstmontag' : [ 'easter', 50 ], 'Fronleichnam' : [ 'easter', 60 ], 'Mariä Himmelfahrt' : [ 8, 15 ], // 'Rupert' : [ 9, 24, [ 'Salzburg' ] ], // 'Tag der Volksabstimmung' : [ 10, 10, [ 'Kärnten' ] ], 'Nationalfeiertag' : [ 10, 26 ], 'Allerheiligen' : [ 11, 1 ], // 'Martin' : [ 11, 11, [ 'Burgenland' ] ], // 'Leopold' : [ 11, 15, [ 'Niederösterreich', 'Wien' ] ], 'Mariä Empfängnis' : [ 12, 8 ], // 'Heiliger Abend' : [ 12, 24 ], 'Christtag' : [ 12, 25 ], 'Stefanitag' : [ 12, 26 ], // 'Silvester' : [ 12, 31 ], }, }, 'ca': { 'PH': { // https://en.wikipedia.org/wiki/Public_holidays_in_Canada "New Year's Day" : [ 1, 1 ], "Good Friday" : [ 'easter', -2 ], "Canada Day" : [ 'canadaDay', 0 ], "Labour Day" : [ 'firstSeptemberMonday', 0 ], "Christmas Day" : [ 12, 25 ] }, 'Alberta': { 'PH': { "New Year's Day" : [ 1, 1 ], "Alberta Family Day" : [ 'firstFebruaryMonday', 14 ], "Good Friday" : [ 'easter', -2 ], "Easter Monday" : [ 'easter', 1 ], "Victoria Day" : [ 'victoriaDay', 0 ], "Canada Day" : [ 'canadaDay', 0 ], "Heritage Day" : [ 'firstAugustMonday', 0 ], "Labour Day" : [ 'firstSeptemberMonday', 0 ], "Thanksgiving" : [ 'firstOctoberMonday', 7 ], "Remembrance Day" : [ 11, 11 ], "Christmas Day" : [ 12, 25 ], "Boxing Day" : [ 12, 26 ] }, }, 'British Columbia': { 'PH': { "New Year's Day" : [ 1, 1 ], "Family Day" : [ 'firstFebruaryMonday', 7 ], "Good Friday" : [ 'easter', -2 ], "Victoria Day" : [ 'victoriaDay', 0 ], "Canada Day" : [ 'canadaDay', 0 ], "British Columbia Day" : [ 'firstAugustMonday', 0 ], "Labour Day" : [ 'firstSeptemberMonday', 0 ], "Thanksgiving" : [ 'firstOctoberMonday', 7 ], "Remembrance Day" : [ 11, 11 ], "Christmas Day" : [ 12, 25 ] }, }, 'Manitoba': { 'PH': { "New Year's Day" : [ 1, 1 ], "Louis Riel Day" : [ 'firstFebruaryMonday', 14 ], "Good Friday" : [ 'easter', -2 ], "Victoria Day" : [ 'victoriaDay', 0 ], "Canada Day" : [ 'canadaDay', 0 ], "Civic Holiday" : [ 'firstAugustMonday', 0 ], "Labour Day" : [ 'firstSeptemberMonday', 0 ], "Thanksgiving" : [ 'firstOctoberMonday', 7 ], "Remembrance Day" : [ 11, 11 ], "Christmas Day" : [ 12, 25 ] }, }, 'New Brunswick': { 'PH': { "New Year's Day" : [ 1, 1 ], "Good Friday" : [ 'easter', -2 ], "Victoria Day" : [ 'victoriaDay', 0 ], "Canada Day" : [ 'canadaDay', 0 ], "New Brunswick Day" : [ 'firstAugustMonday', 0 ], "Labour Day" : [ 'firstSeptemberMonday', 0 ], "Thanksgiving" : [ 'firstOctoberMonday', 7 ], "Remembrance Day" : [ 11, 11 ], "Christmas Day" : [ 12, 25 ], "Boxing Day" : [ 12, 26 ] }, }, 'Newfoundland and Labrador': { 'PH': { "New Year's Day" : [ 1, 1 ], "Saint Patrick's Day" : [ 3, 17 ], "Good Friday" : [ 'easter', -2 ], "Saint George's Day" : [ 4, 23 ], "Discovery Day" : [ 6, 24 ], "Memorial Day" : [ 7, 1 ], "Orangemen's Day" : [ 7, 12 ], "Labour Day" : [ 'firstSeptemberMonday', 0 ], "Armistice Day" : [ 11, 11 ], "Christmas Day" : [ 12, 25 ] }, }, 'Northwest Territories': { 'PH': { "New Year's Day" : [ 1, 1 ], "Good Friday" : [ 'easter', -2 ], "Victoria Day" : [ 'victoriaDay', 0 ], "National Aboriginal Day" : [ 6, 21 ], "Canada Day" : [ 'canadaDay', 0 ], "Civic Holiday" : [ 'firstAugustMonday', 0 ], "Labour Day" : [ 'firstSeptemberMonday', 0 ], "Thanksgiving" : [ 'firstOctoberMonday', 7 ], "Remembrance Day" : [ 11, 11 ], "Christmas Day" : [ 12, 25 ] }, }, 'Nova Scotia': { 'PH': { "New Year's Day" : [ 1, 1 ], "Good Friday" : [ 'easter', -2 ], "Victoria Day" : [ 'victoriaDay', 0 ], "Canada Day" : [ 'canadaDay', 0 ], "Natal Day" : [ 'firstAugustMonday', 0 ], "Labour Day" : [ 'firstSeptemberMonday', 0 ], "Thanksgiving" : [ 'firstOctoberMonday', 7 ], "Remembrance Day" : [ 11, 11 ], "Christmas Day" : [ 12, 25 ], "Boxing Day" : [ 12, 26 ] }, }, 'Nunavut': { 'PH': { "New Year's Day" : [ 1, 1 ], "Good Friday" : [ 'easter', -2 ], "Victoria Day" : [ 'victoriaDay', 0 ], "Canada Day" : [ 'canadaDay', 0 ], "Nunavut Day" : [ 7, 9 ], "Civic Holiday" : [ 'firstAugustMonday', 0 ], "Labour Day" : [ 'firstSeptemberMonday', 0 ], "Thanksgiving" : [ 'firstOctoberMonday', 7 ], "Remembrance Day" : [ 11, 11 ], "Christmas Day" : [ 12, 25 ] }, }, 'Ontario': { 'PH': { "New Year's Day" : [ 1, 1 ], "Family Day" : [ 'firstFebruaryMonday', 14 ], "Good Friday" : [ 'easter', -2 ], "Victoria Day" : [ 'victoriaDay', 0 ], "Canada Day" : [ 'canadaDay', 0 ], "August Civic Public Holiday" : [ 'firstAugustMonday', 0 ], "Labour Day" : [ 'firstSeptemberMonday', 0 ], "Thanksgiving" : [ 'firstOctoberMonday', 7 ], "Remembrance Day" : [ 11, 11 ], "Christmas Day" : [ 12, 25 ], "Boxing Day" : [ 12, 26 ] }, }, 'Prince Edward Island': { 'PH': { "New Year's Day" : [ 1, 1 ], "Islander Day" : [ 'firstFebruaryMonday', 14 ], "Good Friday" : [ 'easter', -2 ], "Easter Monday" : [ 'easter', 1 ], "Victoria Day" : [ 'victoriaDay', 0 ], "Canada Day" : [ 'canadaDay', 0 ], "Civic Holiday" : [ 'firstAugustMonday', 0 ], "Gold Cup Parade Day" : [ 'firstAugustMonday', 18 ], "Labour Day" : [ 'firstSeptemberMonday', 0 ], "Thanksgiving" : [ 'firstOctoberMonday', 7 ], "Remembrance Day" : [ 11, 11 ], "Christmas Day" : [ 12, 25 ], "Boxing Day" : [ 12, 26 ] }, }, 'Quebec': { 'PH': { "Jour de l'an" : [ 1, 1 ], "Vendredi saint" : [ 'easter', -2 ], "Lundi de Pâques" : [ 'easter', 1 ], "Journée nationale des patriotes" : [ 'victoriaDay', 0 ], "Fête nationale du Québec" : [ 6, 24 ], "Fête du Canada" : [ 'canadaDay', 0 ], "Fête du Travail" : [ 'firstSeptemberMonday', 0 ], "Jour de l'Action de grâce" : [ 'firstOctoberMonday', 7 ], "Noël" : [ 12, 25 ] }, }, 'Saskatchewan': { 'PH': { "New Year's Day" : [ 1, 1 ], "Family Day" : [ 'firstFebruaryMonday', 14 ], "Good Friday" : [ 'easter', -2 ], "Victoria Day" : [ 'victoriaDay', 0 ], "Canada Day" : [ 'canadaDay', 0 ], "Saskatchewan Day" : [ 'firstAugustMonday', 0 ], "Labour Day" : [ 'firstSeptemberMonday', 0 ], "Thanksgiving" : [ 'firstOctoberMonday', 7 ], "Remembrance Day" : [ 11, 11 ], "Christmas Day" : [ 12, 25 ] }, }, 'Yukon': { 'PH': { "New Year's Day" : [ 1, 1 ], "Heritage Day" : [ 'lastFebruarySunday', -2 ], "Good Friday" : [ 'easter', -2 ], "Easter Monday" : [ 'easter', 1 ], "Victoria Day" : [ 'victoriaDay', 0 ], "Canada Day" : [ 'canadaDay', 0 ], "Discovery Day" : [ 'firstAugustMonday', 14 ], "Labour Day" : [ 'firstSeptemberMonday', 0 ], "Thanksgiving" : [ 'firstOctoberMonday', 7 ], "Remembrance Day" : [ 11, 11 ], "Christmas Day" : [ 12, 25 ], "Boxing Day" : [ 12, 26 ] }, }, }, 'ua': { '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 "Новий рік" : [ 1, 1 ], "Різдво" : [ 1, 7 ], "Міжнародний жіночий день" : [ 3, 8 ], "Великдень" : [ 'orthodox easter', 1 ], "День Праці 1" : [ 5, 1 ], "День Праці 2" : [ 5, 2 ], "День Перемоги" : [ 5, 9 ], "День Конституції України" : [ 6, 28 ], "День Незалежності України" : [ 8, 24 ], } }, 'si': { 'PH': { // http://www.vlada.si/o_sloveniji/politicni_sistem/prazniki/ 'novo leto' : [ 1, 1 ], 'Prešernov dan, slovenski kulturni praznik' : [ 2, 8 ], 'velikonočna nedelja' : [ 'easter', 0 ], 'velikonočni ponedeljek' : [ 'easter', 1 ], 'dan upora proti okupatorju' : [ 4, 27 ], 'praznik dela 1' : [ 5, 1 ], 'praznik dela 2' : [ 5, 2 ], 'binkoštna nedelja - binkošti' : [ 'easter', 49 ], 'dan državnosti' : [ 6, 25 ], 'Marijino vnebovzetje' : [ 8, 15 ], 'dan reformacije' : [ 10, 31 ], 'dan spomina na mrtve' : [ 11, 1 ], 'božič' : [ 12, 25 ], 'dan samostojnosti in enotnosti' : [ 12, 26 ], }, }, }; // }}} // error correction {{{ // Taken form http://www.netzwolf.info/j/osm/time_domain.js // Credits go to Netzwolf // // Key to word_error_correction is the token name except wrong_words var word_error_correction = { wrong_words: { 'Assuming "" for ""': { spring: 'Mar-May', summer: 'Jun-Aug', autumn: 'Sep-Nov', winter: 'Dec-Feb', // morning: '08:00-12:00', // evening: '13:00-18:00', '_': '-', 'daytime': 'sunrise-sunset', }, 'Bitte benutze die englische Schreibweise "" für "".': { sommer: 'summer', 'werktag': 'Mo-Fr', 'werktags': 'Mo-Fr', }, 'Bitte benutze "" für "". Beispiel: "Mo-Fr 08:00-12:00; Tu off"': { ruhetag: 'off', ruhetage: 'off', geschlossen: 'off', ausser: 'off', außer: 'off', }, 'Neem de engelse afkorting "" voor "" alstublieft.': { 'gesloten': 'off', 'feestdag': 'PH', }, 'Assuming "" for "". Please avoid using "workday": http://wiki.openstreetmap.org/wiki/Talk:Key:opening_hours#need_syntax_for_holidays_and_workingdays': { // // Used around 260 times but the problem is, that work day might be different in other countries. 'wd': 'Mo-Fr', 'weekday': 'Mo-Fr', 'weekdays': 'Mo-Fr', 'vardagar': 'Mo-Fr', }, 'Please use notation something like "Mo off" instead "".': { except: 'off', }, 'Please ommit "" or use a colon instead: "12:00-14:00".': { h: '', }, 'Please ommit "".': { season: '', hs: '', hrs: '', hours: '', }, 'Please ommit "". The key must not be in the value.': { 'opening_hours=': '', }, 'Please ommit "". You might want to express open end which can be specified as "12:00+" for example.': { from: '', }, 'You can use notation "" for "". You might want to express open end which can be specified as "12:00+" for example.': { '-late': '+', }, 'Please use notation "" for "". If the times are unsure or vary consider a comment e.g. 12:00-14:00 "only on sunshine".': { '~': '-', '~': '-', }, 'Please use notation "" for "". Fallback rule: 12:00-14:00 || "call us"': { 'otherwise': '||', }, 'You can use notation "" for "" temporally if the syntax will still be valid.': { '?': 'unknown "please add this if known"', }, 'Please use notation "" for "".': { '→': '-', '–': '-', '−': '-', '=': '-', 'ー': '-', to: '-', 'до': '-', a: '-', // language unknown as: '-', // language unknown 'á': '-', // language unknown 'ás': '-', // language unknown 'à': '-', // language unknown 'às': '-', // language unknown 'ate': '-', // language unknown 'till': '-', 'til': '-', 'until': '-', 'through': '-', and: ',', '&': ',', ':': ':', '°°': ':00', 'daily': 'Mo-Su', 'everyday': 'Mo-Su', 'every day': 'Mo-Su', always: '24/7', nonstop: '24/7', '24x7': '24/7', 'anytime': '24/7', 'all day': '24/7', 'all days': 'Mo-Su', 'every day': 'Mo-Su', '7days': 'Mo-Su', '7j/7': 'Mo-Su', // I guess that it means that '7/7': 'Mo-Su', // I guess that it means that '7 days': 'Mo-Su', '7 days a week': 'Mo-Su', 'midnight': '00:00', holiday: 'PH', holidays: 'PH', 'public holidays': 'PH', 'public holiday': 'PH', // summerholiday: 'SH', // summerholidays: 'SH', weekend: 'Sa,Su', weekends: 'Sa,Su', 'daylight': 'sunrise-sunset', 'оff': 'off', // Russian o }, 'Please use time format in 24 hours notation (""). If PM is used you might have to convert the hours to the 24 hours notation.': { 'pm': '', 'рм': '', 'am': '', 'ам': '', }, 'Bitte verzichte auf "".': { 'uhr': '', 'geöffnet': '', }, 'Bitte verzichte auf "". Sie möchten eventuell eine Öffnungszeit ohne vorgegebenes Ende angeben. Beispiel: "12:00+"': { ab: '', von: '', }, 'Bitte benutze die Schreibweise "" für "".': { bis: '-', 'täglich': 'Mo-Su', }, 'Bitte benutze die Schreibweise "" als Ersatz für "und" bzw. "u.".': { und: ',', u: ',', }, 'Bitte benutze die englische Abkürzung "" für "".': { feiertag: 'PH', feiertags: 'PH', feiertage: 'PH', feiertagen: 'PH' }, 'S\'il vous plaît utiliser "" pour "".': { 'fermé': 'off', 'et': ',', 'à': '-', 'jours fériés': 'PH', }, 'Neem de engelse afkorting "" voor "" alstublieft.': { feestdag: 'PH', feestdagen: 'PH', } }, month: { 'default': { jan: 0, feb: 1, mar: 2, apr: 3, may: 4, jun: 5, jul: 6, aug: 7, sep: 8, oct: 9, nov: 10, dec: 11, }, 'Please use the English abbreviation "" for "".': { 'jänner': 0, // Austria january: 0, february: 1, march: 2, april: 3, // may: 4, june: 5, july: 6, august: 7, september: 8, sept: 8, october: 9, november: 10, december: 11, }, 'Bitte benutze die englische Abkürzung "" für "".': { januar: 0, februar: 1, 'märz': 2, maerz: 2, mai: 4, juni: 5, juli: 6, okt: 9, oktober: 9, dez: 11, dezember: 11, }, 'S\'il vous plaît utiliser l\'abréviation "" pour "".': { janvier: 0, février: 1, fév: 1, mars: 2, avril: 3, avr: 3, mai: 4, juin: 5, juillet: 6, août: 7, aoû: 7, septembre: 8, octobre: 9, novembre: 10, décembre: 11, }, 'Neem de engelse afkorting "" voor "" alstublieft.': { januari: 0, februari: 1, maart: 2, mei: 4, augustus: 7, } }, weekday: { // good source: http://www.omniglot.com/language/time/days.htm 'default': { su: 0, mo: 1, tu: 2, we: 3, th: 4, fr: 5, sa: 6, }, 'Assuming "" for ""': { m: 1, w: 3, f: 5, }, 'Please use the abbreviation "" for "".': { sun: 0, sunday: 0, sundays: 0, mon: 1, monday: 1, mondays: 1, tue: 2, tuesday: 2, tuesdays: 2, wed: 3, wednesday: 3, wednesdays: 3, thu: 4, thur: 4, thursday: 4, thursdays: 4, fri: 5, friday: 5, fridays: 5, sat: 6, saturday: 6, saturdays: 6, }, 'Bitte benutze die englische Abkürzung "" für "". Could also mean Saturday in Polish …': { so: 0, }, 'Bitte benutze die englische Abkürzung "" für "".': { son: 0, sonntag: 0, 'sonn-': 0, sonntags: 0, montag: 1, montags: 1, di: 2, die: 2, dienstag: 2, dienstags: 2, mi: 3, mit: 3, mittwoch: 3, mittwochs: 3, 'do': 4, don: 4, donnerstag: 4, donnerstags: 4, fre: 5, freitag: 5, freitags: 5, sam: 6, samstag: 6, samstags: 6, }, 'S\'il vous plaît utiliser l\'abréviation "" pour "".': { dim: 0, dimanche: 0, lu: 1, lun: 1, lundi: 1, mardi: 2, mer: 3, mercredi: 3, je: 4, jeu: 4, jeudi: 4, ve: 5, ven: 5, vendredi: 5, samedi: 6, }, 'Neem de engelse afkorting "" voor "" alstublieft.': { zo: 0, zon: 0, zontag: 0, // correct? zondag: 0, maandag: 1, din: 2, dinsdag: 2, wo: 3, woe: 3, woensdag: 3, donderdag: 4, vr: 5, vri: 5, vrijdag: 5, za: 6, zat: 6, zaterdag: 6, }, 'Please use the English abbreviation "" for "".': { // FIXME: Translate to Czech. 'neděle': 0, 'ne': 0, 'pondělí': 1, 'po': 1, 'úterý': 2, 'út': 2, 'středa': 3, 'st': 3, 'čtvrtek': 4, 'čt': 4, 'pátek': 5, 'pá': 5, 'sobota': 6, }, 'Please use the English abbreviation "" for "".': { // Spanish. 'martes': 0, 'miércoles': 1, 'jueves': 2, 'viernes': 3, 'sábado': 4, 'domingo': 5, 'lunes': 6, // Indonesian. 'selasa': 0, 'rabu': 1, 'kami': 2, 'jumat': 3, 'sabtu': 4, 'minggu': 5, 'senin': 6, // Swedish 'söndag': 0, 'söndagar': 0, 'måndag': 1, 'ma': 1, 'tisdag': 2, 'onsdag': 3, 'torsdag': 4, 'fredag': 5, 'lördag': 6, 'lördagar': 6, // Polish 'niedziela': 0, 'niedz': 0, 'n': 0, 'ndz': 0, 'poniedziałek': 1, 'poniedzialek': 1, 'pon': 1, 'pn': 1, 'wtorek': 2, 'wt': 2, 'środa': 3, 'sroda': 3, 'śr': 3, 'sr': 3, 'czwartek': 4, 'czw': 4, 'cz': 4, 'piątek': 5, 'piatek': 5, 'pt': 5, 'sobota': 6, 'sob': 6, // 'so': 6 // abbreviation also used in German // Russian 'воскресенье' : 0, 'Вс' : 0, "voskresen'ye": 0, 'понедельник' : 1, 'Пн' : 1, "ponedel'nik" : 1, 'вторник' : 2, 'vtornik' : 2, 'среда' : 3, 'sreda' : 3, 'четверг' : 4, 'chetverk' : 4, 'пятница' : 5, 'pyatnitsa' : 5, 'суббота' : 6, 'subbota' : 6, // Danish 'søndag' : 0, 'mandag' : 1, 'tirsdag': 2, 'onsdag' : 3, 'torsdag': 4, 'fredag' : 5, 'lørdag' : 6, }, }, timevar: { // Special time variables which actual value depends on the date and the position of the facility. 'default': { 'sunrise': 'sunrise', 'sunset': 'sunset', 'dawn': 'dawn', 'dusk': 'dusk', }, 'Please use notation "" for "".': { 'sundown': 'sunset', }, 'Bitte benutze die Schreibweise "" für "".': { 'morgendämmerung': 'dawn', 'abenddämmerung': 'dusk', 'sonnenaufgang': 'sunrise', 'sonnenuntergang': 'sunset', }, }, 'event': { // variable events 'default': { 'easter': 'easter', }, 'Bitte benutze die Schreibweise "" für "".': { 'ostern': 'easter', }, }, }; // }}} // }}} // make the library accessible for the outside world {{{ if (typeof exports === 'object') { // For nodejs var SunCalc = require('suncalc'); module.exports = factory(SunCalc, holidays, word_error_correction); } else { // For browsers root.opening_hours = factory(root.SunCalc, holidays, word_error_correction); } /// }}} }(this, function (SunCalc, holidays, word_error_correction) { return function(value, nominatiomJSON, oh_mode) { // short constants {{{ var word_value_replacement = { // if the correct values can not be calculated dawn : 60 * 5 + 30, sunrise : 60 * 6, sunset : 60 * 18, dusk : 60 * 18 + 30, }; var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; var weekdays = ['Su','Mo','Tu','We','Th','Fr','Sa']; var default_prettify_conf = { 'leading_zero_hour': true, // enforce leading zero 'one_zero_if_hour_zero': false, // only one zero "0" if hour is zero "0" 'leave_off_closed': true, // leave keywords of and closed as is 'keyword_for_off_closed': 'off', // use given keyword instead of "off" or "closed" 'block_sep_string': ' ', // separate blocks by string 'print_semicolon': true, // print token which separates normal blocks '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 'sep_one_day_between': ',' // separator which should be used }; var minutes_in_day = 60 * 24; var msec_in_day = 1000 * 60 * minutes_in_day; var msec_in_week = msec_in_day * 7; // }}} // The big picture -- How does this library work? {{{ //====================================================================== // Constructor - entry to parsing code //====================================================================== // Terminology: // // Mo-Fr 10:00-11:00; Th 10:00-12:00 // \_____block_____/ \____block___/ // // The README refers to blocks as rules, which is more intuitive but less clear. // Because of that only the README uses the term rule in that context. // In all internal parts of this project, the term block is used. // // Mo-Fr Jan 10:00-11:00 // \__/ \_/ \_________/ // selectors (left to right: weekday, month, time) // // Logic: // - Tokenize // Foreach block: // - Run top-level (block) parser // - Which calls sub parser for specific selector types // - Which produce selector functions // }}} // constructor parameters {{{ // Evaluate additional information which can be given. They are // required to reasonably calculate 'sunrise' and to use the correct // holidays. var location_cc, location_state, lat, lon; if (typeof nominatiomJSON != 'undefined') { if (typeof nominatiomJSON.address != 'undefined' && typeof nominatiomJSON.address.state != 'undefined') { // country_code will be tested later … location_cc = nominatiomJSON.address.country_code; location_state = nominatiomJSON.address.state; } if (typeof nominatiomJSON.lon != 'undefined') { // lat will be tested later … lat = nominatiomJSON.lat; lon = nominatiomJSON.lon; } } // 0: time ranges (default), tags: opening_hours, lit, … // 1: points in time // 2: both (time ranges and points in time), tags: collection_times, service_times if (typeof oh_mode == 'undefined') { oh_mode = 0; } else if (!(typeof oh_mode == 'number' && (oh_mode == 0 || oh_mode == 1 || oh_mode == 2))) { throw 'The third constructor parameter is oh_mode and must be a number (0, 1 or 2)' } // }}} // put tokenized blocks into list {{{ if (value.match(/^(\s*;?\s*)+$/)) throw 'Value contains nothing meaningful which can be parsed'; var parsing_warnings = []; var done_with_warnings = false; // The functions which throw warnings can be called multiple times. var has_token = {}; var tokens = tokenize(value); // console.log(JSON.stringify(tokens, null, '\t')); var prettified_value = ''; 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. var week_stable = true; var blocks = []; for (var nblock = 0; nblock < tokens.length; nblock++) { if (tokens[nblock][0].length == 0) continue; // Block does contain nothing useful e.g. second block of '10:00-12:00;' (empty) which needs to be handled. var continue_at = 0; do { if (continue_at == tokens[nblock][0].length) break; // Additional block does contain nothing useful e.g. second block of '10:00-12:00,' (empty) which needs to be handled. var selectors = { // Time selectors time: [], // Temporary array of selectors from time wrapped to the next day wraptime: [], // Date selectors weekday: [], holiday: [], week: [], month: [], monthday: [], year: [], // Array with non-empty date selector types, with most optimal ordering date: [], fallback: tokens[nblock][1], additional: continue_at ? true : false, meaning: true, unknown: false, comment: undefined, build_from_token_block: undefined, }; selectors.build_from_token_block = [ nblock, continue_at ]; continue_at = parseGroup(tokens[nblock][0], continue_at, selectors, nblock); if (typeof continue_at == 'object') continue_at = continue_at[0]; else continue_at = 0; if (selectors.year.length > 0) selectors.date.push(selectors.year); if (selectors.holiday.length > 0) selectors.date.push(selectors.holiday); if (selectors.month.length > 0) selectors.date.push(selectors.month); if (selectors.monthday.length > 0) selectors.date.push(selectors.monthday); if (selectors.week.length > 0) selectors.date.push(selectors.week); if (selectors.weekday.length > 0) selectors.date.push(selectors.weekday); // console.log('weekday: ' + JSON.stringify(selectors.weekday, null, '\t')); blocks.push(selectors); // This handles selectors with time ranges wrapping over midnight (e.g. 10:00-02:00) // it generates wrappers for all selectors and creates a new block. if (selectors.wraptime.length > 0) { var wrapselectors = { time: selectors.wraptime, date: [], meaning: selectors.meaning, unknown: selectors.unknown, comment: selectors.comment, wrapped: true, }; for (var dselg = 0; dselg < selectors.date.length; dselg++) { wrapselectors.date.push([]); for (var dsel = 0; dsel < selectors.date[dselg].length; dsel++) { wrapselectors.date[wrapselectors.date.length-1].push( generateDateShifter(selectors.date[dselg][dsel], -msec_in_day) ); } } blocks.push(wrapselectors); } } while (continue_at) } // }}} /* Tokenization function: Splits string into parts. {{{ * * :param value: Raw opening_hours value. * :returns: Tokenized list object. Complex structure. You can print the * thing as JSON if you would like to know in details. * The most inner list has the following items: [ internal_value, token_name, value_length ]. */ function tokenize(value) { var all_tokens = new Array(); var curr_block_tokens = new Array(); var last_block_fallback_terminated = false; while (value != '') { var tmp; if (tmp = value.match(/^(?:week\b|open\b|unknown\b)/i)) { // Reserved keywords. curr_block_tokens.push([tmp[0].toLowerCase(), tmp[0].toLowerCase(), value.length ]); value = value.substr(tmp[0].length); } else if (tmp = value.match(/^24\/7/i)) { // Reserved keyword. has_token[tmp[0]] = true; curr_block_tokens.push([tmp[0], tmp[0], value.length ]); value = value.substr(tmp[0].length); } else if (tmp = value.match(/^(?:off|closed)/i)) { // Reserved keywords. curr_block_tokens.push([tmp[0].toLowerCase(), 'closed', value.length ]); value = value.substr(tmp[0].length); } else if (tmp = value.match(/^(?:PH|SH)/i)) { // special day name (holidays) curr_block_tokens.push([tmp[0].toUpperCase(), 'holiday', value.length ]); value = value.substr(2); } else if (tmp = value.match(/^days?/i)) { curr_block_tokens.push([tmp[0].toLowerCase(), 'calcday', value.length ]); value = value.substr(tmp[0].length); } 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)) { // Handle all remaining words with error tolerance. var correct_val = returnCorrectWordOrToken(tmp[1].toLowerCase(), value.length); if (typeof correct_val == 'object') { curr_block_tokens.push([ correct_val[0], correct_val[1], value.length ]); value = value.substr(tmp[0].length); } else if (typeof correct_val == 'string') { if (tmp[1].toLowerCase() == 'pm') { var hours_token_at = curr_block_tokens.length - 3; if (hours_token_at > 0) { if (matchTokens(curr_block_tokens, hours_token_at, 'number', 'timesep', 'number') ) { var hours_token = curr_block_tokens[hours_token_at]; } else if (matchTokens(curr_block_tokens, hours_token_at + 2, 'number') ) { hours_token_at += 2; var hours_token = curr_block_tokens[hours_token_at]; } if (hours_token[0] <= 12) { hours_token[0] += 12; curr_block_tokens[hours_token_at] = hours_token; } } } value = correct_val + value.substr(tmp[0].length); } else { // other single-character tokens curr_block_tokens.push([value[0].toLowerCase(), value[0].toLowerCase(), value.length - 1 ]); value = value.substr(1); } } else if (tmp = value.match(/^\d+/)) { // number if (tmp[0] > 1900) // Assumed to be a year number. curr_block_tokens.push([tmp[0], 'year', value.length ]); else curr_block_tokens.push([+tmp[0], 'number', value.length ]); value = value.substr(tmp[0].length); } else if (tmp = value.match(/^"([^"]*)"/)) { // comment curr_block_tokens.push([tmp[1], 'comment', value.length ]); value = value.substr(tmp[0].length); } else if (value.match(/^;/)) { // semicolon terminates block // next tokens belong to a new block all_tokens.push([ curr_block_tokens, last_block_fallback_terminated, value.length ]); value = value.substr(1); curr_block_tokens = []; last_block_fallback_terminated = false; } else if (value.match(/^\|\|/)) { // || terminates block // next tokens belong to a fallback block if (curr_block_tokens.length == 0) throw formatWarnErrorMessage(-1, value.length - 2, 'Rule before fallback rule does not contain anything useful'); all_tokens.push([ curr_block_tokens, last_block_fallback_terminated, value.length ]); value = value.substr(2); curr_block_tokens = []; last_block_fallback_terminated = true; } else if (value.match(/^(?:␣|\s)/)) { // Using "␣" as space is not expected to be a normal mistake. Just ignore it to make using taginfo easier. value = value.substr(1); } else if (tmp = value.match(/^\s+/)) { // whitespace is ignored value = value.substr(tmp[0].length); } else if (value.match(/^[:.]/)) { // time separator if (value[0] == '.' && !done_with_warnings) parsing_warnings.push([ -1, value.length - 1, 'Please use ":" as hour/minute-separator' ]); curr_block_tokens.push([ ':', 'timesep', value.length ]); value = value.substr(1); } else { // other single-character tokens curr_block_tokens.push([value[0].toLowerCase(), value[0].toLowerCase(), value.length ]); value = value.substr(1); } } all_tokens.push([ curr_block_tokens, last_block_fallback_terminated ]); return all_tokens; } // }}} /* error correction/tolerance function {{{ * Go through word_error_correction hash and get correct value back. * * :param word: Wrong Word or character. * :param value_length: Current value_length (used for warnings). * :returns: * * (valid) opening_hours sub string. * * object with [ internal_value, token_name ] if value is correct. * * undefined if word could not be found (and thus not be corrected). */ function returnCorrectWordOrToken(word, value_length) { for (var token_name in word_error_correction) { for (var comment in word_error_correction[token_name]) { for (var old_val in word_error_correction[token_name][comment]) { if (old_val == word) { var val = word_error_correction[token_name][comment][old_val]; if (comment == 'default') { // Return internal representation of word. return [ val, token_name ]; } else if (token_name == 'wrong_words' && !done_with_warnings) { // Replace wrong words or characters with correct ones. // This will return a string which is then being tokenized. parsing_warnings.push([ -1, value_length - old_val.length, comment.replace(//, old_val).replace(//, val) ]); return val; } else { // Get correct string value from the 'default' hash and generate warning. var correct_abbr; for (correct_abbr in word_error_correction[token_name]['default']) { if (word_error_correction[token_name]['default'][correct_abbr] == val) break; } if (typeof correct_abbr == 'undefined') { throw 'Please file a bug for opening_hours.js.' + ' Including the stacktrace.' } if (token_name != 'timevar') { // Everything else than timevar: // E.g. 'Mo' are start with a upper case letter. // It just looks better. correct_abbr = correct_abbr.charAt(0).toUpperCase() + correct_abbr.slice(1); } if (!done_with_warnings) parsing_warnings.push([ -1, value_length - old_val.length, comment.replace(//, old_val).replace(//, correct_abbr) ]); return [ val, token_name ]; } } } } } return undefined; } // }}} /* return warnings as list {{{ * * :param it: Iterator object if available (optional). * :returns: Warnings as list with one warning per element. */ function getWarnings(it) { if (typeof it == 'object') { // getWarnings was called in a state without critical errors. We can do extended tests. // Check if 24/7 is used and it does not mean 24/7 because there are other blocks. var has_advanced = it.advance(); if (has_advanced === true && has_token['24/7'] && !done_with_warnings) { parsing_warnings.push([ -1, 0, 'You used 24/7 in a way that is probably not interpreted as "24 hours 7 days a week".' // Probably because of: "24/7; 12:00-14:00 open", ". Needs extra testing. + ' For correctness you might want to use "open" or "closed"' + ' for this rule and then write your exceptions which should achieve the same goal and is more clear' + ' e.g. "open; Mo 12:00-14:00 off".']); } } var warnings = []; for (var i = 0; i < parsing_warnings.length; i++) { warnings.push( formatWarnErrorMessage(parsing_warnings[i][0], parsing_warnings[i][1], parsing_warnings[i][2]) ); } return warnings; } // }}} /* Function to check token array for specific pattern {{{ * * :param tokens: List of token objects. * :param at: Position at which the matching should begin. * :param token_name(s): One or many token_name strings which have to match in that order. * :returns: true if token_name(s) match in order false otherwise. */ function matchTokens(tokens, at /*, matches... */) { if (at + arguments.length - 2 > tokens.length) return false; for (var i = 0; i < arguments.length - 2; i++) { if (tokens[at + i][1] !== arguments[i + 2]) return false; } return true; } // }}} /* Generate selector wrapper with time offset {{{ * * :param func: Generated selector code function. * :param shirt: Time to shift in milliseconds. * :param token_name(s): One or many token_name strings which have to match in that order. * :returns: See selector code. */ function generateDateShifter(func, shift) { return function(date) { var res = func(new Date(date.getTime() + shift)); if (typeof res[1] === 'undefined') return res; return [ res[0], new Date(res[1].getTime() - shift) ]; } } // }}} /* Top-level parser {{{ * * :param tokens: List of token objects. * :param at: Position at which the matching should begin. * :param selectors: Reference to selector object. * :param nblock: Block number starting with 0. * :param conf: Configuration for prettifyValue. * :returns: See selector code. */ function parseGroup(tokens, at, selectors, nblock, conf) { var prettified_group_value = ''; used_subparsers = { 'time ranges': [ ] }; // console.log(tokens); // useful for debugging of tokenize while (at < tokens.length) { var old_at = at; // console.log('Parsing at position', at +':', tokens[at]); if (matchTokens(tokens, at, 'weekday')) { at = parseWeekdayRange(tokens, at, selectors); } else if (matchTokens(tokens, at, '24/7')) { selectors.time.push(function(date) { return [true]; }); // Not needed. If there is no selector it automatically matches everything. // WRONG: This only works if there is no other selector in this selector group ... at++; } else if (matchTokens(tokens, at, 'holiday')) { if (matchTokens(tokens, at+1, ',')) at = parseHoliday(tokens, at, selectors, true); else at = parseHoliday(tokens, at, selectors, false); week_stable = false; } else if (matchTokens(tokens, at, 'month', 'number') || matchTokens(tokens, at, 'month', 'weekday') || matchTokens(tokens, at, 'year', 'month', 'number') || matchTokens(tokens, at, 'year', 'event') || matchTokens(tokens, at, 'event')) { at = parseMonthdayRange(tokens, at, nblock); week_stable = false; } else if (matchTokens(tokens, at, 'year')) { at = parseYearRange(tokens, at); week_stable = false; } else if (matchTokens(tokens, at, 'month')) { at = parseMonthRange(tokens, at); // week_stable = false; // decided based on actual values } else if (matchTokens(tokens, at, 'week')) { at = parseWeekRange(tokens, at + 1); week_stable = false; // if (prettified_group_value[-1] != ' ') // prettified_group_value = prettified_group_value.substring(0, prettified_group_value.length - 1); } else if (at != 0 && at != tokens.length - 1 && tokens[at][0] == ':') { // Ignore colon if they appear somewhere else than as time separator. // Except the start or end of the value. // This provides compatibility with the syntax proposed by Netzwolf: // http://wiki.openstreetmap.org/wiki/Key:opening_hours:specification if (!done_with_warnings && (matchTokens(tokens, at-1, 'weekday') || matchTokens(tokens, at-1, 'holiday'))) parsing_warnings.push([nblock, at, 'Please don’t use ":" after ' + tokens[at-1][1] + '.']); if (prettified_group_value[-1] != ' ') prettified_group_value = prettified_group_value.substring(0, prettified_group_value.length - 1); at++; } else if (matchTokens(tokens, at, 'number', 'timesep') || matchTokens(tokens, at, 'timevar') || matchTokens(tokens, at, '(', 'timevar') || matchTokens(tokens, at, 'number', '-')) { at = parseTimeRange(tokens, at, selectors, false); used_subparsers['time ranges'].push(at); } else if (matchTokens(tokens, at, 'closed')) { selectors.meaning = false; at++; if (matchTokens(tokens, at, ',')) // additional block at = [ at + 1 ]; if (typeof used_subparsers['state keywords'] != 'object') used_subparsers['state keywords'] = [ at ]; else used_subparsers['state keywords'].push(at); } else if (matchTokens(tokens, at, 'open')) { selectors.meaning = true; at++; if (matchTokens(tokens, at, ',')) // additional block at = [ at + 1 ]; if (typeof used_subparsers['state keywords'] != 'object') used_subparsers['state keywords'] = [ at ]; else used_subparsers['state keywords'].push(at); } else if (matchTokens(tokens, at, 'unknown')) { selectors.meaning = false; selectors.unknown = true; at++; if (matchTokens(tokens, at, ',')) // additional block at = [ at + 1 ]; if (typeof used_subparsers['state keywords'] != 'object') used_subparsers['state keywords'] = [ at ]; else used_subparsers['state keywords'].push(at); } else if (matchTokens(tokens, at, 'comment')) { selectors.comment = tokens[at][0]; if (at > 0) { if (!matchTokens(tokens, at - 1, 'open') && !matchTokens(tokens, at - 1, 'closed')) { // Then it is unknown. Either with unknown explicitly // specified or just a comment behind. selectors.meaning = false; selectors.unknown = true; } } else { // block starts with comment selectors.time.push(function(date) { return [true]; }); // Not needed. If there is no selector it automatically matches everything. // WRONG: This only works if there is no other selector in this selector group ... selectors.meaning = false; selectors.unknown = true; } at++; if (matchTokens(tokens, at, ',')) // additional block at = [ at + 1 ]; if (typeof used_subparsers['comments'] != 'object') used_subparsers['comments'] = [ at ]; else used_subparsers['comments'].push(at); } else { var warnings = getWarnings(); throw formatWarnErrorMessage(nblock, at, 'Unexpected token: "' + tokens[at][1] + '" This means that the syntax is not valid at that point or it is currently not supported.') + (warnings ? ' ' + warnings.join('; ') : ''); } if (typeof conf != 'undefined') { // 'Mo: 12:00-13:00' -> 'Mo 12:00-13:00' if (used_subparsers['time ranges'] && old_at > 1 && tokens[old_at-1][0] == ':' && matchTokens(tokens, old_at - 2, 'weekday')) prettified_group_value = prettified_group_value.substring(0, prettified_group_value.length - 2) + ' '; // 'week 1, week 3' -> 'week 1,week 3' if (prettified_group_value.substr(prettified_group_value.length -2, 2) == ', ' && matchTokens(tokens, old_at, 'week')) prettified_group_value = prettified_group_value.substring(0, prettified_group_value.length - 1); prettified_group_value += prettifySelector(tokens, old_at, at, conf, used_subparsers['time ranges'].length); } if (typeof at == 'object') // additional block break; } prettified_value += prettified_group_value.replace(/\s+$/, ''); if (!done_with_warnings) { for (var subparser_name in used_subparsers) { if (used_subparsers[subparser_name].length > 1) { parsing_warnings.push([nblock, used_subparsers[subparser_name][used_subparsers[subparser_name].length - 1] - 1, 'You have used ' + used_subparsers[subparser_name].length + (subparser_name.match(/^(?:comments|state keywords)/) ? ' ' + subparser_name + ' in one rule.' + ' You may only use one in one rule.' : ' not connected ' + subparser_name + ' in one rule.' + ' This is probably an error.' + ' Equal selector types can (and should) always be written in conjunction separated by comma or something.' + ' Example for time ranges "12:00-13:00,15:00-18:00".' + ' Example for weekdays "Mo-We,Fr".' ) + ' Rules can be separated by ";".' ] ); } } } return at; } // }}} // helper functions for sub parser {{{ /* For given date, returns date moved to the start of the day with an offset specified in minutes. {{{ * For example, if date is 2014-05-19_18:17:12, dateAtDayMinutes would * return 2014-05-19_02:00:00 for minutes=120. * * :param date: Date object. * :param minutes: Minutes used as offset starting from midnight of current day. * :returns: Moved date object. */ function dateAtDayMinutes(date, minutes) { return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, minutes); } // }}} /* For given date, returns date moved to the specific day of week {{{ * * :param date: Date object. * :param day: Integer number for day of week. Starting with zero (Sunday). * :returns: Moved date object. */ function dateAtNextWeekday(date, day) { var delta = day - date.getDay(); return new Date(date.getFullYear(), date.getMonth(), date.getDate() + delta + (delta < 0 ? 7 : 0)); } // }}} /* Function to determine whether an array contains a value {{{ * Source: http://stackoverflow.com/a/1181586 * * :param needle: Element to find. * :returns: Index of element if present, if not present returns -1. */ function indexOf(needle) { if(typeof Array.prototype.indexOf === 'function') { indexOf = Array.prototype.indexOf; } else { indexOf = function(needle) { var i = -1, index = -1; for(i = 0; i < this.length; i++) { if(this[i] === needle) { index = i; break; } } return index; }; } return indexOf.call(this, needle); } // }}} /* Numeric list parser (1,2,3-4,-1) {{{ * Used in weekday parser above. * * :param tokens: List of token objects. * :param at: Position where to start. * :param func: Function func(from, to, at). * :returns: Position at which the token does not belong to the list any more. */ function parseNumRange(tokens, at, func) { for (; at < tokens.length; at++) { if (matchTokens(tokens, at, 'number', '-', 'number')) { // Number range func(tokens[at][0], tokens[at+2][0], at); at += 3; } else if (matchTokens(tokens, at, '-', 'number')) { // Negative number func(-tokens[at+1][0], -tokens[at+1][0], at); at += 2 } else if (matchTokens(tokens, at, 'number')) { // Single number func(tokens[at][0], tokens[at][0], at); at++; } else { throw formatWarnErrorMessage(nblock, at + matchTokens(tokens, at, '-'), 'Unexpected token in number range: ' + tokens[at][1]); } if (!matchTokens(tokens, at, ',')) break; } return at; } // }}} /* List parser for constrained weekdays in month range {{{ * e.g. Su[-1] which selects the last Sunday of the month. * * :param tokens: List of token objects. * :param at: Position where to start. * :returns: Array: * 0. Constrained weekday number. * 1. Position at which the token does not belong to the list any more (after ']' token). */ function getConstrainedWeekday(tokens, at) { var number = 0; var endat = parseNumRange(tokens, at, function(from, to, at) { // bad number if (from == 0 || from < -5 || from > 5) throw formatWarnErrorMessage(nblock, at, 'Number between -5 and 5 (except 0) expected'); if (from == to) { if (number != 0) throw formatWarnErrorMessage(nblock, at, 'You can not use more than one constrained weekday in a month range'); number = from; } else { throw formatWarnErrorMessage(nblock, at+2, 'You can not use a range of constrained weekdays in a month range'); } }); if (!matchTokens(tokens, endat, ']')) throw formatWarnErrorMessage(nblock, endat, '"]" expected.'); return [ number, endat + 1 ]; } // }}} // Check if period is ok. Period 0 or 1 don’t make much sense. /* List parser for constrained weekdays in month range {{{ * e.g. Su[-1] which selects the last Sunday of the month. * * :param tokens: List of token objects. * :param at: Position where to start. * :returns: Array: * 0. Constrained weekday number. * 1. Position at which the token does not belong to the list any more (after ']' token). */ function checkPeriod(at, period, period_type, parm_string) { if (done_with_warnings) return; if (period === 0) { throw formatWarnErrorMessage(nblock, at, 'You can not use '+ period_type +' ranges with period equals zero.'); } else if (period === 1) { if (typeof parm_string == 'string' && parm_string == 'no_end_year') parsing_warnings.push([nblock, at, 'Please don’t use '+ period_type +' ranges with period equals one.' + ' If you want to express that a facility is open starting from a year without limit use "+".']); else parsing_warnings.push([nblock, at, 'Please don’t use '+ period_type +' ranges with period equals one.']); } } function getDateForConstrainedWeekday(year, month, weekday, constrained_weekday, add_days) { var tmp_date = dateAtNextWeekday( new Date(year, month + (constrained_weekday[0] > 0 ? 0 : 1), 1), weekday); tmp_date.setDate(tmp_date.getDate() + (constrained_weekday[0] + (constrained_weekday[0] > 0 ? -1 : 0)) * 7); if (typeof add_days != 'undefined' && add_days[1]) tmp_date.setDate(tmp_date.getDate() + add_days[0]); return tmp_date; } function formatWarnErrorMessage(nblock, at, message) { var pos = 0; if (nblock == -1) { // Usage of block index not required because we do have access to value.length. pos = value.length - at; } else { // Issue accrued at a later time, position in string needs to be reconstructed. if (typeof tokens[nblock][0][at] == 'undefined') { pos = value.length; if (typeof tokens[nblock][0][tokens[nblock][0].length-1] != 'undefined') { // pos -= tokens[nblock][0][tokens[nblock][0].length-1][2]; console.warn("FIXME"); } } else { pos = value.length; if (typeof tokens[nblock][0][at+1] != 'undefined') { pos -= tokens[nblock][0][at+1][2]; } else if (typeof tokens[nblock][2] != 'undefined') { pos -= tokens[nblock][2]; } else { } } } return value.substring(0, pos) + ' <--- (' + message + ')'; } // check if date is valid function isValidDate(month, day, nblock, at) { // month == 0 is Jan // May use this instead. Does not say, what is wrong as good was implementation below. // var testDate = new Date(year, month, day); // if (testDate.getDate() != day || testDate.getMonth() != month || testDate.getFullYear() != year) { // console.error('date not valid'); // } // https://en.wikipedia.org/wiki/Month#Julian_and_Gregorian_calendars if (day < 1 || day > 31) throw formatWarnErrorMessage(nblock, at, 'Day must be between 1 and 31.'); if ((month==3 || month==5 || month==8 || month==10) && day==31) throw formatWarnErrorMessage(nblock, at, 'Month ' + months[month] + " doesn't have 31 days.!"); if (month == 1 && day == 30) throw formatWarnErrorMessage(nblock, at, 'Month ' + months[1]+ " either has 28 or 29 days (leap years)."); } // }}} // Time range parser (10:00-12:00,14:00-16:00) {{{ // // extended_open_end: