日期-fns |如何格式化为 UTC

Posted

技术标签:

【中文标题】日期-fns |如何格式化为 UTC【英文标题】:date-fns | How do I format to UTC 【发布时间】:2020-02-21 23:06:10 【问题描述】:

问题

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

【问题讨论】:

我在这里测试了你的代码。这似乎工作正常。 repl.it/repls/RepentantDimFactor @khan - repl.it 以 UTC 运行,这就是原因。 解析时,2019-10-25 08:10:00 将被解释为本地,而不是 UTC,并且在某些浏览器中将被视为无效日期。 【参考方案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");

像这样。

【讨论】:

【参考方案2】:

这是我的做法

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

我刚刚从 ISO 字符串中删除了 Z。我不确定它是否解决了这个issue 虽然

【讨论】:

【参考方案3】:

我使用 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')

【讨论】:

我现在卡在 1.30.1 上,这对我有用 可以告诉你我爱你吗? :) 你保存了我的项目谢谢【参考方案4】:

试试

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

【讨论】:

【参考方案5】:

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

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

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。

【讨论】:

您应该注意,此解决方案不适用于所有时区,正如您提到的线程中所指出的那样:github.com/date-fns/date-fns/issues/1401#issuecomment-621897094 @Sherwin,对我来说不是 +5.30 ,而是 -5.30 。那我应该怎么改正呢? @KomalKhatkole getTimezoneOffset 返回将本地时间转换为 UTC 时间所需的分钟数,因此如果您的偏移量为 +5:30,它将返回 -330 分钟。这是怎么回事?【参考方案6】:

你快到了。这对我有用:

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

现在问题是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() - 我相信是一个安全的配方。

【讨论】:

对于任何想知道这是否是 hack 的人 -- 实际上这是格式化到某个时区的官方方式,包括 UTC:npmjs.com/package/date-fns-tz#format【参考方案7】:

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

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

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

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

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

【讨论】:

【参考方案8】:

我建议使用内置的Date util:

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

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

【讨论】:

感谢您的回复,但遗憾的是,我选择使用库的原因是我需要对日期进行计算:( 你仍然可以使用date-fns 来处理除了最后一部分的输出。毕竟,它确实返回了Date 对象。 如果我想使用 date-fns,这似乎是唯一的出路。很好的答案!

以上是关于日期-fns |如何格式化为 UTC的主要内容,如果未能解决你的问题,请参考以下文章

如何轻松地将GQLQuery的日期字段格式化为另一个时区?

使用 date-fns 将日期解析为 UTC 的正确方法

如何使用 date-fns 格式化日期?

如何使用 JavaScript date-fns 库在特定时区格式化日期/时间

如何在 Go 中将时间戳格式化为 GMT?

date-fns - 有没有办法获取短日期格式字符串