我正在尝试测试我的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
函数,该函数应该自动调整它,有什么方法可以改进它?在我的代码中使用此功能有哪些潜在的陷阱?
用于“调整”时区的方法实际上并未调整。相反,它创建了另一个时间点。通常认为一个人可以减去一个偏移量来考虑时区,但这是两个截然不同的概念。 (有关此谬论的幽默但内容丰富的示例,请参见this Dilbert cartoon。)
Date
对象中仅存储一个实际值,这是您在调用getTime
,valueOf
,parse
等时看到的数字时间戳。使用本地时区的所有其他函数( (例如toString
)或命名时区(例如timeZone
的toLocaleString
选项)将期望内部时间戳是基于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中,而是存储在本地时间中。
2029-01-23T00:28:32.000Z
,这是不正确的。有几种不同的解决方法:
UTC
。SET TIME ZONE 'UTC'; INSERT INTO ...
date_published TIMESTAMP DEFAULT (now() AT TIME ZONE 'UTC') NOT NULL
date_published
字段定义为TIMESTAMPTZ
而不是TIMESTAMP
。 (可以说这是最好的方法。)date_published TIMESTAMPTZ DEFAULT now() NOT NULL
有了这些,您就可以删除adjustingForTimezone
函数并直接使用查询返回的时间戳。