UNPKG

@heinlein-video/rrule

Version:

rrule fork. Includes the src/ folder for typescript sourceMaps

269 lines (233 loc) 5.84 kB
import { ParsedOptions, Frequency } from './types' import { pymod, divmod, empty, includes } from './helpers' import { getWeekday, MAXYEAR, monthRange } from './dateutil' export class Time { public hour: number public minute: number public second: number public millisecond: number constructor( hour: number, minute: number, second: number, millisecond: number ) { this.hour = hour this.minute = minute this.second = second this.millisecond = millisecond || 0 } getHours() { return this.hour } getMinutes() { return this.minute } getSeconds() { return this.second } getMilliseconds() { return this.millisecond } getTime() { return ( (this.hour * 60 * 60 + this.minute * 60 + this.second) * 1000 + this.millisecond ) } } export class DateTime extends Time { public day: number public month: number public year: number static fromDate(date: Date) { return new this( date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.valueOf() % 1000 ) } constructor( year: number, month: number, day: number, hour: number, minute: number, second: number, millisecond: number ) { super(hour, minute, second, millisecond) this.year = year this.month = month this.day = day } getWeekday() { return getWeekday(new Date(this.getTime())) } getTime() { return new Date( Date.UTC( this.year, this.month - 1, this.day, this.hour, this.minute, this.second, this.millisecond ) ).getTime() } getDay() { return this.day } getMonth() { return this.month } getYear() { return this.year } public addYears(years: number) { this.year += years } public addMonths(months: number) { this.month += months if (this.month > 12) { const yearDiv = Math.floor(this.month / 12) const monthMod = pymod(this.month, 12) this.month = monthMod this.year += yearDiv if (this.month === 0) { this.month = 12 --this.year } } } public addWeekly(days: number, wkst: number) { if (wkst > this.getWeekday()) { this.day += -(this.getWeekday() + 1 + (6 - wkst)) + days * 7 } else { this.day += -(this.getWeekday() - wkst) + days * 7 } this.fixDay() } public addDaily(days: number) { this.day += days this.fixDay() } public addHours(hours: number, filtered: boolean, byhour: number[]) { if (filtered) { // Jump to one iteration before next day this.hour += Math.floor((23 - this.hour) / hours) * hours } for (;;) { this.hour += hours const { div: dayDiv, mod: hourMod } = divmod(this.hour, 24) if (dayDiv) { this.hour = hourMod this.addDaily(dayDiv) } if (empty(byhour) || includes(byhour, this.hour)) break } } public addMinutes( minutes: number, filtered: boolean, byhour: number[], byminute: number[] ) { if (filtered) { // Jump to one iteration before next day this.minute += Math.floor((1439 - (this.hour * 60 + this.minute)) / minutes) * minutes } for (;;) { this.minute += minutes const { div: hourDiv, mod: minuteMod } = divmod(this.minute, 60) if (hourDiv) { this.minute = minuteMod this.addHours(hourDiv, false, byhour) } if ( (empty(byhour) || includes(byhour, this.hour)) && (empty(byminute) || includes(byminute, this.minute)) ) { break } } } public addSeconds( seconds: number, filtered: boolean, byhour: number[], byminute: number[], bysecond: number[] ) { if (filtered) { // Jump to one iteration before next day this.second += Math.floor( (86399 - (this.hour * 3600 + this.minute * 60 + this.second)) / seconds ) * seconds } for (;;) { this.second += seconds const { div: minuteDiv, mod: secondMod } = divmod(this.second, 60) if (minuteDiv) { this.second = secondMod this.addMinutes(minuteDiv, false, byhour, byminute) } if ( (empty(byhour) || includes(byhour, this.hour)) && (empty(byminute) || includes(byminute, this.minute)) && (empty(bysecond) || includes(bysecond, this.second)) ) { break } } } public fixDay() { if (this.day <= 28) { return } let daysinmonth = monthRange(this.year, this.month - 1)[1] if (this.day <= daysinmonth) { return } while (this.day > daysinmonth) { this.day -= daysinmonth ++this.month if (this.month === 13) { this.month = 1 ++this.year if (this.year > MAXYEAR) { return } } daysinmonth = monthRange(this.year, this.month - 1)[1] } } public add(options: ParsedOptions, filtered: boolean) { const { freq, interval, wkst, byhour, byminute, bysecond } = options switch (freq) { case Frequency.YEARLY: return this.addYears(interval) case Frequency.MONTHLY: return this.addMonths(interval) case Frequency.WEEKLY: return this.addWeekly(interval, wkst) case Frequency.DAILY: return this.addDaily(interval) case Frequency.HOURLY: return this.addHours(interval, filtered, byhour) case Frequency.MINUTELY: return this.addMinutes(interval, filtered, byhour, byminute) case Frequency.SECONDLY: return this.addSeconds(interval, filtered, byhour, byminute, bysecond) } } }