Generate array of times (as strings) for every X m

2020-05-17 04:15发布

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

15条回答
冷血范
2楼-- · 2020-05-17 05:09

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>

查看更多
孤傲高冷的网名
3楼-- · 2020-05-17 05:10

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;
}
查看更多
混吃等死
4楼-- · 2020-05-17 05:14

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

查看更多
登录 后发表回答