简体   繁体   English

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

[英]date-fns | How do I format to UTC

Problem问题

It looks like when I use the format() function, it automatically convert the original UTC time into my timezone (UTC+8).看起来当我使用format() function 时,它会自动将原始 UTC 时间转换为我的时区(UTC+8)。 I have been digging through their docs for hours and couldn't seem to find a way to default it to UTC time.我一直在研究他们的文档几个小时,似乎找不到将其默认为 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!!

I have tried to use the package data-fns-tz and use something like我尝试使用 package data-fns-tz并使用类似的东西

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

still no luck.仍然没有运气。

Please help!请帮忙!

Expected Output预计 Output

2019-10-25 08:10:00

Actual Output实际 Output

2019-10-25 16:10:00

You were almost there.你快到了。 This works for me:这对我有用:

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

Behind the scenes在幕后

The date-fns[-tz] libraries stick to the built-in Date data type that carries no TZ info . date-fns[-tz] 库坚持使用不携带 TZ 信息的内置Date数据类型。
Some functions treat it as a moment-in-time, but some like format treat it more like a struct of calendaric components — year 2019, ..., day 25, hour 08, ....一些函数将其视为时间点,但有些函数将其视为日历组件的结构format年,...,第 25 天,第 8 小时,...。

Now the trouble is a Date is internally only a moment in time.现在问题是Date在内部只是一个时刻。 Its methods provide a mapping to/from calendaric components in local time zone .它的方法在本地时区提供到/来自日历组件的映射。

So to represent a different time zone, date-fns-tz/utcToZonedTime temporarily produces Date instances which represent the wrong moment in time — just to get its calendaric components in local time to be what we want!因此,为了表示不同的时区, date-fns-tz/utcToZonedTime临时生成代表错误时间点Date实例——只是为了让它在本地时间的日历组件成为我们想要的!

And the date-fns-tz/format function's timeZone input affects only the template chars that print the time zone ( XX..X , xx..x , zz..z , OO..O ).并且date-fns-tz/format函数的 timeZone 输入影响打印时区的模板字符( XX..Xxx..xzz..zOO..O )。

See https://github.com/marnusw/date-fns-tz/issues/36 for some discussion of this "shifting" technique (and of real use cases that motivated them)...请参阅https://github.com/marnusw/date-fns-tz/issues/36了解有关这种“转移”技术(以及激发它们的真实用例)的一些讨论......
It's a bit low-level & risky, but the specific way I composed them above — formatInTimeZone() — is I believe a safe recipe.这有点低级和风险,但我在上面编写它们的具体方式formatInTimeZone() ——我相信是一个安全的方法。

Note笔记
The following solution will not work for all time zones, so if timezone accuracy is critical for your application you might want to try something like the answer from Beni.以下解决方案不适用于所有时区,因此如果时区准确性对您的应用程序至关重要,您可能想尝试类似 Beni 的答案。 See this link for more info有关更多信息,请参阅此链接

I had the exact same question today and did some research to see if anyone has come up with anything better since this question was posed.我今天有完全相同的问题,并做了一些研究,看看自从提出这个问题以来是否有人提出了更好的办法。 I came across this solution which fit my needs and stylistic preference:我遇到了这个适合我的需求和风格偏好的解决方案:

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

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

Explanation解释

getTimezoneOffset returns the number of minutes needed to convert that date to UTC. getTimezoneOffset返回将该日期转换为 UTC 所需的分钟数。 In PST (-0800 hours) it would return 480 whereas for somebody on CST (+0800 hours) it would return -480.在 PST(-0800 小时)中,它将返回 480,而对于 CST(+0800 小时)中的某人,它将返回 -480。

I would suggest using the built-in Date util:我建议使用内置的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)}`);

Outputs:输出:

2019-10-25 08:10:00

Not a general solution for any format, but no external libraries required.不是任何格式的通用解决方案,但不需要外部库。

I had the same problem.我有同样的问题。 What I do is remove the timezone from the ISO string and then use that time with date-fns:我所做的是从 ISO 字符串中删除时区,然后将该时间与 date-fns 一起使用:

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

The above is a time with no time zone, and because there is no timezone date-fns assumes the local timezone, so when you do:上面是一个没有时区的时间,并且因为没有时区 date-fns 假定本地时区,所以当你这样做时:

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

you get: 8:10 AM , or whatever format you prefer.你会得到: 8:10 AM ,或者你喜欢的任何格式。 You just have to be careful with the string that you are slicing.你只需要小心你正在切片的字符串。 If its always the same format then it should work.如果它总是相同的格式,那么它应该可以工作。

I did something like this using date/fns and native date methods我使用日期/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') }

Here is how I did it这是我的做法

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

I just removed the Z from the ISO string.我刚刚从 ISO 字符串中删除了 Z。 I'm not sure if it solves this issue though我不确定它是否能解决这个问题

I guess我猜

To construct the date as UTC before parsing would be helpful.在解析之前将日期构造为 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");

like this.像这样。

try尝试

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM