Skip to content

Commit

Permalink
Fixing periodic job scheduling timezone issue. #273
Browse files Browse the repository at this point in the history
Note: current time format change from valid timestamp to hours*60+minutes, current config wont be valid.
  • Loading branch information
bpatrik committed May 21, 2021
1 parent 01f858b commit 2190873
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 28 deletions.
6 changes: 6 additions & 0 deletions src/backend/model/jobs/JobManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ export class JobManager implements IJobManager, IJobListener {
this.timers = [];
}

/**
* Schedules all jobs to run
*/
public runSchedules(): void {
this.stopSchedules();
Logger.info(LOG_TAG, 'Running job schedules');
Expand All @@ -100,6 +103,9 @@ export class JobManager implements IJobManager, IJobListener {
return this.getAvailableJobs().find((t): boolean => t.Name === jobName);
}

/**
* Schedules a single job to run
*/
private runSchedule(schedule: JobScheduleDTO): void {
const nextDate = JobScheduleDTOUtils.getNextRunningDate(new Date(), schedule);
if (nextDate && nextDate.getTime() > Date.now()) {
Expand Down
6 changes: 3 additions & 3 deletions src/common/config/private/PrivateConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,17 +144,17 @@ export class ScheduledJobTrigger implements JobTrigger {
@ConfigProperty({type: JobTriggerType})
readonly type = JobTriggerType.scheduled;

@ConfigProperty()
@ConfigProperty({type: 'unsignedInt'})
time: number; // data time
}

@SubConfigClass()
export class PeriodicJobTrigger implements JobTrigger {
@ConfigProperty({type: JobTriggerType})
readonly type = JobTriggerType.periodic;
@ConfigProperty()
@ConfigProperty({type: 'unsignedInt', max: 7})
periodicity: number; // 0-6: week days 7 every day
@ConfigProperty()
@ConfigProperty({type: 'unsignedInt', max: 23 * 60 + 59})
atTime: number; // day time
}

Expand Down
25 changes: 12 additions & 13 deletions src/common/entities/job/JobScheduleDTO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export interface ScheduledJobTrigger extends JobTrigger {
export interface PeriodicJobTrigger extends JobTrigger {
type: JobTriggerType.periodic;
periodicity: number; // 0-6: week days 7 every day
atTime: number; // day time
atTime: number; // day time min value: 0, max: 23*60+59
}

export interface AfterJobTrigger extends JobTrigger {
Expand All @@ -37,26 +37,26 @@ export interface JobScheduleDTO {

export const JobScheduleDTOUtils = {

getNextDayOfTheWeek: (refDate: Date, dayOfWeek: number) => {
getNextDayOfTheWeek: (refDate: Date, dayOfWeek: number): Date => {
const date = new Date(refDate);
date.setDate(refDate.getDate() + (dayOfWeek + 1 + 7 - refDate.getDay()) % 7);
if (date.getDay() === refDate.getDay()) {
return new Date(refDate);
}
date.setHours(0, 0, 0, 0);
date.setUTCHours(0, 0, 0, 0);
return date;
},

nextValidDate: (date: Date, h: number, m: number, dayDiff: number): Date => {

date.setSeconds(0);
if (date.getHours() < h || (date.getHours() === h && date.getMinutes() < m)) {
date.setHours(h);
date.setMinutes(m);
date.setUTCSeconds(0);
date.setUTCMilliseconds(0);
if (date.getUTCHours() < h || (date.getUTCHours() === h && date.getUTCMinutes() < m)) {
date.setUTCHours(h);
date.setUTCMinutes(m);
} else {
date.setTime(date.getTime() + dayDiff);
date.setHours(h);
date.setMinutes(m);
date.setUTCHours(h);
date.setUTCMinutes(m);
}
return date;
},
Expand All @@ -68,9 +68,8 @@ export const JobScheduleDTOUtils = {

case JobTriggerType.periodic:


const hour = Math.floor(schedule.trigger.atTime / 1000 / (60 * 60));
const minute = (schedule.trigger.atTime / 1000 / 60) % 60;
const hour = Math.min(23, Math.floor(schedule.trigger.atTime / 60));
const minute = schedule.trigger.atTime % 60;

if (schedule.trigger.periodicity <= 6) { // Between Monday and Sunday
const nextRunDate = JobScheduleDTOUtils.getNextDayOfTheWeek(refDate, schedule.trigger.periodicity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,13 @@ <h5 class="card-header">
<ng-container [ngSwitch]="schedule.trigger.type">
<ng-container *ngSwitchCase="JobTriggerType.periodic">
<ng-container i18n>every</ng-container>
{{periods[schedule.trigger.periodicity]}} {{schedule.trigger.atTime | date:"HH:mm":"+0"}}
{{periods[schedule.trigger.periodicity]}} {{atTimeLocal(schedule.trigger.atTime) | date:"HH:mm (z)"}}
</ng-container>
<ng-container
*ngSwitchCase="JobTriggerType.scheduled">{{schedule.trigger.time | date:"medium"}}</ng-container>
<ng-container *ngSwitchCase="JobTriggerType.never" i18n>never</ng-container>
<ng-container *ngSwitchCase="JobTriggerType.after">
<ng-container i18n>after</ng-container>
:
{{schedule.trigger.afterScheduleName}}
<ng-container i18n>after</ng-container>: {{schedule.trigger.afterScheduleName}}
</ng-container>
</ng-container>
</div>
Expand Down
16 changes: 12 additions & 4 deletions src/frontend/app/ui/settings/jobs/jobs.settings.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {SettingsComponentDirective} from '../_abstract/abstract.settings.compone
import {ScheduledJobsService} from '../scheduled-jobs.service';
import {
AfterJobTrigger,
JobScheduleDTO, JobScheduleDTOUtils,
JobScheduleDTO,
JobScheduleDTOUtils,
JobTriggerType,
NeverJobTrigger,
PeriodicJobTrigger,
Expand All @@ -17,7 +18,7 @@ import {ConfigTemplateEntry} from '../../../../../common/entities/job/JobDTO';
import {ModalDirective} from 'ngx-bootstrap/modal';
import {JobProgressDTO, JobProgressStates} from '../../../../../common/entities/job/JobProgressDTO';
import {BackendtextService} from '../../../model/backendtext.service';
import {ServerConfig, ServerJobConfig} from '../../../../../common/config/private/PrivateConfig';
import {ServerJobConfig} from '../../../../../common/config/private/PrivateConfig';

@Component({
selector: 'app-settings-jobs',
Expand Down Expand Up @@ -78,6 +79,14 @@ export class JobsSettingsComponent extends SettingsComponentDirective<ServerJobC
$localize`day`]; // 7
}


atTimeLocal(atTime: number): Date {
const d = new Date();
d.setUTCHours(Math.floor(atTime / 60));
d.setUTCMinutes(Math.floor(atTime % 60));
return d;
}

getConfigTemplate(JobName: string): ConfigTemplateEntry[] {
const job = this.settingsService.availableJobs.value.find(t => t.Name === JobName);
if (job && job.ConfigTemplate && job.ConfigTemplate.length > 0) {
Expand Down Expand Up @@ -161,7 +170,7 @@ export class JobsSettingsComponent extends SettingsComponentDirective<ServerJobC
}

public sortedSchedules(): JobScheduleDTO[] {
return this.states.scheduled.value.slice().sort((a: JobScheduleDTO, b: JobScheduleDTO) => {
return (this.states.scheduled.value as JobScheduleDTO[]).slice().sort((a: JobScheduleDTO, b: JobScheduleDTO) => {
return this.getNextRunningDate(a, this.states.scheduled.value) - this.getNextRunningDate(b, this.states.scheduled.value);
});
}
Expand All @@ -174,7 +183,6 @@ export class JobsSettingsComponent extends SettingsComponentDirective<ServerJobC
this.jobModal.hide();
}


getProgress(schedule: JobScheduleDTO): JobProgressDTO {
return this.jobsService.getProgress(schedule);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,38 @@ import {Component, EventEmitter, Input, Output} from '@angular/core';
export class TimeStampTimePickerComponent {

timestampValue = 0;
timezoneOffset = (new Date()).getTimezoneOffset() * 60 * 1000;
@Output() timestampChange = new EventEmitter<number>();

date: Date = new Date();

@Input() name: string;

constructor() {
this.date.setUTCSeconds(0);
this.date.setUTCMilliseconds(0);
}

@Input()
public get timestamp(): number {
return this.timestampValue;
}

public set timestamp(val: number) {
this.date.setTime(val + this.timezoneOffset);
const h = Math.min(23, Math.floor(val / 60));
const m = val % 60;
this.date.setUTCHours(h);
this.date.setUTCMinutes(m);

if (this.timestampValue === val) {
return;
}
this.timestampValue = val;
this.timestampChange.emit(this.timestampValue);

}

onChange(date: Date | string): void {
this.timestamp = (new Date(date)).getTime() - this.timezoneOffset;
const d = new Date(date);
this.timestamp = d.getUTCHours() * 60 + d.getUTCMinutes();
}


Expand Down

0 comments on commit 2190873

Please sign in to comment.