My server has many application instances.
I came across a problem that one of my application instance needs to be tested with the future date. i.e I want to test the application as it is running in 2013.
If i change the system date then it will work fine but the other instances will also get effected.
I want the future date for only one instance and the rest should work as it is.
i.e if i use date('Y-m-d'); it should jump for 3 months and display the future date.
and i dont want to add seconds to the default date as that might be a huge change in my application.
And that's why you write your application in a way that is testable.
Not good:
function doSomething() {
$date = date('Y-m-d');
...
}
Good:
function doSomething($ts = null) {
if (!$ts) {
$ts = time();
}
$date = date('Y-m-d', $ts);
...
}
you can make your own date function. It would serve as a hook to all date usage.
function mydate($format) {
$jump = ' +3 months';
return date($format, strtotime(date($format) . $jump));
}
you can than change all occurrences of date to mydate. If you decide to switch back to present, just leave $jump = ''
You can just do
date('Y-m-d', time() + 3 * 30 * 24 * 3600);
I recommend using the PHP5 DateTime classes. They're a bit more wordy, but much more powerful than the old-style PHP date handling functions.
$dateNow = new DateTime();
$dateAhead = $dateNow->add(DateInterval::createFromDateString('3 months'));
print $dateAhead->format('Y-m-d');
Related
I have these two functions:
function time_is_older_than($timestamp, $time_string)
{
if (strtotime($timestamp) < strtotime('-' . $time_string))
return true;
return false;
}
function time_is_younger_than($timestamp, $time_string)
{
if (strtotime($timestamp) > strtotime('-' . $time_string))
return true;
return false;
}
They enable me to do neat things like:
if (time_is_older_than($last_time_some_action_happened, '5 minutes'))
do_it_again();
They normally work, except for during one hour every six months, when my timezone switches over to "summer time" or "winter time". This means that the clocks are increased or put back one hour at midnight (according to this timezone).
The PHP manual states this for strtotime:
The Unix timestamp that this function returns does not contain information about time zones. In order to do calculations with date/time information, you should use the more capable DateTimeImmutable.
However, if I provide the exact same date/time string, with "+08:00" added in the end versus "+00:00", for example, I get different numbers of seconds returned. So strtotime() does understand timezones when it parses the provided time, even if the returned integer obviously doesn't contain this information. (Nor is it expected or required to by me.)
I've spent countless hours trying to debug this, testing countless things, and just sitting here thinking, but I can't figure out what exactly would make the code I have fail, specifically for one hour. And especially what about it I need to change. Setting the second parameter for strtotime() seems likely, but I just couldn't make it work correctly.
My hottest "lead" for quite some time was that the strtotime('-' . $time_string) part is ending up using a different timezone than the timestamp strings provided, but I do provide timezone data to it most of the time! An example of $last_time_some_action_happened might be something like 2020-10-28 02:22:41.123456+01.
I set the timezone with date_default_timezone_set().
I suspect that I only need to make some very minor change, but I've been experimenting so much and so long now, even taking rests in between, that my brain can no longer see this clearly. I bet the solution is something awfully simple.
Please don't tell me to use DateTimeImmutable. This would fundamentally change my entire structure and require me to do things very differently. Perhaps I should, and even will, at some point, but for now, I just wish to fix this rare but still very annoying bug in my existing code. (If it's possible at all, which I very much believe is the case.)
I'm able to reproduce the issue you are having:
date_default_timezone_set('Pacific/Auckland');
// Daylight saving time 2020 in New Zealand began at 2:00am on Sunday, 27 September
$current = strtotime('2020-09-27 02:04:00');
$d1 = strtotime('2020-09-27 02:05:00', $current);
$d2 = strtotime('-5 minutes', $current);
var_dump($d1 > $d2); // false
var_dump(date('Y-m-d H:i:s', $d1)); // 2020-09-27 03:05:00
var_dump(date('Y-m-d H:i:s', $d2)); // 2020-09-27 03:59:00
This person looks to be having the same issue as you and may appear to be a bug.
DateTime::modify and DST switch
The solution is to convert the dates to UTC then compare:
// Convert to UTC and compare
$d1 = new \DateTime('2020-09-27 02:05:00', new \DateTimeZone('Pacific/Auckland'));
$d2 = new \DateTime('2020-09-27 02:04:00', new \DateTimeZone('Pacific/Auckland'));
$d2->setTimezone(new \DateTimeZone('UTC'));
$d2->modify('-5 minutes');
$d2->setTimezone(new \DateTimeZone('Pacific/Auckland'));
var_dump($d1 > $d2); // true
var_dump($d1->format(\DateTimeInterface::RFC3339_EXTENDED)); // 2020-09-27T03:05:00.000+13:00
var_dump($d2->format(\DateTimeInterface::RFC3339_EXTENDED)); // 2020-09-27T01:59:00.000+12:00
I've updated your functions:
function time_is_older_than($datetime, $time_string)
{
$d1 = new \DateTime($datetime);
$d1->setTimezone(new \DateTimeZone('UTC'));
$d2 = new \DateTime();
$d2->setTimezone(new \DateTimeZone('UTC'));
$d2->modify('-' . $time_string);
return $d1 < $d2;
}
function time_is_younger_than($datetime, $time_string)
{
$d1 = new \DateTime($datetime);
$d1->setTimezone(new \DateTimeZone('UTC'));
$d2 = new \DateTime();
$d2->setTimezone(new \DateTimeZone('UTC'));
$d2->modify('-' . $time_string);
return $d1 > $d2;
}
Could you consider a solution:
In the timestamp string(like Thu, 21 Dec 2000 16:01:07 +0200), add a timezone tag which specify timezone without difference of daylight saving time.
Im trying to get the difference between 2 differente dates in minutes, but is not outputting correctly.
Ex:
$then = "2017-01-23 18:21:24";
//Convert it into a timestamp.
$then = strtotime($then);
//Get the current timestamp.
$now = time();
//Calculate the difference.
$difference = $now - $then;
//Convert seconds into minutes.
$minutes = floor($difference / 60);
echo $minutes;
Is outputting 611 minutes, and is wrong since from "2017-01-23 18:21:24" to "2017-01-24 12:36:24" it past much more than 611 minutes. Is my code incorrect?
Try to set your default timezone
date_default_timezone_set('Europe/Copenhagen');
Ofc change Europe/Copenhagen for the one that suits your needs.
If you are using or able to use PHP 5.3.x or later, you can use its DateTime object functionality:
$date_a = new DateTime('2010-10-20 08:10:00');
$date_b = new DateTime('2008-12-13 10:42:00');
$interval = date_diff($date_a,$date_b);
echo $interval->format('%h:%i:%s');
You can play with the format in a variety of ways, and once you have dates in DateTime objects, you can take advantage of a lot of different functionality, for example comparison via normal operators. See the manual for more: http://us3.php.net/manual/en/datetime.diff.php
I've checked your code it works perfectly So if have any doubt see your result
But you got wrong, so to ignore this set your timezone.
I need to create a PHP script that pulls the timestamps of various stuff from a database (logs, messages, logins, etc) and removes them if they are older than X amount of days. I am poor at doing work with time and am a bit stumped on the best way to do this.
I realize I could separate the day/month/year in the string using explode() and compare these with a bunch of If statements, but would like to use a more efficient method. Something like the following would be the correct way to do this correct?
$dt = "2011-03-19 10:05:44";
//if $dt is older than 90 days
if((time()-(60*24*90)) > strtotime($dt))
{
}
Subtract (minutes*hours*days) from time() or are the numbers wrong?
You can use DateTime class for this. Example:
$dt = "2011-03-19 10:05:44";
$date = new DateTime($dt);
$now = new DateTime();
$diff = $now->diff($date);
if($diff->days > 90) {
echo 'its greater than 90 days';
}
This question already has answers here:
How we can add two date intervals in PHP
(4 answers)
Closed 9 years ago.
I have two DateTime object.
$time1 = new DateTime('01:04:00');
$time2 = new DateTime('00:13:22');
Addition of this two will be : 01:17:22. How can I do it?
A "time of day" is not the same thing as a "duration of time". It doesn't makes sense to add together two time of day values - regardless of platform or language. Think about it - what does "11:00 PM" + "4:00 AM" equal? It's a nonsensical question.
You should be thinking about PHP's DateInterval class, not the DateTime class.
It should be noted that if you follow the examples on the dup posts of using strtotime it will work only when each individual input, and the final result, are all under 24 hours. Why? Because that's the maximum amount of time allowed in a standard day. That's the consequence of mixing "time of day" with "duration of time".
This should work for you:
function time_to_interval($time) {
$parts = explode(':',$time);
return new DateInterval('PT'.$parts[0].'H'.$parts[1].'M'.$parts[2].'S');
}
function add_intervals($a,$b) {
$zerodate = new DateTime('0000-01-01 00:00:00');
$dt = clone $zerodate;
$dt->add($a);
$dt->add($b);
return $zerodate->diff($dt);
}
function format_interval_hhmmss($interval){
$totalhours = $interval->h + ($interval->d * 24);
return $totalhours.$interval->format(':%I:%S');
}
$interval1 = time_to_interval('01:04:00');
$interval2 = time_to_interval('00:13:22');
$interval3 = add_intervals($interval1,$interval2);
echo format_interval_hhmmss($interval3);
Note that the choice of value for $zerodate isn't really all that important. It's just that some reference point is required, since PHP doesn't provide operations directly on DateInterval.
Also note that the the DateInterval::format function doesn't have a formatter to get you total number of hours inclusive of days, so if there's any chance the total could be 24 hours or more, then you have to format that part yourself, like I showed in the format_interval_hhmmss function.
Also note that my PHP skills are not all that great, so there may be a more efficient way to write these functions.
function addtime($time1,$time2)
{
$x = new DateTime($time1);
$y = new DateTime($time2);
$interval1 = $x->diff(new DateTime('00:00:00')) ;
$interval2 = $y->diff(new DateTime('00:00:00')) ;
$e = new DateTime('00:00');
$f = clone $e;
$e->add($interval1);
$e->add($interval2);
$total = $f->diff($e)->format("%H:%I:%S");
return $total;
}
The only built-in DateTime add/substract methods require using a DateInterval. e.g
$t1 = new DateTime('01:04:33');
$new = $t1->add(new DateInterval('PT13M22S'));
^^^^^^---13 minutes, 22 seconds
however, note that since DateTime works on DATES as well as times, you can't just slam together two times like this and expect to get reliable results. Consider what happens if you're doing the addition on an interval that happens to span a daylight savings border, or crosses over a day boundary, etc...
I am running a service hosted on a server in the US which reads an XML feed that has been created with a local date - currently just the UK, but I want to ensure the service works with all timezones.
My process looks at the date of a post in a feed and compares it with the date/time right now(on the server in the US).
The solution I came up with localises the system to the originator of the feed and then creates a timestamp with which to compare 'now' with:
protected function datemath($thedate){
$currenttimezone = date_default_timezone_get();
date_default_timezone_set($this->feedtimezone);
$thedate = mktime substr($thedate,11,2),substr($thedate,14,2),
substr($thedate,17,2),substr($thedate,3,2),substr($thedate,0,2),
substr($thedate,6,4));
date_default_timezone_set($currenttimezone);
return $thedate;
}
My question is this... Is this a reasonable way of handling this issue or is there a better, more standardized way that I really should know?
Here's a function I wrote to do timezone conversions. Should be pretty self-explanatory:
function switch_timezone($format, $time = null,
$to = "America/Los_Angeles", $from = "America/Los_Angeles")
{
if ($time == null) $time = time();
$from_tz = new DateTimeZone($from);
$to_tz = new DateTimeZone($to);
if (is_int($time)) $time = '#' . $time;
$dt = date_create($time, $from_tz);
if ($dt)
{
$dt->setTimezone($to_tz);
return $dt->format($format);
}
return date($format, $time);
}
After a bit more checking of other peoples code I see the function
strtotime($thedate);
is a little bit more succinct than using mktime and also allows for different time formats.