首页 > 解决方案 > 有没有办法在Javascript中覆盖`new Date()`,所以它总是返回考虑到一个特定硬编码时区的日期?

问题描述

我正在开发一个 React.js 项目,该项目处理与 DateTime 相关的大量比较(将小时、月份、年份等与从 API 检索到的日期进行比较)。对于这个特定的 React.js 应用程序,我希望始终将 DateTimes (from new Date()) 视为用户处于服务器时区。假设服务器位于“欧洲/柏林”时区,我希望在应用程序中的任何时候,调用new Date('2019-01-01')都会检索我一个 DateTime,它指的是“欧洲/柏林”时区中的这个时间,即Tue Jan 01 2019 01:00:00 GMT+0100 (Central European Standard Time). 例如,如果我将计算机的日期和时间设置为就像我在巴西一样,我会得到Mon Dec 31 2018 22:00:00 GMT-0200 (Brasilia Summer Time),但希望得到和以前一样的结果。这是一个问题的主要原因是我们从这些 DateTimes 中提取数据,例如.getHours(),.getDate()等。

这将适合这个特定的应用程序,因为对于这个项目来说,我们只支持服务器时区非常重要,无论用户在哪里。因此,为了与服务器时间保持一致,调用new Date('2019-01-01').getDate()应该返回1,因为它将是 1 月 1 日在柏林。但是,如果用户在巴西,同样的呼叫将返回31,因为巴西比格林威治标准时间早几个小时,当格林威治标准时间午夜时分,仍然是巴西的前一天。

考虑到服务器时区,我首先尝试使用date-fnswithdate-fns-timezone设置 DateTime 以向客户端显示日期和时间。这可以很好地显示正确的数据,但没有解决由于从日期中提取这些属性而引起的一些问题,并且这些问题会因用户所在的位置而异。

所以这就是为什么我现在要做的是以new Date()某种方式覆盖该方法,它总是会检索日期,就好像用户处于服务器时间一样。我还没有设法做到这一点。每当我从我的计算机更改日期和时间时,输出new Date()已经考虑了这个新的日期和时间设置。

那么我怎样才能强制new Date()总是用硬编码的时区返回 DateTime 呢?此外,如果我可以在不使用外部库(例如 moment.js)的情况下做到这一点,并且只使用普通的 Javascript 来做到这一点,那就太好了。

我正在查看window.navigator变量以查看是否可以将其设置为将日期强制为服务器时区,但看起来这不是解决我的问题的方法。

我为这个答案看了很多,但没有找到任何与这个答案非常接近的问题。我将在这里列出我之前看过的一些问题以及为什么我的案例与他们不同。

1- JavaScript 中特定时区的 new Date():在这种情况下,moment使用了 ,并且无法为new Date()自身完成此覆盖。

2-在不考虑时区的情况下将字符串转换为日期:在这一个中,答案会返回一个字符串,其日期格式为所需的时区,但不是 Date 对象本身。

3-考虑 Request.UserLanguages[0] 的 javascript 日期:同样在这一个中,问题/答案是关于格式化日期输出,而不是使用新时区检索 Date 对象本身。

4-如何将 moment.js 时区与 toDate 结合起来构建一个新的日期对象?:在这一个中,答案也是关于使用moment.js,我想避免的,因为我真正想要实现的是覆盖该new Date()方法。

标签: javascripttimezone

解决方案


一些东西:

  • 一般来说,应该尝试设计他们的应用程序,使服务器的时区完全不相关。这意味着仅依赖服务器的 UTC 功能,并使用特定的命名时区。询问服务器的本地时间往往会成为问题,尤其是在处理您可能无法完全控制服务器的环境时。

  • 请记住,DateJavaScript 中的对象名称错误。这真的是一个时间戳。本质上,它只是一个对象包装器,围绕着您获得的值,.valueOf()或者.getTime()当您将其强制为一个数字时。对象上的 Everything 函数Date只是读取这个值,应用一些逻辑(根据函数可能使用也可能不使用本地时区),并发出一些结果。同样,Date对象的构造函数解释您的输入,然后在结果对象中分配这个数字。换句话说,Date对象根本不跟踪时区。它只是在需要时应用它。因此,无法改变它。

  • 当您将yyyy-MM-dd格式字符串传递给Date构造函数时,根据 ECMAScript 规范,它被解释为午夜 UTC,而不是本地时间午夜。这是与 ISO 8601 的偏差,这常常使人们感到困惑。

  • 您显示为输出的字符串Tue Jan 01 2019 01:00:00 GMT+0100 (Central European Standard Time)是在本地时间发出的,并且是调用.toString()函数或在某些环境中将Date对象传递给的结果。其他环境显示 的结果,以 UTC 发出。console.log.toISOString()

  • 没有window.navigator可以更改本地时区的全局或其他地方。在 Node.js 应用程序中,如果您确实需要全局设置服务器的时区,您可以TZ在启动 Node.js 之前设置环境变量。但是,这在 Windows 环境中不起作用,并且对浏览器没有帮助。

  • 您正在使用诸如date-fnswith之类的库date-fns-timezone。还有其他库,在这个答案中列出。或者,您可以.toLocaleString使用timeZone选项调用,例如:

    new Date().toLocaleString("en-US", {timeZone: "America/New_York"})
    

    此 API 提供了在特定时区发出字符串的功能,但它不执行任何将时区应用于输入字符串的操作。

所以最终,回答你的问题:

那么如何强制 new Date() 总是用硬编码的时区返回 DateTime 呢?

对不起,你不能。您可以使用不同的对象来有状态地跟踪时区,也可以使用将时区作为参数的函数。两者都是现有库提供的东西,但只有我上面展示的一个函数目前内置在 JavaScript 中。


推荐阅读