最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - Is there a built in way to normalize a duration within Luxon? - Stack Overflow

matteradmin5PV0评论

I am migrating from Momentjs to Luxon. I allow users to pick a number of hours that a task will take. When we save this value, I'd like it to normalize. So if a task takes 90 hours, I would prefer if we stored 3 days and 18 hours. I store the ISO Duration String so I'd like to convert PT90H to P3DT18H... of course with any given value.

I have tried Luxon's normalize function, I tried to call it like so:

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

However, normalize does not seem to do anything to the result. I still get PT90H. Is there a built in way to do this with Luxon?

I am migrating from Momentjs to Luxon. I allow users to pick a number of hours that a task will take. When we save this value, I'd like it to normalize. So if a task takes 90 hours, I would prefer if we stored 3 days and 18 hours. I store the ISO Duration String so I'd like to convert PT90H to P3DT18H... of course with any given value.

I have tried Luxon's normalize function, I tried to call it like so:

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

However, normalize does not seem to do anything to the result. I still get PT90H. Is there a built in way to do this with Luxon?

Share Improve this question asked Dec 14, 2021 at 13:28 nephiwnephiw 2,04620 silver badges42 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 5

Durtation.normalize() won't add properties to the Duration object so you need to supply the units you want it to normalize to. (This is odd to me, but provides implicit control over oute).

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./ajax/libs/luxon/2.2.0/luxon.min.js"></script>
<script>const { Duration } = luxon;</script>

Alternatively you can use Duration.shiftTo() to explicitly force the duration into specific units.

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

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


If you know you will always want to normalize into all units you could declare a utility to return a Duration object initialized with all units.

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./ajax/libs/luxon/2.2.0/luxon.min.js"></script>
<script>const { Duration } = luxon;</script>

Per @pilchard's answer, I ended up using this function to normalize my duration.

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./ajax/libs/luxon/2.2.0/luxon.min.js"></script>
<script>const { Duration } = luxon;</script>

[EDIT] The step that filters out 0'ed units is unneeded for my stated goals, the toISO method does this for us. My needs related to making spec's pass, and it seems like it will be better change the specs than waste the CPU cycles normalizing during calculations. Using the above method will make the resulting ISO duration strings normalized units - PT1H30M instead of PT90M.

In the end I chose not to use the 0-unit filtering and just allow that to happen when I convert it to an ISO string.

Post a comment

comment list (0)

  1. No comments so far