1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2024-12-12 11:15:22 +02:00

Fixing periodic job scheduling timezone issue. #273

Note: current time format change from valid timestamp to hours*60+minutes, current config wont be valid.
This commit is contained in:
Patrik J. Braun 2021-05-21 16:38:29 +02:00
parent 01f858b092
commit 21908732c6
6 changed files with 48 additions and 28 deletions

View File

@ -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');
@ -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()) {

View File

@ -144,7 +144,7 @@ export class ScheduledJobTrigger implements JobTrigger {
@ConfigProperty({type: JobTriggerType})
readonly type = JobTriggerType.scheduled;
@ConfigProperty()
@ConfigProperty({type: 'unsignedInt'})
time: number; // data time
}
@ -152,9 +152,9 @@ export class ScheduledJobTrigger implements JobTrigger {
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
}

View File

@ -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 {
@ -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;
},
@ -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);

View File

@ -18,15 +18,13 @@
<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>

View File

@ -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,
@ -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',
@ -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) {
@ -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);
});
}
@ -174,7 +183,6 @@ export class JobsSettingsComponent extends SettingsComponentDirective<ServerJobC
this.jobModal.hide();
}
getProgress(schedule: JobScheduleDTO): JobProgressDTO {
return this.jobsService.getProgress(schedule);
}

View File

@ -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();
}