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

Get client's timezone offset in ExpressJS

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

有些人喜欢使用库 momentJS for anything dealing with time, but I believe the Date object in Javascript suffices what you are looking for and does not require a library. The getTimezoneOffset 正是您所需要的。我希望这有帮助!如果您还有其他问题,请告诉我!

如果你控制客户端,你可以do this with client-side JavaScript

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

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

现实情况是,即使您获得了时区偏移,也不意味着您在客户端的时间是正确的,考虑到某些地区有“夏令时”。

但是,考虑到以下数据,您可以“猜出”用户所在的时区:

  1. req.get('Accept-Language'),用户现在可能居住在哪个国家;
  2. req.ip,在数据库中搜索并找出大致位置;
  3. 客户端(new Date).getTimezoneOffset(),用于时区偏移;

最后,通过上面结果的计算,你的猜测应该差不多了。时区应该存储在像 'America/New_York' 这样的字符串中,而不是时区偏移量。

http://momentjs.com/timezone/应该是处理时区的好工具

保存“几乎正确”的时区后,不要忘记留下用户可以更改的地方。

正如其他人提到的,无法通过 HTTP 获取 client-side browser/OS 时区偏移量,因此您需要从客户端发送此数据。

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

我不相信浏览器时间是正确的。用户可能还搞砸了他们的 OS 时区设置...因此时区偏移也可能不正确。然而,大多数现代 OSes 会根据 Geo-IP 隐含位置自动设置时区...因此对于许多用户来说,能够环游世界并登录应用程序并查看 date/time 的便利性无论他们碰巧处于什么当地时区,都值得为用户体验付出努力。始终希望查看特定时区的用户可以对其进行配置,我们将改用该首选项。

我这样做的方法如下...在登录表单上添加一个隐藏字段并使用 javascript 设置值。当用户登录时,将此时区偏移量存储在 session 中。如果用户没有设置首选时区,那么我们在渲染时使用这个偏移量 date/time。这意味着如果你有很长的 session 并且用户可以在国家之间旅行......他们仍然会显示旧的时区偏移量直到下一个 logout/login。如果您愿意,您当然可以更频繁地甚至在每次请求时获取此数据……但出于我的目的,在登录时获取此数据就足够了。无论如何,我的 sessions 在 IP 地址更改时已过期...所以是的。当然,如果他们的 session 跨过夏令时开关,那么在下次登录之前偏移量不会准确(假设他们的 OS/browser TZ 首先是正确的)。

客户端

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

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

服务器端

然后在服务器端(快速)如果登录成功,我将那个 tzOffset 值粘贴在 session。

然后当使用 moment-timezone 格式化日期时,我可以执行如下操作。此函数是一个“格式化程序”,我可以将其公开给 pug/views,然后使用用户的正确 timezone/formats 格式化任何随机日期 object。

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');
}

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

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

另一种方法

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

我只是根据用户区域设置和用户偏好配置我的格式化程序 server-side,然后公开这些格式化程序以便在我的 express 哈巴狗模板中使用。到目前为止,它对我来说效果很好。

有趣的故事

我有一个 co-worker 在他们的计算机上手动设置了错误的时区,所以时间是错误的。他们没有修复时区,而是禁用了网络时间并手动将时间设置为“正确”时间。

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

所以是的...不能保证 client-side 时间或时区偏移量是正确的。