64

问题

看起来当我使用该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

4

8 回答 8

37

你快到了。这对我有用:

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] 库坚持不携带 TZ info的内置Date数据类型。 有些函数将其视为一个时刻,但有些函数则将其视为日历组件的结构——2019 年,...,第 25 天,第 8 小时,...。
format

现在的麻烦是在Date内部只是一个瞬间。它的方法在本地时区提供到/来自日历组件的映射。

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

并且该date-fns-tz/format函数的 timeZone 输入XX..X影响打印时区 ( , xx..x, zz..z, )的模板字符OO..O

请参阅https://github.com/marnusw/date-fns-tz/issues/36以了解有关这种“转移”技术(以及激发它们的实际用例)的一些讨论......
这有点低级和风险,但我在上面编写它们的具体方式formatInTimeZone()——我相信一个安全的食谱。

于 2020-08-03T09:58:55.440 回答
27

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

我今天有完全相同的问题,并做了一些研究,看看自从提出这个问题以来是否有人提出了更好的办法。我遇到了这个适合我的需求和风格偏好的解决方案:

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

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

解释

getTimezoneOffset返回将该日期转换为 UTC 所需的分钟数。在 PST(-0800 小时)中,它将返回 480,而对于 CST(+0800 小时)中的某人,它将返回 -480。

于 2020-04-27T22:30:24.247 回答
20

我建议使用内置的Dateutil:

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

console.log(`${isoDate.substr(0, 10)} ${isoDate.substr(11, 8)}`);

输出:

2019-10-25 08:10:00

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

于 2019-10-25T15:24:10.363 回答
10

我有同样的问题。我所做的是从 ISO 字符串中删除时区,然后将该时间与 date-fns 一起使用:

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

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

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

你会得到:8:10 AM,或者你喜欢的任何格式。你只需要小心你正在切片的字符串。如果它总是相同的格式,那么它应该可以工作。

于 2019-12-15T17:51:16.267 回答
7

我使用日期/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')
}

于 2021-03-17T11:47:36.847 回答
4

这是我的做法

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

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

于 2021-05-27T22:21:57.010 回答
1

我猜

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

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

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

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

像这样。

于 2021-06-18T17:18:14.897 回答
-2

尝试

const formatDate = new Date().toISOString().substr(0, 19).replace('T', ' ');
于 2020-12-04T20:20:21.677 回答