Last active
March 18, 2019 14:54
-
-
Save rolandpeelen/6b3e286bc2e8a8fdbe8d69bccd5141d3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ********************************************** | |
| // Imports | |
| // ********************************************** | |
| const R = require('ramda') | |
| // ********************************************** | |
| // Input data | |
| // ********************************************** | |
| console.time('timer'); | |
| const roomOpen = [ | |
| { startTime: new Date('2018-07-02T09:00:00Z'), endTime: new Date('2018-07-02T12:00:00Z') }, | |
| { startTime: new Date('2018-07-02T13:00:00Z'), endTime: new Date('2018-07-02T17:00:00Z') }, // ma | |
| { startTime: new Date('2018-07-03T09:00:00Z'), endTime: new Date('2018-07-03T12:00:00Z') }, | |
| { startTime: new Date('2018-07-03T13:00:00Z'), endTime: new Date('2018-07-03T17:00:00Z') }, // di | |
| { startTime: new Date('2018-07-04T09:00:00Z'), endTime: new Date('2018-07-04T12:00:00Z') }, | |
| { startTime: new Date('2018-07-04T13:00:00Z'), endTime: new Date('2018-07-04T17:00:00Z') }, // wo | |
| { startTime: new Date('2018-07-05T09:00:00Z'), endTime: new Date('2018-07-05T12:00:00Z') }, | |
| { startTime: new Date('2018-07-05T13:00:00Z'), endTime: new Date('2018-07-05T17:00:00Z') }, // do | |
| { startTime: new Date('2018-07-06T09:00:00Z'), endTime: new Date('2018-07-06T12:00:00Z') } // vrij | |
| ]; | |
| const roomBlocked = [ | |
| // ma | |
| { startTime: new Date('2018-07-03T09:00:00Z'), endTime: new Date('2018-07-03T11:00:00Z') }, // di | |
| // wo | |
| { startTime: new Date('2018-07-05T09:00:00Z'), endTime: new Date('2018-07-05T10:00:00Z') }, | |
| { startTime: new Date('2018-07-05T14:00:00Z'), endTime: new Date('2018-07-05T16:30:00Z') }, // do | |
| { startTime: new Date('2018-07-06T09:00:00Z'), endTime: new Date('2018-07-06T11:15:00Z') } // vrij | |
| ]; | |
| // ********************************************** | |
| // Root Functions | |
| // t for time, a for array, i for item, a,b for comparison | |
| // ********************************************** | |
| // Takes epoch milliseconds and converts it to minutes | |
| const msToMinutes = t => t / 1000 / 60; | |
| // Takes minutes and converts them to epoch milliseconds | |
| const minutesToMs = t => t * 1000 * 60; | |
| // Takes a date and converts it to epoch | |
| const dateToEpoch = i => i.getTime(); | |
| // Takes an epoch and converts it to date | |
| const epochTodate = i => new Date(i); | |
| // Takes two arguments, adds one to the first and checks if that's equal to the second | |
| const isEqualToNextPlusOne = (a, b) => a + 1 === b; | |
| // Check if an array does not include an item | |
| const doesNotInclude = R.curry((a, i) => !a.includes(i)); | |
| // Flattens recursively | |
| const deepFlatten = a => [].concat(...a.map(i => (Array.isArray(i) ? deepFlatten(i) : i))); | |
| // ********************************************** | |
| // Composed Functions | |
| // ********************************************** | |
| // Takes amount of minutes since 1970, converts it to a date object | |
| const toMsAndDate = R.compose(epochTodate, minutesToMs); | |
| // Takes a date object, converts it to minutes since 1970 | |
| const epochAndToMinutes = R.compose(msToMinutes, dateToEpoch); | |
| // Takes an item and maps it to a start / end date object {startTime: epochMinutes } --> {startTime: Date } | |
| const toDates = i => ({ startTime: toMsAndDate(i[0]), endTime: toMsAndDate(i[i.length - 1]) }); | |
| // Takes one start / endTime tuple and converts it to a range (including the last time -- thats the + 1) | |
| const getMinuteRange = ({ startTime, endTime }) => R.range(epochAndToMinutes(startTime), epochAndToMinutes(endTime) + 1); | |
| // Takes an array, passes each item through the getMinuteRange, flattens that and outputs it (creating one array of values) | |
| const getMinuteRangeForArray = a => deepFlatten(a.map(getMinuteRange)); | |
| const getActualRange = (openTimes, closedTimes) => { | |
| // Convert the rangeOpen and rangeBlocked to arrays of numbers | |
| const rangeOpen = getMinuteRangeForArray(openTimes); | |
| const rangeBlocked = getMinuteRangeForArray(closedTimes); | |
| // Filter the ones that don't match | |
| const intersection = rangeOpen.filter(doesNotInclude(rangeBlocked)); | |
| // from those ranges group them to have blocks of ranges. IE; | |
| // [1,2,3,4,5,6,7,12,13,14,15,16] to: | |
| // [[1,2,3,4,5,6,7],[12,13,14,15,16]] | |
| // The toDates function takes the first of those groups and the last of those groups and maps them | |
| // to a startdate and endDate | |
| return R.groupWith(isEqualToNextPlusOne, intersection).map(toDates) | |
| }; | |
| // Actual use | |
| const roomActual = getActualRange(roomOpen, roomBlocked); | |
| console.timeEnd('timer'); | |
| // ********************************************** | |
| // Output data (~19ms) | |
| // ********************************************** | |
| // [ { startTime: 2018-07-02T09:00:00.000Z, endTime: 2018-07-02T12:00:00.000Z }, | |
| // { startTime: 2018-07-02T13:00:00.000Z, endTime: 2018-07-02T17:00:00.000Z }, | |
| // { startTime: 2018-07-03T11:01:00.000Z, endTime: 2018-07-03T12:00:00.000Z }, | |
| // { startTime: 2018-07-03T13:00:00.000Z, endTime: 2018-07-03T17:00:00.000Z }, | |
| // { startTime: 2018-07-04T09:00:00.000Z, endTime: 2018-07-04T12:00:00.000Z }, | |
| // { startTime: 2018-07-04T13:00:00.000Z, endTime: 2018-07-04T17:00:00.000Z }, | |
| // { startTime: 2018-07-05T10:01:00.000Z, endTime: 2018-07-05T12:00:00.000Z }, | |
| // { startTime: 2018-07-05T13:00:00.000Z, endTime: 2018-07-05T13:59:00.000Z }, | |
| // { startTime: 2018-07-05T16:31:00.000Z, endTime: 2018-07-05T17:00:00.000Z }, | |
| // { startTime: 2018-07-06T11:16:00.000Z, endTime: 2018-07-06T12:00:00.000Z } ] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment