dayjs icon indicating copy to clipboard operation
dayjs copied to clipboard

How to round to next/previous 15 minutes?

Open katerlouis opened this issue 3 years ago • 6 comments

const now = dayjs(); // e.g. 'HH:mm' is 17:37

But what I want to modify the object to snap to 17:30 or 17:45.

Is there a way to do it? "Rounding" only seems to be a thing in relative time, which is not what I'm looking for.

katerlouis avatar Sep 01 '21 15:09 katerlouis

Friendly push.

katerlouis avatar Sep 13 '21 10:09 katerlouis

@katerlouis did you find a solution?

tanthammar avatar Nov 01 '21 19:11 tanthammar

I created my own ceil function, I think I originally stole it from moment-round

import inst, { PluginFunc, UnitType } from 'dayjs';

declare module 'dayjs' {
    interface Dayjs {
        ceil(unit: UnitType, amount: number): inst.Dayjs;
    }
}
const ceil: PluginFunc = (option, dayjsClass) => {
    dayjsClass.prototype.ceil = function (unit, amount) {
        return this.add(amount - (this.get(unit) % amount), unit).startOf(unit);
    };
};
export default ceil;

Can be used like

import dayjs from 'dayjs';
import ceil from './ceil';
dayjs.extend(ceil);

console.log(dayjs().ceil('minutes', 15).format());

cjsewell avatar Nov 30 '21 21:11 cjsewell

I've created a version to round (up or down) to the nearest time.

19:52 becomes 19:50 19:53 becomes 19:55

const round: PluginFunc = (option, dayjsClass) => {
  dayjsClass.prototype.round = function (amount, unit) {
    const mod = this.get(unit as UnitType) % amount;

    if(mod < amount / 2) {
      return this.subtract(mod, unit).startOf(unit);
    }

    return this.add(amount - mod, unit).startOf(unit);
  };
};

vendramini avatar Jul 15 '22 16:07 vendramini

  1. I start to test @cjsewell solution and soon I found a bug, imho:
dayjs('2023-06-29T14:14:14+00:00').ceil(24 * 60, 'minutes').utc().format()

result is 2023-06-30T14:00:00+00:00', but I expected '2023-06-30T00:00:00+00:00'

  1. So this is the solution based on stackoverflow
import duration from "dayjs/plugin/duration";

export default (option, dayjsClass, dayjsFactory) => {
    dayjsFactory.extend(duration);

    // @see https://stackoverflow.com/a/39637877
    const _round = function (amount, unit, method) {
        const duration = dayjsFactory.duration(amount, unit);
        return dayjsFactory(Math[method](this.valueOf() / duration.as("milliseconds")) * duration.as("milliseconds"));
    };

    "floor ceil round".split(" ").forEach((method) => {
        dayjsClass.prototype[method] = function (amount, unit) {
            return _round.call(this, amount, unit, method);
        };
    });
};

cakkypamucm avatar Jun 29 '23 18:06 cakkypamucm