-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
162 lines (128 loc) · 4.39 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
const MINUTES_PER_HOUR = 60;
const MILLISECONDS_PER_MINUTE = 60 * 1000;
const TIME_SEPARATOR = ':';
const _isValidNumber = number => !Number.isNaN(Number(number));
const _isValidObjectValue = (obj, key) =>
Object.prototype.hasOwnProperty.call(obj, key) && (typeof obj[key] !== 'undefined');
const _objectToNumber = (obj) => {
const hours = _isValidObjectValue(obj, 'hours') ? obj.hours : 0;
const minutes = _isValidObjectValue(obj, 'minutes') ? obj.minutes : 0;
if (_isValidNumber(hours) && _isValidNumber(minutes)) {
const absMinute = (
(Math.abs(Number(hours)) * MINUTES_PER_HOUR) + Math.abs(Number(minutes))
);
if (Object.is(Number(hours), -0) || Number(hours) < 0) {
return -absMinute;
}
return absMinute;
}
throw new Error(`Cannot convert object ${JSON.stringify(obj)} to TimeDuration`);
};
const _stringToObject = (str, separator = TIME_SEPARATOR) => {
const [hours, minutes] = str.split(' ').join('').split(separator);
if (_isValidNumber(hours) && _isValidNumber(minutes)) {
return {
hours: Number(hours),
minutes: Number(minutes)
};
}
throw new Error(`Cannot convert string "${str}" to TimeDuration`);
};
const _isNegativeZero = x => Object.is(-0, x);
class TimeDuration {
constructor(...args) {
this._minutes = 0;
const [firstValue, secondValue] = args;
if (typeof firstValue === 'number' && args.length === 1) {
this._minutes = firstValue;
} else if (firstValue instanceof TimeDuration) {
this._minutes = firstValue.valueOf();
} else if (firstValue instanceof Date && secondValue instanceof Date) {
this._firstConversionFromDateDiff(firstValue, secondValue);
} else {
this._firstConversionFromCommonFormats(firstValue, secondValue, args.length);
}
}
_firstConversionFromDateDiff(firstValue, secondValue) {
const milisecondsDiff = Math.abs(firstValue - secondValue);
this._minutes = Math.round(milisecondsDiff / MILLISECONDS_PER_MINUTE);
}
_firstConversionFromCommonFormats(firstValue, secondValue, argsLength) {
const fistValueType = typeof firstValue;
if (fistValueType === 'string' && argsLength === 1 &&
firstValue.includes(TIME_SEPARATOR)) {
const timeObj = _stringToObject(firstValue);
this._minutes = _objectToNumber(timeObj);
} else if (fistValueType === 'object' && argsLength === 1) {
this._minutes = _objectToNumber(firstValue);
} else if (argsLength === 2 && fistValueType === 'number' &&
typeof secondValue === 'number') {
this._minutes = _objectToNumber({
hours: firstValue,
minutes: secondValue
});
}
}
/* Conversion operations (output) */
toMinutes() {
return this._minutes;
}
valueOf() {
return this._minutes;
}
toHours(roundDigits = 2) {
const hours = this._minutes / MINUTES_PER_HOUR;
const factor = 10 ** roundDigits;
return Math.round(hours * factor) / factor;
}
toObject() {
const roundFn = this._minutes > 0 ? Math.floor : Math.ceil;
const hours = roundFn(this._minutes / MINUTES_PER_HOUR);
const minutes = this._minutes % MINUTES_PER_HOUR;
return { hours, minutes };
}
toString(hoursWithZero = false) {
const { hours, minutes } = this.toObject();
const absMinutes = Math.abs(minutes);
const minutesZeroed = absMinutes < 10 ? `0${absMinutes}` : absMinutes;
const hoursZeroed = hours < 10 && hoursWithZero ? `0${hours}` : hours;
const hoursProcessed = !hours && _isNegativeZero(hours) ?
`-${hoursZeroed}` : hoursZeroed;
return `${hoursProcessed}:${minutesZeroed}`;
}
/* Getters and setters */
get hours() {
return this.toObject().hours;
}
get minutes() {
return this.toObject().minutes;
}
set hours(hours) {
const minutes = this._minutes % MINUTES_PER_HOUR;
this._minutes = (hours * MINUTES_PER_HOUR) + minutes;
}
set minutes(minutes) {
const hours = Math.floor(this._minutes / MINUTES_PER_HOUR);
this._minutes = (hours * MINUTES_PER_HOUR) + minutes;
}
/* Modification operations */
add(timeToAdd) {
const timeToAddNormalized = new TimeDuration(timeToAdd);
this._minutes = this._minutes + timeToAddNormalized;
return this;
}
subtract(timeToSubtract) {
const timeToAddNormalized = new TimeDuration(timeToSubtract);
this._minutes = this._minutes - timeToAddNormalized;
return this;
}
multiplyBy(multiplicationFactor) {
this._minutes = this._minutes * multiplicationFactor;
return this;
}
divideBy(divisionFactor) {
this._minutes = Math.round(this._minutes / divisionFactor);
return this;
}
}
module.exports = TimeDuration;