问题
当我使用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
你差不多到了。这对我有效:
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
幕后
日期fns[-tz]库坚持使用不携带tz信息的内置Date
数据类型
有些函数将其视为一个时刻,但有些函数(如format
(则将其更像是日历组件的结构——2019年。。。,第25天08小时。。。。
现在的问题是Date
在内部只是一个瞬间。它的方法提供了到本地时区中日历组件的映射。
因此,为了表示不同的时区,date-fns-tz/utcToZonedTime
临时生成Date
实例,这些实例表示错误的时间时刻——只是为了使其在本地时间的日历组件成为我们想要的!
date-fns-tz/format
函数的时区输入仅影响打印时区的模板字符(XX..X
、xx..x
、zz..z
、OO..O
(。
请参阅https://github.com/marnusw/date-fns-tz/issues/36为了对此进行一些讨论;移位";技术(以及激励他们的真实用例(
这有点低级&风险很大,但我在上面编写它们的具体方式——formatInTimeZone()
——是我认为安全的配方。
我建议使用内置的Date
util:
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
不是任何格式的通用解决方案,但不需要外部库。
注意
以下解决方案不适用于所有时区,因此,如果时区准确性对您的应用程序至关重要,您可能需要尝试类似Beni的答案。查看此链接了解更多信息
我今天也有同样的问题,并做了一些研究,看看自从这个问题提出以来,是否有人想出了更好的办法。我发现了一个符合我的需求和风格偏好的解决方案:
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,而在CST(+0800小时(,则返回-480。
我也遇到了同样的问题。我所做的是从ISO字符串中删除时区,然后将该时间与日期fns:一起使用
let time = "2019-10-25T08:10:00Z".slice(0, -1)
上面是一个没有时区的时间,因为没有时区,所以fns假设为本地时区,所以当你这样做时:
format(parseISO(time), 'h:mm a')
您可以得到:8:10AM,或者您喜欢的任何格式。你只需要小心你正在切的绳子。如果它总是相同的格式,那么它应该可以工作。
我使用日期/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。我不确定它是否通过解决了这个问题
时间戳解决方案
format(utcToZonedTime(timestamp, 'UTC'), 'MM/dd/yyyy hh:mm a', { timeZone: 'UTC' })
我猜
在解析之前将日期构造为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");
像这样。
尝试
const formatDate = new Date().toISOString().substr(0, 19).replace('T', ' ');