later
later copied to clipboard
Time zone support
Are there plans to support date calculations based on CRON expressions in other time zones than local or UTC?
Currently no. Some people have added timezone support using another library like timezone-js. You would need to update date/timezone.js
to create timezone aware date instances.
Thanks for your prompt response!
I'm a bit stuck what route I need to follow, currently I replaced the later
internal method stub with the following
later.date.build = function (Y, M, D, h, m, s) {
var value = new timezoneJS.Date(Y, M, D, h, m, s, tz);
return value;
};
Is this the route to go? Can you maybe refer me to other solutions or people that implemented this?
Yes, this should be the way to go. You can search the issues for other people looking for timezone support.
I have a 'easy' workaround for missing timezone. I use the momentjs timezone library http://momentjs.com/timezone/.
That looks promising and less hackish than my start. I still have to wrap my head around it and test how it works for my issue. (especially the part where the offset of and 'old' date is used for calculating a 'new' date in a possible other time zone)
I hope to find the time soon and give you an update.
If I understand your comment correctly you have a user in location X that says execute at 17:00. Then the user goes on a vacation to location Y and it still needs to execute at 17:00. My solution would be to run the calculation again when the user changes timezones. But you can go for a more complicated solution if you know the date/time when the user changes timezones. Similar to how I did daylight saving correction you could use the offset of the new timezone and adjust the output.
No It's a somewhat different situation: A have a bunch of schedules that are executed using CRON jobs in different time zones. I need to calculate the next execution of that job and then present the next execution in the clients' time zone. I know the CRON expression and the timezone of these schedules and can deliver them to the client.
I think your previous solution may still work.
Right now I'm thinking of migrating my client-side calculation to server side next execution calculation, in order to just support one method of time zone correction, with one set of time zones and time zone ids for simplicity's sake. The calculation will be needed server side anyway. This question remains valid though.
That is the same use-case I have, and the gist is the same as I implemented. Server does the calculation and stores the timezone, previous date, and next date.
Okay, I will test it then, thanks for your prompt response.
If this works I still have one hurdle to overcome: mapping my Windows Time Zones to TimeZone.js time zone id's, which may still drive me to a server side solution to prevent time zone maintenance
Your solution worked flawlessly!
Due to objections mentioned earlier, I did switch to server-side calculation though.
@osteenbergen I believe there is a simpler way:
var moment = require('moment');
var tz = moment(/* our date object here */);
var laterDate = moment.utc(tz).toDate();
// laterDate is our date object to use in later.js!
Did some testing and mmathys simpler way is not a valid solution as the resulting list still runs according to UTC. Or i misunderstand your solution. Could you please submit your solution for the example used in my gist:
- User writes text schedule "at 17:00"
- User lives (and thinks) in "Europe/Amsterdam"
- User expects the system to start the run exactly at 17.00 local time even when the local time changes due to daylight saving
var moment = require("moment-timezone");
var later = require("later");
// The schedule we would like to support specified in local timezone:
var sched = later.parse.text("at 17:00");
// In March CET switches to CEST (daylight saving) so this is a nice example
var timezone = "Europe/Amsterdam";
var start_date = new Date("2015-03-24");
// Calculate the list of occurences using the virtual time
var list = later.schedule(sched).next(10, start_date);
/*
Schedule now runs at 17.00 UTC
[ Tue Mar 24 2015 18:00:00 GMT+0100 (CET),
Wed Mar 25 2015 18:00:00 GMT+0100 (CET),
Thu Mar 26 2015 18:00:00 GMT+0100 (CET),
Fri Mar 27 2015 18:00:00 GMT+0100 (CET),
Sat Mar 28 2015 18:00:00 GMT+0100 (CET),
Sun Mar 29 2015 19:00:00 GMT+0200 (CEST),
Mon Mar 30 2015 19:00:00 GMT+0200 (CEST),
Tue Mar 31 2015 19:00:00 GMT+0200 (CEST),
Wed Apr 01 2015 19:00:00 GMT+0200 (CEST),
Thu Apr 02 2015 19:00:00 GMT+0200 (CEST) ]
*/
list.map(function(item){
var tz = moment(item);
return moment.utc(tz).toDate();
});
/*
Schedule still runs at 17.00 UTC
[ Tue Mar 24 2015 18:00:00 GMT+0100 (CET),
Wed Mar 25 2015 18:00:00 GMT+0100 (CET),
Thu Mar 26 2015 18:00:00 GMT+0100 (CET),
Fri Mar 27 2015 18:00:00 GMT+0100 (CET),
Sat Mar 28 2015 18:00:00 GMT+0100 (CET),
Sun Mar 29 2015 19:00:00 GMT+0200 (CEST),
Mon Mar 30 2015 19:00:00 GMT+0200 (CEST),
Tue Mar 31 2015 19:00:00 GMT+0200 (CEST),
Wed Apr 01 2015 19:00:00 GMT+0200 (CEST),
Thu Apr 02 2015 19:00:00 GMT+0200 (CEST) ]
*/
For everyone who uses later with nodejs and doesn't mind having moment as a dependency you can use this fork for time zone support. the text and cron parsers accept the time zone as last argument and execute the schedule in that zone, e.g. later.parse.cron(pattern,true,'America/Toronto')
@bunkat will you accept a PR for timezone support?
If you added it as a build option so we could build versions with or without timezone support, than sure. Sort of like what I did to build the core library and then the library with parsers. Otherwise it just increases the size of the library too much for those people that don't need it.
It's pretty annoying that setting something to run at 8am actually runs at 9am for 6 months of the year. If you don't intend to support this perhaps it should be mentioned somewhere obvious in the documentation?
This does work if you set Later to use your local timezone. The only scenario that doesn't work is if you want to use an arbitrary timezone. I'd be happy to take a PR that adds full timezone support, but since I don't need it, I'm not planning on adding it myself.
Yep, adding later.date.localTime()
fixed my problem, thanks.
Is there a way to make timezones work with setInterval and the text parser?
@osteenbergen 's solution works for getting a finite number, but what if I want this schedule to execute indefinitely?
Also, just my 2 cents. If your interval directly specifies the TIME block (if looking at the Text Parser diagram) and you set later.js to be in UTC. Then any DateTime that gets output will be at UTC time zone. But the user who has a TZ specified that schedule, so now we need to deduct his TZ offset to get "Actual UTC". I saw that this is not the case if you are omitting the TIME block, then it does provide "Actual UTC", so no need to further process it.
Below is what works for me
var clientTZ = "Africa/Johannesburg";
// var interval = "every 3 min";
var interval = every 1 day at 08:00;
var sched = later.parse.text(interval);
var nextRunDTs = later.schedule(sched).next(1);
if(interval.includes("at") || interval.includes("after") || interval.includes("before"))
momentFirstRundDT = DateTime_TZ_to_UTC(clientTZ, nextRunDT);
else
momentFirstRundDT = moment(nextRunDT);