Moment: рдирд┐рдХрдЯрддрдо 15 рдорд┐рдирдЯ рдХреЗ рдЕрдВрддрд░рд╛рд▓ рдкрд░ рдЧреЛрд▓рд╛рдИред

рдХреЛ рдирд┐рд░реНрдорд┐рдд 27 рдЬреБрд▓ре░ 2013  ┬╖  18рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: moment/moment

рдореИрдВ рд╕реЛрдЪ рд░рд╣рд╛ рдерд╛ рдХрд┐ рдореЗрд░реЗ рд▓рд┐рдП рдирд┐рдХрдЯрддрдо 15 рдорд┐рдирдЯ рдХреЗ рдЕрдВрддрд░рд╛рд▓ рдореЗрдВ рдКрдкрд░ рдпрд╛ рдиреАрдЪреЗ рдЪрдХреНрдХрд░ рд▓рдЧрд╛рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдкрд▓ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЕрдЪреНрдЫреА рд╡рд┐рд╢реЗрд╖рддрд╛ рд╣реЛрдЧреА рдХреНрдпреЛрдВрдХрд┐ рдбреЗрдЯрдЬ рдЬреИрд╕реЗ рдХреБрдЫ рдХрд╛рдореЛрдВ рдореЗрдВ рдпрд╣ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рд╣реЛрддреА рд╣реИ рдЬреЛ рдореИрдВрдиреЗ рдЦреЛрдЬрддреЗ рд╕рдордп рджреЗрдЦреА рдереАред рдореЗрд░рд╛ рдкрд░рд┐рджреГрд╢реНрдп рдпрд╣ рд╣реИ рдХрд┐ рдореЗрд░реЗ рдкрд╛рд╕ рдбреЗрдЯрд╛ рдмрд┐рдВрджреБ рд╣реИрдВ рдЬреЛ 15 рдорд┐рдирдЯ рдХреА рдмрд╛рд▓реНрдЯреА рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рд╣реИрдВ, рдЪрдпрди рдЙрдкрдХрд░рдг рд╕рдордп рдХреЗ рдХрд┐рд╕реА рднреА рдмреНрд▓реЙрдХ рдХреЛ рд▓реМрдЯрд╛рддрд╛ рд╣реИ рдФрд░ рдореБрдЭреЗ рдирд┐рдХрдЯрддрдо 15 рдорд┐рдирдЯ рддрдХ рдЧреЛрд▓ рдХрд░рдиреЗ рдФрд░ рдЕрдВрддрд┐рдо рд╕рдордп рдХреЗ рд▓рд┐рдП рд░рд╛рдЙрдВрдб рдЕрдк рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред

рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдХрд░рдирд╛ (http://stackoverflow.com/questions/4968250/how-to-round-time-to-the-nearest-quarter-hour-in-javascript) рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рджрд░реНрдж рд╣реЛрдЧрд╛ .. рдЬрдм рдпрд╣ lib рдореЗрдВ рд╣реА рдЙрдкрдпреЛрдЧреА рд╣реЛрдЧрд╛ред

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рдЬрдЯрд┐рд▓, рд╕рд░рд▓ рдЧрдгрд┐рдд рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ:

const rounded = Math.round(moment().minute() / 15) * 15;
const roundedDown = Math.floor(moment().minute() / 15) * 15;
const roundedUp = Math.ceil(moment().minute() / 15) * 15;

moment().minute(roundedUp).second(0)

рдирд┐рдХрдЯрддрдо 15 рдорд┐рдирдЯ рдХреА рддрд┐рдорд╛рд╣реА рдореЗрдВ рдЖрдЙрдЯрдкреБрдЯред

рд╕рднреА 18 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

moment.fn.roundMinutes = function () { return ~(this.minutes() / 15) * 15; }

рдореИрдВрдиреЗ рдЗрд╕реЗ рдЕрдкрдиреЗ рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП рдмрдирд╛рдпрд╛ рд╣реИ рдФрд░ рдореБрдЭреЗ рд▓рдЧрд╛ рдХрд┐ рдпрд╣ рджреВрд╕рд░реЛрдВ рдХреА рдорджрдж рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдзреНрдпрд╛рди рд░рдЦреЗрдВ рдХрд┐ рдпрд╣ рдирд┐рдХрдЯрддрдо NEXT 15 рдорд┐рдирдЯ рддрдХ рдЪрдХреНрдХрд░ рд▓рдЧрд╛рддрд╛ рд╣реИред

moment.fn.roundNext15Min = function () {
var intervals = Math.floor(this.minutes() / 15);
if(this.minutes() % 15 != 0)
    intervals++;
    if(intervals == 4) {
        this.add('hours', 1);
        intervals = 0;
    }
    this.minutes(intervals * 15);
    this.seconds(0);
    return this;
}

рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ: рдЗрд╕ рдХреЗ рдкрдХреНрд╖ рдореЗрдВ this.incrementHours() рд╣рдЯрд╛ рджрд┐рдпрд╛ред рдЬреЛрдбрд╝реЗрдВ ('рдШрдВрдЯреЗ', 1);

рдХреНрдпрд╛ рдЖрдк рдХреГрдкрдпрд╛ рдЗрди рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдкрд▓ рдореЗрдВ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ .. рдирд┐рдХрдЯрддрдо, рдЕрдЧрд▓реЗ рдФрд░ рдкрд┐рдЫрд▓реЗ рд╕рдордп рдЕрдВрддрд░рд╛рд▓ рдореЗрдВ рдЪрдХреНрдХрд░ рд▓рдЧрд╛рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ ... рдЗрд╕рдХреЗ рд▓рд┐рдП рд▓рд╛рдЦреЛрдВ Google рдкрд░рд┐рдгрд╛рдо рд╣реИрдВ рдФрд░ рд╕реИрдХрдбрд╝реЛрдВ рд╕реНрдЯреИрдХ рдУрд╡рд░рдлреНрд▓реЛ рдЕрдкрд╡реЛрдЯ рд╣реИрдВ ..

рдЕрдм рдЬрдм рдореИрдВ рдЗрд╕реЗ рдлрд┐рд░ рд╕реЗ рджреЗрдЦрддрд╛ рд╣реВрдВ рддреЛ рдореБрдЭреЗ рдирд╣реАрдВ рдкрддрд╛ рдХрд┐ рдХреИрд╕реЗ рд╡реЗрддрди рд╡реГрджреНрдзрд┐ рдШрдВрдЯреЗ рдХрд╛рдо рдХрд░ рд░рд╣реЗ рдереЗред
рдореИрдВрдиреЗ рдЕрдкрдиреА рдкреЛрд╕реНрдЯ рдХреЛ рд╕рд╣реА рдХреЛрдб рдХреЗ рд╕рд╛рде рдЗрд╕ рдореБрджреНрджреЗ рдкрд░ рд╕рдВрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рд╣реИред рдЖрдирдВрдж рд▓реЗрдирд╛!

рд╕реЛрдо, рдорд╛рд░реНрдЪ резреж, реирежрезрек рдЕрдкрд░рд╛рд╣реНрди реи:реиреп рдЕрдкрд░рд╛рд╣реНрди, рдмреНрд▓реЗрдХ рдиреАрдореАрдЬрд╝реНрд╕реНрдХреА рдкрд░
рд╕реВрдЪрдирд╛рдПрдВ@github.comрд▓рд┐рдЦрд╛ :

рдЗрдВрдХреНрд░реАрдореЗрдВрдЯ рдЖрд╡рд░реНрд╕ рдХреЗ рд▓рд┐рдП рдЖрдкрдХрд╛ рдХреНрдпрд╛ рдХрд╛рд░реНрдп рдерд╛? рдореИрдВ рдЕрдиреБрдорд╛рди рд▓рдЧрд╛ рд░рд╣рд╛ рд╣реВрдБ рдХрд┐ рджрд┐рди рднреА рдХрд┐рдпрд╛ рдерд╛
рдмрд╣реБрддред

рдЗрд╕ рдИрдореЗрд▓ рдХрд╛ рд╕реАрдзреЗ рдЙрддреНрддрд░ рджреЗрдВ рдпрд╛ рдЗрд╕реЗ Gi tHub рдкрд░ рджреЗрдЦреЗрдВhttps://github.com/moment/moment/issues/959#issuecomment -37223821
.

рдЙрд╕ рд╡рд┐рдзрд┐ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж @zbarnett ред рдареАрдХ рд╡рд╣реА рдЬреЛ рдореБрдЭреЗ рдЕрдкрдиреЗ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреЗ рд▓рд┐рдП рдЪрд╛рд╣рд┐рдП рдерд╛

рд╡реИрд╕реЗ рд╣рдо startOf рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдЗрд╕ рддрд░рд╣ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ startOf(15, 'm') ред рдпрд╣ рд╕рднреА рдЗрдХрд╛рдЗрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдЬрдирд╕рдВрдкрд░реНрдХ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдореЗрдВ :)

рдпрд╣рд╛рдБ рдПрдХ рдмрд╣реБрдд рд╣реА рд╕рд░рд▓ рд╕реВрддреНрд░ рд╣реИ (рдХреЙрдлрд╝реАрд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╕рд┐рдВрдЯреИрдХреНрд╕ рдореЗрдВ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣реА рд╡рд╣ рд╕рдВрджрд░реНрдн рд╣реИ рдЬрд╣рд╛рдБ рдореИрдВ рдЗрд╕ рдореБрджреНрджреЗ рдкрд░ рднрд╛рдЧрд╛ рдерд╛):

round_interval = 15
remainder = time.minute() % round_interval
time.subtract('minutes', remainder).add('minutes', if remainder > round_interval / 2 then round_interval else 0)

рдореИрдВ рдЕрднреА рдЕрдиреНрдп рдЪреАрдЬреЛрдВ рдореЗрдВ рдХрд╛рдлреА рд╡реНрдпрд╕реНрдд рд╣реВрдВ, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдХреЛрдИ рдЗрд╕ рдХреЛрдб рдХреЛ рд▓реЗрдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рд╕реАрдзреЗ рдкреАрдЖрд░ рдореЗрдВ рдбрд╛рд▓рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реИ, рддреЛ рдмреЗрдЭрд┐рдЭрдХред

#1595 . рдХреЗ рдкрдХреНрд╖ рдореЗрдВ рд╕рдорд╛рдкрди

рдЬрдЯрд┐рд▓, рд╕рд░рд▓ рдЧрдгрд┐рдд рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ:

const rounded = Math.round(moment().minute() / 15) * 15;
const roundedDown = Math.floor(moment().minute() / 15) * 15;
const roundedUp = Math.ceil(moment().minute() / 15) * 15;

moment().minute(roundedUp).second(0)

рдирд┐рдХрдЯрддрдо 15 рдорд┐рдирдЯ рдХреА рддрд┐рдорд╛рд╣реА рдореЗрдВ рдЖрдЙрдЯрдкреБрдЯред

рдореБрдЭреЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП @janwerkhoven рдХрд╛ рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ рдорд┐рд▓рд╛, рдЗрд╕рд▓рд┐рдП рдпрд╣ рдореЗрд░рд╛ рд╣реИ:

function round15(minute) {
  let intervals = [15, 30, 45, 59, 0];
  let closest;
  let min = 90;

  for (let i = 0; i < intervals.length; i++) {
    let iv = intervals[i];
    let maybeMin = Math.abs(minute - iv);

    if (maybeMin < min) {
      min = maybeMin;
      closest = iv;
    }
  }

  if (closest === 59) {
    closest = 0;
  }

  return closest;
}

let myMoment = moment();
myMoment.minutes(round15(myMoment.minutes()));

@ рдЧреНрд░рд╛рдЙрдВрдб5рд╣рд╛рд░реНрдХ

function nearestMinutes(interval, someMoment){
  const roundedMinutes = Math.round(someMoment.clone().minute() / interval) * interval;
  return someMoment.clone().minute(roundedMinutes).second(0);
}

function nearestPastMinutes(interval, someMoment){
  const roundedMinutes = Math.floor(someMoment.minute() / interval) * interval;
  return someMoment.clone().minute(roundedMinutes).second(0);
}

function nearestFutureMinutes(interval, someMoment){
  const roundedMinutes = Math.ceil(someMoment.minute() / interval) * interval;
  return someMoment.clone().minute(roundedMinutes).second(0);
}

const now = moment();
const nearest5min = nearestMinutes(5, now);
const nearest15min = nearestMinutes(15, now);
const nearest30min = nearestMinutes(30, now);
const nearestFuture5min = nearestFutureMinutes(5, now);
const nearestPast5min = nearestPastMinutes(5, now);

рдХреЛрдб рдкреЗрди рдкрд░ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдпрд╛ рдЧрдпрд╛

рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрд┐рдЯ рдХрд░ рд░рд╣рд╛ рд╣реИ .clone() ред рдЗрд╕рдХреЗ рдмрд┐рдирд╛ рдЖрдк рдореВрд▓ moment() рдХрд╛ рд╕рдВрдкрд╛рджрди рдХрд░ рд░рд╣реЗ рд╣реЛрдВрдЧреЗ рдЬреЛ рдХрд┐ Moment.js рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рдиреБрдХрд╕рд╛рди рд╣реИред

рдпрд╣ рдХреЛрд╢рд┐рд╢ рдХрд░реЛ рджреЛрд╕реНрддреЛрдВ

time = moment("01:46", "HH:mm");
round_interval = 30;//15;
intervals = Math.floor(time.minutes() / round_interval);
minutesToRound = time.minutes() % round_interval;
minutesRounded = minutesToRound>round_interval/2 ? round_interval: 0;
minutes = intervals * round_interval + minutesRounded;
time.minutes(minutes);

alert(time.format("HH:mm"))

рдкрд╛рд░реНрдЯреА рдХреЗ рд▓рд┐рдП рджреЗрд░ рд╣реЛ рдЪреБрдХреА рд╣реИ, рдореБрдЭреЗ рдкрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди ...

@janwerkhoven рдХрд╛ nearestMinutes рдлрд╝рдВрдХреНрд╢рди рд╕рд╣реА рдирд╣реАрдВ рд╣реИ; рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рдпрд╣ рдорд┐рдирдЯ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдКрдкрд░ рдпрд╛ рдиреАрдЪреЗ рд╣реЛрдЧрд╛, рдЗрд╕рд▓рд┐рдП рдирд┐рдХрдЯрддрдо 15 рддрдХ рд╣рдо 12:34 -> 12:30 рдФрд░ 12:39 -> 12:45 рдЕрдкреЗрдХреНрд╖рд╛ рдХрд░реЗрдВрдЧреЗ

const roundedMinutes = Math.round(someMoment.clone().minute() / interval) * interval;

// 12:34 is fine...
// => Math.round(34 / 15) * 15
// => 2 * 15
30

// ... but 12:39 is not - it should be 45
// => Math.round(39 / 15) * 15
// => 2 * 15
30

@Silviusconcept рдХрд╛ рд╕рдорд╛рдзрд╛рди minutesRounded рд╕рд╛рде рдЗрд╕ рдкрд░ рдХрд╛рдмреВ рдкрд╛рддрд╛ рд╣реИ

@kevlarr
Math.round(39/15) рд░рд┐рдЯрд░реНрди 3 рдирд╣реАрдВ 2ред
Math.round(39/15) * 15 45 рдирд╣реАрдВ 30 рджреЗрддрд╛ рд╣реИред

рд╣рд╛рд╣рд╛ рдореБрдЭреЗ рджрд┐рди рдХреЗ рдЕрдВрдд рдореЗрдВ рдмрд╣реБрдд рд╕рд╛рд░реЗ рд╕реВрддреНрд░ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдорд┐рд▓рддрд╛ рд╣реИ рдЬрдм рдореИрдВ рд╕реЛрдпрд╛ рдирд╣реАрдВ рдерд╛ .. рдореИрдВ Math.floor рдХрд░ рд░рд╣рд╛ рдерд╛

рдореБрдЭреЗ _zbarnett рд╕рдорд╛рдзрд╛рди_ рдкрд╕рдВрдж рд╣реИ! рдкреНрд░рдпреЛрдЧ рдХрд░рдиреЗ рдореЗрдВ рдЖрд╕рд╛рди
рд╕рдорд╛рд░реЛрд╣ рдХреЗ рд▓рд┐рдП рдереЛрдбрд╝рд╛ рдЕрджреНрдпрддрди _ this.milliseconds(0); _

var newdate=turno.date.clone().roundNext15Min().add(рдкреНрд░рддреНрдпрд╛рд╢рд╛, 'рдорд┐рдирдЯ');

рдореЛрдореЗрдВрдЯ.fn.рд░рд╛рдЙрдВрдбрдиреЗрдХреНрд╕реНрдЯрезрелрдорд┐рди = рдлрдВрдХреНрд╢рди () {
рд╡рд░ рдЕрдВрддрд░рд╛рд▓ = Math.floor (рдпрд╣ред рдорд┐рдирдЯ () / 15);
рдЕрдЧрд░ (рдпрд╣ред рдорд┐рдирдЯ ()% 15! = 0)
рдЕрдВрддрд░рд╛рд▓++;
рдЕрдЧрд░ (рдЕрдВрддрд░рд╛рд▓ == 4) {
this.add ('рдШрдВрдЯреЗ', 1);
рдЕрдВрддрд░рд╛рд▓ = 0;
}
рдпрд╣ред рдорд┐рдирдЯ (рдЕрдВрддрд░рд╛рд▓ * 15);
рдпрд╣ред рд╕реЗрдХрдВрдб (0);
_ рдпрд╣ред рдорд┐рд▓реАрд╕реЗрдХрдВрдб (0); _
рдЗрд╕реЗ рд╡рд╛рдкрд╕ рдХрд░реЛ;
}

рдЙрддреНрддрд░ рдХрд╛ рдореЗрд░рд╛ рд╕рдВрд╕реНрдХрд░рдг

const startOf = (m, n, unit) => {
  const units = [
    'year',
    'month',
    'hour',
    'minute',
    'second',
    'millisecond',
  ];
  const pos = units.indexOf(unit);
  if (pos === -1) {
    throw new Error('Unsupported unit');
  }
  for (let i = pos + 1; i < units.length; i++) {
    m.set(units[i], 0);
  }
  m.set(unit, Math.floor(m.get(unit) / n) * n);

  return m;
};

const endOf = (m, n, unit) => {
  const units = [
    'year',
    'month',
    'hour',
    'minute',
    'second',
    'millisecond',
  ];
  const pos = units.indexOf(unit);
  if (pos === -1) {
    throw new Error('Unsupported unit');
  }
  for (let i = pos + 1; i < units.length; i++) {
    m.set(units[i], units[i] === 'millisecond' ? 999 : 59);
  }
  m.set(unit, Math.floor(m.get(unit) / n) * n + n - 1);

  return m;
};

рдРрд╕реЗ рдХрд░реЗрдВ рдЗрд╕реНрддреЗрдорд╛рд▓:

startOf(moment(), 15, 'minute');
endOf(moment(), 15, 'minute')
// with moment-timezone
startOf(moment().tz("Europe/London"), 15, 'minute');

рдпреЗ рдлрд╝рдВрдХреНрд╢рди рдореВрд▓ рд╡рд╕реНрддреБ рдХреЛ рдмрджрд▓ рджреЗрдВрдЧреЗ, рдЬрд░реВрд░рдд рдкрдбрд╝рдиреЗ рдкрд░ clone() рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ

рдПрдХ рдФрд░ рд╕рдорд╛рдзрд╛рди рд╣реЛрдЧрд╛:
let next15Minutes = moment().add(15, 'minutes'); next15Minutes.minutes(Math.floor(next15Minutes.minutes() / 15) * 15); next15Minutes.format('HH:mm');

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕