-
Notifications
You must be signed in to change notification settings - Fork 161
Update CronDate addSecond and subtractSecond to set milliseconds to 0 #389
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
Hi @asuhag113! Thanks for opening a PR!
I'm already working on this as there are couple of related issues (that proposed approach may fix or not) as #273, #378 and #385 Haven't had time to put together the proper fix. |
Hey @harrisiirak, thanks for the quick response! My bad on missing the bench. Hmm, it definitely seems to have a bit of a surprising performance impact. FWIW, I also tried something like: addSecond(): void {
const currentMs = this.#date.valueOf();
const nextSecondMs = Math.floor(currentMs / 1000) * 1000 + 1000;
this.#date = DateTime.fromMillis(nextSecondMs, { zone: this.#date.zone });
}Which seemed to also resolve the issue and pass the tests. Just gonna drop some benchmarks below that may be helpful Original code (before PR)
Current PR
New rewrite (removing luxon plus and startOf)
Replacing only startOf (with Math.ceil)
Finally, I also tried a small change to #findSchedule(reverse = false): CronDate {
const dateMathVerb: DateMathOp = reverse ? DateMathOp.Subtract : DateMathOp.Add;
const currentDate = new CronDate(this.#currentDate);
+
+ // Preserve milliseconds for reverse scheduling
+ const hadMilliseconds = currentDate.getMilliseconds() !== 0;
+
+ if (currentDate.getMilliseconds() !== 0) {
+ currentDate.setMilliseconds(0);
+ }
const startTimestamp = currentDate.getTime();
let stepCount = 0;
while (++stepCount < LOOP_LIMIT) {
this.#validateTimeSpan(currentDate);
if (!this.#matchDayOfMonth(currentDate)) {
currentDate.applyDateOperation(dateMathVerb, TimeUnit.Day, this.#fields.hour.values.length);
continue;
}
if (
!(this.#fields.dayOfWeek.nthDay <= 0 || Math.ceil(currentDate.getDate() / 7) === this.#fields.dayOfWeek.nthDay)
) {
currentDate.applyDateOperation(dateMathVerb, TimeUnit.Day, this.#fields.hour.values.length);
continue;
}
if (!CronExpression.#matchSchedule(currentDate.getMonth() + 1, this.#fields.month.values)) {
currentDate.applyDateOperation(dateMathVerb, TimeUnit.Month, this.#fields.hour.values.length);
continue;
}
if (!this.#matchHour(currentDate, dateMathVerb, reverse)) {
continue;
}
if (!CronExpression.#matchSchedule(currentDate.getMinutes(), this.#fields.minute.values)) {
currentDate.applyDateOperation(dateMathVerb, TimeUnit.Minute, this.#fields.hour.values.length);
continue;
}
if (!CronExpression.#matchSchedule(currentDate.getSeconds(), this.#fields.second.values)) {
currentDate.applyDateOperation(dateMathVerb, TimeUnit.Second, this.#fields.hour.values.length);
continue;
}
if (startTimestamp === currentDate.getTime()) {
- if (dateMathVerb === 'Add' || currentDate.getMilliseconds() === 0) {
+ if (dateMathVerb === 'Add' || !hadMilliseconds) {
currentDate.applyDateOperation(dateMathVerb, TimeUnit.Second, this.#fields.hour.values.length);
}
continue;
}
break;
}
/* istanbul ignore next - should be impossible under normal use to trigger the branch */
if (stepCount > LOOP_LIMIT) {
throw new Error(LOOPS_LIMIT_EXCEEDED_ERROR_MESSAGE);
}
- if (currentDate.getMilliseconds() !== 0) {
- currentDate.setMilliseconds(0);
- }
this.#currentDate = currentDate;
return currentDate;
}Editing findSchedule
Thanks for linking these. I tried pulling in some test cases described in the issues. It does seem like these changes resolve #385 but not the others. Happy to help keep digging or provide anything else. |
|
@asuhag113 This NB: I’ve also tested other methods ( |
Overview
This PR fixes an issue where using the CronExpressionParser to parse the next scheduled time yielded an
Out of the timespan rangeerror whencurrentDateandendDatewhere milliseconds apart. Since cron expressions don't need to worry about milliseconds and we set milliseconds to 0 for otheraddUnitoperations, it seems reasonable to apply this to the seconds operations as well.Issue
It appears that when using
addSecondto go to the next time candidate, the milliseconds are preserved. This causes potential candidates to be skipped over in specific cases like when trying to schedule every minute.Failing example