Transform seconds into an ISO 8601 duration using JavaScript

Dealing with ISO 8601 durations can be quite tricky.

Efficiently converting seconds to durations is my current challenge, especially in JavaScript.

Stay tuned for my solution and the Jest test script coming up next.

Answer №1

Converting Seconds to Duration

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 timeUnits = [
  ['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;

  timeUnits.forEach(([unit, value]) => {
    const timeValue = Math.floor(remainder / value);

    remainder = remainder % value;

    if (timeValue) {
      duration += `${timeValue}${unit}`;
    }
  });

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

  return duration;
}

Testing the Conversion with Jest

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

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

      while (--i) {
        expect(secondsToDuration(SECONDS_PER_DAY * i)).toEqual(`P${i}D`);
      }
    });

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

      while (--i) {
        expect(secondsToDuration(SECONDS_PER_HOUR * i)).toEqual(`P${i}H`);
      }
    });

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

      while (--i) {
        expect(secondsToDuration(SECONDS_PER_MINUTE * i)).toEqual(`P${i}M`);
      }
    });

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

      while (--i) {
        expect(secondsToDuration(SECONDS_PER_SECOND * i)).toEqual(`P${i}S`);
      }
    });

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

  describe('handling uneven time units', () => {
    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${days}D${hours}H${minutes}M${seconds}S`.replace(/(?<=\D)0\w/g, '');
  const result = secondsToDuration(totalSeconds);

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

  expect(result).toEqual(expected);
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can you pass two distinct variables in a JavaScript function?

This is the JavaScript code for my first page: <script> function MessageDetailsById(id) { $("#active"+id).css({"color":"red"}); var http = new XMLHttpRequest(); var url = "Ajax.php"; ...

Is it possible to alter objects through the use of jQuery.map?

I'm working with a key-value pair that looks like this: var classes = { red: 'Red', green: 'Green' }; Is there a way to add a specific value before each key in the pair? Can jQuery.map help with this task? The desired end result ...

Can you provide the name of the slideshow plugin used on the Wipro website?

Can anyone tell me the name of the image slide show featured on: http://www.wipro.com/index.htm? Also, does anyone know where I can find the script for free? I am looking to incorporate it into a page that is coded in php, html, css, and javascript. Than ...

Angular UI Grid failing to properly display date formatting

Currently, I am using Angular's UI Grid to showcase multiple columns. However, I am facing an issue with formatting the date column. The date is being displayed as /Date(1451346632162-0000)/, and similar formats. I have attempted to apply filters in ...

Is the NPM package not being imported? How exactly is it being utilized?

mediacms-vjs-plugin is a unique plugin designed for Video.js. The MediaCmsVjsPlugin.js source code begins with: import { version as VERSION } from '../package.json'; import 'mediacms-vjs-plugin-font-icons/dist/mediacms-vjs-icons.css'; ...

Emotion, material-ui, and typescript may lead to excessively deep type instantiation that could potentially be infinite

I encountered an issue when styling a component imported from the Material-UI library using the styled API (@emotion/styled). Error:(19, 5) TS2589: Type instantiation is excessively deep and possibly infinite. Despite attempting to downgrade to typescript ...

Having trouble establishing a connection with Mongo.Client on localhost 27017 for MongoDB

Encountering issues with connecting to MongoDB database and storing data in localhost:27017 using MongoClient. Unable to display connection results in the console for both successful and failed connections. var express = require('express'); var r ...

Executing server-side method with jQuery in .Net 1.1

Currently, I am utilizing .net1.1 and attempting to invoke a server-side method using jQuery upon clicking the browser's Close button. However, my code does not seem to be functioning correctly. I have provided my code below for reference. Can anyone ...

Tips for creating a unique design for a form that includes a non-binary mask, inspired by bitmasks

Currently, I am in the process of creating an app using Reactjs and Material-UI. The main requirement is for users to input a mask of specific length containing various letters such as I, V, and C. In search of a suitable design pattern or solution for thi ...

Having trouble getting JavaScript to work when returned via AJAX

After triggering a lightbox by clicking on a business name, I encountered an issue when trying to replicate the same functionality using AJAX. The lightbox fails to show up. Can anyone provide assistance? The following code represents a 3rd party publishe ...

Ionic timer binding issue: troubleshooting tips

Recently, I developed a stopwatch factory service that primarily focuses on running. Please disregard the reset and other functionalities as they are not yet implemented. Despite setting up $scope.time to capture timer changes, it doesn't seem to upd ...

Can you explain the distinction between browser.sleep() and browser.wait() functions?

Encountering timing problems with my protractor tests. Occasionally, test cases fail because of network or performance-related issues. I managed to resolve these issues using browser.sleep(), but recently discovered browser.wait(). What sets them apart an ...

Displaying JSON array data across three different pages using AngularJS and Ionic framework

I have an array of categories with multiple products. I want to display these categories on a category page. When a category is clicked, it should redirect to the product page and show the relevant products. Similarly, when a product is clicked, it shou ...

Is it possible to apply several 'where' condition in pg-promise?

I am currently using pg-promise in combination with express 4 on node 8.2.0. I am trying to concatenate the where condition. However, I have been unable to find a way to achieve this. Can you please assist me? This is what I am aiming for. let ids = [10 ...

Alert popup onclick feature is malfunctioning

SOLVED: I finally figured out the issue and it is now working perfectly. I had to manually switch to Chrome instead of using the Brackets live viewer. I want an alert box to pop up when the "Home" link is clicked on my website. I tried creating a separate ...

Margin ambiguity in a vue.js application

I am facing an issue with my Vue.JS project setup. I want the App.vue to occupy the entire page and have different routes displayed within App.vue using router-view. But, when I try to add a margin to the content of my Game component, the margin seems to ...

When trying to append in jQuery, the error "JQuery V[g].exec is not a

Attempting to create a script that adds a table to a div within the website using the following function: function generateTable(container, data) { var table = $("<table/>"); $.each(data, function (rowIndex, r) { var row = $("<tr/>"); ...

What is the process of retrieving the return value after creating data in Firestore

I have been experimenting with creating data using firestore in the following manner: createData({state}) { return db.collection('items').add({ title: state.title, ingredients: state.ingredients, creat ...

How can I turn off the animation for a q-select (quasar select input)?

I'm just starting out with Quasar and I'm looking to keep the animation/class change of a q-select (Quasar input select) disabled. Essentially, I want the text to remain static like in this image: https://i.stack.imgur.com/d5O5s.png, instead of c ...

I have the latitude and longitude for both the shop and user, and I am looking to display a list of shops in order based

Currently, I have the latitude and longitude for both my shop and the user. My objective is to display a list of shops that fall within the geographic area between the user's location and the shop's coordinates using Sequelize ORM. Can you provid ...