-
Notifications
You must be signed in to change notification settings - Fork 2
/
DateTime.js
178 lines (145 loc) · 4.75 KB
/
DateTime.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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/* @flow */
const SECRET_KEY = {_: 'secret'};
export const ONE_SECOND = 1000;
export const ONE_MINUTE = ONE_SECOND * 60;
export const ONE_HOUR = ONE_MINUTE * 60;
export const ONE_DAY = ONE_HOUR * 24;
const JSON_DATE_TIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z/;
const JSON_DATE_ONLY = /^\d{4}-\d{2}-\d{2}/;
export default class DateTime {
_dateTime: Date;
constructor(secretKey: Object, value: number) {
if (secretKey !== SECRET_KEY) {
throw new Error("Don't construct `DateTime` directly. Use a static method like `DateTime.fromString()`.");
}
let isNaN = (value !== value); // eslint-disable-line no-self-compare
let date = new Date(isNaN ? 0 : truncateMilliseconds(value));
// This helps with console.log.
Object.defineProperty(date, 'toString', {value: date.toUTCString});
this._dateTime = date;
}
static now(): DateTime {
return new DateTime(SECRET_KEY, Date.now());
}
static fromNumber(milliseconds: number): DateTime {
return new DateTime(SECRET_KEY, milliseconds);
}
static fromParts(year: number, month: number, day: number, hours: number, minutes: number, seconds: number): DateTime {
return new DateTime(SECRET_KEY, Date.UTC(year, month, day, hours, minutes, seconds));
}
static fromDateParts(year: number, month: number, day: number): DateTime {
return new DateTime(SECRET_KEY, Date.UTC(year, month, day));
}
static fromString(dateString: string): DateTime {
if (!JSON_DATE_TIME.test(dateString)) {
throw new Error('Unable to parse date: ' + dateString);
}
return new DateTime(SECRET_KEY, Date.parse(dateString));
}
static fromDateString(dateString: string): DateTime {
if (!JSON_DATE_ONLY.test(dateString)) {
throw new Error('Unable to parse date: ' + dateString);
}
return new DateTime(SECRET_KEY, Date.parse(dateString + 'T00:00:00Z'));
}
// 2016-01-10T12:03:49Z
toString(): string {
return this._dateTime.toISOString().slice(0, 19) + 'Z';
}
// 2016-01-10
toDateString(): string {
return this._dateTime.toISOString().slice(0, 10);
}
// 2016-01-10T12:03:49.000Z
toJSON(): string {
return this._dateTime.toISOString();
}
inspect(): string {
return this._dateTime.toUTCString();
}
toNumber(): number {
return this._dateTime.valueOf();
}
// This is used implicitly when comparing such as: `date1 < date2`.
valueOf(): number {
return this._dateTime.valueOf();
}
// This returns the day of the month.
getDate(): number {
return this._dateTime.getUTCDate();
}
// This returns the day of the week.
getDay(): number {
return this._dateTime.getUTCDay();
}
getMonth(): number {
return this._dateTime.getUTCMonth();
}
getYear(): number {
return this._dateTime.getUTCFullYear();
}
getHours(): number {
return this._dateTime.getUTCHours();
}
getMinutes(): number {
return this._dateTime.getUTCMinutes();
}
getSeconds(): number {
return this._dateTime.getUTCSeconds();
}
addMonths(num: number): DateTime {
let newMonth = this.getMonth() + num;
let yearsToAdd = truncate(newMonth / 12);
newMonth = newMonth % 12;
if (newMonth < 0) {
newMonth = 12 + newMonth;
yearsToAdd -= 1;
}
let newYear = this.getYear() + yearsToAdd;
let newDate = DateTime.fromParts(
newYear,
newMonth,
this.getDate(),
this.getHours(),
this.getMinutes(),
this.getSeconds(),
);
// If the new date has a month we don't expect then the day must have
// caused an overflow (like 31st Feb) which increased the month.
while (newDate.getMonth() !== newMonth) {
newDate = newDate.addDays(-1);
}
return newDate;
}
addDays(num: number): DateTime {
let newValue = this._dateTime.valueOf() + (ONE_DAY * num);
return new DateTime(SECRET_KEY, newValue);
}
addHours(num: number): DateTime {
let newValue = this._dateTime.valueOf() + (ONE_HOUR * num);
return new DateTime(SECRET_KEY, newValue);
}
addMinutes(num: number): DateTime {
let newValue = this._dateTime.valueOf() + (ONE_MINUTE * num);
return new DateTime(SECRET_KEY, newValue);
}
addSeconds(num: number): DateTime {
let newValue = this._dateTime.valueOf() + (ONE_SECOND * num);
return new DateTime(SECRET_KEY, newValue);
}
isEqualTo(otherDate: DateTime): boolean {
return (this.toNumber() === otherDate.toNumber());
}
isLessThan(otherDate: DateTime): boolean {
return (this.toNumber() < otherDate.toNumber());
}
isGreaterThan(otherDate: DateTime): boolean {
return (this.toNumber() > otherDate.toNumber());
}
}
function truncateMilliseconds(num: number) {
return truncate(num / 1000) * 1000;
}
function truncate(num: number) {
return (num > 0) ? Math.floor(num) : Math.ceil(num);
}