Home > Enterprise >  Convert xx:xx into xxhxx in JS
Convert xx:xx into xxhxx in JS

Time:04-04

I have time data coming to me in Json format: "7:00", "7:30", "8:00", "8:30", "9:00", "9:30", "10:00", "10:30", "11:00", "11:30", … ]... until "18:00" basically over a day I have 30-minute slots in this format.

I display them in a web page and I want to display them in the format 7h30 / 8h / 8h30/ 9h etc.

Basically, I'm trying to remove the ':', replace them with h and remove the 00 when there are any.

I guess best practice would be to convert my data so that JS recognizes it as time and knows it's hours?

I've tried this

slots.replace(':', 'h').replace('00', ' ');

it's ok but the aim is to recognize the data as time. So I guess i have to create a function to divide the time in minutes or seconds and pass it into time for js ? I tell myself that if the site is on a browser in English or another language, it would be great if the hours were converted accordingly. For the moment, replace works with typical hours 7:00 - 8:00 ... 14h 15h which is ok in french, italian, etc. but if I pass in 7am / 4pm it will not be great...

What do you think ?

Thank you for any help and time spent responding to me.

CodePudding user response:

Why not just use String.replace()?

slots = slots.replace(':', 'h').replace('00', '')

CodePudding user response:

You mention that you're obtaining your "time data" in JSON format, so I'm assuming that you've converted that JSON into an Array of times. In the code below I create the Array, but obviously that can be skipped if you already have your array of times.

That said, this is one approach, explanatory comments are in the code:

// defining a named function to generate the times, with given increments;
// the function is written with Arrow syntax, and passes in an Opts argument
// which defaults to an empty Object-literal if no argument(s) are passed by
// the user:
const timeSteps = (opts = {}) => {
    // default settings:
    let settings = {
      // start: Integer, the hour of the day (24hr format) that
      //        the time-steps should start:
      start: 7,
      // end:   Integer, the hour of the day (24hr format) that
      //        the time-steps should finish:
      end: 18,
      // increments: Integer, the number of minutes between increments (there
      //             are no sanity checks, so ideally 60 should be divisible
      //             by this number:
      increments: 30
    };

    // updating the settings Object, using Object.keys() to retrieve an Array
    // of the keys of the opts Object, iterating over that Array with
    // Array.prototype.forEach():
    Object.keys(opts).forEach(
      // passing the current key, of the array of keys, into the function,
      // in which we update the settings[key] property to be equal to the
      // value of the opts[key] property-value:
      (key) => settings[key] = opts[key]
    );

    // using destructuring assignment to instantiate the named variables
    // to be the property-value of those properties from the settings
    // Object:
    let {
      start,
      end,
      increments
    } = settings,
    // defining the duration (in hours):
    duration = end - start,
      // number of minutes in one hour:
      hours = 60,
      // creating an Array, using Array.from() and an Object literal
      // with its length defined as hours / increments (to get the
      // number of steps per hour):
      hourSteps = Array.from({
        length: hours / increments
        // iterating over the created Array, using Array.prototype.map()
        // to return a new Array based on the old:
      }).map(
        // here we don't use the (undefined) array-value, but we do
        // use the index (i) of the current array-value from the
        // created Array; we return the value of the current index
        // multiplied by the number of hours multiplied by the
        // fraction created by 1 divided by the number of increments
        // per hour (so for thirty minute increments:
        // i * (60 * (1/(60/30))
        // i * (60 * (1/2)
        // i * (60 * 0.5)
        // i * 30 (this works, but I think it's horribly written and
        // should be simplified):
        (_, i) => i * (hours * (1 / (hours / increments)))
      );
    // here we create another Array using the same approach, this time based
    // on the duration (calculated earlier):
    return Array.from({
      length: duration
      // iterating over that Array with Array.prototype.map():
    }).map(
      // passing in the index of the array-element:
      (_, i) => {
        // returning the result of the following call to Array.prototype.map()
        // on the hourSteps Array:
        return hourSteps.map(
          // here we use a template literal to:
          // increase the value of start by the value of the index to increase the
          // time over the course of the array processing, calling toString() on
          // the resulting number, and then padding the start of that string to
          // 2 places, padded with the 0 character.
          // we then have a literal ':' character,
          // then we convert the hStep to a String, with Number.prototype.toString()
          // chaining it with String.prototype.padEnd(), to convert a single-digit
          // number to a String of length = 2, padded with 0 characters:
          (hStep) => `${(start   i).toString().padStart(2,'0')}:${hStep.toString().padEnd(2,0)}`
        )
        // flattening the 2 dimensional Array to a single dimension:
      }).flat();
  },
  // getting the times:
  incrementedHours = timeSteps(),
  // creating an <li> element:
  li = document.createElement('li'),
  // creating a document fragment, to minimise the number paints
  // the browser has to execute:
  fragment = document.createDocumentFragment(),
  // getting a reference to the element to which the times will be added:
  list = document.querySelector('ol');

// using Array.prototype.forEach() to iterate over the incrementedHours Array:
incrementedHours.forEach(
  // passing in the time from the Array of times:
  (time) => {
    // cloning the created <li> element:
    let clone = li.cloneNode();
    // setting the text-content of the clone to
    // be equal to the time; then using String.prototype.replace()
    // to replace either ":" or "00", globally (so replacing both),
    // using an anonymous Arrow function, with a conditional (ternary)
    // operator to see if the matched sequence is equal to ':', if it
    // is we replace that ':' character with 'h' or, otherwise, with
    // an empty-string:
    clone.textContent = time.replace(/\:|00/g, (match) => match === ':' ? 'h' : '');
    // appending the clone to the document-fragment:
    fragment.append(clone);
  });

// appending the fragment to the <ol>
list.append(fragment);
*,
::before,
::after {
  box-sizing: border-box;
  font: normal 400 1rem / 1.5 sans-serif;
  margin: 0;
  padding: 0;
}

ul,
ol,
li {
  list-style-type: none;
}

ol {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4em;
  width: clamp(10em, 70vw, 700px);
  margin-block: 1em;
  margin-inline: auto;
}

li {
  border: 1px solid #000;
  padding: 0.2em;
  border-radius: 0.3em;
}
<ol></ol>

JS Fiddle demo.

References:

  • Related