[英]How to write a function that can add hours and days correctly to the target time zone with date-fns?
Lets say I have a timestamp with the IANA time zone identifier:假设我有一个带有 IANA 时区标识符的时间戳:
2021-11-07T00:00:00-04:00[America/New_York] 2021-11-07T00:00:00-04:00[美国/纽约]
Note : This timestamp is 2 hours away from transitioning from DST to standard time.注意:此时间戳是从 DST 转换到标准时间的2 小时。
I want to write a function that can take the timestamp, time zone identifier and a Duration , and return a new "future" timestamp in the target timezone.我想编写一个 function 可以获取时间戳、时区标识符和Duration ,并在目标时区返回一个新的“未来”时间戳。
For instance:例如:
zonedAddDuration("2021-11-07T00:00:00-04:00", "America/New_York", {
days: 1
})
// => "2021-11-08T00:00:00-05:00"
zonedAddDuration("2021-11-07T00:00:00-04:00", "America/New_York", {
hours: 5
})
// "2021-11-07T04:00:00-05:00"
I seem to have found a way to make zonedAddDuration
handle both these scenarios, but not at the same time :我似乎找到了一种让
zonedAddDuration
处理这两种情况的方法,但不能同时处理:
import { add, Duration, parseISO } from "date-fns";
import {
utcToZonedTime,
format as formatTz
} from "date-fns-tz";
// Handles "hours" scenario (also minutes and seconds)
export const zonedAddDuration1 = (
isoDateStr: string,
zoneIana: string,
duration: Duration
) => {
const startDate = parseISO(isoDateStr);
const futureDate = add(startDate, duration);
const zonedTime = utcToZonedTime(futureDate, zoneIana);
return formatTz(zonedTime, "yyyy-MM-dd'T'HH:mm:ssXXXzzz", {
timeZone: zoneIana
});
};
// handles "days" scenario (also months, weeks, years)
export const zonedAddDuration2 = (
isoDateStr: string,
zoneIana: string,
duration: Duration
) => {
const startDate = parseISO(isoDateStr);
const zonedTime = utcToZonedTime(startDate, zoneIana);
const futureDate = add(zonedTime, duration);
return formatTz(futureDate, "yyyy-MM-dd'T'HH:mm:ssXXXzzz", {
timeZone: zoneIana
});
};
As you might notice, the only difference between zonedAddDuration1
and zonedAddDuration2
is the order in which I use utcToZonedTime
.您可能会注意到,
zonedAddDuration1
和zonedAddDuration2
之间的唯一区别是我使用utcToZonedTime
的顺序。 I need this function to be general purpose, and should handle all kinds of durations correctly, including DST transitions.我需要这个 function 是通用的,并且应该正确处理各种持续时间,包括 DST 转换。 I should add that the local timezone of the system should not matter, I want the same results regardless of where I run this code .
我应该补充一点,系统的本地时区应该无关紧要,无论我在哪里运行此代码,我都想要相同的结果。
I think my understanding of date-fns-tz might be lacking, I've read the documentation many times and still not sure I'm grasping it correctly.我认为我可能缺乏对 date-fns-tz 的理解,我已经阅读了很多次文档,但仍然不确定我是否正确掌握了它。
If it is not possible to write such a function, then any help understanding why it behaves as it does would be appreciated (why the ordering matters).如果不可能写出这样的 function,那么任何帮助理解它为什么会这样表现将不胜感激(为什么排序很重要)。
I've been experimenting in this Codesandbox (which includes the 2 test scenarios): https://codesandbox.io/s/exciting-fog-tke86?file=/src/dateUtil.ts我一直在这个 Codesandbox(包括 2 个测试场景)中进行试验: https://codesandbox.io/s/exciting-fog-tke86?file=/src/dateUtil.ts
I found a way that will add durations correctly for both dates and times.我找到了一种可以为日期和时间正确添加持续时间的方法。 What I did was to split the input duration in to a time duration and a date duration , and add those to the input date separately.
我所做的是将输入持续时间拆分为持续时间和日期持续时间,并将它们分别添加到输入日期。 This way I can apply the
utcToZonedTime
in the correct order for both scenarios.这样,我可以在两种情况下以正确的顺序应用
utcToZonedTime
。
All this feels like a hack though, and I'm still not sure why it works (or even if it works as expected for all concievable scenarios).尽管如此,所有这一切都感觉像是一种黑客行为,我仍然不确定它为什么会起作用(或者即使它在所有可能的场景中都能按预期工作)。
import { add, Duration, parseISO } from "date-fns";
import {
utcToZonedTime,
format as formatTz
} from "date-fns-tz";
export const zonedAddDuration = (
isoDateStr: string,
zoneIana: string,
duration: Duration
) => {
const startDate = parseISO(isoDateStr);
const dateDuration: Duration = {
years: duration.years ?? 0,
months: duration.months ?? 0,
weeks: duration.weeks ?? 0,
days: duration.days ?? 0
};
const timeDuration: Duration = {
hours: duration.hours ?? 0,
minutes: duration.minutes ?? 0,
seconds: duration.seconds ?? 0
};
const futureDateTime = add(startDate, timeDuration);
const zonedTime = utcToZonedTime(futureDateTime, zoneIana);
const futureDate = add(zonedTime, dateDuration);
return formatTz(futureDate, "yyyy-MM-dd'T'HH:mm:ssXXXzzz", {
timeZone: zoneIana
});
};
Here is a Codesandbox with the working version plus tests. 这是一个带有工作版本和测试的 Codesandbox 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.