In this code
$start = $this->getStart();
var_dump($start);
$start->modify('Monday this week');
var_dump($this->getStart());
-
public function getStart()
{
return $this->start;
}
how is it possible, that the second dump actually shows the modified date?
I know that modify operates on the date object itself and not merely returns the new value. But why is the actual object property changed? When I change the value otherwise, e.g.
$start = $this->getStart();
var_dump($start);
$start = false;
var_dump($this->getStart());
two times the same date is dumped, as I would expect.
Related
I am pulling DateTime timestamp result from another table which is set as:
When dumping specific value of $post->getUploadTime() I get:
"2602585961"
It's in string format.
In my entity I have modified the setter to:
public function setStartTime($startTime)
{
$date = new \DateTime($startTime);
$this->startTime = $date->getTimestamp();
return $this;
}
And my code:
$newEntityObject->setStartTime(intval($post->getUploadTime()));
I am using intval() to transform string to integer (timestamp) so I can insert it in db but I get an error:
DateTime::__construct(): Failed to parse time string (2602585961) at position 8 (6): Unexpected character"
It's an error with or without the intval().
I can not figure out what is wrong?
I know there are a lot of posts about the issue. I tried them, but the problem still remains.
Try :
$date = new \DateTime();
$date->setTimestamp($startTime);
$this->startTime = $date->getTimestamp();
But since you are trying to assign a timestamp to your startTime property and you are already passing a timestamp to your function you can just assign whatever timestamp you are passing:
$this->startTime = $startTime;
You have a timestamp, and you are trying to make it a DateTime and get timestamp from the new datetime object.
The DateTime constructor only accept specific date and time format.
Also, the given value refer to the year 2052. So it's possible that you have another issue before.
You don't need to convert to a number. Because you need a string argument that starts with #
You need use #. Read Documentation.
<?php
$a = "#2602585961";
function setStartTime($startTime)
{
$date = new \DateTime($startTime);
$b = $date->getTimestamp();
return $b;
}
echo setStartTime($a);
https://www.php.net/manual/ru/datetime.formats.compound.php
In your code:
$newEntityObject->setStartTime("#" . $post->getUploadTime());
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 want to find the difference between two dates and I have used date_diff for the same. When format function is applied on date_diff object it returns an error.
Call to a member function format() on boolean
$field_value is fetched from the database and it's format is dd/mm/YYYY. When I hard-code the values for $field_value and $indexing_value the following code works.
Everything is running fine till line number 8. I have tried outputting the value of
$diff->format("%R%a")
and it is returning exact value but the code gives error near the if statement.
$date = new DateTime();
$current_date = $date->format('d/m/Y');
$indexing_value = str_replace("/", "-", $field_value);
$current_value = str_replace("/", "-", $current_date);
$indexing_value = date_create($indexing_value);
$current_value = date_create($current_value);
$diff = date_diff($indexing_value, $current_value);
if ($diff->format("%R%a") < 0) {
echo "1";
} else {
echo "2";
}
Please let me know what is wrong with the above code.
add condition to check whether you got the diff or not, as it returns false if there is error . Check manual for the same
$diff = date_diff($indexing_value, $current_value);
if ($diff) {
if ($diff->format("%R%a") < 0) {
echo "1";
}else{
echo "2";
}
}
You are getting error because for some values the diff is not calculated and have value False in $diff
Please let me know what is wrong with the above code.
There are several issues with the code:
You don't check the values returned by date_create(); it returns FALSE on error.
What's the point of formatting $date then creating $current_value back from the resulting string? If you don't care about the time components and need to use only the date part of a DateTime object you can use its setTime() method to set the time components to 0.
What's the point of using str_replace() to manipulate the text representation of a date when you know its format? DateTime::createFromFormat() can be used to parse the string into a DateTime object.
There is no need to compute the difference of the two dates and the format it and compare the value to 0. The DateTime objects can be compared directly.
All in all, all the code you need is:
// Current date & time
$today = new DateTime();
// Ignore the time (change $today to "today at midnight")
$today->setTime(0, 0, 0);
// Parse the value retrieved from the database
$field = DateTime::createFromFormat('d/m/Y', $field_value);
// We don't care about the time components of $field either (because the time
// is not provided in the input string it is created using the current time)
$field->setTime(0, 0, 0);
// Directly compare the DateTime objects to see which date is before the other
if ($field < $today) {
echo "1";
} else {
echo "2";
}
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;
?>
function is_due($due_date)
{
$now=new DateTime('now');
$dnow=$now->format('Y-m-d');
$due=$due_date->format('Y-m-d');
$interval =(strtotime($dnow)-strtotime($due));
print_r($due_date->format('Y-m-d'));
return $interval;
}
i use that function to check if the given date is due
The $due_date is passed in after being retrieved from an external file as a string '2012-12-12' which is assigned as an array element, for example,
$datetime['due']=ReadExtFile();
When I call that function as print_r(is_due($datetime['due'])); or
$due=new DateTime($datetime['due']);
nothing seems to work, I see no output. But print_r($datetime) will display the result of [due].
The way this method is written, it expects $due_date to be a DateTime object, and not a string. You indicate you are passing in a string and not an object.
It looks like you just want to return $interval as a count of from the date given until now. I would suggest just using a simple method that only deals with strings.
function is_due($due_date) {
return time() - strtotime($due_date);
// return ((time() - strtotime($due_date)) >= 0); // depending on function you want this might work
}