-
Notifications
You must be signed in to change notification settings - Fork 120
/
Copy pathindex.js
135 lines (105 loc) · 3.16 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
import tzTokenizeDate from '../tzTokenizeDate/index.js'
var MILLISECONDS_IN_HOUR = 3600000
var MILLISECONDS_IN_MINUTE = 60000
var patterns = {
timezone: /([Z+-].*)$/,
timezoneZ: /^(Z)$/,
timezoneHH: /^([+-])(\d{2})$/,
timezoneHHMM: /^([+-])(\d{2}):?(\d{2})$/
}
// Parse various time zone offset formats to an offset in milliseconds
export default function tzParseTimezone(timezoneString, date, isUtcDate) {
var token
var absoluteOffset
// Z
token = patterns.timezoneZ.exec(timezoneString)
if (token) {
return 0
}
var hours
// ±hh
token = patterns.timezoneHH.exec(timezoneString)
if (token) {
hours = parseInt(token[2], 10)
if (!validateTimezone(hours)) {
return NaN
}
absoluteOffset = hours * MILLISECONDS_IN_HOUR
return token[1] === '+' ? -absoluteOffset : absoluteOffset
}
// ±hh:mm or ±hhmm
token = patterns.timezoneHHMM.exec(timezoneString)
if (token) {
hours = parseInt(token[2], 10)
var minutes = parseInt(token[3], 10)
if (!validateTimezone(hours, minutes)) {
return NaN
}
absoluteOffset = hours * MILLISECONDS_IN_HOUR + minutes * MILLISECONDS_IN_MINUTE
return token[1] === '+' ? -absoluteOffset : absoluteOffset
}
// IANA time zone
if (isValidTimezoneIANAString(timezoneString)) {
date = new Date(date || Date.now())
var utcDate = isUtcDate ? date : toUtcDate(date)
var offset = calcOffset(utcDate, timezoneString)
var fixedOffset = isUtcDate ? offset : fixOffset(date, offset, timezoneString)
return -fixedOffset
}
return 0
}
function toUtcDate(date) {
return new Date(
Date.UTC(
date.getFullYear(),
date.getMonth(),
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds(),
date.getMilliseconds()
)
)
}
function calcOffset(date, timezoneString) {
var tokens = tzTokenizeDate(date, timezoneString)
var asUTC = Date.UTC(tokens[0], tokens[1] - 1, tokens[2], tokens[3] % 24, tokens[4], tokens[5])
var asTS = date.getTime()
var over = asTS % 1000
asTS -= over >= 0 ? over : 1000 + over
return asUTC - asTS
}
function fixOffset(date, offset, timezoneString) {
var localTS = date.getTime()
// Our UTC time is just a guess because our offset is just a guess
var utcGuess = localTS - offset
// Test whether the zone matches the offset for this ts
var o2 = calcOffset(new Date(utcGuess), timezoneString)
// If so, offset didn't change and we're done
if (offset === o2) {
return offset
}
// If not, change the ts by the difference in the offset
utcGuess -= o2 - offset
// If that gives us the local time we want, we're done
var o3 = calcOffset(new Date(utcGuess), timezoneString)
if (o2 === o3) {
return o2
}
// If it's different, we're in a hole time. The offset has changed, but the we don't adjust the time
return Math.max(o2, o3)
}
function validateTimezone(hours, minutes) {
if (minutes != null && (minutes < 0 || minutes > 59)) {
return false
}
return true
}
function isValidTimezoneIANAString(timeZoneString) {
try {
Intl.DateTimeFormat(undefined, {timeZone: timeZoneString});
return true;
} catch (error) {
return false;
}
}