0

I am trying to schedule WP Cron that should run every midnight at Local Timestamp, but it is taking UTC only. This the code I am trying with,

if ( ! wp_next_scheduled( 'midnight_cron' ) ) {
        $now = current_time('timestamp', 1 );
        $time = strtotime('tomorrow', $now );

        wp_schedule_event($time, 'daily', 'midnight_cron');
    }

I know by default WP cron uses UTC/GMT time, not local time, but what could be the possible way to achieve this?

Update:

if ( ! wp_next_scheduled( 'midnight_cron' ) ) {

        $gmt = get_option( 'gmt_offset' );
        $time = strtotime('midnight') + ((24 - $gmt) * HOUR_IN_SECONDS);
        if($time < time()) $time + (24 * HOUR_IN_SECONDS);

        wp_schedule_event($time, 'daily', 'midnight_cron');
    }

2 Answers 2

3

Part 1. The Time != The Timestamp

enter image description here

This is your problem:

every midnight at Local Timestamp

There is no such thing as a local timestamp. Timestamps are not timezoned, it's not that WP uses UTC, but rather that UTC timestamps just happen to be +0 hours.

If you want it to happen at midnight local time, you need to convert that time into a timestamp, and UTC is the easiest way to do that. For example midnight BST is 11pm UTC, so I would need to schedule a cron job for 11pm for it to run at midnight. If I set the cron job to run at 00:00, then that would be 1am local time, which is not what I wanted.

So take your desired localized timezoned time, and convert it to UTC in code. You can always undo the math at a later date if you need to display it.

e.g. here we take a UTC date and change it to Moscow time:

$date = new DateTime('2012-07-16 01:00:00 +00');
$date->setTimezone(new DateTimeZone('Europe/Moscow')); // +04

echo $date->format('Y-m-d H:i:s'); // 2012-07-15 05:00:00 

And here we take a Bangkok time and convert it to UTC:

$given = new DateTime("2014-12-12 14:18:00 +07");
echo $given->format("Y-m-d H:i:s e") . "\n"; // 2014-12-12 14:18:00 Asia/Bangkok

$given->setTimezone(new DateTimeZone("UTC"));
echo $given->format("Y-m-d H:i:s e") . "\n"; // 2014-12-12 07:18:00 UTC

If you still want to specify things in local time just write a function to do the conversion, e.g. $utc_time = convert_to_utc( "time in local timezone")

Part 2. Why UTC?

Have you ever noticed why some timezones are referenced as +8 hours or -2? That would be UTC+8 or UTC-2. UTC is also known as coordinated universal time.

It's the time system used as the base standard that all the usual time systems we use day to day are derived from. So your local time is defined as some offset of UTC.

So Can I make WP use the local timezone for timestamps?

If WP stored everything using local time, then changing your local time would involve modifying every timestamp in the database. It would cause issues with communications with other APIs. It would also cause issues with plugins and themes that try to convert from UTC to your local timezone, doubling the offset, and causing compounding errors. It could also cause issues with the REST API, 2 factor auth, etc

It's a very bad idea. It also breaks the fundamental system of a timestamp on your site.

Think of it this way. You see times and dates in WordPress with a timezone modifier attached. When WP stores the data, it strips away the modifier, and stores it as a standardised value that all WP sites and computers understand. It then re-applies the timezone modifier whenever it displays the date.

5
  • You pointed out some important factors, I would have to reconsider my initial logics. In my case, the cron job will run a fallback function which will insert a new row every midnight if not inserted already by another function. Oct 20, 2018 at 22:19
  • So I am using wp GMT offset to create the timestamp for the same and doing some math. Please check the update. If that is the cleanest way? Oct 20, 2018 at 22:26
  • if it works for you then it works. Keep in mind though that WP Cron won't run exactly at midnight as it depends on page loads to run. If nobody visits your site until 1am, the cron job won't run until 1am because that's the earliest opportunity it had. For precise cron jobs that run exactly when wanted you'll need to set up a real system cron job that uses WP CLI to trigger WP Cron at the right intervals. I also would not add in the if condition though that checks if $time < time(), especially if your servers system clock isn't in UTC
    – Tom J Nowell
    Oct 20, 2018 at 23:34
  • Thank you :) It seem to be working for now but I am just trying to learn more about WP Cron. I know about the real cron method but in this case, can't use. It just needs one-time page load to add my event to the wp cron events list, after that, it will be triggered without any page load as per given interval, am I understanding it correctly? Oct 21, 2018 at 0:19
  • As I said, WP Cron runs after a page load. If no pages are loaded no cron runs. If you only load the page once, the cron only runs once, it can't run on its own without somebody refreshing the page. I think at this point though you're asking a new question though ( how does WP Cron work? ), that's related but not the same question, and comments is not a good place for it, so I will not continue on that front. If this answer answers your question as it was asked, you can mark it as accepted. If you have more Q's about WP Cron you should create new questions
    – Tom J Nowell
    Oct 21, 2018 at 3:29
0

The wp_schedule_event function has the schedule_event filter inside it. If you take a look at the wp-includes/cron.php lines 102-106 you can see how it is used.

Perhaps you could hook a custom function to that filter. In your custom filter function you could then do some local time check and short circuit the main function (i.e. return false), if it's the wrong time.

I haven't tested or done this myself before, but this idea just came to my mind.

3
  • Hi, Thank you. I am not sure if this the cleanest way, but it seems to be working with these changes, Please check the updated code. Oct 20, 2018 at 21:03
  • Yea, it might not be the cleanest way, but hey, if it works and doesn't cause any errors just go with it. You can always come back to the code and refine it later, if you find or come up with a more elegant solution. I haven't worked with WP_Cron before that much so I don't have much suggestion to give. Oct 20, 2018 at 21:23
  • Yes, As per initial test that seems to serve the cause. Thank you :) Oct 20, 2018 at 22:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.