用于Windows的Node中process.env.TZ的解决方案='UTC'?

问题描述 投票:1回答:1

我正在尝试测试我的Postgres数据库,以确保所有内容均已正确添加,并且将以2029-01-22T16:28:32.000Z格式包含硬编码日期。

这里是表格:

CREATE TABLE blogful_articles (
    id INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
    title TEXT NOT NULL,
    content TEXT,
    date_published TIMESTAMP DEFAULT now() NOT NULL
);

我希望重新获得2029-01-22T16:28:32.000Z,但重新获得2029-01-23T00:28:32.000Z,因为Windows会针对时区差异自动调整它,并且我的测试将失败。

它应该自动调整夏令时,但这是我的解决方法:

function adjustingForTimezone(dateToAdjust) {
  const offsetInMilliseconds = dateToAdjust.getTimezoneOffset() * 60000;
  const theDateWithOffsetAdded =
    Date.parse(dateToAdjust) - offsetInMilliseconds;
  const adjustedTime = new Date(theDateWithOffsetAdded);
  return adjustedTime;
}

这是我的用法:

app.get("/articles", (req, res, next) => {
  const knexInstance = req.app.get("db");
  ArticlesService.getAllArticles(knexInstance)
    .then(articles => {
      const os = process.platform

      function adjustingForTimezone(dateToAdjust) {
        const offsetInMilliseconds = dateToAdjust.getTimezoneOffset() * 60000
        const theDateWithOffsetAdded = Date.parse(dateToAdjust) - offsetInMilliseconds
        const adjustedTime = new Date(theDateWithOffsetAdded)
        return adjustedTime
      }

      res.json(
        articles.map(article => ({
          id: article.id,
          title: article.title,
          style: article.style,
          content: article.content,
          date_published: os === "win32" ? adjustingForTimezone(article.date_published) : new Date(article.date_published)
        }))
      );
    })
    .catch(next);
});

我做了adjustingForTimezone函数,该函数应该自动调整它,有什么方法可以改进它?在我的代码中使用此功能有哪些潜在的陷阱?

node.js windows postgresql timezone utc
1个回答
0
投票

用于“调整”时区的方法实际上并未调整。相反,它创建了另一个时间点。通常认为一个人可以减去一个偏移量来考虑时区,但这是两个截然不同的概念。 (有关此谬论的幽默但内容丰富的示例,请参见this Dilbert cartoon。)

Date对象中仅存储一个实际值,这是您在调用getTimevalueOfparse等时看到的数字时间戳。使用本地时区的所有其他函数( (例如toString)或命名时区(例如timeZonetoLocaleString选项)将期望内部时间戳是基于UTC的。如果不是,那么您可能会得到错误的结果。

在代码中这很重要的地方是您调用的getTimezoneOffset。您要求的时间点应该基于UTC,但是由于您需要进行调整,因此它已经是错误的时间点。您可以在DST转换的临近日期/时间进行测试,您会发现它切换偏移量的时间过早或过晚。

因此,让我们回到最初的问题-您从Postgres中获得了一个时间戳,该时间戳已被本地时区偏移。这是罪魁祸首:

date_published TIMESTAMP DEFAULT now() NOT NULL

这里可能正在发生的事情:

  • now()函数使用插入行时有效的会话时区返回TIMESTAMP WITH TIME ZONE(又名TIMESTAMPTZ)。在您的示例中,它返回2029-01-23T00:28:32.000+08:00。因此,会话时区可能是默认值,它是从服务器的时区设置中提取的。 (UTC + 8-在中国,澳大利亚和其他一些地方使用。)

  • 然后将其传递给TIMESTAMP,在Postgres中,该[知道时区。因此,它将去除偏移量并存储2029-01-23T00:28:32.000。因此,您的时间戳记不会存储在UTC中,而是存储在本地时间中。

  • 稍后查询时,会话时区设置为UTC,因此您会返回2029-01-23T00:28:32.000Z,这是不正确的。

有几种不同的解决方法:

  • 您可以确保在行插入期间将会话时区设置为UTC

    SET TIME ZONE 'UTC'; INSERT INTO ...

  • 您可以在定义表时在存储时间戳之前显式转换为UTC:

    date_published TIMESTAMP DEFAULT (now() AT TIME ZONE 'UTC') NOT NULL

  • 您可以将date_published字段定义为TIMESTAMPTZ而不是TIMESTAMP。 (可以说这是最好的方法。)

    date_published TIMESTAMPTZ DEFAULT now() NOT NULL

  • 您可以确保查询时的会话时区与插入时的本地时区相同。但是,我不建议您这样做,因为如果服务器的时区发生变化,或者您使用的时区在夏令时的偏移量之间转换,则您会有所差异。
  • 有了这些,您就可以删除adjustingForTimezone函数并直接使用查询返回的时间戳。

    © www.soinside.com 2019 - 2024. All rights reserved.