nhb-toolbox
Version:
A versatile collection of smart, efficient, and reusable utility functions, classes and types for everyday development needs.
81 lines (80 loc) • 3.88 kB
JavaScript
import { roundToNearest } from '../../number/utilities.js';
import { INTERNALS, MS_PER_DAY } from '../constants.js';
export const roundPlugin = ($Chronos) => {
const { internalDate, withOrigin, offset } = $Chronos[INTERNALS];
$Chronos.prototype.round = function (unit, nearest = 1) {
const date = new Date(internalDate(this));
switch (unit) {
case 'millisecond': {
const rounded = roundToNearest(date.getMilliseconds(), nearest);
date.setMilliseconds(rounded);
break;
}
case 'second': {
const fullSecond = date.getSeconds() + date.getMilliseconds() / 1000;
const rounded = roundToNearest(fullSecond, nearest);
date.setSeconds(rounded, 0);
break;
}
case 'minute': {
const fullMinute = date.getMinutes() + date.getSeconds() / 60 + date.getMilliseconds() / 60000;
const rounded = roundToNearest(fullMinute, nearest);
date.setMinutes(rounded, 0, 0);
break;
}
case 'hour': {
const fullHour = date.getHours() +
date.getMinutes() / 60 +
date.getSeconds() / 3600 +
date.getMilliseconds() / 3600000;
const rounded = roundToNearest(fullHour, nearest);
date.setHours(rounded, 0, 0, 0);
break;
}
case 'day': {
const fullDay = date.getDate() +
(date.getHours() / 24 +
date.getMinutes() / 1440 +
date.getSeconds() / 86400 +
date.getMilliseconds() / MS_PER_DAY);
const rounded = roundToNearest(fullDay, nearest);
date.setDate(rounded);
date.setHours(0, 0, 0, 0);
break;
}
case 'week': {
const weekday = date.getDay();
const offsetToMonday = (weekday + 6) % 7;
const startOfWeek = new Date(date);
startOfWeek.setDate(startOfWeek.getDate() - offsetToMonday);
startOfWeek.setHours(0, 0, 0, 0);
const endOfWeek = new Date(startOfWeek);
endOfWeek.setDate(endOfWeek.getDate() + 7);
const diffToStart = Math.abs(date.getTime() - startOfWeek.getTime());
const diffToEnd = Math.abs(endOfWeek.getTime() - date.getTime());
const rounded = diffToEnd < diffToStart ? endOfWeek : startOfWeek;
return withOrigin(new $Chronos(rounded), 'round', offset(this), this.timeZoneName, this.timeZoneId, this.$tzTracker);
}
case 'month': {
const fullMonth = date.getMonth() + date.getDate() / this.lastDateOfMonth;
const roundedMonth = roundToNearest(fullMonth, nearest);
date.setMonth(roundedMonth, 1);
date.setHours(0, 0, 0, 0);
break;
}
case 'year': {
const dayOfYear = Math.floor((date.getTime() - new Date(date.getFullYear(), 0, 1).getTime()) / MS_PER_DAY);
const isLeap = new Date(date.getFullYear(), 1, 29).getDate() === 29;
const totalDays = isLeap ? 366 : 365;
const fullYear = date.getFullYear() + dayOfYear / totalDays;
const roundedYear = roundToNearest(fullYear, nearest);
date.setFullYear(roundedYear, 0, 1);
date.setHours(0, 0, 0, 0);
break;
}
default:
return this;
}
return withOrigin(new $Chronos(date), 'round', offset(this), this.timeZoneName, this.timeZoneId, this.$tzTracker);
};
};