避免 JavaScript 日期的时区校正
Avoid timezone correction for JavaScript Date
我有一个 JavaScript 函数,它接受一个数字 (1-31),创建一个 Date
并通过 AJAX
请求将它发送到服务器:
sendDate(d) {
let date = new Date(this.year, this.month, d);
htmx.ajax("GET", "/some/url", { values: { "date": date.toISOString() } });
}
问题是,JavaScript 正在做一些具有效果的时区校正,如果我创建一个像 new Date(2022, 09, 14)
这样的日期,我会得到一个日期 Wed Sep 14 2022 00:00:00 GMT+0200 (Central European Summer Time)
,当转换为ISO 格式变为 2022-09-13T22:00:00.000Z
,即。前一天。
我知道我可以使用 .toLocaleDateString()
,但我想坚持使用 ISO 格式,并且我也想避免一些老套的解决方案,例如总是在某个指定时间的中间创建日期那天或其他什么。
有没有一种简单的方法可以创建常规日期对象并将其传递到没有时区恶作剧的服务器?
有一种方法可以做到这一点:将日期存储为 UNIX 时间戳。我这样做,当需要时,我将时间戳从服务器传递到客户端并将其转换为本地日期。
也就是说,我认为在客户端构建日期并将其传递给服务器不是一个好主意,因为它可以在客户端进行修改。我相信这主要是通过这种方式完成的(我的项目也是如此):在服务器端,您检查当前时间戳(在发送请求时)并随心所欲地使用它。
您似乎允许用户选择日期。将其转换为时间戳并将其传递给服务器将是一个很好的方法。
How would you do that? If I return date.getTime()
and then parse it (in python) with datetime.fromtimestamp(int(request.GET['date']) / 1000)
I still get the same timezone issue...
在这种情况下您不会有任何问题 - 除了您的服务器可能碰巧有不同的当地时间。 time-zone 独立解决方案必须使用 utcfromtimestamp
而不是 fromtimestamp
。
无论如何,时间戳 本身 不能有任何时区问题 by definition.
查看 RobG 的回答...使用 new Date(Date.UTC(year, month, day))
格式要好得多。
传递给 Date 构造函数的值被视为本地值,toISOString 使用 UTC。不幸的是,ECMAScript 没有无时区、只有日期的形式。
如果您想使用 toISOString 来格式化时间戳,那么一种解决方案是首先将值解析为 UTC,例如
sendDate(d) {
let date = new Date(Date.UTC(this.year, this.month, d));
htmx.ajax("GET", "/some/url", { values: { "date": date.toISOString() } });
}
示例:
let d = new Date()
let year = d.getFullYear();
let month = d.getMonth()
let day = d.getDate();
let date = new Date(Date.UTC(year, month, day))
// Always shows the current local date as 00:00:00Z
console.log( date.toISOString() );
您还应该 trim 最后的 Z,因为时间戳确实是本地的。
我有一个 JavaScript 函数,它接受一个数字 (1-31),创建一个 Date
并通过 AJAX
请求将它发送到服务器:
sendDate(d) {
let date = new Date(this.year, this.month, d);
htmx.ajax("GET", "/some/url", { values: { "date": date.toISOString() } });
}
问题是,JavaScript 正在做一些具有效果的时区校正,如果我创建一个像 new Date(2022, 09, 14)
这样的日期,我会得到一个日期 Wed Sep 14 2022 00:00:00 GMT+0200 (Central European Summer Time)
,当转换为ISO 格式变为 2022-09-13T22:00:00.000Z
,即。前一天。
我知道我可以使用 .toLocaleDateString()
,但我想坚持使用 ISO 格式,并且我也想避免一些老套的解决方案,例如总是在某个指定时间的中间创建日期那天或其他什么。
有没有一种简单的方法可以创建常规日期对象并将其传递到没有时区恶作剧的服务器?
有一种方法可以做到这一点:将日期存储为 UNIX 时间戳。我这样做,当需要时,我将时间戳从服务器传递到客户端并将其转换为本地日期。
也就是说,我认为在客户端构建日期并将其传递给服务器不是一个好主意,因为它可以在客户端进行修改。我相信这主要是通过这种方式完成的(我的项目也是如此):在服务器端,您检查当前时间戳(在发送请求时)并随心所欲地使用它。
您似乎允许用户选择日期。将其转换为时间戳并将其传递给服务器将是一个很好的方法。
How would you do that? If I return
date.getTime()
and then parse it (in python) withdatetime.fromtimestamp(int(request.GET['date']) / 1000)
I still get the same timezone issue...
在这种情况下您不会有任何问题 - 除了您的服务器可能碰巧有不同的当地时间。 time-zone 独立解决方案必须使用 utcfromtimestamp
而不是 fromtimestamp
。
无论如何,时间戳 本身 不能有任何时区问题 by definition.
查看 RobG 的回答...使用 new Date(Date.UTC(year, month, day))
格式要好得多。
传递给 Date 构造函数的值被视为本地值,toISOString 使用 UTC。不幸的是,ECMAScript 没有无时区、只有日期的形式。
如果您想使用 toISOString 来格式化时间戳,那么一种解决方案是首先将值解析为 UTC,例如
sendDate(d) {
let date = new Date(Date.UTC(this.year, this.month, d));
htmx.ajax("GET", "/some/url", { values: { "date": date.toISOString() } });
}
示例:
let d = new Date()
let year = d.getFullYear();
let month = d.getMonth()
let day = d.getDate();
let date = new Date(Date.UTC(year, month, day))
// Always shows the current local date as 00:00:00Z
console.log( date.toISOString() );
您还应该 trim 最后的 Z,因为时间戳确实是本地的。