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>
References:
Array.protoype.forEach()
.Array.prototype.from()
.Array.prototype.map()
.- Arrow functions.
document.createDocumentFragment()
.document.createElement()
.document.querySelector()
.Element.append()
.Number.prototype.toString()
.Object.keys()
.String.prototype.padEnd()
.String.prototype.padStart()
.String.prototype.replace()
.- Template literals.