Date-fns | 如何格式化为 UTC

问题

它看起来像当我使用 format()函数时,它会自动将原来的 UTC 时间转换成我的时区(UTC + 8)。我已经在他们的文档里找了好几个小时了,似乎找不到一种默认使用 UTC 时间的方法。

import { parseISO, format } from "date-fns";


const time = "2019-10-25T08:10:00Z";


const parsedTime = parseISO(time);
console.log(parsedTime); // 2019-10-25T08:10:00.000Z


const formattedTime = format(parsedTime, "yyyy-MM-dd kk:mm:ss");
console.log(formattedTime); // 2019-10-25 16:10:00 <-- 8 HOURS OFF!!

我已经尝试使用包 data-fns-tz和使用类似

format(parsedTime, "yyyy-MM-dd kk:mm:ss", {timeZone: "UTC"});

还是没找到。

救命啊!

预期产出

2019-10-25 08:10:00

实际输出

2019-10-25 16:10:00

95919 次浏览

我建议使用内置的 Date直到:

const date = new Date("2019-10-25T08:10:00Z");
const isoDate = date.toISOString();


console.log(`${isoDate.substring(0, 10)} ${isoDate.substring(11, 19)}`);

产出:

2019-10-25 08:10:00

不是任何格式的通用解决方案,但不需要外部库。

我也有同样的问题。我所做的就是从 ISO 字符串中删除时区,然后在 date-fns 中使用该时区:

let time = "2019-10-25T08:10:00Z".slice(0, -1)

以上是一个没有时区的时间,因为没有时区日期-fns 假定为本地时区,所以当你这样做:

format(parseISO(time), 'h:mm a')

你得到: 早上8:10,或者任何你喜欢的格式。你只需要小心你切割的那根线。如果它总是相同的格式,那么它应该工作。

注意
下面的解决方案不适用于所有的时区,所以如果时区的准确性对于您的应用程序是至关重要的,您可能想要尝试类似于贝尼的答案。更多信息请参见 链接

我今天也有同样的问题,我做了一些研究,看看自从这个问题提出以来,是否有人提出了更好的问题。我偶然发现了适合我的需求和风格偏好的 这个解决方案:

import { format, addMinutes } from 'date-fns';


function formatDate(date) {
return format(addMinutes(date, date.getTimezoneOffset()), 'yyyy-MM-dd HH:mm:ss');
}

解释

getTimezoneOffset返回将该日期转换为 UTC 所需的分钟数。在太平洋标准时间(-0800小时)它会返回480,而在科技中心(+ 0800小时)它会返回 -480。

你差点就成功了,这对我有用:

import { parseISO } from "date-fns";
import { format, utcToZonedTime } from "date-fns-tz";


const time = "2019-10-25T08:10:00Z";


const parsedTime = parseISO(time);
console.log(parsedTime); // 2019-10-25T08:10:00.000Z


const formatInTimeZone = (date, fmt, tz) =>
format(utcToZonedTime(date, tz),
fmt,
{ timeZone: tz });


const formattedTime = formatInTimeZone(parsedTime, "yyyy-MM-dd kk:mm:ss xxx", "UTC");
console.log(formattedTime); // 2019-10-25 08:10:00 +00:00

在幕后

Date-fns [-tz ]库坚持内置的 Date数据类型,即 没有 TZ 的信息
有些函数将其视为时间片刻,但有些函数像 format一样将其视为日历组件的结构ーー2019年,... ... ,第25天,08小时,... ... 。

现在的问题是 Date在内部只有一瞬间的时间。它的方法提供了与 当地时区中的日历组件的映射。

因此,为了表示一个不同的时区,date-fns-tz/utcToZonedTime临时生成代表 错误的时间Date实例ーー只是为了让它的日历组件在当地时间成为我们想要的!

date-fns-tz/format函数的 timeZone 输入影响 只有打印时区的模板字符(XX..Xxx..xzz..zOO..O)。

有关这种“转换”技术(以及激励它们的实际用例)的讨论,请参见 https://github.com/marnusw/date-fns-tz/issues/36..。
这有点低级和冒险,但我上面所说的具体方法ーー formatInTimeZone()ーー是我相信一个安全的配方。

试试看

const formatDate = new Date().toISOString().substr(0, 19).replace('T', ' ');

我使用 date/fns 和本机日期方法做了类似的事情

import format from 'date-fns/format';
import parseISO from 'date-fns/parseISO';


export const adjustForUTCOffset = date => {
return new Date(
date.getUTCFullYear(),
date.getUTCMonth(),
date.getUTCDate(),
date.getUTCHours(),
date.getUTCMinutes(),
date.getUTCSeconds(),
);
};


const formatDate = (dateString) = > {
const date = parseISO(dateString);
const dateWithOffset = adjustForUTCOffset(date)
return format(dateWithOffset, 'LLL dd, yyyy HH:mm')
}

我是这么做的

const now = new Date()
const date = format(
new Date(now.toISOString().slice(0, -1)),
'yyyy-MM-dd HH:mm:ss'
)

我只是从 ISO 字符串中删除了 Z。我不确定它是否解决了这个 问题

我想是吧

在解析之前将日期构造为 UTC 将很有帮助。

import { parseISO, format } from "date-fns";


const time = "2019-10-25T08:10:00Z";


const parsedTime = parseISO(new Date(Date.UTC(time)));
const formattedTime = format(parsedTime, "yyyy-MM-dd kk:mm:ss");

像这样。