在ExpressJS中获取客户端的时区偏移量

Zia*_*iad 4 javascript timezone node.js express

我正在寻找一种在ExpressJS中获取客户端时区偏移的方法(例如,使用req对象,这将非常棒).

bra*_*ipt 8

如果您控制客户端,则可以使用客户端JavaScript执行此操作.

如果你不这样做(例如你正在构建像API这样的服务器端组件),那么你就无法将其从HTTP请求中拉出来(除非你正在使用会话,但即使这样也不一定可靠).

从好的方面来说,如果它只是服务器端,你也不应该担心:将所有日期对象设置为UTC或Unix时间戳,并将其留给客户端开发人员来处理时区.

  • 实际上,如果你要向用户发送一些通知(电子邮件等),你还是需要用户的时区.因为在半夜向用户发送电子邮件是一个非常糟糕的惯例. (6认同)
  • 抱歉,但这对我来说听起来不是一个好的答案。正如@user3812138所说,即使在服务器端,您也可能需要稍后通知客户端,因此时区很重要。在这种情况下,使用外部服务(例如基于 IP 的查找)可能是一个不错的建议。 (2认同)

mat*_*tpr 8

正如其他人所提到的,无法通过 HTTP 获取客户端浏览器/操作系统时区偏移量,因此您需要从客户端发送此数据。

就我而言,我有一个需要登录的应用程序……所以我可以存储用户的首选项。默认是使用浏览器时区,但用户也可以配置一个特定的时区来使用所有的时间,而不是存储在他们的用户配置文件中(例如America/DallasEurope/Amsterdam)。

我不相信浏览器时间是正确的。用户也可能搞砸了他们的操作系统时区设置……所以时区偏移也可能不正确。然而,大多数现代操作系统会根据 Geo-IP 隐含位置自动设置时区……因此,对于许多用户而言,可以方便地环游世界并登录应用程序并查看他们碰巧所在的本地时区的日期/时间为用户体验付出的努力是值得的。总是想要查看特定时区的用户可以配置它,我们将改用该首选项。

我这样做的方法如下......在登录表单上添加一个隐藏字段并使用javascript设置值。当用户登录时,将此时区偏移量存储在会话中。如果用户没有设置首选时区,那么我们在渲染日期/时间时使用这个偏移量。这意味着如果您的会话时间很长并且用户可以在国家/地区之间旅行......他们仍然会显示旧时区偏移量,直到下一次注销/登录。如果您愿意,您当然可以更频繁地或什至在每次请求时获取这些数据……但对我而言,在登录时获取此数据就足够了。无论如何,我的会话已因 IP 地址更改而过期...所以是的。当然,如果他们的会话跨越了夏令时开关,那么在下次登录之前偏移量不会准确(假设他们的操作系统/浏览器 TZ 首先是正确的)。

客户端

<input type="hidden" name="tzOffset" id="tzOffset">
<!-- ... -->
<script>
var tzOffset = new Date().getTimezoneOffset(),
    tzInput = document.getElementById('tzOffset');
tzInput.value = tzOffset*(-1);
</script>
Run Code Online (Sandbox Code Playgroud)

请注意,我将其乘以倍数,-1因为我将使用 moment.js 在 express 端进行格式化,并且偏移量是向后的(来自本地的 utc 偏移量与来自 utc 的本地偏移量)。您也可以在服务器端执行此操作。在使用它之前,您可能也应该验证这个数字......这里只是最少的示例代码。

服务器端

然后在服务器端(快速)如果登录成功,我会在会话中保留该 tzOffset 值。

然后当用 express 格式化日期时,moment-timezone我可以执行以下操作。这个函数是一个“格式化程序”,我可以将它暴露给 pug/views,然后使用正确的时区/格式为用户格式化任何随机日期对象。

function formatDateTimeForUser (date) {
    var userTZ,     // user specified TZ like Europe/Berlin
        userTZoffset, // tzOffset we got from login form
        userDateFormat,  // user specified date format (or default)
        userTimeFormat; // user specified time format (or default)

    if (userTZ)
        return moment(date).tz(userTZ).format(userDateFormat+' '+userTimeFormat+' zz');
    else
        return moment(date).utcOffset(userTZoffset).format(userDateFormat+' '+userTimeFormat+' ZZ');
}
Run Code Online (Sandbox Code Playgroud)

ZZ格式用于以数字偏移格式显示时区(当我们使用来自客户端的固定数字偏移时相关。

zz格式用于以字符格式(例如 PDT、PST、EST 等)显示时区,当我们有一个像欧洲/柏林这样的时区而不是固定的数字偏移时,这是相关的。

另一种方法

将原始日期推送到客户端并进行客户端格式化。缺点是更少的控制和一致性以及更多的 js 推送到浏览器。如果您愿意,moment 也将运行客户端。

我只是根据用户区域设置和用户首选项配置我的格式化程序服务器端,然后公开这些格式化程序以用于我在 express 中的 pug 模板。到目前为止,它对我来说效果很好。

好笑的故事

我有一个同事在他们的电脑上手动设置了错误的时区,所以时间是错误的。他们没有修复时区,而是禁用网络时间并手动将时间设置为“正确”时间。

然后,当每个人都迟到一个小时参加他们安排的会议时,他们变得脾气暴躁。

所以是的......不能保证客户端时间或时区偏移量是正确的。