├── .gitignore
├── tsconfig.json
├── example
└── example.html
├── .eslintrc.json
├── README.md
├── package.json
├── LICENSE
├── test
└── parser.tests.js
├── src
└── simple-opening-hours.ts
└── dist
├── simple-opening-hours.js.map
└── simple-opening-hours.js
/.gitignore:
--------------------------------------------------------------------------------
1 | openingparser-tests._ts
2 | tasks.json
3 | node_modules
4 | .nyc_output
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "umd",
4 | "target": "es5",
5 | "noImplicitAny": false,
6 | "removeComments": false,
7 | "preserveConstEnums": true,
8 | "sourceMap": true,
9 | "watch": true,
10 | "outDir": "./dist"
11 | },
12 | "exclude": []
13 | }
--------------------------------------------------------------------------------
/example/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 | Please open console
13 |
14 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "commonjs": true,
5 | "es6": true,
6 | "node": true
7 | },
8 | "parserOptions": {
9 | "ecmaFeatures": {
10 | "jsx": true
11 | },
12 | "sourceType": "module"
13 | },
14 | "rules": {
15 | "no-const-assign": "warn",
16 | "no-this-before-super": "warn",
17 | "no-undef": "warn",
18 | "no-unreachable": "warn",
19 | "no-unused-vars": "warn",
20 | "constructor-super": "warn",
21 | "valid-typeof": "warn"
22 | }
23 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SimpleOpeningHours()
2 |
3 | SimpleOpeningHours is a small JavaScript class to parse OpenStreetMap `opening_hours`.
4 | It only supports the human readable parts and not [this complete crazy overengineered specification](https://wiki.openstreetmap.org/wiki/Key:opening_hours/specification).
5 |
6 | ## Supported opening_hours examples
7 |
8 | * `Mo-Sa 06:00-22:00`
9 | * `Mo-Fr 08:00-18:00; Sa 10:00-14:00`
10 | * `Mo-Fr 08:00-18:00; Sa,Su 10:00-20:00`
11 | * `Mo-Fr 08:00-12:00, We 14:00-18:00`
12 | * `Mo-Fr 08:00-12:00, 14:00-18:00`
13 | * `Mo-Fr 08:00-18:00; We off`
14 | * `24/7`
15 |
16 | ## Usage
17 | ```javascript
18 | var opening = new SimpleOpeningHours('Mo-Sa 06:00-22:00');
19 | console.log('Is this open now?', opening.isOpenNow());
20 | console.log('Is this open on 2016-10-01 18:00?', opening.isOpenOn(new Date('2016-10-01 18:00')));
21 | console.table(opening.getTable());
22 | ```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "simple-opening-hours",
3 | "version": "1.0.0",
4 | "description": "Less crazy opening hours parser",
5 | "main": "dist/simple-opening-hours.js",
6 | "directories": {
7 | "example": "example",
8 | "test": "test"
9 | },
10 | "dependencies": {},
11 | "devDependencies": {
12 | "eslint": "^3.16.1",
13 | "tap": "^10.2.1",
14 | "nodemon": "1.11.0"
15 | },
16 | "scripts": {
17 | "test": "tap test/*.js --cov",
18 | "compile": "tsc",
19 | "watch": "nodemon -x \"npm test\"",
20 | "develop": "compile & watch"
21 | },
22 | "repository": {
23 | "type": "git",
24 | "url": "git+https://github.com/pke/simple-opening-hours.git"
25 | },
26 | "keywords": [
27 | "opening hours"
28 | ],
29 | "author": "",
30 | "license": "MIT",
31 | "bugs": {
32 | "url": "https://github.com/pke/simple-opening-hours/issues"
33 | },
34 | "homepage": "https://github.com/pke/simple-opening-hours#readme"
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Constantin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/test/parser.tests.js:
--------------------------------------------------------------------------------
1 | const t = require("tap")
2 |
3 | const { default: oh, map } = require("../dist/simple-opening-hours")
4 |
5 | t.ok((new oh("24/7")).isOpen())
6 | t.ok((new oh(" 24/7")).isOpen())
7 | t.ok((new oh(" 24/7 ")).isOpen())
8 | t.ok((new oh("24/7 ")).isOpen())
9 | t.ok((new oh("24 / 7")).isOpen())
10 | t.ok((new oh("24/7")).getTable())
11 | t.ok((new oh("24/7")).alwaysOpen)
12 |
13 | t.notOk((new oh("off")).isOpen())
14 | t.notOk((new oh(" off")).isOpen())
15 | t.notOk((new oh("off ")).isOpen())
16 | t.notOk((new oh(" off ")).isOpen())
17 | t.ok((new oh("off")).alwaysClosed)
18 |
19 | t.ok((new oh("Mo-Sa 06:00-22:00")).isOpen(new Date('2016-10-01 18:00')))
20 | t.notOk((new oh("Mo 06:00-22:00")).isOpen(new Date('2016-10-01 18:00')))
21 | t.ok((new oh("Mo-Sa 09:00+")).isOpen(new Date('2016-10-01 18:00')))
22 | t.notOk((new oh("Mo-Sa off")).isOpen(new Date('2016-10-01 18:00')))
23 | t.notOk((new oh("Mo-Sa 06:00-22:00")).isOpen(new Date('2016-10-01 05:00')))
24 | t.ok((new oh("Mo-Sa 06:00-22:00")).getTable())
25 |
26 | t.test("Simple Time tables", t => {
27 | const table = (new oh("Mo-Sa 06:00-22:00")).getTable()
28 | t.same(table, {
29 | su: [],
30 | mo: ["06:00-22:00"],
31 | tu: ["06:00-22:00"],
32 | we: ["06:00-22:00"],
33 | th: ["06:00-22:00"],
34 | fr: ["06:00-22:00"],
35 | sa: ["06:00-22:00"],
36 | ph: [],
37 |
38 | })
39 | t.end()
40 | })
41 |
42 | t.test("Complex Time tables", t => {
43 | const table = (new oh("Mo-Sa 06:00-14:00,15:00-22:00")).getTable()
44 | t.same(table, {
45 | su: [],
46 | mo: ["06:00-14:00", "15:00-22:00"],
47 | tu: ["06:00-14:00", "15:00-22:00"],
48 | we: ["06:00-14:00", "15:00-22:00"],
49 | th: ["06:00-14:00", "15:00-22:00"],
50 | fr: ["06:00-14:00", "15:00-22:00"],
51 | sa: ["06:00-14:00", "15:00-22:00"],
52 | ph: [],
53 |
54 | })
55 | t.end()
56 | })
57 |
58 | t.test("Time tables", t => {
59 | const openingHours = new oh("Mo-Sa 06:00-14:00")
60 | const weekdays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
61 | const result = map(openingHours, (weekday, times) => {
62 | if (times && times.length) {
63 | return weekdays[weekday] + " " + times.map(time => time).join("\t")
64 | } else {
65 | return weekdays[weekday] + " Closed"
66 | }
67 | }).join("\n")
68 | t.equal(result, "Mon 06:00-14:00\nTue 06:00-14:00\nWed 06:00-14:00\nThu 06:00-14:00\nFri 06:00-14:00\nSat 06:00-14:00\nSun Closed")
69 | t.end()
70 | })
--------------------------------------------------------------------------------
/src/simple-opening-hours.ts:
--------------------------------------------------------------------------------
1 | export default class SimpleOpeningHours {
2 | /**
3 | * Creates the OpeningHours Object with OSM opening_hours string
4 | */
5 | constructor(input: string) {
6 | this.parse(input);
7 | }
8 |
9 | /**
10 | * returns the OpeningHours Object
11 | */
12 | public getTable() {
13 | return typeof this.openingHours === "object" ? this.openingHours : {};
14 | }
15 |
16 | public isOpen(date?: Date): boolean {
17 | if (typeof this.openingHours === "boolean") {
18 | return this.openingHours
19 | }
20 | date = date || new Date()
21 | const testDay = date.getDay();
22 | const testTime = date.getHours() + ":" + (date.getMinutes() < 10 ? ("0" + date.getMinutes()) : date.getMinutes())
23 | let i = 0;
24 | let times: string[];
25 | for (let key in this.openingHours) {
26 | if (i == testDay) {
27 | times = this.openingHours[key];
28 | }
29 | i++;
30 | }
31 | let isOpen = false
32 | times.some(time => {
33 | const timeData = time.replace(/\+$/, "-24:00").split("-")
34 | if ((this.compareTime(testTime, timeData[0]) != -1)
35 | && (this.compareTime(timeData[1], testTime) != -1)) {
36 | isOpen = true;
37 | return true;
38 | }
39 | });
40 | return isOpen;
41 | }
42 |
43 | /**
44 | * Parses the input and creates openingHours Object
45 | */
46 | private parse(input:string) {
47 | if (/24\s*?\/\s*?7/.test(input)) {
48 | this.openingHours = this.alwaysOpen = true;
49 | return
50 | } else if (/\s*off\s*/.test(input)) {
51 | this.openingHours = false
52 | this.alwaysClosed = true
53 | return
54 | }
55 | this.init();
56 | const parts = input.toLowerCase().replace(/\s*([-:,;])\s*/g, '$1').split(";")
57 | parts.forEach(part => {
58 | this.parseHardPart(part)
59 | });
60 | }
61 |
62 | private parseHardPart(part: string) {
63 | if (part == "24/7") {
64 | part = "mo-su 00:00-24:00";
65 | }
66 | let segments = part.split(/\ |\,/);
67 |
68 | let tempData = {}
69 | let days = []
70 | let times = []
71 | segments.forEach((segment) => {
72 | if (this.checkDay(segment)) {
73 | if (times.length == 0) {
74 | days = days.concat(this.parseDays(segment));
75 | }
76 | else {
77 | //append
78 | days.forEach((day) => {
79 | if (tempData[day]) {
80 | tempData[day] = tempData[day].concat(times)
81 | }
82 | else {
83 | tempData[day] = times
84 | }
85 | })
86 | days = this.parseDays(segment)
87 | times = [];
88 | }
89 | }
90 | if (this.isTimeRange(segment)) {
91 | if (segment == "off") {
92 | times = []
93 | }
94 | else {
95 | times.push(segment)
96 | }
97 | }
98 | })
99 |
100 | //commit last times to it days
101 | days.forEach((day) => {
102 | if (tempData[day]) {
103 | tempData[day] = tempData[day].concat(times)
104 | }
105 | else {
106 | tempData[day] = times
107 | }
108 | })
109 |
110 | //apply data to main obj
111 | for (let key in tempData) {
112 | this.openingHours[key] = tempData[key];
113 | }
114 | }
115 |
116 | private parseDays(part: string): string[] {
117 | let days = []
118 | let softparts = part.split(',');
119 | softparts.forEach((part) => {
120 | let rangecount = (part.match(/\-/g) || []).length;
121 | if (rangecount == 0) {
122 | days.push(part)
123 | }
124 | else {
125 | days = days.concat(this.calcDayRange(part))
126 | }
127 | })
128 |
129 | return days
130 | }
131 |
132 | private init() {
133 | this.openingHours = {
134 | su: [],
135 | mo: [],
136 | tu: [],
137 | we: [],
138 | th: [],
139 | fr: [],
140 | sa: [],
141 | ph: []
142 | }
143 | }
144 |
145 | /**
146 | * Calculates the days in range "mo-we" -> ["mo", "tu", "we"]
147 | */
148 | private calcDayRange(range: string): string[] {
149 | let def = {
150 | su: 0,
151 | mo: 1,
152 | tu: 2,
153 | we: 3,
154 | th: 4,
155 | fr: 5,
156 | sa: 6
157 | }
158 |
159 | let rangeElements = range.split('-');
160 |
161 | let dayStart = def[rangeElements[0]]
162 | let dayEnd = def[rangeElements[1]]
163 |
164 | let numberRange = this.calcRange(dayStart, dayEnd, 6);
165 | let outRange: string[] = [];
166 | numberRange.forEach(n => {
167 | for (let key in def) {
168 | if (def[key] == n) {
169 | outRange.push(key)
170 | }
171 | }
172 | });
173 | return outRange;
174 | }
175 |
176 | /**
177 | * Creates a range between two number.
178 | * if the max value is 6 a range bewteen 6 and 2 is 6, 0, 1, 2
179 | */
180 | private calcRange(min: number, max: number, maxval): number[] {
181 | if (min == max) {
182 | return [min]
183 | }
184 | let range = [min];
185 | let rangepoint = min
186 | while (rangepoint < ((min < max) ? max : maxval)) {
187 | rangepoint++
188 | range.push(rangepoint)
189 | }
190 | if (min > max) {
191 | //add from first in list to max value
192 | range = range.concat(this.calcRange(0, max, maxval))
193 | }
194 |
195 | return range;
196 | }
197 |
198 | /**
199 | * Check if string is time range
200 | */
201 | private isTimeRange(input: string): boolean {
202 | //e.g. 09:00+
203 | if (input.match(/[0-9]{1,2}:[0-9]{2}\+/)) {
204 | return true
205 | }
206 | //e.g. 08:00-12:00
207 | if (input.match(/[0-9]{1,2}:[0-9]{2}\-[0-9]{1,2}:[0-9]{2}/)) {
208 | return true
209 | }
210 | //off
211 | if (input.match(/off/)) {
212 | return true
213 | }
214 | return false
215 | }
216 |
217 | /**
218 | * check if string is day or dayrange
219 | */
220 | private checkDay(input: string): boolean {
221 | let days = ["mo", "tu", "we", "th", "fr", "sa", "su", "ph"]
222 | if (input.match(/\-/g)) {
223 | let rangeElements = input.split('-');
224 | if (days.indexOf(rangeElements[0]) !== -1
225 | && days.indexOf(rangeElements[1]) !== -1) {
226 | return true
227 | }
228 | }
229 | else if (days.indexOf(input) !== -1) {
230 | return true
231 | }
232 | return false
233 | }
234 |
235 | /**
236 | * Compares to timestrings e.g. "18:00"
237 | * if time1 > time2 -> 1
238 | * if time1 < time2 -> -1
239 | * if time1 == time2 -> 0
240 | */
241 | private compareTime(time1: string, time2: string) {
242 | const date1 = Number(time1.replace(":", ""))
243 | const date2 = Number(time2.replace(":", ""))
244 | if (date1 > date2) {
245 | return 1
246 | } else if (date1 < date2) {
247 | return -1
248 | } else {
249 | return 0
250 | }
251 | }
252 |
253 | private openingHours: Object | boolean
254 | private alwaysOpen?: boolean
255 | private alwaysClosed?: boolean
256 | }
257 |
258 | export function map(oh: SimpleOpeningHours, callback: (index:number, times: Array)=>T): T[] {
259 | const table = oh.getTable()
260 | return ["mo", "tu", "we", "th", "fr", "sa", "su"].map((weekday, index) => (
261 | callback(((index + 1) % 7), table[weekday])
262 | ))
263 | }
--------------------------------------------------------------------------------
/dist/simple-opening-hours.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"simple-opening-hours.js","sourceRoot":"","sources":["../src/simple-opening-hours.ts"],"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/dist/simple-opening-hours.js:
--------------------------------------------------------------------------------
1 | (function (factory) {
2 | if (typeof module === "object" && typeof module.exports === "object") {
3 | var v = factory(require, exports);
4 | if (v !== undefined) module.exports = v;
5 | }
6 | else if (typeof define === "function" && define.amd) {
7 | define(["require", "exports"], factory);
8 | }
9 | })(function (require, exports) {
10 | "use strict";
11 | Object.defineProperty(exports, "__esModule", { value: true });
12 | var SimpleOpeningHours = (function () {
13 | /**
14 | * Creates the OpeningHours Object with OSM opening_hours string
15 | */
16 | function SimpleOpeningHours(input) {
17 | this.parse(input);
18 | }
19 | /**
20 | * returns the OpeningHours Object
21 | */
22 | SimpleOpeningHours.prototype.getTable = function () {
23 | return typeof this.openingHours === "object" ? this.openingHours : {};
24 | };
25 | SimpleOpeningHours.prototype.isOpen = function (date) {
26 | var _this = this;
27 | if (typeof this.openingHours === "boolean") {
28 | return this.openingHours;
29 | }
30 | date = date || new Date();
31 | var testDay = date.getDay();
32 | var testTime = date.getHours() + ":" + (date.getMinutes() < 10 ? ("0" + date.getMinutes()) : date.getMinutes());
33 | var i = 0;
34 | var times;
35 | for (var key in this.openingHours) {
36 | if (i == testDay) {
37 | times = this.openingHours[key];
38 | }
39 | i++;
40 | }
41 | var isOpen = false;
42 | times.some(function (time) {
43 | var timeData = time.replace(/\+$/, "-24:00").split("-");
44 | if ((_this.compareTime(testTime, timeData[0]) != -1)
45 | && (_this.compareTime(timeData[1], testTime) != -1)) {
46 | isOpen = true;
47 | return true;
48 | }
49 | });
50 | return isOpen;
51 | };
52 | /**
53 | * Parses the input and creates openingHours Object
54 | */
55 | SimpleOpeningHours.prototype.parse = function (input) {
56 | var _this = this;
57 | if (/24\s*?\/\s*?7/.test(input)) {
58 | this.openingHours = this.alwaysOpen = true;
59 | return;
60 | }
61 | else if (/\s*off\s*/.test(input)) {
62 | this.openingHours = false;
63 | this.alwaysClosed = true;
64 | return;
65 | }
66 | this.init();
67 | var parts = input.toLowerCase().replace(/\s*([-:,;])\s*/g, '$1').split(";");
68 | parts.forEach(function (part) {
69 | _this.parseHardPart(part);
70 | });
71 | };
72 | SimpleOpeningHours.prototype.parseHardPart = function (part) {
73 | var _this = this;
74 | if (part == "24/7") {
75 | part = "mo-su 00:00-24:00";
76 | }
77 | var segments = part.split(/\ |\,/);
78 | var tempData = {};
79 | var days = [];
80 | var times = [];
81 | segments.forEach(function (segment) {
82 | if (_this.checkDay(segment)) {
83 | if (times.length == 0) {
84 | days = days.concat(_this.parseDays(segment));
85 | }
86 | else {
87 | //append
88 | days.forEach(function (day) {
89 | if (tempData[day]) {
90 | tempData[day] = tempData[day].concat(times);
91 | }
92 | else {
93 | tempData[day] = times;
94 | }
95 | });
96 | days = _this.parseDays(segment);
97 | times = [];
98 | }
99 | }
100 | if (_this.isTimeRange(segment)) {
101 | if (segment == "off") {
102 | times = [];
103 | }
104 | else {
105 | times.push(segment);
106 | }
107 | }
108 | });
109 | //commit last times to it days
110 | days.forEach(function (day) {
111 | if (tempData[day]) {
112 | tempData[day] = tempData[day].concat(times);
113 | }
114 | else {
115 | tempData[day] = times;
116 | }
117 | });
118 | //apply data to main obj
119 | for (var key in tempData) {
120 | this.openingHours[key] = tempData[key];
121 | }
122 | };
123 | SimpleOpeningHours.prototype.parseDays = function (part) {
124 | var _this = this;
125 | var days = [];
126 | var softparts = part.split(',');
127 | softparts.forEach(function (part) {
128 | var rangecount = (part.match(/\-/g) || []).length;
129 | if (rangecount == 0) {
130 | days.push(part);
131 | }
132 | else {
133 | days = days.concat(_this.calcDayRange(part));
134 | }
135 | });
136 | return days;
137 | };
138 | SimpleOpeningHours.prototype.init = function () {
139 | this.openingHours = {
140 | su: [],
141 | mo: [],
142 | tu: [],
143 | we: [],
144 | th: [],
145 | fr: [],
146 | sa: [],
147 | ph: []
148 | };
149 | };
150 | /**
151 | * Calculates the days in range "mo-we" -> ["mo", "tu", "we"]
152 | */
153 | SimpleOpeningHours.prototype.calcDayRange = function (range) {
154 | var def = {
155 | su: 0,
156 | mo: 1,
157 | tu: 2,
158 | we: 3,
159 | th: 4,
160 | fr: 5,
161 | sa: 6
162 | };
163 | var rangeElements = range.split('-');
164 | var dayStart = def[rangeElements[0]];
165 | var dayEnd = def[rangeElements[1]];
166 | var numberRange = this.calcRange(dayStart, dayEnd, 6);
167 | var outRange = [];
168 | numberRange.forEach(function (n) {
169 | for (var key in def) {
170 | if (def[key] == n) {
171 | outRange.push(key);
172 | }
173 | }
174 | });
175 | return outRange;
176 | };
177 | /**
178 | * Creates a range between two number.
179 | * if the max value is 6 a range bewteen 6 and 2 is 6, 0, 1, 2
180 | */
181 | SimpleOpeningHours.prototype.calcRange = function (min, max, maxval) {
182 | if (min == max) {
183 | return [min];
184 | }
185 | var range = [min];
186 | var rangepoint = min;
187 | while (rangepoint < ((min < max) ? max : maxval)) {
188 | rangepoint++;
189 | range.push(rangepoint);
190 | }
191 | if (min > max) {
192 | //add from first in list to max value
193 | range = range.concat(this.calcRange(0, max, maxval));
194 | }
195 | return range;
196 | };
197 | /**
198 | * Check if string is time range
199 | */
200 | SimpleOpeningHours.prototype.isTimeRange = function (input) {
201 | //e.g. 09:00+
202 | if (input.match(/[0-9]{1,2}:[0-9]{2}\+/)) {
203 | return true;
204 | }
205 | //e.g. 08:00-12:00
206 | if (input.match(/[0-9]{1,2}:[0-9]{2}\-[0-9]{1,2}:[0-9]{2}/)) {
207 | return true;
208 | }
209 | //off
210 | if (input.match(/off/)) {
211 | return true;
212 | }
213 | return false;
214 | };
215 | /**
216 | * check if string is day or dayrange
217 | */
218 | SimpleOpeningHours.prototype.checkDay = function (input) {
219 | var days = ["mo", "tu", "we", "th", "fr", "sa", "su", "ph"];
220 | if (input.match(/\-/g)) {
221 | var rangeElements = input.split('-');
222 | if (days.indexOf(rangeElements[0]) !== -1
223 | && days.indexOf(rangeElements[1]) !== -1) {
224 | return true;
225 | }
226 | }
227 | else if (days.indexOf(input) !== -1) {
228 | return true;
229 | }
230 | return false;
231 | };
232 | /**
233 | * Compares to timestrings e.g. "18:00"
234 | * if time1 > time2 -> 1
235 | * if time1 < time2 -> -1
236 | * if time1 == time2 -> 0
237 | */
238 | SimpleOpeningHours.prototype.compareTime = function (time1, time2) {
239 | var date1 = Number(time1.replace(":", ""));
240 | var date2 = Number(time2.replace(":", ""));
241 | if (date1 > date2) {
242 | return 1;
243 | }
244 | else if (date1 < date2) {
245 | return -1;
246 | }
247 | else {
248 | return 0;
249 | }
250 | };
251 | return SimpleOpeningHours;
252 | }());
253 | exports.default = SimpleOpeningHours;
254 | function map(oh, callback) {
255 | var table = oh.getTable();
256 | return ["mo", "tu", "we", "th", "fr", "sa", "su"].map(function (weekday, index) { return (callback(((index + 1) % 7), table[weekday])); });
257 | }
258 | exports.map = map;
259 | });
260 | //# sourceMappingURL=simple-opening-hours.js.map
--------------------------------------------------------------------------------