涉及日期fns格式的时区问题()

问题描述 投票:2回答:1
const dt = new Date('2017-12-12');
console.log(format(dt, 'YYYY-MM-DD'));

以上代码记录2017-12-11在美国,但2017-12-12在印度。

我跟着这个github线程here并尝试了一些东西,但没有得到理想的结果。

我的期望是打印相同的日期而不考虑时区

为什么我需要这个:考虑一个涉及生日的情景。如果我提供一些输入日期,则必须在所有地区显示为相同日期,而不管其时区如何。

javascript datetime location locale date-fns
1个回答
2
投票

在从Date传递给format之前,您需要从date-fns实例中减去本地时区的时区偏移量。例如:

const dt = new Date('2017-12-12');
const dtDateOnly = new Date(dt.valueOf() + dt.getTimezoneOffset() * 60 * 1000);
console.log(format(dtDateOnly, 'YYYY-MM-DD')); // Always "2017-12-12"

问题

您只想处理Date实例的日期部分,因为时间部分对于生日没有意义。但是,Date对象不提供任何“仅限日期”模式。您可以使用本地时区或UTC访问其日期和时间部分。问题是,来自formatdate-fns始终在当地时区打印输出。

当您仅使用日期部分执行构造函数时:

const dt = new Date('2017-12-12');

JavaScript引擎实际上采用了不完整的ISO 8601格式的字符串并执行了以下操作:

const dt = new Date('2017-12-12T00:00:00.000Z');

它可能仍然看起来“无害”,但date实例不仅暴露了UTC的值,还暴露了本地时区的值。如果您在美国东海岸构建Date实例,您将看到以下输出:

> const dt = new Date('2017-12-12');
> dt.toISOString()
'2017-12-12T00:00:00.000Z'
> dt.toString()
'Tue Dec 11 2017 19:00:00 GMT-0500 (EST)'
> d.toLocaleString()
'12/11/2017 7:00:00 PM'

如果你知道,来自formatdate-fns从当地时区的date实例中读取日期和时间部分,你需要让你的日期“看起来像”当地时区的午夜而不是UTC,你传递给它Date构造函数。然后,您将看到保留的年,月和日期编号。这意味着,您需要在指定日期减去当地时区的时区偏移量。 Date.prototype.getTimezoneOffset返回偏移量,但是带有倒置符号并且以分钟为单位。

const dt = new Date('2017-12-12');
// Tue Dec 11 2017 19:00:00 GMT-0500 (EST)
const dtDateOnly = new Date(dt.valueOf() + dt.getTimezoneOffset() * 60 * 1000);
// Tue Dec 12 2017 00:00:00 GMT-0500 (EST)
console.log(format(dtDateOnly, 'YYYY-MM-DD'));
// Prints always "2017-12-12", regardless the time zone it executed in

但是,这样的Date实例只能用于格式化仅日期值。您不能将它用于计算日期差异,例如,需要原始和正确的UTC值。

替代

如果您始终需要dame date-only格式而不是特定于当前语言环境的格式,则不需要date-fns。您可以通过填充数字的串联来格式化字符串:

const dt = new Date('2017-12-12');

const year = dt.getUTCFullYear()
const month = dt.getUTCMonth() + 1 // Date provides month index; not month number
const day = dt.getUTCDate()

// Print always "2017-12-12", regardless the time zone it executed in
console.log(year + '-' + padToTwo(month) + '-', padToTwo(day));
// Or use a template literal
console.log(`${year}-${padToTwo(month)}-${padToTwo(day)}`);

function padToTwo (number) {
  return number > 9 ? number : '0' + number
}
© www.soinside.com 2019 - 2024. All rights reserved.