DateTime, +1 week and -1 week not working the same - php

I have a couple of functions juggling back and forth with weeks.
One surprising, and unwanted, behavior I discovered was this:
$date = new DateTime();
$date->setISODate(2014, 52);
$date->modify('+1 week');
echo date('YW', $date->getTimestamp()) . '<br />';
$date->setISODate(2014, 01);
$date->modify('-1 week');
echo date('YW', $date->getTimestamp()) . '<br />';
This code prints:
201401
201352
My expectation was:
201501
201352
Three questions:
1) Have I done something wrong in the code above or is there an inconsistent behavior between "+1 week" and "-1 week" (as in year not being stepped in the first case)?
Answer from comment:
It never increase/decrease year but week 1 happens to start in December 2013 thus it seems like it decrease year in the "-1 week" example.
2) If there is an inconsistency, can I trust the code will work the same on various platforms and PHP versions?
Answer:
No inconsistency (see accepted answer)
3) Is there a better way to step 1 week backward and forward in time (input is year and week, output is also year and week)?
bonus question) If there actually is an inconsistency, does anyone know why?
Answer:
No inconsistency, see answer on number 1 for explanation

Y is year from the date
o is ISO-8601 year number
W is ISO-8601 week number of year
if using 'W' for the week number use 'o' for the year.

Related

reset week counter when crossing the new year

I am taking week number from given date, but I observed date('W',strtotime("2015-12-31")); and date('W',strtotime("2016-01-01")); returns week number 53, because year is changed but week doesn't , so is there any way to reset week counter when crossing the new year?
Note: I am using php5.3
While technically correct, the answer PHP gives you may not be the one you were looking for. I suppose you could keep compatibility by calling that half week "week 0"
You would have to target the next Monday and then subtract 1 to the result. This for example should work for you:
<?php
echo date('W', strtotime('NEXT MONDAY', strtotime('2016-01-01'))) - 1;
As you can see, for the first of January you get the result int(0) which doesn't break compatibility the rest of the year, but works nicely for the year 2016.
NOTE: You will have to fix it for the last week of December yourself. But I hope this gives you a direction you can work with.
echo date('m') == 1? date('W', strtotime('NEXT MONDAY', time())) - 1 : date('W', time())
Could be an example.
here is your solution
This checks for month and checks get week as per your requirement
$w=(int)date('W', strtotime('2016-01-01'));
$m=(int)date('n', strtotime('2016-01-01'));
$week = $w==1?($m==12?53:1):($w>=51?($m==1?0:$w):$w);
echo $week;

PHP DateTime->diff dont works as expected [duplicate]

i'm trying to use the class DateTime (php>=5.3) to calculate difference from 2 date.
The example from the manual is simple and clear, i tried that example and work good.
But if a change the start and end date, there a problem:
$this->start_date = '2011-03-01';
$this->end_date = '2011-03-31';
var_dump($this->start_date, $this->end_date);
$datetime1 = new DateTime($this->start_date);
$datetime2 = new DateTime($this->end_date);
$interval = $datetime2->diff($datetime1);
echo $interval->format('%a total days')."\n";
echo $interval->format('%m month, %d days');
Output is:
30 total days //ok
1 month, 2 days //no! i think it should be 0 month, 30 days
With march don't work very well! :)
Aren't there 28 days in February? It might be picking February for the "month" unit for some reason or other. The PHP documentation for the method seems to suggest this kind of thing could easily be the case. Saying "x Months" isn't overly useful anyway as a month isn't a fixed unit, it could be 28, 29, 30 or 31 days.
Extract from the PHP dateinterval format documentation below.
The DateInterval::format() method does
not recalculate carry over points in
time strings nor in date segments.
This is expected because it is not
possible to overflow values like "32
days" which could be interpreted as
anything from "1 month and 4 days" to
"1 month and 1 day".

Month by week of the year?

I'm trying to get the number of the month of the year by the number of a week of the year and the year.
So for example week 1 is in january and returns 1, week 6 is in february so I want 2.
I tried to go with date_parse_from_format('W/Y') but had no success (it's giving me errors).
Is there any way to go with date_parse_from_format() or is there another way?
print date("m",strtotime("2011-W6-1"));
(noting that in 2011, January has six weeks so week 6 (by some definitions) is in month 1).
Just wanted to add a note for the first answer, the week number should be 01-09 for Weeks 1 through 9 (it will always give month 1 if you don't add the leading zero)
date("m",strtotime("2011-W06-1"));
Using PHP DateTime objects (which is the preferred way of dealing with dates see links below for more info) you can accomplish it this way:
$dateTime = new \DateTime();
$dateTime->setISODate($year,$week);
$month = $dateTime->format('n');
Note that the following will not work as week "W" is not a supported format:
$month = \DateTime::createFromFormat("W/Y ", "1/2015")->format('n');
The format used by this method is the same supported by the function you where trying to use date_parse_from_format, hence the errors.
Why PHP DateTime Rocks
DateTime class vs. native PHP date-functions
strtotime notes
PHP/Architect's Guide to Date and Time Programming (Chapter 2)
Something like this will do, this is also tested and works:
function getMonthByNumber($number,$year)
{
return date("F",strtotime('+ '.$number.' weeks', mktime(0,0,0,1,1,$year,-1)));
}
echo getMonthByNumber(27,2011);
Hope this helps

Error to calculate date diff with DateTime class

i'm trying to use the class DateTime (php>=5.3) to calculate difference from 2 date.
The example from the manual is simple and clear, i tried that example and work good.
But if a change the start and end date, there a problem:
$this->start_date = '2011-03-01';
$this->end_date = '2011-03-31';
var_dump($this->start_date, $this->end_date);
$datetime1 = new DateTime($this->start_date);
$datetime2 = new DateTime($this->end_date);
$interval = $datetime2->diff($datetime1);
echo $interval->format('%a total days')."\n";
echo $interval->format('%m month, %d days');
Output is:
30 total days //ok
1 month, 2 days //no! i think it should be 0 month, 30 days
With march don't work very well! :)
Aren't there 28 days in February? It might be picking February for the "month" unit for some reason or other. The PHP documentation for the method seems to suggest this kind of thing could easily be the case. Saying "x Months" isn't overly useful anyway as a month isn't a fixed unit, it could be 28, 29, 30 or 31 days.
Extract from the PHP dateinterval format documentation below.
The DateInterval::format() method does
not recalculate carry over points in
time strings nor in date segments.
This is expected because it is not
possible to overflow values like "32
days" which could be interpreted as
anything from "1 month and 4 days" to
"1 month and 1 day".

Get Last Monday - Sunday's dates: Is there a better way?

I'm preparing a query for mySQL to grab record from the previous week, but I have to treat weeks as Monday - Sunday. I had originally done this:
WHERE YEARWEEK(contactDate) = YEARWEEK(DATE_SUB(CURDATE(),INTERVAL 7 DAY))
to discover that mySQL treats weeks as Sunday - Monday. So instead I'm parsing getting the begin & end dates in php like this:
$i = 0;
while(date('D',mktime(0,0,0,date('m'), date('d')-$i, date('y'))) != "Mon") {
$i++;
}
$start_date = date('Y-n-j', mktime(0,0,0,date('m'), date('d')-($i+7), date('y')));
$end_date = date('Y-n-j', mktime(0,0,0,date('m'), date('d')-($i+1), date('y')));
This works - it gets the current week's date for monday (walking backwards until a monday is hit) then calculates the previous week's dates based on that date.
My question is: Is there a better way to do this? Just seems sloppy, and I expect someone out there can give me a cleaner way to do it - or perhaps not because I need Monday - Sunday weeks.
Edit
Apparently, there is:
$start = date('Y-m-d',strtotime('last monday -7 days'));
$end = date('Y-m-d',strtotime('last monday -1 days'));
That's about a million times more readable. Thank you.
you can use strtotime for this kind of date issues
echo strtotime("last Monday");
(complementing on marvin and Stomped ) Also you can use it this way
echo date('Y-m-d',strtotime('-1 Monday')); //last Monday
echo date('Y-m-d',strtotime('-2 Monday')); //two Mondays ago
echo date('Y-m-d',strtotime('+1 Monday')); //next Monday
strtotime("previous week Monday")
Monday of the previous week.
Marvin's answer is really elegant, although if you really wanted to go for performance you could do it with a little arithmetic. You could derive a formula/method to convert an arbitrary date to "days since some starting point" (probably 01.01.0000) and then the rest of the operations would be easy with that. Getting the day of week from such a number is as simple as subtracting and getting the remainder of a division.
Actually, PHP had a Date class in its PEAR library which did exactly this.
I have to point out for all the readers here there is a big issue with marvin's answer
Here is the catch
The "last Monday" function will return date the "latest" Monday.It will be explained like this , if today is Monday, then it will return the date of "LAST WEEK" Monday, however if today is not Monday, it will return "THIS WEEK" Monday
The Question is request to return "Last Week" Monday. Therefore the result will be incorrect if today is not Monday.
I have solved the issue and wrapped in my Date Time Helper
It will be only one line after you "INCLUDE" the class
$lastWeekMonday = Model_DTHpr::getLastWeekMonday();
Check Here
https://github.com/normandqq/Date-Time-Helper

Categories