Here is a thing that took me longer to work out than it should have. I am storing some dates in a MySql database in the UTC timezone, but on my webpage I want to have them show as the local time. The problem I found is that PHP assumed that the date from the database was already in the local time (BST) and so did not adjust the hour on the datetime object when the timezone was applied.
This is fixed by setting the timezone when creating the datetime object from the string:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?php // this goes at the start of your script, in the index.php date_default_timezone_set('Europe/London'); // create the datetime object, and set the timezone to UTC: $sqlDate = "2023-04-02 10:40:36"; $datetime = DateTime::createFromFormat('Y-m-d H:i:s', $sqlDate, new DateTimeZone('UTC')); // displays: 02 Apr 2023 10:40:36 UTC echo "<p>". $datetime->format('d M Y H:i:s T') ."</p>"; // now set the timezone: $datetime->setTimezone(new DateTimeZone(date_default_timezone_get())); // displays: 02 Apr 2023 11:40:36 BST echo "<p>". $datetime->format('d M Y H:i:s T') ."</p>"; // format for output: $output = $datetime->format('d F Y H:i:s T'); echo "<p>".$output."</p>"; // 02 April 2023 11:40:36 BST ?> |
Also here it is again, but with a Unix Timestamp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?php // this goes at the start of your script, in the index.php date_default_timezone_set('Europe/London'); // create the datetime object, and set the timezone to UTC: $unixtime = 1680428135; $datetime = new DateTime("@$unixtime", new DateTimeZone('UTC')); // displays: 02 Apr 2023 09:35:35 GMT+0000 echo "<p>". $datetime->format('d M Y H:i:s T') ."</p>"; // now set the timezone: $datetime->setTimezone(new DateTimeZone(date_default_timezone_get())); // displays: 02 Apr 2023 10:35:35 BST echo "<p>". $datetime->format('d M Y H:i:s T') ."</p>"; // format for output: $output = $datetime->format('d F Y H:i:s T'); echo "<p>".$output."</p>"; // 02 April 2023 10:35:35 BST ?> |
I hope this saves someone half a day. Although it occurs to me that I should really have the PHP output the date as the UTC and then have the javascript deal with it. Then the date would be displayed as how the users timezone is set rather than the servers.
So, in our PHP code, we setup a suitable output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?php // code snippet $sqlDate = "2023-04-02 11:55:37"; $data = array(); $data["importantDate"] = setISO8601date($sqlDate); header("HTTP/1.1 200 OK"); header('Content-Type: application/json; charset=utf-8'); echo json_encode($data); exit(); function setISO8601date($sqlDate) { $datetime = DateTime::createFromFormat('Y-m-d H:i:s', $sqlDate, new DateTimeZone('UTC')); return $datetime->format("Y-m-d\TH:i:s.Z\Z"); } ?> |
and in your javascript file, after you have picked up the data with your ajax call, or whatever, I have two functions, one to convert the ISO 8601 format (YYYY-MM-DDTHH:mm:ss.sssZ) UTC date time to local and another to make for a nicely formatted output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
// ... javascript code snippet ... // using jquery to fill the html void $("#importantdate").html(unixtimestampToLocaldate(data["importantDate"])); function unixtimestampToLocaldate(utcDateStr) { const unixtimestamp = Date.parse(utcDateStr); var dd = new Date(unixtimestamp); // this date is adjusted to local time console.log(ut); // 2023-04-02T00:21:46.000Z console.log(unixtime); // 1680394906000 console.log(dd); // Sun Apr 02 2023 01:21:46 GMT+0100 (British Summer Time) return datetimeToStr(dd, true); } // for some reason the native javascript date functions have very poor options for formatting // without you having to write lots of extra code. function datetimeToStr(datetime, withtime=false) { const days = ["Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat", "Sun"]; const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; var yy = datetime.getFullYear(); var mm = datetime.getMonth(); var dt = datetime.getDate(); var dd = datetime.getDay(); var hh = datetime.getHours().toString(); var ii = datetime.getMinutes().toString(); var ss = datetime.getSeconds().toString(); var date = days[dd]+" "+dt+" "+ months[mm] +" "+yy; if (withtime) { return date + " "+ hh.padStart(2, '0') + ":"+ii.padStart(2, '0')+":"+ss.padStart(2, '0'); // Sun 2 Apr 2023 01:21:46 } return date; // Sun 2 Apr 2023 } |
I’ve created the separate function for the date formatting as this has more flexibility.
Links and Sources
- PHP Datetime Docs: https://www.php.net/manual/en/book.datetime.php
- MDN Web Docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date