woocommerce / action-scheduler

A scalable, traceable job queue for background processing large queues of tasks in WordPress. Specifically designed for distribution in WordPress plugins (and themes) - no server access required.
https://actionscheduler.org
GNU General Public License v3.0
637 stars 116 forks source link

Local timezone schedule #219

Closed alexminza closed 5 years ago

alexminza commented 5 years ago
$timezone = get_option('timezone_string');
$timestamp = strtotime('midnight tomorrow');
$local_timestamp = as_get_datetime_object($timestamp, $timezone);

$action_id = as_schedule_recurring_action($local_timestamp, DAY_IN_SECONDS, 'my_hook');

will schedule at 00:00 UTC, while the WP configuration has a timezone with an offset UTC+2.

alexminza commented 5 years ago
$timezone = get_option('timezone_string');
$timestamp = strtotime('midnight tomorrow');
$local_timestamp1 = as_get_datetime_object($timestamp, $timezone);
$local_timestamp = new DateTime('midnight tomorrow', new DateTimeZone($timezone));

wc_get_logger()->debug($local_timestamp1->format(DateTime::ATOM));
wc_get_logger()->debug($local_timestamp->format(DateTime::ATOM));

Outputs:

DEBUG 2018-12-07T00:00:00+00:00
DEBUG 2018-12-07T00:00:00+02:00
alexminza commented 5 years ago

Passing $local_timestamp with the value of 2018-12-07T00:00:00+02:00 to as_schedule_recurring_action schedules an action at midnight but in UTC, effectively discarding the time zone info:

screenshot 2018-12-06 at 11 49 24
alexminza commented 5 years ago
$ date
Thu Dec  6 17:06:23 EET 2018
$timestamp = as_get_datetime_object('midnight tomorrow', 'Europe/Chisinau');
$action_id = as_schedule_recurring_action($timestamp, DAY_IN_SECONDS, 'my_hook');

Schedules recurring action at 2018-12-07 00:00:00 +00:00:

screenshot 2018-12-06 at 17 11 29
rrennick commented 5 years ago

When you pass a timestamp to the DateTime constructor the timezone is ignored - http://php.net/manual/en/datetime.construct.php. To use a timestamp adjust the timestamp to UTC.

alexminza commented 5 years ago

According to the comment by @thenbrent in WooCommerce issue #10179 does it mean that all the timestamps passed to Action Scheduler must be in UTC?

$timestamp = as_get_datetime_object('midnight tomorrow', 'Europe/Chisinau');
$timestamp->setTimezone(new DateTimeZone('UTC'));
$action_id = as_schedule_recurring_action($timestamp, DAY_IN_SECONDS, 'my_hook');

Or what would be the proper way to schedule events occurring at a specific moment in the configured WP timezone?

rrennick commented 5 years ago

In my previous comment, by timestamp I meant a unix (epoch) timestamp (ex. 1544140800). The strtotime() function returns a timestamp.

as_get_datetime_object('midnight tomorrow') returns a DateTime object. If you pass a timestamp to as_get_datetime_object(), the timezone parameter is ignored (ex as_get_datetime_object(1544140800) ).

thenbrent commented 5 years ago

According to the comment by @thenbrent in WooCommerce issue #10179 does it mean that all the timestamps passed to Action Scheduler must be in UTC?

@alexminza what Ron said is correct.

Also as_schedule_recurring_action(), and the other procedural APIs, require a Unix timestamp, i.e. an int, not a date/time string or object. For more details, see the Parameters section of the API Reference:

$timestamp (integer)(required) The Unix timestamp representing the date you want the action to run. Default: none.

Or the PHP Docblock, which specifies an int (but is not as detailed as the API reference unfortunately).