50

I'm trying to create an array of times (strings, not Date objects) for every X minutes throughout a full 24 hours. For example, for a 5 minute interval the array would be:

['12:00 AM', '12:05 AM', '12:10 AM', '12:15 AM', ..., '11:55 PM']

My quick and dirty solution was to use 3 nested for loops:

var times = []
  , periods = ['AM', 'PM']
  , hours = [12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
  , prop = null
  , hour = null
  , min = null; 

for (prop in periods) {
  for (hour in hours) {
    for (min = 0; min < 60; min += 5) {
      times.push(('0' + hours[hour]).slice(-2) + ':' + ('0' + min).slice(-2) + " " + periods[prop]);
    }
  }
}

This outputs the desired result but I'm wondering if there's a more elegant solution. Is there a way to do this that's:

  • more readable
  • less time complex
2
  • 5
    Don't use for…in enumerations on arrays! Commented Mar 21, 2016 at 12:28
  • How do I generate something just between 9am and 5:30 pm? Commented Feb 14, 2017 at 20:54

15 Answers 15

65

If the interval is only to be set in minutes[0-60], then evaluate the below solution w/o creating the date object and in single loop:

var x = 5; //minutes interval
var times = []; // time array
var tt = 0; // start time
var ap = ['AM', 'PM']; // AM-PM

//loop to increment the time and push results in array
for (var i=0;tt<24*60; i++) {
  var hh = Math.floor(tt/60); // getting hours of day in 0-24 format
  var mm = (tt%60); // getting minutes of the hour in 0-55 format
  times[i] = ("0" + (hh % 12)).slice(-2) + ':' + ("0" + mm).slice(-2) + ap[Math.floor(hh/12)]; // pushing data in array in [00:00 - 12:00 AM/PM format]
  tt = tt + x;
}

console.log(times);

Sign up to request clarification or add additional context in comments.

8 Comments

This was helpful. If anyone would like to show 12:00 instead of 0:00 it's a simple change: times[i] = ("" + ((hh==12)?12:hh%12)).slice(-2) + ':' + ("0" + mm).slice(-2) + ap[Math.floor(hh/12)];
@Khaleel Remove the modulus operator in first expression to make 24hr clock " times[i] = ("0" + hh ).slice(-2) + ':' + ("0" + mm).slice(-2) ; // push to array in [00:00 - 24:00"
Is there anything if I want to start from particular time like from morning 7:00AM to next morning 6:00AM?
Not sure if it matters but i'm having trouble with what @Codeply-er suggested. 12am becomes 0am. I'm using this instead if it helps! - time[i] = `${hour === 0 || hour === 12 ? '12' : (hour % 12).toString().slice(-2)}:${( '0' + minute).slice(-2)} ${meridiem[hour < 12 ? 0 : 1]}`; meridiem[ ] just contains ['AM', 'PM']. Thank you @Codeply-er!
@FaizanSaiyed for range change the followings var tt = 60*6.5; // Starting time will be morning 6:30AM for ending time inside the for loop condition var i=0;tt<16.5*60; i++ //ending will be noon 4:30PM
|
24

Allocating the resulting array to avoid the overhead of push, parameter validation and locale specifics notwithstanding:

    function generate_series(step) {
        const dt = new Date(1970, 0, 1);
        const rc = [];
        while (dt.getDate() === 1) {
            rc.push(dt.toLocaleTimeString('en-US'));
            dt.setMinutes(dt.getMinutes() + step);
        }
        return rc;
    }

Here's a demo snippet.

function generate_series(step) {
  const dt = new Date(1970, 0, 1);
  const rc = [];
  while (dt.getDate() === 1) {
    rc.push(dt.toLocaleTimeString('en-US'));
    dt.setMinutes(dt.getMinutes() + step);
  }
  return rc;
}

function on_generate_series(step) {
  const dt = new Date(1970, 0, 1);
  const el = document.getElementById("series")
  while (el.firstChild)
    el.removeChild(el.firstChild);
  const series = generate_series(step);
  while (series.length > 0) {
    let item = document.createElement("div");
    item.innerText = series.shift();
    el.appendChild(item);
  }
}
<h1 id="title">24 Hour Minute Series</h1>
<input type="number" id="step" value="30" />
<input type="submit" id="byBtn" value="Generate Series" onclick="on_generate_series(parseInt(document.getElementById('step').value,10))" />
<div id="series">
</div>

Comments

17

The following is massively flexible with the help of Moment.js.

This code uses

There's no error handling, so you can pass in stupid parameters, but it gets the point across. :-D

The desiredStartTime parameter takes a time in hh:mm format.

The period parameter accepts any of the moment.duration inputs.
period key

const timelineLabels = (desiredStartTime, interval, period) => {
  const periodsInADay = moment.duration(1, 'day').as(period);

  const timeLabels = [];
  const startTimeMoment = moment(desiredStartTime, 'hh:mm');
  for (let i = 0; i <= periodsInADay; i += interval) {
    startTimeMoment.add(i === 0 ? 0 : interval, period);
    timeLabels.push(startTimeMoment.format('hh:mm A'));
  }

  return timeLabels;
};

/* A few examples */
const theDiv = document.getElementById("times");
let content;

content = JSON.stringify(timelineLabels('18:00', 2, 'hours'))
theDiv.appendChild(document.createTextNode(content));
theDiv.appendChild(document.createElement("p"));

content = JSON.stringify(timelineLabels('06:00', 30, 'm'))
theDiv.appendChild(document.createTextNode(content));
theDiv.appendChild(document.createElement("p"));

content = JSON.stringify(timelineLabels('00:00', 5, 'minutes'))
theDiv.appendChild(document.createTextNode(content));
theDiv.appendChild(document.createElement("p"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.js"></script>

<div id="times"></div>

Comments

15

if you have access to moment, you can always do something like this:

const locale = 'en'; // or whatever you want...
const hours = [];

moment.locale(locale);  // optional - can remove if you are only dealing with one locale

for(let hour = 0; hour < 24; hour++) {
    hours.push(moment({ hour }).format('h:mm A'));
    hours.push(
        moment({
            hour,
            minute: 30
        }).format('h:mm A')
    );
}

the result is the following array:

["12:00 AM", "12:30 AM", "1:00 AM", "1:30 AM", "2:00 AM", "2:30 AM", "3:00 AM", "3:30 AM", "4:00 AM", "4:30 AM", "5:00 AM", "5:30 AM", "6:00 AM", "6:30 AM", "7:00 AM", "7:30 AM", "8:00 AM", "8:30 AM", "9:00 AM", "9:30 AM", "10:00 AM", "10:30 AM", "11:00 AM", "11:30 AM", "12:00 PM", "12:30 PM", "1:00 PM", "1:30 PM", "2:00 PM", "2:30 PM", "3:00 PM", "3:30 PM", "4:00 PM", "4:30 PM", "5:00 PM", "5:30 PM", "6:00 PM", "6:30 PM", "7:00 PM", "7:30 PM", "8:00 PM", "8:30 PM", "9:00 PM", "9:30 PM", "10:00 PM", "10:30 PM", "11:00 PM", "11:30 PM"]

7 Comments

how to do it for 24 hours format value start from 00:00 ,00:30,01:00,01:30 ..23:30
isn't what the OP is asking for
Is there anything if I want to start from particular time like from morning 7:00AM?
i guess you could split your array at 7am - show all the values, and then finish by showing the remaining items in the second array - probably easiest to do that than to re-sort, map, concat or some other jazzy method of reusing the same array. k.i.s.s. is my philosophy for staying sane and lazy =)
@MohamedSahir use uppercase H.
|
10

This snippet generates a range base on locale, so you do not need to handle AM/PM manually. By default, it will use browser language, but you can pass a user-selected one.

function getTimeRanges(interval, language = window.navigator.language) {
    const ranges = [];
    const date = new Date();
    const format = {
        hour: 'numeric',
        minute: 'numeric',
    };

    for (let minutes = 0; minutes < 24 * 60; minutes = minutes + interval) {
        date.setHours(0);
        date.setMinutes(minutes);
        ranges.push(date.toLocaleTimeString(language, format));
    }

    return ranges;
}

console.log('English', getTimeRanges(30, 'en'));
console.log('Russian', getTimeRanges(30, 'ru'));

1 Comment

This is a good answer. Seems unfortunate to me that so many people seem to think they need to pull in libraries to solve a simple problem like this.
5

You need only one loop, follow this approach

var d = new Date(); //get a date object
d.setHours(0,0,0,0); //reassign it to today's midnight

Now keep adding 5 minutes till the d.getDate() value changes

var date = d.getDate();
var timeArr = [];
while ( date == d.getDate() )
{
   var hours = d.getHours();
   var minutes = d.getMinutes();
   hours = hours == 0 ? 12: hours; //if it is 0, then make it 12
   var ampm = "am";
   ampm = hours > 12 ? "pm": "am";
   hours = hours > 12 ? hours - 12: hours; //if more than 12, reduce 12 and set am/pm flag
   hours = ( "0" + hours ).slice(-2); //pad with 0
   minute = ( "0" + d.getMinutes() ).slice(-2); //pad with 0
   timeArr.push( hours + ":" + minute + " " + ampm );
   d.setMinutes( d.getMinutes() + 5); //increment by 5 minutes
}

Demo

2 Comments

This will create duplicates values for all of 12:00 as it doesn't switch to PM.
Likely very slow
4

Loops are unnecessary in this case.

ES6

//Array.from, only supported by Chrome 45+, Firefox 32+, Edge and Safari 9.0+
//create an array of the expected interval
let arr = Array.from({
  length: 24 * 60 / 5
}, (v, i) => {
  let h = Math.floor(i * 5 / 60);
  let m = i * 5 - h * 60;
  //convert to 12 hours time
  //pad zero to minute
  if (m < 10) {
    m = '0' + m;
  }
  let label = 'AM';
  if (h > 12) {
    label = 'PM';
    h -= 12;
  }
  if (h === 0) {
    h = 12;
  }
  return h + ':' + m + ' ' + label;
});

document.body.textContent = JSON.stringify(arr);

Wider browser support

var arr = Array.apply(null, {
  length: 24 * 60 / 5
}).map(function(v, i) {
  var h = Math.floor(i * 5 / 60);
  var m = i * 5 - h * 60;
  if (m < 10) {
    m = '0' + m;
  }
  var label = 'AM';
  if (h > 12) {
    label = 'PM';
    h -= 12;
  }
  if (h === 0) {
    h = 12;
  }
  return h + ':' + m + ' ' + label;
});

document.body.textContent = JSON.stringify(arr);

1 Comment

Above code is incorrectly generating AM for times between midday and 1PM. if( h > 12) needs to be if(h >= 12) to correct this
3

In any case you need to do O(N) operations to enumerate array elements. However, you could iterate through Date objects itself.

function timeArr(interval) //required function with custom MINUTES interval
{
  var result = [];
  var start = new Date(1,1,1,0,0);
  var end = new Date(1,1,2,0,0);
  for (var d = start; d < end; d.setMinutes(d.getMinutes() + 5)) {
      result.push(format(d));
  }

  return result;
}

function format(inputDate) // auxiliary function to format Date object
{
    var hours = inputDate.getHours();
    var minutes = inputDate.getMinutes();
    var ampm = hours < 12? "AM" : (hours=hours%12,"PM");
    hours = hours == 0? 12 : hours < 10? ("0" + hours) : hours;
    minutes = minutes < 10 ? ("0" + minutes) : minutes;
    return hours + ":" + minutes + " " + ampm;
}

Demo

Comments

2

You could use a single for loop, while loop , Array.prototype.map(), Array.prototype.concat() , String.prototype.replace()

var n = 0,
  min = 5,
  periods = [" AM", " PM"],
  times = [],
  hours = [12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];

for (var i = 0; i < hours.length; i++) {
  times.push(hours[i] + ":" + n + n + periods[0]);
  while (n < 60 - min) {
    times.push(hours[i] + ":" + ((n += 5) < 10 ? "O" + n : n) + periods[0])
  }
  n = 0;
}

times = times.concat(times.slice(0).map(function(time) {
  return time.replace(periods[0], periods[1])
}));

console.log(times)

Comments

2

My solution with emphasize on readability. It first creates objects that represent correct times and then formats them to strings. JsFiddle https://jsfiddle.net/6qk60hxs/

var periods = ['AM', 'PM'];
var hours = [12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
var minutes = ["00", "05", 10, 15, 20, 25, 30, 35, 40, 45, 50, 55];


timeObj = add([{}], "p", periods);
timeObj = add(timeObj, "h", hours);
timeObj = add(timeObj, "m", minutes);

times = []
for (t of timeObj) {
  times.push(t.h + ':' + t.m + ' ' + t.p);
}

console.log(times)

function add(tab, prop, val) {
  var result = [];
  for (t of tab) {
    for (v of val) {
      tc = _.clone(t);
      tc[prop] = v;
      result.push(tc);
    }
  }
  return result
}

Comments

2

This is an iteration of Faizan Saiyed's answer.

const startHour = moment().format('k');
const endHour = 22

const arr = () => {
  return Array.from({
  length: endHour - startHour
  }, (v, index) => {
    return [0,15,30,45].map((interval) => {
      return moment({
        hour: index,
        minute: interval
      })
      .add(startHour, 'hours')
      .format('h:mm A')
    })
  }).flat()
}

Comments

1

Manipulating with a date as with integer and using single loop:

var interval = 5 * 60 * 1000; //5 minutes 
var period = 24 * 60 * 60 * 1000; //dat period

//just converts any time to desired string
var toString = function toString(time){  
  var h = time.getHours();
  var m = time.getMinutes();
  var p = h >= 12 ? "PM" : "AM";
  h = h || 12;
  h = h > 12 ? h - 12 : h;  
  return ("0" + h).slice(-2) + ":" + ("0" + m).slice(-2) + " " + p;
}

//start time
var time = new Date(2010, 0, 1);

//resulting array
var times = [];

for ( var t = +time; t < +time + period; t += interval){  
  var d = toString(new Date(t));  
  times.push(d);
}

Comments

0
const getTimes = (increment = 2) => {
  const times = [];
  for (let i = 0; i < 24; i++) {
    times.push({
      value: `${i === 0 || i - 12 === 0 ? 12 : i < 12 ? i : i - 12}:00 ${i < 12 ? 'AM' : 'PM'}`,
      label: `${i === 0 || i - 12 === 0 ? 12 : i < 12 ? i : i - 12}:00 ${i < 12 ? 'AM' : 'PM'}`,
    });
    for (let j = 60 / increment; j < 60; j += 60 / increment) {
      times.push({
        value: `${i === 0 || i - 12 === 0 ? 12 : i < 12 ? i : i - 12}:${Math.ceil(j)} ${i < 12 ? 'AM' : 'PM'}`,
        label: `${i === 0 || i - 12 === 0 ? 12 : i < 12 ? i : i - 12}:${Math.ceil(j)} ${i < 12 ? 'AM' : 'PM'}`,
      });
    }
  }
  return times;
};

Comments

0

The result of this is an array times converted into markup that I place in a <select> object. I found that underscore.js's _.range allows me to step through increments but only as integers. So, I used moment.js to convert to unix time. I needed to iterate over minutes slottime, but other intervals can be accomplished with the multiplier, again in my case 60000 making minutes added to valueOf().

function slotSelect(blockstart, blockend, slottime) {
    var markup = "";
    var secs = parseInt(slottime * 60000); // steps
    var a = parseInt( moment(blockstart).valueOf() ); // start
    var b = parseInt( moment(blockend).valueOf() );
    var times = _.range(a, b, secs);

    _.find( times, function( item ) {
        var appttime = moment(item).format('h:mm a');
        var apptunix = moment(item).format();
        markup += '<option value="'+apptunix+'"> ' + appttime + ' </option>'+"\n";
    });
    return markup;
}

Comments

0

To start list from particular time like 3:00 PM and loop quarterly(every 15 minutes):

const hours = [];
const startHour = 15;

for (let hour = 0; hour < 24; hour++) {
  hours.push(
    moment({ hour })
      .add(startHour, 'hours')
      .format('h:mm A')
  );

  hours.push(
    moment({
      hour,
      minute: 15
    })
      .add(startHour, 'hours')
      .format('h:mm A')
  );

  hours.push(
    moment({
      hour,
      minute: 30
    })
      .add(startHour, 'hours')
      .format('h:mm A')
  );

  hours.push(
    moment({
      hour,
      minute: 45
    })
      .add(startHour, 'hours')
      .format('h:mm A')
  );
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.