I stumbled onto a really weird problem:
For my task I wrote a method that would give me the current date in a specific format,
another method would then extract the date so I could compare it with dates in the database.
public static function getCurrentDate()
{
return date("Y-m-d H:i:s a");
}
public static function extractDate($date)
{
return date("Y-m-d", strtotime($date));
}
Because I've noticed that the time wasn't right, I've set the default timezone at the beginning of the script like this:
date_default_timezone_set('Europe/Berlin');
Running this script, I've noticed that it gives the wrong output, maybe you could already help me here.
$currentDate = getCurrentDate();
echo $currentDate."\n";
$extractedDate = extractDate($currentDate );
echo $extractedDate."\n";
Output:
2020-08-25 21:58:13 pm
1970-01-01
Then I tried it in another way with DateTime, where it still produced the wrong output
public static function extractDate($date)
{
$timezone = new DateTimeZone('Europe/Berlin');
$dt = DateTime::createFromFormat("Y-m-d H:i:s a", $date, $timezone);
return $dt->format("Y-m-d");
}
Output:
2020-08-25 21:58:13 pm
2020-08-26
I would understand if there was an error so it would lead to the Unix epoch again, but this time it somehow added a day.
It would be nice if you knew where my error at the first approach was and I'm also really interested to hear why PHP behaves like that in the second approach
Change:
public static function getCurrentDate()
{
return date("Y-m-d H:i:s a");
}
to
public static function getCurrentDate()
{
return date("Y-m-d H:i:s");
}
and you are all set.
In 24h time you do not need the a or am/pm, which makes the datetime unrecognizable via strtotime, it cannot convert it , and it returns false, thus the invalid date 1970-01-01which is qeuivalent tounixtime = 0`
I'm new to php unit testing. How do I mock the date in the function below. Currently it is getting the current date. But I want to change the date in the mock to the first day of a month.
function changeStartEndDate() {
if (date('j', strtotime("now")) === '1') {
$this->startDate = date("Y-n-j", strtotime("first day of previous month"));
$this->endDate = date("Y-n-j", strtotime("last day of previous month")) . ')';
} else {
$this->startDate = date("Y-n-j", strtotime(date("Y-m-01")));
$this->endDate = date("Y-n-j", strtotime("yesterday"));
}
}
I've tried doing this but its not working.
public function testServicesChangeStartEndDate() {
$mock = $this->getMockBuilder('CoreFunctions')
->setMethods(array('changeStartEndDate'))
->getMock();
$mock->method('changeStartEndDate')
->with(date("Y-n-j", strtotime(date("Y-m-01"))));
$this->assertSame(
'1',
$this->core->changeStartEndDate()
);
}
Unit testing works best by avoiding side effects. Both date and strtotime are depending on an external state defined on your host system, namely the current time.
One way to deal with that is to make current time an injectable property allowing you to "freeze" it or to set it to a specific value.
If you look at at the definition to strtotime it allows setting current time:
strtotime ( string $time [, int $now = time() ] ) : int
Same with date:
date ( string $format [, int $timestamp = time() ] ) : string
So always inject that value from your function to decouple the results of your code from your host's state.
function changeStartEndDate($now) {
if (date('j', strtotime("now", $now), $now) === '1') {
...
$this->startDate = date("Y-n-j", strtotime(date("Y-m-01", $now), $now));
$this->endDate = date("Y-n-j", strtotime("yesterday", $now), $now);
}
Is your function part of a class? I would then make the $now part of the constructor, and have it default to time(). In your test cases, you can always inject a fixed number, and it will always return the same output.
class MyClassDealingWithTime {
private $now;
public function __construct($now = time()) {
$this->now = $now;
}
private customDate($format) {
return date($format, $this->now);
}
private customStringToTime($timeSring) {
return strtotime($timeStrimg, $this->now);
}
}
In your test cases you then set $now to the value you need, e.g. via
$firstDayOfAMonth = (new DateTime('2017-06-01'))->getTimestamp();
$testInstance = new MyClassDealingWithTime(firstDayOfAMonth);
$actual = $testInstance->publicMethodYouWantTotest();
...
Disclaimer: I wrote the library mentioned on this answer.
I'm adding an answer to provide an alternative way that works with zero modifications to your code, and no need to inject the current time.
If you can afford to install the php uopz extension, then you can use https://github.com/slope-it/clock-mock.
You can then use ClockMock::freeze and ClockMock::reset to "move" the internal php clock to a specific point in time during your tests.
I need a function which returns the number of days since 1.1.1970 but depending on the timezone.
I wrote the following function but was wondering if there is a better way to do it (some better way to determinate the offset from gmt would be a good thing).
function getDaysSinceUnix($time = null){
if($time === null){$time = time();}
$day = 24*60*60;
$offset = intval(substr(date('O'),0,-2))*60*60;
return intval(floor(($time+$offset)/$day));
}
If not, is there something you would add that could give this function more stability ?
Using DateTime:
function getDaysSinceUnix( $time = 0, $timeZone = Null )
{
$time = "#$time";
$tz = new DateTimeZone( $timeZone ?: date_default_timezone_get() );
return date_create( $time )->setTimeZone( $tz )->diff( date_create( '1970-01-01', $tz ) )->days;
}
If no Time Zone is passed, current Time Zone is used.
The Carbon library is pretty much the gold standard for PHP date/time work.
Carbon\Carbon::createFromTimestamp(0)->diffInDays();
How to get millisecond between two DateTime objects?
$date = new DateTime();
$date2 = new DateTime("1990-08-07 08:44");
I tried to follow the comment below, but I got an error.
$stime = new DateTime($startTime->format("d-m-Y H:i:s"));
$etime = new DateTime($endTime->format("d-m-Y H:i:s"));
$millisec = $etime->getTimestamp() - $stime->getTimestamp();`
I get the error
Call to undefined method DateTime::getTimestamp()
In the strict sense, you can't.
It's because the smallest unit of time for the DateTime class is a second.
If you need a measurement containing milliseconds then use microtime()
Edit:
On the other hand if you simply want to get the interval in milliseconds between two ISO-8601 datetimes then one possible solution would be
function millisecsBetween($dateOne, $dateTwo, $abs = true) {
$func = $abs ? 'abs' : 'intval';
return $func(strtotime($dateOne) - strtotime($dateTwo)) * 1000;
}
Beware that by default the above function returns absolute difference. If you want to know whether the first date is earlier or not then set the third argument to false.
// Outputs 60000
echo millisecsBetween("2010-10-26 20:30", "2010-10-26 20:31");
// Outputs -60000 indicating that the first argument is an earlier date
echo millisecsBetween("2010-10-26 20:30", "2010-10-26 20:31", false);
On systems where the size of time datatype is 32 bits, such as Windows7 or earlier, millisecsBetween is only good for dates between 1970-01-01 00:00:00 and 2038-01-19 03:14:07 (see Year 2038 problem).
Sorry to digg out an old question, but I've found a way to get the milliseconds timestamp out of a DateTime object:
function dateTimeToMilliseconds(\DateTime $dateTime)
{
$secs = $dateTime->getTimestamp(); // Gets the seconds
$millisecs = $secs*1000; // Converted to milliseconds
$millisecs += $dateTime->format("u")/1000; // Microseconds converted to seconds
return $millisecs;
}
It requires however that your DateTime object contains the microseconds (u in the format):
$date_str = "20:46:00.588";
$date = DateTime::createFromFormat("H:i:s.u", $date_str);
This is working only since PHP 5.2 hence the microseconds support to DateTime has been added then.
With this function, your code would become the following :
$date_str = "1990-08-07 20:46:00.588";
$date1 = DateTime::createFromFormat("Y-m-d H:i:s.u", $date_str);
$msNow = (int)microtime(true)*1000;
echo $msNow - dateTimeToMilliseconds($date1);
DateTime supports microseconds since 5.2.2. This is mentioned in the documentation for the date function, but bears repeating here. You can create a DateTime with fractional seconds and retrieve that value using the 'u' format string.
<?php
// Instantiate a DateTime with microseconds.
$d = new DateTime('2011-01-01T15:03:01.012345Z');
// Output the microseconds.
echo $d->format('u'); // 012345
// Output the date with microseconds.
echo $d->format('Y-m-d\TH:i:s.u'); // 2011-01-01T15:03:01.012345
// Unix Format
echo "<br>d2: ". $d->format('U.u');
function get_data_unix_ms($data){
$d = new DateTime($data);
$new_data = $d->format('U.u');
return $new_data;
}
function get_date_diff_ms($date1, $date2)
{
$d1 = new DateTime($date1);
$new_d1 = $d1->format('U.u');
$d2 = new DateTime($date2);
$new_d2 = $d2->format('U.u');
$diff = abs($new_d1 - $new_d2);
return $diff;
}
https://www.php.net/manual/en/class.datetime.php
Here's a function to do that + tests.
https://gist.github.com/vudaltsov/0bb623b9e2817d6ce359eb88cfbf229d
DateTime dates are only stored as whole seconds. If you still need the number of milliseconds between two DateTime dates, then you can use getTimestamp() to get each time in seconds (then get the difference and turn it into milliseconds):
$seconds_diff = $date2.getTimestamp() - $date.getTimestamp()
$milliseconds_diff = $seconds_diff * 1000
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