微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何编写一个可以使用 date-fns 将小时和天正确添加到目标时区的函数?

如何解决如何编写一个可以使用 date-fns 将小时和天正确添加到目标时区的函数?

假设我有一个带有 IANA 时区标识符的时间戳:

2021-11-07T00:00:00-04:00[美国/纽约]

注意:这个时间戳是 2 hours away 从 DST 过渡到标准时间。

我想编写一个函数,它可以接受时间戳、时区标识符和 Duration,并在目标时区返回一个新的“未来”时间戳。

例如:

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",{
  hours: 5
})
// "2021-11-07T04:00:00-05:00"

我似乎找到了让 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,duration: Duration
) => {
  const startDate = parseISO(isoDateStr);

  const zonedTime = utcToZonedTime(startDate,zoneIana);
  const futureDate = add(zonedTime,duration);

  return formatTz(futureDate,{
    timeZone: zoneIana
  });
};

您可能会注意到,zonedAddDuration1zonedAddDuration2间的唯一区别是我使用 utcToZonedTime 的顺序。我需要这个函数是通用的,并且应该正确处理各种持续时间,包括 DST 转换。我应该补充一点,系统的本地时区应该无关紧要,无论我在哪里运行此代码,我都希望得到相同的结果

我认为我对 date-fns-tz 的理解可能有所欠缺,我已经阅读了 the documentation 多次,但仍然不确定我是否理解正确。

如果无法编写这样的函数,那么将不胜感激(为什么排序很重要)。

我一直在这个 CodesandBox 中进行试验(其中包括 2 个测试场景): https://codesandbox.io/s/exciting-fog-tke86?file=/src/dateUtil.ts

解决方法

我找到了一种可以为日期和时间正确添加持续时间的方法。我所做的是将输入持续时间分成持续时间日期持续时间,并将它们分别添加到输入日期中。这样我就可以在两种情况下以正确的顺序应用 utcToZonedTime

尽管所有这些都感觉像是一个黑客,但我仍然不确定它为什么起作用(或者即使它在所有可能的场景中都按预期工作)。

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 带有工作版本和测试。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。