I have a bug on one of my feature with timezone, let me explain.
The goal of this feature is to copy user events of a week to the next week.
I have a UserEvent model with this properties
/**
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserEventRepository")
*/
class UserEvent
{
/**
* #ORM\Id()
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="datetime")
*/
private $start;
/**
* #ORM\Column(type="datetime")
*/
private $end;
/**
* #ORM\ManyToOne(targetEntity="UserEventType")
* #ORM\JoinColumn(nullable=false)
*/
private $type;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="userEvents")
* #ORM\JoinColumn(nullable=false)
*/
private $user;
/* GETTERS AND SETTERS */
}
The datetime are stored in datebase in UTC timezone, and at the moment the client using the application is in the Europe/Paris timezone.
This is the logic to copy events to the next week
$newEvents = [];
foreach ($eventsToCopy as $event) {
$newEvent = clone $event;
$newEvent->getStart()->modify('+1 week');
$newEvent->getEnd()->modify('+1 week');
$newEvents[] = $newEvent;
}
The weekend are exlude from the week
The problem appear on this weeks
WEEK A: 2017-10-23 to 2017-10-27
WEEK B: 2017-10-30 to 2017-11-03
There is a time change schedules between week A and week B therefore the planified hours on the second week are shifted on hour forward.
I can't do a high level change to handling DateTime and timezone, I can only modify this code (legacy application)
I'm not very confortable with timezone, maybe I'm missing something obvious.
Please give me your magic guideline to fix this case ! :)
I solved my problem by:
Converting UTC from database to Europe/Paris
Do my stuff to modify the datetime like I want
Then I convert back my Europe/Paris datetime to UTC and save it in database
Code example
$newEvent = new UserEvent();
$newEvent->setUser($event->getUser());
$newEvent->setType($event->getType());
// Convert the datetimes of event to copy to Europe timezone
// For my case I have only one timezone to handle at the moment, so it's always about Europe/Paris <=> UTC
// In advanced use case you could convert the UTC datetime to the user's timezone
list($start, $end) = $this->timezoneFormater->convertUTCDatetimeToEuropeDatetime([$event->getStart(), $event->getEnd()]);
// Now set the date
$start->modify('+1 week');
$end->modify('+1 week');
// Then convert back to UTC timezone
list($start, $end) = $this->timezoneFormater->convertEuropeDatetimeToUTCDatetime([$start, $end]);
$newEvent->setStart($start);
$newEvent->setEnd($end);
$newEvents[] = $newEvent;
I'm using the below method to convert the UTC time to an other time zone. But the below method seems to returning back the UTC time. Will any of you be kind enough to point out whats wrong in the method I'm using?
static function formatDateMerchantTimeZone($t, $tz) {
if (isset($t)) {
return date('Y-m-d H:i:s', strtotime($t , $tz));
} else {
return null;
}
}
$t is the datetime I pass
$tz is the time zone such as America/Los_Angeles
It surprises me that many people are unaware of, or do not use the DateTime classes. They make tasks like this almost trivial.
I have assumed that the date string you pass to the function is in the UTC timezone.
function formatDateMerchantTimeZone($t, $tz)
{
$date = new \DateTime($t, new \DateTimeZone('UTC'));
$date->setTimezone(new \DateTimeZone($tz));
return $date->format('Y-m-d H:i:s');
}
See it working
Strtotime converts a timestamp in string format to a valid date time like '09-29-2013 07:00:00' as second parameter, it does not convert a timezone to a time. php has numerous functions for timezones such as timezone_offset that does calculate the difference between two timezones. take a look in the documentation for more info:
http://php.net/manual/en/function.timezone-offset-get.php
static function formatDateMerchantTimeZone($t, $tz) {
if (isset($t)) {
date_default_timezone_set($tz);
return date('Y-m-d H:i:s', strtotime($t));
} else {
return null;
}
}
From php.net first comment.
To avoid frustrating confusion I recommend always calling
date_default_timezone_set('UTC') before using strtotime().
Because the UNIX Epoch is always in UTC; you will most likely output the wrong time if you do not do this.
try this:
<?php
/** Returns the offset from the origin timezone to the remote timezone, in seconds.
* #param $remote_tz;
* #param $origin_tz; If null the servers current timezone is used as the origin.
* #return int;
*/
function get_timezone_offset($remote_tz, $origin_tz = null) {
if($origin_tz === null) {
if(!is_string($origin_tz = date_default_timezone_get())) {
return false; // A UTC timestamp was returned -- bail out!
}
}
$origin_dtz = new DateTimeZone($origin_tz);
$remote_dtz = new DateTimeZone($remote_tz);
$origin_dt = new DateTime("now", $origin_dtz);
$remote_dt = new DateTime("now", $remote_dtz);
$offset = $origin_dtz->getOffset($origin_dt) - $remote_dtz->getOffset($remote_dt);
return $offset;
}
?>
Examples:
<?php
// This will return 10800 (3 hours) ...
$offset = get_timezone_offset('America/Los_Angeles','America/New_York');
// or, if your server time is already set to 'America/New_York'...
$offset = get_timezone_offset('America/Los_Angeles');
// You can then take $offset and adjust your timestamp.
$offset_time = time() + $offset;
?>
I had this construction error when trying to creating a new DateTime object using a timestamp:
Exception: DateTime::_construct(): Failed to parse time string (1372622987) at position 8 (8): Unexpected character in DateTime->_construct()
The object creation code is:
$start_date = new DateTime( "#{$dbResult->db_timestamp}" );
Where $dbResult->db_timestamp is a valid unix timestamp taken from a database. The timestamp in question was:
1372622987
I would understand this error for invalid formats being passed, but this is a genuine timestamp.
The reason this is very strange: I since ran a script to create a new DateTime object with the timestamp passed in as a hard coded value, and it reported no errors.
This seems to have been a one off, but I need an explanation if there is one, as I can't afford for this to happen again.
You should use setTimestamp instead, if you hardcode it:
$start_date = new DateTime();
$start_date->setTimestamp(1372622987);
in your case
$start_date = new DateTime();
$start_date->setTimestamp($dbResult->db_timestamp);
Use the createFromFormat method:
$start_date = DateTime::createFromFormat("U", $dbResult->db_timestamp);
UPDATE
I now recommend the use of Carbon
change your code to this
$start_date = new DateTime( "#" . $dbResult->db_timestamp );
and it will work fine
This worked for me.
/**
* return date in specific format, given a timestamp.
*
* #param timestamp $datetime
* #return string
*/
public static function showDateString($timestamp)
{
if ($timestamp !== NULL) {
$date = new DateTime();
$date->setTimestamp(intval($timestamp));
return $date->format("d-m-Y");
}
return '';
}
$start_date = new DateTime();
$start_date->setTimestamp($dbResult->db_timestamp);
I have timestamp from specific timezone (Jamaica) and i want to get GMT timestamp of it. Is there more elegant solution than this one :
$start = DateTime::createFromFormat('U', 1330560000);
$start->setTimezone(new DateTimeZone('America/Jamaica'));
$start->format('Y-m-d H:i:s');//2012-02-29 19:00:00 NO NO NO
$tz = new DateTimeZone( 'America/Jamaica' );
$transition = $tz->getTransitions($start->getTimestamp(),$start->getTimestamp());
$offset = $transition[0]['offset'];
$start = DateTime::createFromFormat('U', $params['start'] - 2*$transition[0]['offset']);
$start->setTimezone(new DateTimeZone('America/Jamaica'));
$start->format('Y-m-d H:i:s'); // "2012-03-01 05:00:00" YESSSS!!!
Unix time, or POSIX time, is a system for describing instances in time, defined as the number of seconds that have elapsed since midnight Coordinated Universal Time (UTC), 1 January 1970.
source Wikipedia
The idea of the UNIX timestamp is that it is always in UTC (everywhere in the world xD ). If it does not represents the time in UTC it's not a UNIX timestamp anymore
This is a part of my class that create a well-formatted time stamp as I wrote in the comment of the function, it's very easy to use just pass the string of the date, time zone and the identifier.
Hope it helps you
/**
* Default timestamp format for formatted_time
* #var string
*/
public static $timestamp_format = 'Y-m-d H:i:s';
/**
* Returns a date/time string with the specified timestamp format
* #example $time = Date::formatted_time('5 minutes ago');
* #link http://www.php.net/manual/datetime.construct
* #param string $datetime_str datetime string
* #param string $timestamp_format timestamp format
* #param string $timezone timezone identifier
* #return string
*/
public static function formatted_time($datetime_str = 'now', $timestamp_format = NULL, $timezone = NULL){
$timestamp_format = ($timestamp_format == NULL) ? Date::$timestamp_format : $timestamp_format;
$timezone = ($timezone === NULL) ? Date::$timezone : $timezone;
$tz = new DateTimeZone($timezone ? $timezone : date_default_timezone_get());
$time = new DateTime($datetime_str, $tz);
if ($time->getTimeZone()->getName() !== $tz->getName()){
$time->setTimeZone($tz);
}
return $time->format($timestamp_format);
}
Is there a PHP function that returns the date and time in the same format as the MySQL function NOW()?
I know how to do it using date(), but I am asking if there is a function only for this.
For example, to return:
2009-12-01 00:00:00
You can use the date function:
date("Y-m-d H:i:s");
date('Y-m-d H:i:s')
Look here for more details: http://pl.php.net/manual/en/function.date.php
With PHP version >= 5.4 DateTime can do this:-
echo (new \DateTime())->format('Y-m-d H:i:s');
See it working.
Use this function:
function getDatetimeNow() {
$tz_object = new DateTimeZone('Brazil/East');
//date_default_timezone_set('Brazil/East');
$datetime = new DateTime();
$datetime->setTimezone($tz_object);
return $datetime->format('Y\-m\-d\ h:i:s');
}
Short answer
$now = date_create()->format('Y-m-d H:i:s');
Read below for the long answer.
The mimicry of the MySQL NOW() function in PHP
Here is a list of ways in PHP that mimic the MySQL NOW() function.
// relative date
$now = date_create('now')->format('Y-m-d H:i:s'); // works in php 5.2 and higher
$now = date_create()->format('Y-m-d H:i:s'); // also works in php 5.2
$now = new DateTime('now')->format('Y-m-d H:i:s'); // syntax error!!!
$now = (new DateTime('now'))->format('Y-m-d H:i:s'); // works in php 5.4 and higher
$now = date('Y-m-d H:i:s'); // Slightly higher performance, but less usable for date/time manipulations
// From Unix timestamp
// Using date_create() with a Unix timestamp will give you a FALSE,
// and if you try to invoke format() on a FALSE then you'll get a:
// Fatal error: Call to a member function format() on boolean
// So if you work with Unix timestamps then you could use: date_create_from_format().
$unixTimeStamp = 1420070400; // 01/01/2015 00:00:00
$y2015 = date_create_from_format('U', $unixTimeStamp, timezone_open('Europe/Amsterdam'))->format('Y-m-d H:i:s');
$y2015 = date('Y-m-d H:i:s', $unixTimeStamp);
I think that date_create()->format('Y-m-d H:i:s') is the best way because this approach allows you to handle time/time-zone manipulations easier than date('Y-m-d H:i:s') and it works since php 5.2.
MySQL NOW() function
The MySQL function NOW() gives the dateTime value in this format: 'YYYY-MM-DD HH:MM:SS'. See here: https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_now.
An interesting fact is that it's possible to get the datetime format by running this query: SHOW VARIABLES LIKE 'd%e_format', the result could be something like this:
Variable_name Value
date_format %Y-%m-%d
datetime_format %Y-%m-%d %H:%i:%s
The variables up here are read-only variables. So you can't change it.
I guess the MySQL NOW() function gets it's format from the datetime_format variable.
Advantages of using date_create()->format() instead date() summary
The favorable facts of date_create('now')->format('Y-m-d H:i:s') over date('Y-m-d H:i:s') are:
O.O.P.
easier to handle time manipulations
easier to handle timezones
Disadvanteages of using date_create()->format() instead date() summary
date() performs slightly better
Advantages of using date_create()->format() instead date() detailed
Read on for the detailed explanation.
O.O.P.
The function date_create() is a constructor function for the DateTime object. The documentation of that Object gives the programmer a quick view that describes the possibilities.
Documentation: https://www.php.net/manual/en/class.datetime.php
The function date() just gives you a string.
My taste for usability lies in O.O.P.
easier to handle time manipulations
date_create() accepts a relative date/time format (like now, yesterday or +1 day) see this link, example:
$tomorrow = date_create('+1 day')->format('Y-m-d H:i:s');
date() accepts a relative date/time format as well, like this:
$tomorrow = date('Y-m-d H:i:s', strtotime('+1 day'));
$tomorrow = date('Y-m-d H:i:s', (time() + 86400)); // 86400 seconds = 1 day
easier to handle timezones
When timezones matter then the usage of date_create()->format() makes a lot more sense then date() because date() uses the default time zone which is configured in php.ini at the date.timezone directive. Link: http://php.net/manual/en/datetime.configuration.php#ini.date.timezone .
It is possible to change the timezone during run-time. Example:
date_default_timezone_set('Asia/Tokyo');.
The downside of that is that it will affect all date/time functions. This problem doesn't exists if you are using date_create()->format() in combination with timezone_open().
PHP supports major timezones. The funny thing is that it even supports the Arctic circle, and Antarctica. Have you ever heard about Longyearbyen? If not, then don't worry, neither did I until I read the official PHP documentation. Does it matter? Well... yes if you run an international e-commerce platform and do something bound to local time, for example: calculate delivery date-time.
$nowLongyearbyen = date_create('now', timezone_open('Arctic/Longyearbyen'))->format('Y-m-d H:i:s');
See a list of all supported timezones:
http://php.net/manual/en/timezones.php.
date_create() VS new DateTime()
The favorable facts of date_create() over new DateTime() are:
Namespaces
Namespaces
If you work in a namespace and want to initialise a DateTime object with the new keyword, then you have to do it like this:
namespace my_namespace;
// The backslash must be used if you are in a namespace.
// Forgetting about the backslash results in a fatal error.
$dt = new \DateTime();
There is nothing wrong with this, but the downside of the above is that people forget sporadically about the backslash. By using the date_create() constructor function you don't have to worry about namespaces.
$dt = date_create(); // in or not in a namespace it works in both situations
Disadvantages of using date_create()->format() instead date()
The function date() has a slightly better performance than date_create()->format(). However, it's only visible if you would instantiate DateTime millions of times. Which might never happen in a real-life situation. However, here is the benchmark test:
$start = time();
for ($i = 0; $i <= 5000000; $i++) {
$a = date_create('now')->format('Y-m-d H:i:s');
}
$end = time();
$elapsedTimeA = $end - $start;
echo 'Case date_create(), elapsed time in seconds: ' . $elapsedTimeA;
echo '<br>';
$start = time();
for ($i = 0; $i <= 5000000; $i++) {
$b = date('Y-m-d H:i:s');
}
$end = time();
$elapsedTimeB = $end - $start;
echo 'Case date(), elapsed time in seconds: ' . $elapsedTimeB;
echo '<br>';
// OUTPUT
Case date_create(), elapsed time in seconds: 31
Case date(), elapsed time in seconds: 14
Examples of date_create()->format()
I use this approach for my projects if I have to fill an array. Like this:
$array = array(
'name' => 'John',
'date_time' => date_create('now')->format('Y-m-d H:i:s'), // uses the default timezone
'date_time_japan' => date_create('now', timezone_open('Asia/Tokyo'))->format('Y-m-d H:i:s'),
);
Try this:
date("Y-m-d H:i:s");
I was looking for the same answer, and I have come up with this solution for PHP 5.3 or later:
$dtz = new DateTimeZone("Europe/Madrid"); //Your timezone
$now = new DateTime(date("Y-m-d"), $dtz);
echo $now->format("Y-m-d H:i:s");
One more answer I find easy to use:
echo date('c');
// 2015-07-27T00:00:00+02:00
This is ISO 8601 date (added in PHP 5) which MySQL uses
Edit
MySQL 5.7 do not allow timezone in the datetime by default. You can disable the error with SQL_MODE=ALLOW_INVALID_DATES. See the answer here for more details: https://stackoverflow.com/a/35944059/2103434. But that also means that the timezone will be lost when saving to the database!
By default MySQL uses the system's timezone, and as long as PHP uses the same timezone you should be okay. In my case CET / UTC+2.
That means that if I insert 2015-07-27T00:00:00+02:00 to the database, only 2015-07-27T00:00:00 will be stored (but that is the correct local time!).
When I load the time back in to PHP,
$importedDate = new \DateTime('2015-07-27T00:00:00')
it will automatically assume it's +02:00 timezone since it's the default. Printing this will be correct again:
echo $importedDate->format('c');
// 2015-07-27T00:00:00+02:00
To be safe, always use UTC on the server, specify it in MySQL and PHP, and then only convert it to your user's locale when displaying the date:
date_default_timezone_set('UTC');
$importedDate = new \DateTime('2015-07-27T00:00:00+02:00');
echo $importedDate->format('c');
// 2015-07-27T00:00:00+02:00
$importedDate->setTimezone(new \DateTimeZone("America/New_York"));
echo $importedDate->format('c');
// 2015-07-26T18:00:00-04:00
MySQL function NOW() returns the current timestamp. The only way I found for PHP is using the following code.
$curr_timestamp = date('Y-m-d H:i:s');
Use strftime:
strftime("%F %T");
%F is the same as %Y-%m-%d.
%T is the same as %H:%M:%S.
Here's a demo on ideone.
Or you can use DateTime constants:
echo date(DateTime::W3C); // 2005-08-15T15:52:01+00:00
Here's the list of them:
ATOM = "Y-m-d\TH:i:sP" ; // -> 2005-08-15T15:52:01+00:00
COOKIE = "l, d-M-Y H:i:s T" ; // -> Monday, 15-Aug-2005 15:52:01 UTC
ISO8601 = "Y-m-d\TH:i:sO" ; // -> 2005-08-15T15:52:01+0000
RFC822 = "D, d M y H:i:s O" ; // -> Mon, 15 Aug 05 15:52:01 +0000
RFC850 = "l, d-M-y H:i:s T" ; // -> Monday, 15-Aug-05 15:52:01 UTC
RFC1036 = "D, d M y H:i:s O" ; // -> Mon, 15 Aug 05 15:52:01 +0000
RFC1123 = "D, d M Y H:i:s O" ; // -> Mon, 15 Aug 2005 15:52:01 +0000
RFC2822 = "D, d M Y H:i:s O" ; // -> Mon, 15 Aug 2005 15:52:01 +0000
RFC3339 = "Y-m-d\TH:i:sP" ; // -> 2005-08-15T15:52:01+00:00 ( == ATOM)
RFC3339_EXTENDED = "Y-m-d\TH:i:s.vP" ; // -> 2005-08-15T15:52:01.000+00:00
RSS = "D, d M Y H:i:s O" ; // -> Mon, 15 Aug 2005 15:52:01 +0000
W3C = "Y-m-d\TH:i:sP" ; // -> 2005-08-15T15:52:01+00:00
For debugging I prefer a shorter one though (3v4l.org):
echo date('ymd\THisP'); // 180614T120708+02:00
I like the solution posted by user1786647, and I've updated it a little to change the timezone to a function argument and add optional support for passing either a Unix time or datetime string to use for the returned datestamp.
It also includes a fallback for "setTimestamp" for users running version lower than PHP 5.3:
function DateStamp($strDateTime = null, $strTimeZone = "Europe/London") {
$objTimeZone = new DateTimeZone($strTimeZone);
$objDateTime = new DateTime();
$objDateTime->setTimezone($objTimeZone);
if (!empty($strDateTime)) {
$fltUnixTime = (is_string($strDateTime)) ? strtotime($strDateTime) : $strDateTime;
if (method_exists($objDateTime, "setTimestamp")) {
$objDateTime->setTimestamp($fltUnixTime);
}
else {
$arrDate = getdate($fltUnixTime);
$objDateTime->setDate($arrDate['year'], $arrDate['mon'], $arrDate['mday']);
$objDateTime->setTime($arrDate['hours'], $arrDate['minutes'], $arrDate['seconds']);
}
}
return $objDateTime->format("Y-m-d H:i:s");
}
You can use the PHP date function with the correct format as the parameter,
echo date("Y-m-d H:i:s");
My answer is superfluous, but if you are OCD, visually oriented and you just have to see that now keyword in your code, use:
date( 'Y-m-d H:i:s', strtotime( 'now' ) );
There is no built-in PHP now() function, but you can do it using date().
Example
function now() {
return date('Y-m-d H:i:s');
}
You can use date_default_timezone_set() if you need to change timezone.
Otherwise you can make use of Carbon - A simple PHP API extension for DateTime.
shortly
echo date('Y-m-d H:i:s');
php advanced now class extra addMinute addYear as such addHour etc ...
<?php /** #noinspection PhpUnhandledExceptionInspection */
/**
* Class Now
* #author dılo sürücü <berxudar#gmail.com>
*/
class Now
{
/**
* #var DateTime
*/
private $dateTime;
/**
* Now constructor.
* #throws Exception
*/
public function __construct()
{
$this->dateTime = new DateTime('now');
}
/**
* #param int $year
* #return Now
* #throws Exception
* #noinspection PhpUnused
*/
public function addYear(int $year): self
{
$this->dateTime->add(new DateInterval('P' . $year . 'Y'));
return $this;
}
/**
* #noinspection PhpUnused
* #param int $month
* #return Now
* #throws Exception
* #noinspection PhpUnused
*/
public function addMonth(int $month):self
{
$this->dateTime->add(new DateInterval('P' . $month . 'M'));
return $this;
}
/**
* #param int $day
* #return $this
* #throws Exception
*/
public function addDay(int $day): self
{
$this->dateTime->add(new DateInterval('P' . $day . 'D'));
return $this;
}
/**
* #noinspection PhpUnused
* #param int $week
* #return $this
* #throws Exception
*/
public function addWeek(int $week): self
{
return $this->addDay($week * 7);
}
/**
* #noinspection PhpUnused
* #param int $second
* #return $this
* #throws Exception
*/
public function addSecond(int $second): self
{
$this->dateTime->add(new DateInterval('PT' . $second . 'S'));
return $this;
}
/**
* #param int $minute
* #return $this
* #throws Exception
*/
public function addMinute(int $minute): self
{
$this->dateTime->add(new DateInterval('PT' . $minute . 'M'));
return $this;
}
/**
* #param int $hour
* #return $this
* #throws Exception
*/
public function addHour(int $hour): self
{
$this->dateTime->add(new DateInterval('PT' . $hour . 'H'));
return $this;
}
/**
* #return string
*/
public function get(): string
{
return $this->dateTime->format('Y-m-d H:i:s');
}
/**
* #return string
*/
public function __toString()
{
return $this->get();
}
}
/**
* #return Now
* #throws Exception
*/
function now()
{
return new Now();
}
using
echo now(); //2020-03-10 22:10
echo now()->addDay(1); //2020-03-11 22:10
echo now()->addDay(1)->addHour(1); // //2020-03-11 23:10
echo now()->addDay(1)->addHour(1)->addMinute(30); // //2020-03-11 23:40
echo now()->addDay(1)->addHour(1)->addMinute(30)->addSecond(10); // //2020-03-11 23:50
//or u can use get method for example
echo now()->addDay(1)->addHour(1)->addMinute(30)->get(); // //2020-03-11 23:40
In PHP the logic equivalent of the MySQL's function now() is time().
But time() return a Unix timestamp that is different from a MySQL DATETIME.
So you must convert the Unix timestamp returned from time() in the MySQL format.
You do it with:
date("Y-m-d H:i:s");
But where is time() in the date() function? It's the second parameter: infact you should provide to date() a timestamp as second parameter, but if it is omissed it is defaulted to time().
This is the most complete answer I can imagine.
Greetings.
If you want to get time now including AM / PM
<?php
$time_now = date("Y-m-d h:i:s a");
echo $time_now;
?>
It outputs 2020-05-01 05:45:28 pm
or
<?php
$time_now = date("Y-m-d h:i:s A");
echo $time_now;
?>
It outputs 2020-05-01 05:45:28 PM
You might find this helpful
new \DateTime()
The PHP equivalent is time(): http://php.net/manual/en/function.time.php