Генерация массива раз (в виде строк) для каждых X минут в JavaScript

Я пытаюсь создать массив времен (строк, а не объектов Date) для каждых X минут в течение полных 24 часов. Например, для 5-минутного интервала массив будет:

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

Моим быстрым и грязным решением было использование 3 вложенных циклов for:

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]);
    }
  }
}

Это выводит желаемый результат, но мне интересно, есть ли более элегантное решение. Есть ли способ сделать это:

  • более читабельный
  • менее сложный по времени

Ответы

Ответ 1

Если интервал устанавливается только в минутах [0-60], то оцените приведенное ниже решение без создания объекта даты и в одном цикле:

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);

Ответ 2

Выделение результирующего массива, чтобы избежать накладных расходов на push, проверку параметров и языковые особенности:

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

Здесь сценарий https://jsfiddle.net/m1ruw1x6/35/

Ответ 3

Следующее является чрезвычайно гибким с помощью Moment.js.

Этот код использует

Там нет обработки ошибок, так что вы можете передать глупые параметры, но это все понятно.: -D

Параметр desiredStartTime занимает время в формате hh:mm.

Параметр period принимает любой из входов moment.duration. enter image description here

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>

Ответ 4

если у вас есть доступ к moment, вы всегда можете сделать что-то вроде этого:

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')
    );
}

результатом является следующий массив:

["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"]

Ответ 5

Вам нужен только один цикл, следуйте этому подходу

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

Продолжайте добавлять 5 минут, пока значение d.getDate() не изменится.

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

Ответ 6

В этом случае петли не нужны.

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);

Ответ 7

Вы можете использовать одиночный цикл for, цикл while, 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)

Ответ 8

Манипуляция с датой как с целым числом и с использованием одного цикла:

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);
}

Ответ 9

В любом случае вам нужно выполнить операции O (N) для перечисления элементов массива. Тем не менее, вы можете выполнять итерацию через объекты Date.

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;
}

Демо

Ответ 10

Мое решение, подчеркивающее читаемость. Сначала он создает объекты, которые представляют правильное время, а затем форматирует их для строк.  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
}

Ответ 11

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;
};

Ответ 12

В результате получается массив times, преобразованный в разметку, который я помещаю в объект <select>. Я обнаружил, что underscore.js _.range позволяет мне шаг за шагом, но только в виде целых чисел. Итак, я использовал moment.js для конвертации в unix time. Мне нужно было выполнить итерации за минуты slottime, но другие интервалы могут быть достигнуты с помощью множителя, опять же в моем случае 60000 добавление минут к 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;
}

Ответ 13

function timegenerate(starth,startm,endh,endm,interval)
    {
        times=[]
        size= endh>starth ? endh-starth+1 : starth-endh+1
        hours=[...Array(size).keys()].map(i => i + starth);
        for (hour in hours)
        {
            for (min = startm; min < 60; min += interval) 
            {
                startm=0
                if ((hours.slice(-1)[0] === hours[hour]) && (min > endm))
                {
                    break;
                }
                if (hours[hour] > 11 && hours[hour] !== 24 )
                {
                    times.push(('0' + (hours[hour]%12 === 0 ? '12': hours[hour]%12)).slice(-2) + ':' + ('0' + min).slice(-2) + " " + 'PM');
                }
                else
                {
                    times.push(('0' +  (hours[hour]%12 === 0 ? '12': hours[hour]%12)).slice(-2) + ':' + ('0' + min).slice(-2) + " " + 'AM');
                }
            }
        }
        return times
    }

    starthour=13
    startminute=30
    endhour=23
    endminute=30
    interval=30
    console.log(timegenerate(starthour,startminute,endhour,endminute,interval))