carpark-test/lib/carpark.js

173 lines
4.5 KiB
JavaScript
Raw Normal View History

2020-11-03 23:00:17 +00:00
/*
The following charges are used:
Short Stay
£1.10 per hour between 8am and 6pm on weekdays, free outside of these times.
Visits need not be whole hours and can last more than one day.
Long Stay
£7.50 per day or part day including weekends, so the minimum charge will be for one day.
A stay entirely outside of a chargeable period will return £0.00
A short stay from 07/09/2017 16:50:00 to 09/09/2017 19:15:00 would cost £12.28
Thursday => Saturday ( 1504803000 => 1504984500)
Thursday: 1h 10m = 1.28
Friday: 10h = 11.00
Saturday: free
A long stay from 07/09/2017 07:50:00 to 09/09/2017 05:20:00 would cost £22.50
Thursday => Saturday ( 1504770600 => 1504934400)
Thursday: 1 = 7.5
Friday: 1
Saturday: 1
Total: 22.50
---
hour = 3600 seconds
1604414190894
*/
const fecha = require('fecha');
class Carpark {
#_startDT;
#_endDT;
#_dayLength = 60 * 60 * 24;
#_hourLength = 60 * 60;
#_validDays = [1, 2, 3, 4, 5]; // Monday, Tuesday, Wednesday, Thursday, Friday
#_validStart = this.#_hourLength * 8; // 8AM // 08:00
#_validEnd = this.#_hourLength * 18; // 6PM // 18:00
#_longPrice = 7.5;
#_shortPrice = 1.1;
#_secondPrice = this.#_shortPrice / this.#_hourLength;
/**
* Check if a specific timestamp is a valid date
* @param workTime
* @returns {boolean}
* @private
*/
_isValidTime(workTime) {
const day = new Date(workTime * 1000).getDay();
if (this.#_validDays.indexOf(day) > -1) {
const dayBase = ~~(workTime / this.#_dayLength) * this.#_dayLength;
const dayPosition = workTime - dayBase;
return dayPosition >= this.#_validStart && dayPosition < this.#_validEnd - 1;
} else {
return false;
}
}
/**
* Calculate short term parking costs
* @returns {number}
* @private
*/
_calcShortTerm() {
let startSeconds = this.#_startDT.getTime() / 1000;
let endSeconds = this.#_endDT.getTime() / 1000;
let workTime, total;
let validHours = 0;
let startHourPart = 0;
// Calculate Start Hour
let startBaseHour = ~~(startSeconds / this.#_hourLength) * this.#_hourLength;
// Calculate End Hour
let endBaseHour = ~~(endSeconds / this.#_hourLength) * this.#_hourLength;
// Check if the very first portion of the hour is valid
if (this._isValidTime(startSeconds)) {
startHourPart = this.#_hourLength - (startSeconds - startBaseHour);
}
// Go to the next hour after the initial start
workTime = startBaseHour + this.#_hourLength;
// If there's more of an hours worth of time then loop through the next hours
if (endBaseHour - workTime > this.#_hourLength) {
do {
validHours = validHours + (this._isValidTime(workTime) ? 1 : 0);
workTime = workTime + this.#_hourLength;
} while (workTime <= endBaseHour);
}
// Sum it all
total = startHourPart * this.#_secondPrice + validHours * this.#_shortPrice;
return total;
}
/**
* Calculate long term parking costs
* @returns {number}
* @private
*/
_calcLongTerm() {
// convert to time stamps and make them second based
const startSeconds = this.#_startDT.getTime() / 1000;
const endSeconds = this.#_endDT.getTime() / 1000;
// Very start of the first day
const startBaseSeconds = ~~(startSeconds / this.#_dayLength) * this.#_dayLength;
// Very end of the second day
const endBaseSeconds = ~~(endSeconds / this.#_dayLength) * this.#_dayLength + this.#_dayLength;
// Subtract the start seconds from the end seconds
const distance = endBaseSeconds - startBaseSeconds;
// divide them by number of seconds in a day and multiply by cost
return (distance / this.#_dayLength) * this.#_longPrice;
}
/**
* The public calculate method
* @param start
* @param end
* @param mode
* @returns {number}
*/
calculate(start, end, mode = 'longterm') {
let workVal = 0.0;
// Ensure there are 3 arguments
if (arguments.length < 3) return workVal;
2020-11-03 23:00:17 +00:00
this.#_startDT = fecha.parse(start, 'DD/MM/YYYY HH:mm:ssZ');
this.#_endDT = fecha.parse(end, 'DD/MM/YYYY HH:mm:ssZ');
// Ensure that endDT is after startDT;
if (this.#_endDT.getTime() <= this.#_startDT.getTime()) return workVal;
2020-11-03 23:00:17 +00:00
switch (mode.toLowerCase()) {
case 'short':
case 'shortterm':
workVal = this._calcShortTerm();
break;
case 'long':
case 'longterm':
workVal = this._calcLongTerm();
break;
default:
}
return parseFloat(workVal.toFixed(2));
}
}
module.exports = Carpark;