【问题标题】:How to write a function that can add hours and days correctly to the target time zone with date-fns?如何使用 date-fns 编写一个可以将小时和天正确添加到目标时区的函数?
【发布时间】:2021-08-11 13:57:20
【问题描述】:

假设我有一个带有 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", "America/New_York", {
  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,
  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
  });
};

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

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

如果不可能编写这样的函数,那么任何帮助理解它为什么会这样表现将不胜感激(为什么排序很重要)。

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

【问题讨论】:

    标签: javascript date-fns


    【解决方案1】:

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

    不过,所有这一切都感觉像是一种 hack,我仍然不确定它为什么会起作用(或者即使它在所有可能的场景中都能按预期工作)。

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

    【讨论】:

      猜你喜欢
      • 2019-08-28
      • 2020-12-18
      • 2021-09-27
      • 2021-04-01
      • 2021-08-21
      • 2022-12-17
      • 2022-11-15
      • 2020-04-08
      • 2019-06-30
      相关资源
      最近更新 更多