-
Notifications
You must be signed in to change notification settings - Fork 1
/
nanodate.ts
167 lines (156 loc) · 4.87 KB
/
nanodate.ts
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
163
164
165
166
167
/**
* Contains the nanodate class in it
* @module
*/
// the composed precision of the nanodate, basically how much more precision
// we need over millisecond precision
const NanoSecondComposedDatePrecision = 6; // +3 of the millisecond precision makes a 9 aka nanoseconds
/**
* The nanosecond composed date allows to parse nanosecond ISO dates and keep and mantain their precision
* this class is useful for handling postgresql dates, in the case of itemize, created_at, edited_at are given
* with nanodate level precision so if fine adjustment is needed please use this class instead of Date
*/
export class NanoSecondComposedDate {
/**
* The original date
*/
public date: Date;
/**
* The original string
*/
public original: string;
/**
* The remainder numeric value, this is the number
* left after the first 3 numbers after the decimal in seconds
*/
public remainder: number;
/**
* the millisecond time
*/
public time: number;
/**
* Build a new nanodate
* @param str the ISO date
*/
constructor(str: string) {
// first we assign all these
this.original = str;
this.date = new Date(str);
this.time = this.date.getTime();
// now we need to remove timezone data, to the left, now we split
// for the seconds section, and get the remainder; the date component
// can parse the first 3 values, but not the remaining values
let strRemainder: string;
if (str) {
if (str.endsWith("Z")) {
const splitted = str.split("Z");
strRemainder = splitted[0].split(".")[1].substr(3);
} else {
let splitted = str.split("+");
if (splitted.length === 1) {
splitted = str.split("-");
}
strRemainder = splitted[0].split(".")[1].substr(3);
}
} else {
strRemainder = "";
}
// since we are using a total number, we need to ensure the size is exact
// as our precision because we are parsing decimals
if (strRemainder.length > NanoSecondComposedDatePrecision) {
strRemainder = strRemainder.substr(0, NanoSecondComposedDatePrecision);
}
// and we pad
strRemainder = strRemainder.padEnd(NanoSecondComposedDatePrecision, "0");
// and this is our remainder, for the case of a 6 precision, as for nanoseconds
// this is a number between 0 and 999999 so for a date with 12.345678 seconds
// this value will be 678000
this.remainder = parseInt(strRemainder) || 0;
}
/**
* Tells wether the date is invalid
* @returns
*/
public isInvalid() {
return isNaN(this.time);
}
/**
* Checks whether a given nano date is greater than another
* @param otherDate the other date
* @returns a boolean
*/
public greaterThan(otherDate: NanoSecondComposedDate) {
// first we check if the time itself is greater than the other
if (this.time > otherDate.time) {
return true;
// otherwise if these dates are equal in milliseconds
} else if (this.time === otherDate.time) {
// We use the more precise remainder
return this.remainder > otherDate.remainder;
} else {
// or return false
return false;
}
}
/**
* Checks whether a given nano date is greater than or equal
* @param otherDate the other date to check
* @returns a boolean
*/
public greaterThanEqual(otherDate: NanoSecondComposedDate) {
if (this.time >= otherDate.time) {
return true;
} else if (this.time === otherDate.time) {
// Need more precision
return this.remainder >= otherDate.remainder;
} else {
return false;
}
}
/**
* Checks whether a given nano date is less than
* @param otherDate the other date to check
* @returns a boolean
*/
public lessThan(otherDate: NanoSecondComposedDate) {
if (this.time < otherDate.time) {
return true;
} else if (this.time === otherDate.time) {
// Need more precision
return this.remainder < otherDate.remainder;
} else {
return false;
}
}
/**
* Checks whether a given nano date is less than or equal
* @param otherDate the other date to check
* @returns a boolean
*/
public lessThanEqual(otherDate: NanoSecondComposedDate) {
if (this.time < otherDate.time) {
return true;
} else if (this.time === otherDate.time) {
// Need more precision
return this.remainder <= otherDate.remainder;
} else {
return false;
}
}
/**
* Checks whether a given nano date is equal to another
* @param otherDate the other date to check
* @returns a boolean
*/
public equal(otherDate: NanoSecondComposedDate) {
return this.time === otherDate.time && this.remainder === otherDate.remainder;
}
/**
* Checks whether two given nano dates are not equal
* @param otherDate the other date to check
* @returns a boolean
*/
public notEqual(otherDate: NanoSecondComposedDate) {
return !this.equal(otherDate);
}
}