I just ran into a strange bug that has occurs in PHP running in Pacific Time (and probably others). I had code to get the first day of a week (sunday) given an arbitrary date (in UNIX timestamp) in that week:
$day = date('w', $date);
$start_of_week = date('Y-m-d', $date - ($day * 60*60*24));
echo $start_of_week;
Prints 2014-03-08
This works for every single date that I've tried, except for those in the week of March 9th, 2014, which happens to be the week of daylight savings time in the US. For those, $start_of_week is '2014-03-08', which is a Saturday.
When I run this code with the timezone set to GMT, I get the correct output ('2014-03-09').
Additionally, when I change the code to the following in PST, I get the correct output:
$day = date('w', $date);
$start_of_week = date('Y-m-d', strtotime("-$day day", $date));
echo $start_of_week;
Prints 2014-03-09
So...WTF? Why is there a difference between strtotime("-1 day", $date) and $date - 60*60*24? Seems like it's jumping between different timezones.
codepad example
When you use -1 day, it uses the time-of-day from $date, and just changes the date. When you use - 60 * 60 * 24 it rolls the clock back 24 hours. On the day that DST changes, there are only 23 hours in the day, so it goes an hour too far.
– Barmar Mar 19 '14 at 22:11
Related
I have the following code which gets the date parsed, the subtracts 1 month. This works perfectly.
$date = '22-05-2016';
print(date("Y-m-d 23:59:59", strtotime($date.' -1 months')));
// outputs 2016-04-22 23:59:59
There are times where I need to force the date to month end. For this I use Y-m-t instead of Y-m-d Which works perfectly.
$date = '22-05-2016';
print(date("Y-m-t 23:59:59", strtotime($date.' -1 months')));
// outputs 2016-04-30 23:59:59
The problem comes when the date that is parsed is actually the last day of that month. It then flips to end of the next month.
$date = '31-05-2016';
print(date("Y-m-t 23:59:59", strtotime($date.' -1 months')));
Actual Output 2016-05-31 23:59:59 (hasn't removed 1 month)
Desired Output 2016-04-30 23:59:59
EDIT: Fiddle example http://ideone.com/0fqlor
Try:
$date = '31-05-2016';
print(date("Y-m-d 23:59:59", strtotime($date.' last day of last month')));
and dig into strtotime possibilities ;)
Take a look here: http://php.net/manual/en/datetime.formats.relative.php
Last Note: -1 month only gets 30 days back in time. Therefore it will not work allways. Some kind of PHP stuff, i think ;)
strtotime is your friend. The last day of any "given" month can be retrieved using the verbal String last day of May 2015 - so, for easy input (guess you have a date-picker not a month-picker), convert the selected date to its month expression first:
date_default_timezone_set('Europe/London');
$to = '31-05-2016';
$month = date("M Y", strtotime($to));
$strtotime_expression = "last day of " . $month;
echo $strtotime_expression.": <br />";
print(date("Y-m-t 23:59:59", strtotime($strtotime_expression)));
http://ideone.com/YvjVeP
Currently, I have the timezone set to America/New York.
I have a timestamp of 1448933400, thats Monday, November 30, 2015 - 08:30 PM. I would like to get a relative time from this current timestamp as the "First Sun of Next Month".
So I am doing the following code:
strtotime("First Sun of Next Month", 1448933400);
The problem I am having is, is the returned value of 1449378000.
This is not at 8:30 PM, but instead at 12:00 AM. Is there an easy way to get relative dates to retain the relative time of the source timestamp?
There are many possible answers, but what you can do is first calculate the time offset for the day of your timestamp and apply it to the result:
<?php
$stamp = 1448933400;
$offset = $stamp - strtotime(date("Y-m-d", $stamp));
var_dump(strtotime("First Sun of Next Month", $stamp) + $offset);
?>
Output
int(1449451800) // or "2015-12-06 20:30:00"
I have a script that gets the current and last month in PHP like so:
$currentMonth = date('m');
//Expected:07
//Result:07
$lastMonth = date('m', strtotime('-1 months'));
//Expected:06
//Result:07
Today happens to be the 31 or end of the month of July. Is this result to be expected from PHP?
When using -31 days the result is as expected:
$lastMonth = date('m', strtotime('-31 days'));
//Expected:06
//Result:06
Here's a cleaner test case that doesn't expire:
<?php
$origin = mktime(18, 0, 0, 7, 31, 2015);
var_dump( date('r', $origin), date('r', strtotime('-1 months', $origin)) );
string(31) "Fri, 31 Jul 2015 18:00:00 +0200"
string(31) "Wed, 01 Jul 2015 18:00:00 +0200"
I'm pretty sure it's a documentation issue, because the manual clearly states this (emphasis mine):
Relative month values are calculated based on the length of months
that they pass through. An example would be "+2 month 2011-11-30",
which would produce "2012-01-30". This is due to November being 30
days in length, and December being 31 days in length, producing a
total of 61 days.
... and it's wrong.
PHP bug tracker has tons of dupes about this. They're all closed as not a bug. Here's a relevant comment from 2009 that explains it:
I agree that this is an annoying behaviour.
Also, the implementation is problematic. Basically if you use '+1
month' it takes the month number, adds 1 and parses result as a new
date.
If you use '+1 month' on the first of the month, it sets the date to
the next first of the month.
This behaviour gives the impression, that php considers the length of
a month, which is not true.
But if you use '+1 month' on the last day of a month, the result is
unexpected as 2009-05-31 becomes 2009-06-31 which is an invalid date
and then interpreted as 2009-07-01.
This should at least be mentioned in the documentation.
You can do this way
$d = new DateTime();
$currentMonth = $d->format('m');
//Expected:07
//Result:07
print $currentMonth;
$d->modify('first day of previous month');
print "<br/>";
$lastMonth = $d->format('m');
//Expected:06
//Result:06
print $lastMonth;
DEMO: http://codepad.viper-7.com/kokWi8
This is a issue with PHP's date-string parser. See here:
http://derickrethans.nl/obtaining-the-next-month-in-php.html
#Mr. Llama made a script showing what other dates this issue effects:http://codepad.viper-7.com/E4gP0W
The solution I went with:
//Date:07/31/15
$currentMonth = date('m');
//Result:07
$lastMonth = date('m', strtotime('first day of -1 months'));
//Result:06
-1 month is interpreted as "same day of month, last month". If this day does not exist, the date overflows into the next month. Actually the result is the same as strtotime("31.6.2015") - try it!
There is "s" in excess in month. It should be like this:
$lastMonth = date('m', strtotime('-1 month'));
I'm trying to calculate the difference in days between two dates. I'm getting bizzare behaviour - I've narrowed it down to 6th and 7th October, 2013, as you can see below. Whenever the date range spans those dates, the calculation is a day out.
// WRONG! current year - 2013
$datediff = strtotime('2013-10-07') - strtotime('2013-10-06');
$startToEndDays = floor($datediff/(60*60*24));
print_r($startToEndDays); // Outputs 0 - should output 1
// RIGHT! next year - 2014
$datediff = strtotime('2014-10-07') - strtotime('2014-10-06');
$startToEndDays = floor($datediff/(60*60*24));
print_r($startToEndDays); // Outputs 1 - correct
Any idea what could be the issue here?
haha OK, it turns out 6th/7th October 2013 is when daylight savings starts in Sydney, Australia. So, the number of hours between those dates is calculated (correctly) as 23. But, 23 hrs is not quite a day.
If you're using PHP 5.3+, then this is how you should calculate the difference between dates in days, to save yourself any daylight savings headaches:
$startDate = new DateTime('2013-10-07');
$endDate = new DateTime('2013-10-06');
$interval = $startDate->diff($endDate);
$days = $interval->days;
I expected this functional to return 6/30/2005 instead of 7/1/2005.
print date("m/d/Y", strtotime("12/31/2004 +6 month"));
Similarly, print date("m/d/Y", strtotime("1/31/2011 +1 month")) returns 03/03/2011 while would like it to return 2/28/2011.
Does anyone know if there is a straight forward way to show the last day of the added month?
How about this?
echo date("m/d/Y", strtotime("last day of 12/31/2004 + 6 month")); // 6/30/2005
echo date("m/d/Y", strtotime("last day of 1/31/2011 + 1 month")); // 2/28/2011
Demo
Edit: For your reference, here is a link to the documentation for relative times.
as strtotime continue in to next month if there isn't enoghe days that month,
you can back 6 month and check if its end up on the start date
$date2 = date("Y-m-d", strtotime("{$date} +6 months"));
$date3 = date("Y-m-d", strtotime("{$date2} -6 months"));
if($date3 != $date)
{
$date2 = date("Y-m-t", strtotime("{$date2} -1 months"));
}
(or in your case "m/t/Y")
One simple way is to actually go one month ahead of the day you want and then make the day value zero. Also, mktime() might be easier
$mymonth = 2; // I want the last day of February
echo date('m/d/Y', mktime(0,0,0,$mymonth+1,0,2011));
This should return 2/28/2011.
strtotime does the best it can with conflicting information. Saying
1/31/2011 +1month
would mean advancing to
2/31/2011
but February only has 28 (sometimes 29) days. 2011 isn't a leap year, so the "31st of February" gets normalized to "March 3rd".
The same applies for '12/31/2004 +6month'. That takes you to June 31st, 2005. But June only has 30 days, so the date is normalized to July 1st instead.