使用 JavaScript 将秒转换为 ISO 8601 持续时间

Posted

技术标签:

【中文标题】使用 JavaScript 将秒转换为 ISO 8601 持续时间【英文标题】:Convert seconds to ISO 8601 duration with JavaScript 【发布时间】:2019-08-31 11:03:07 【问题描述】:

ISO 8601 durations 计算起来很麻烦。

我想尽可能高效地从秒到持续时间。我正在使用 javascript

我将在下面发布我的答案和 Jest 测试。

【问题讨论】:

【参考方案1】:

seconds-to-duration.js

export const SECONDS_PER_SECOND = 1;
export const SECONDS_PER_MINUTE = 60;
export const SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE;
export const SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR;

const designations = [
  ['D', SECONDS_PER_DAY],
  ['H', SECONDS_PER_HOUR],
  ['M', SECONDS_PER_MINUTE],
  ['S', SECONDS_PER_SECOND],
];

export default function secondsToDuration(seconds) 
  let duration = 'P';
  let remainder = seconds;

  designations.forEach(([sign, seconds]) => 
    const value = Math.floor(remainder / seconds);

    remainder = remainder % seconds;

    if (value) 
      duration += `$value$sign`;
    
  );

  if (duration == 'P') 
    duration = 'P0S';
  

  return duration;


seconds-to-duration.spec.js

import secondsToDuration, 
  SECONDS_PER_SECOND,
  SECONDS_PER_MINUTE,
  SECONDS_PER_HOUR,
  SECONDS_PER_DAY,
 from './seconds-to-duration';

describe('secondsToDuration', () => 
  describe('even units', () => 
    it('should handle days', () => 
      let i = 10;

      while (--i) 
        expect(secondsToDuration(SECONDS_PER_DAY * i)).toEqual(`P$iD`);
      
    );

    it('should handle hours', () => 
      let i = 10;

      while (--i) 
        expect(secondsToDuration(SECONDS_PER_HOUR * i)).toEqual(`P$iH`);
      
    );

    it('should handle minutes', () => 
      let i = 10;

      while (--i) 
        expect(secondsToDuration(SECONDS_PER_MINUTE * i)).toEqual(`P$iM`);
      
    );

    it('should handle seconds', () => 
      let i = 10;

      while (--i) 
        expect(secondsToDuration(SECONDS_PER_SECOND * i)).toEqual(`P$iS`);
      
    );

    it('should handle zero seconds', () => 
      expect(secondsToDuration(0)).toEqual('P0S');
    );
  );

  describe('uneven', () => 
    it('should break across periods', () => 
      let days = 2;

      while (days--) 
        let hours = 24;

        while (hours--) 
          let minutes = 60;

          while (minutes--) 
            testDuration( days, hours, minutes, seconds: 59 );
            testDuration( days, hours, minutes, seconds: 1 );
          
        
      
    );
  );
);

function testDuration( days, hours, minutes, seconds ) 
  const totalSeconds =
    days * SECONDS_PER_DAY +
    hours * SECONDS_PER_HOUR +
    minutes * SECONDS_PER_MINUTE +
    seconds * SECONDS_PER_SECOND;
  const expected = `P$daysD$hoursH$minutesM$secondsS`.replace(/(?<=\D)0\w/g, '');
  const result = secondsToDuration(totalSeconds);

  if (result != expected) 
    console.info( totalSeconds, expected, result );
  

  expect(result).toEqual(expected);


【讨论】:

上面的脚本有一个bug。 secondsToDuration(60) 返回 'P1M' codesandbox.io/s/…(看控制台)那将是 1 个月——不是一分钟:'为了解决歧义,“P1M”是一个月的持续时间,“PT1M”是一分钟持续时间(注意时间指示符 T,它位于时间值之前)。 en.wikipedia.org/wiki/ISO_8601#Durations使用这个NPM包tinyduration,确认这个错误:codesandbox.io/s/tinyduration-js-test-wz3te?file=/src/index.js【参考方案2】:

该脚本有一个错误(请参阅我的评论),我建议改用这个包:https://www.npmjs.com/package/tinyduration

【讨论】:

以上是关于使用 JavaScript 将秒转换为 ISO 8601 持续时间的主要内容,如果未能解决你的问题,请参考以下文章

使用 JavaScript 将秒转换为 HH-MM?

将秒转换为时:分:秒

js将秒转换为 分:秒 函数

将秒转换为天、小时、分钟、秒格式 (C++)

使用 Prometheus 和 Grafana 将秒转换为 HH:MM:SS

Android : 将秒转换为年、日、小时、分钟、秒