更新:
在尝试在自定义日期时间选择器中使用这些函数后,我注意到从3月切换到4月会像预期的那样切换时区,因为我的区域在3月切换夏令时。出乎意料的是,它正在切换到下一个时区,而不是在同一时区的标准时区和夏令时时区之间切换。
原来,这是因为我原来的函数总是为当前时间或过去的任意固定时间创建新的Date()。将其与3月和4月的相对时间进行比较,意味着它将在逻辑上检测到夏令时切换为切换时区。
解决办法是将相对时间传递到效用函数中,所以我所有的比较都是相对时间,而不是现在或任意固定的时间。失去了一些紧凑性,但现在逻辑可以根据需要工作。
更新工作流程:
t parameter defaults to new Date()
For fixed time, pass in an existing Date
For current time, pass in null or nothing
std() updated to use t.setMonth(v); to change the month for fixed times
.getTimezoneOffset() cannot chain to .setMonth(), so we need to swap from one-line notation to use closures ({}), terminators (;), and return
console.log() example loops through each month (0 to 11)
The fixed date object needs to be cloned using the same timestamp (let ts = +t;)
The + before the Date type casts it to a number with the Unix timestamp
Date() also accepts Unix timestamps to create fixed times
If we don't clone it, each call would pass around the same Date object with the months set to 6, which defeats the purpose
Ok, we're not actually cloning, just creating a new object using the same settings; same difference ;)
let ns = {
std: (t = new Date()) => Math.max(...[0, 6].map(v => {
t.setMonth(v);
return t.getTimezoneOffset();
})),
is_dst: (t = new Date()) => t.getTimezoneOffset() < ns.std(t),
utc: (t, std = 0) => {
t = t || new Date();
let z = std ? ns.std(t) : t.getTimezoneOffset(),
zm = z % 60;
return 'UTC' + (z > 0 ? '-' : '+') + (z / 60) + (zm ? ':' + zm : '');
}
};
//current time only
console.log(ns.std(), ns.is_dst(), ns.utc(), ns.utc(null, 1));
//iterate each month
let t = new Date(2021,0,1);
for (let i = 0; i < 12; i++) {
t.setMonth(i);
let ts = +t;
console.log(t.toDateString().split(" ")[1], ns.std(new Date(ts)), ns.is_dst(new Date(ts)), ns.utc(new Date(ts)), ns.utc(new Date(ts), 1));
}
扩展来自@nkitku的紧凑而神秘的解决方案,将其转换为一组可重用的函数。
工作流程:
All functions are scoped in a namespace ns so they don't conflict with other functions in the code that may have the same name
Namespacing also allows for compact function notation; std: ()=>Math.max(), is equivalent to function std(){ return Math.max(); }
std() returns the timezone offset in Standard Time
[0, 6] sets up a comparison of a month without DST and a month with DST
0 for January, since Date.setMonth() is zero-indexed
6 for July
Apparently, Standard Time is not in January for everyone, so we have to check both January and July
...[] converts the Array of months to a Set so we can apply the map() function
Raw arrays cannot run map()
map() runs a set of variables on the same function and returns an array of results
Create a new Date object with year, month, day
The year (95 in the example) is arbitrary since the year isn't important for this calculation
The month plugs in our values [0, 6] as a variable v
The day (1 in the example) is also arbitrary
Logically we could have created a new Date(), then .setMonth(v), but using the arbitrary numbers is more compact and faster
Now that we have the dates, getTimezoneOffset() returns the offsets for each month and pushes them to the results array
Math.max() finds the largest value from the results, which will be the Standard Time offset
is_dst() checks if it is currently Daylight Savings Time
new Date().getTimezoneOffset() gets the current offset, with or without DST
ns.std() gets the offset in Standard Time
If the current offset is lower, then it's DST
utc() returns a string in UTC notation
The std parameter defaults to off
z = std ? ns.std() : new Date().getTimezoneOffset() sets the time to DST or standard based on the flag
zm = z % 60 captures minutes since some zones use 30 minutes for example
(z > 0 ? '-' : '+') assigns the correct sign per UTC notation; positive offset values are shown as negative offsets in the notation
(z / 60) captures the hours in single-digit format per the notation, so no need to .toString().padStart(2,'0)` for double-digit format
(zm ? ':' + zm : '') appends minutes if they exist for the timezone
由于这个版本是紧凑的,您可以通过去掉多余的空白来节省更多的空间。不过这真的是一个迷你机的工作。
std:()=>Math.max(...[0,6].map(v=>new Date(95,v,1).getTimezoneOffset())),
Const ns = {
std: () => Math.max(…(0, 6)。map(v => new Date(95, v, 1).getTimezoneOffset())),
is_dst: () => new Date().getTimezoneOffset() < ns.std(),
Utc: (std = 0) => {
让z = STD ?ns.std(): new Date().getTimezoneOffset(),
Zm = z % 60;
返回'UTC' + (z > 0 ?'-': '+') + (z / 60) + (zm ?':' + zm: ");
}
};
ns.is_dst console.log (ns.std () (), ns.utc (), ns.utc (1));