是否有内置的方法来规范 Luxon 内的持续时间?

Is there a built in way to normalize a duration within Luxon?

我正在从 Momentjs 迁移到 Luxon。我允许用户选择任务将花费的小时数。当我们保存这个值时,我希望它正常化。因此,如果一项任务需要 90 个小时,我更愿意存储 3 天 18 个小时。我存储了 ISO 持续时间字符串,所以我想将 PT90H 转换为 P3DT18H...当然可以使用任何给定值。

我试过Luxon的normalize函数,我试过这样调用它:

const duration = Duration.fromObject({ hours: 90 });
duration.normalize().toISO();

然而,normalize似乎对结果没有任何作用。我仍然得到 PT90H。 Luxon 有内置的方法吗?

Durtation.normalize() 不会向 Duration 对象添加属性,因此您需要提供您希望其标准化的单位。 (这对我来说很奇怪,但提供了对结果的隐式控制)。

normalize() – Reduce this Duration to its canonical representation in its current units.

const duration = Duration
  .fromObject({ days: 0, hours: 90 })
  .normalize()
  .toISO();

console.log(duration);
<script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/2.2.0/luxon.min.js"></script>
<script>const { Duration } = luxon;</script>

或者,您可以使用 Duration.shiftTo() 明确地将持续时间强制为特定单位。

const duration = Duration
  .fromObject({hours: 90 })
  .shiftTo('days', 'hours')
  .toISO();

console.log(duration);
<script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/2.2.0/luxon.min.js"></script>
<script>const { Duration } = luxon;</script>


如果您知道您总是想要标准化为所有单位,您可以声明一个实用程序 return 用所有单位初始化的 Duration 对象。

function createDuration(duration) {
  return Duration.fromObject(
    Object.assign(
      { years: 0, months: 0, weeks: 0, days: 0, hours: 0, minutes: 0, seconds: 0, milliseconds: 0 },
      duration
    )
  );
}

const duration = createDuration({ hours: 90, minutes: 3004 }).normalize().toISO();

console.log(duration);
<script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/2.2.0/luxon.min.js"></script>
<script>const { Duration } = luxon;</script>

根据@pilchard 的回答,我最终使用这个函数来标准化我的持续时间。

function normalize(duration) {
  const durationObject = duration.shiftTo(
    'years',
    'months',
    'days',
    'hours',
    'minutes',
    'seconds'
  ).toObject();

  // filter out units with 0 values.
  const resultObject = Object.keys(durationObject).reduce((result, key) => {
    const value = durationObject[key];
    return value ? { ...result, [key]: value } : result;
  }, {});

  return Duration.fromObject(resultObject);
}

console.log(normalize(Duration.fromObject({ hours: 90 })));
<script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/2.2.0/luxon.min.js"></script>
<script>const { Duration } = luxon;</script>

[编辑] 过滤掉 0'ed 单元的步骤对于我的既定目标来说是不需要的,toISO 方法为我们做了这个。我的需求与规范的通过有关,看起来改变规范比在计算期间浪费 CPU 周期归一化更好。使用上述方法将使生成的 ISO 持续时间字符串标准化单位 - PT1H30M 而不是 PT90M.

最后我选择不使用 0 单位过滤,只是在将其转换为 ISO 字符串时允许它发生。