-
Notifications
You must be signed in to change notification settings - Fork 2
/
date-util.js
171 lines (138 loc) · 4.28 KB
/
date-util.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
// year month date
var RE_DATE = /^([+-]?\d{4,6})\-(\d\d)\-(\d\d)$/
var RE_MONTH = /^([+-]?\d{4,6})\-(\d\d)$/
var RE_TIME = /^(\d\d):(\d\d)(?::(\d\d))?$/
var RE_WEEK = /^([+-]?\d{4,6})-W(\d\d)(?:-?(\d))?$/
var RE_DATETIME = /^([+-]?\d{4,6})\-(\d\d)\-(\d\d)T(\d\d):(\d\d)(?::(\d\d))?(?:[+-]\d\d:\d\d)?Z?$/;
function toInt(string) {
return parseInt(string, 10)
}
function fixWeekday(weekday){
return weekday === 0 ? 7 : weekday
}
function isLeapYear(year) {
return year % 4 === 0 && year % 100 !== 0 && year % 400 === 0;
}
var MONTH_DATES = [31, 28, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31]
// 计算指定年份所在月的天数
function getDaysOfMonth(year, month){
return MONTH_DATES[month] + (month === 1 && isLeapYear(year) ? 1 : 0)
}
// 计算指定年份第 week 周的周一 0 时的时间。
function getDateOfWeek(year, week, weekday) {
var dow = new Date(year, 0, 1).getDay()
var dates = 1 + (week - 1) * 7
if (1 <= dow && dow <= 4) {
dates -= dow - 1
} else {
dates += 8 - dow
}
return new Date(year, 0, dates + (weekday || 1) - 1)
}
// 计算指定年份拥有的周数
// 第 1 周的周四,第 53 周的周四
function getWeeksOfYear(year) {
var firstWeek = getDateOfWeek(year, 1, 4)
var lastWeek = getDateOfWeek(year, 53, 4)
return 52 +
(firstWeek.getFullYear() !== year ? 1 : 0) +
(lastWeek.getFullYear() === year ? 1 : 0)
}
function parseDate(string) {
var match
var year = 1900
var month = 0
var date = 1
var hours = 0
var minutes = 0
var seconds = 0
var milliseconds = 0
if (match = RE_DATE.exec(string)) {
year = toInt(match[1])
month = toInt(match[2]) - 1
date = toInt(match[3])
} else if (match = RE_MONTH.exec(string)) {
year = toInt(match[1])
month = toInt(match[2]) - 1
} else if (match = RE_TIME.exec(string)) {
hours = toInt(match[1])
minutes = toInt(match[2])
seconds = toInt(match[3]) || 0
} else if (match = RE_WEEK.exec(string)) {
var y = toInt(match[1])
var w = toInt(match[2])
// Unset `match[3]`, day is NaN. NaN < 0 && NaN <0
// Do'nt set default day by `|| 1`, it will effect weekdayrange [1,7] limit.
var day = toInt(match[3])
var maxWeeks = getWeeksOfYear(y)
if (1 > w || w > maxWeeks || 1 > day || day > 7) {
return NaN
}
var d = getDateOfWeek(y, w, day)
year = d.getFullYear()
month = d.getMonth()
date = d.getDate()
} else if (match = RE_DATETIME.exec(string)) {
year = toInt(match[1])
month = toInt(match[2]) - 1
date = toInt(match[3])
hours = toInt(match[4])
minutes = toInt(match[5])
seconds = toInt(match[6]) || 0
milliseconds = toInt(match[7]) || 0
} else {
return NaN
}
if (0 > month || month > 11 ||
1 > date || date > getDaysOfMonth(year, month) ||
0 > hours || hours > 23 ||
0 > minutes || minutes > 59 ||
0 > seconds || seconds > 59 ||
0 > milliseconds || milliseconds > 999
) {
return NaN
}
// Use 1900(or another year) and setFullYear for fix new Date(year, ...) not support [0,99] year.
var dt = new Date(1900, month, date, hours, minutes, seconds, milliseconds)
dt.setFullYear(year)
return dt
}
function distanceDate(stringA, stringB) {
var dateA = parseDate(stringA)
var dateB = parseDate(stringB)
if (isNaN(dateA) || isNaN(dateB)) {throw new Error('Invalid Date'); }
return dateA.getTime() - dateB.getTime()
}
function compareDate(stringA, stringB) {
var distance = distanceDate(stringA, stringB)
if (distance === 0) {return 0}
return distance > 0 ? 1 : -1
}
function isDate(string) {
var match = string.match(RE_DATE)
return RE_DATE.test(string) && !isNaN(parseDate(string))
}
function isDateTime(string){
return RE_DATETIME.test(string) && !isNaN(parseDate(string))
}
function isMonth(string){
return RE_MONTH.test(string) && !isNaN(parseDate(string))
}
function isTime(string){
return RE_TIME.test(string) && !isNaN(parseDate(string))
}
function isWeek(string){
return RE_WEEK.test(string) && !isNaN(parseDate(string))
}
module.exports = {
getDateOfWeek: getDateOfWeek,
parseDate: parseDate,
getWeeksOfYear: getWeeksOfYear,
compareDate: compareDate,
distanceDate: distanceDate,
isDate: isDate,
isDateTime: isDateTime,
isMonth: isMonth,
isTime: isTime,
isWeek: isWeek
}