I like to iterate through all weeks in a date range that spawns 2 years. Starting at the current week number two years ago, until the current week number this year.
The problem is that a year can either have 52 weeks or 53 weeks, for example:
2015 had 53 weeks (the 53th was from 2015-12-28 till 2016-01-03)
2016 had 52 weeks (the 52th was from 2016-12-26 till 2017-01-01)
So this is currently my php code:
# start with the current week 2 years ago
$year = date("Y") - 2;
$week = (int) date("W"); // (int) removes leading zero for weeks < 10
$endYear = date("Y");
$endWeek = (int) date("W");
# iterate through all weeks until now
do {
echo $week. " of ". $year;
$week++;
if ($week > 52) { // or greater 53 ?????????????
$year ++;
$week = 1;
}
}
while ($year < $endYear || $week < $endWeek);
Instead of trying to keep track of the bounds, let PHP do it for you.
$start = new DateTime('-2 years');
$end = new DateTime();
$interval = new DateInterval('P1W');
$period = new DatePeriod($start, $interval, $end);
foreach ($period as $date) {
echo $date->format('W') . " of ". $date->format('Y') . "\n";
}
Demo
With the help of Ross Wilson and John Conde I found a solution:
$now = new DateTime;
$from = (new DateTime)->setISODate($now->format('Y') - 2, $now->format('W'));
$from->modify("thursday this week"); // see ISO 8601
while($from < $now) {
echo $from->format('W Y').'<br />';
$from->modify("+1 week");
}
It is important so set the week day to thursday, because according to ISO 8601, the week "belongs" to the year which still contains the thursday.
You could use DateTime and setISODate for something like this:
$now = new DateTime;
$from = (new DateTime)->setISODate($now->format('Y') - 2, $now->format('W'));
while($from < $now) {
echo $from->format('W Y').'<br />';
$from->modify("1 week");
}
Hope this helps!
Related
How to enlist all the days between for instance 2018-06-04 and 2018-06-10 that between 2018-06-04 - 2018-06-10 those days will be 2018-06-05, 2018-06-06, 2018-06-07, 2018-06-08, 2018-06-09, the same goes for 2018-06-11 - 2018-06-17 and so on...
So far I'ive managed to divide month into week chunks (below), I want to further divide weeks into days...
2018-06-04 - 2018-06-10
2018-06-11 - 2018-06-17
2018-06-18 - 2018-06-24
2018-06-25 - 2018-07-01
http://zakodowac.pl/
This is my PHP code which produces week chunks above 2018-06-04 - 2018-06-10 and so on...:
function getMondays($y, $m) {
return new DatePeriod(
new DateTime("first monday of $y-$m"),
DateInterval::createFromDateString('next monday'),
new DateTime("last day of $y-$m")
);
}
function list_week_days($year, $month) {
foreach (getMondays($year, $month) as $monday) {
echo $monday->format(" Y-m-d\n");
echo '-';
$sunday = $monday->modify('next Sunday');
echo $sunday->format(" Y-m-d\n");
echo '<br>';
}
}
list_week_days(2018, 06);
could you try this:
$begin = strtotime('2018-06-04');
$end = strtotime('2018-06-10');
while($begin < $end){
$begin = $begin +84600;
echo date('Y-m-d', $begin) . ' ';
}
if correctly understood, then the following should yield the results you expect:
// set current date
$date = '04/30/2009';
// parse about any English textual datetime description into a Unix timestamp
$ts = strtotime($date);
// calculate the number of days since Monday
$dow = date('w', $ts);
$offset = $dow - 1;
if ($offset < 0) {
$offset = 6;
}
// calculate timestamp for the Monday
$ts = $ts - $offset*86400;
// loop from Monday till Sunday
for ($i = 0; $i < 7; $i++, $ts += 86400){
print date("m/d/Y l", $ts) . "\n";
}
if you want to be even more clever, you can use:
// set current date
$date = '04/30/2009';
// parse about any English textual datetime description into a Unix timestamp
$ts = strtotime($date);
// find the year (ISO-8601 year number) and the current week
$year = date('o', $ts);
$week = date('W', $ts);
// print week for the current date
for($i = 1; $i <= 7; $i++) {
// timestamp from ISO week date format
$ts = strtotime($year.'W'.$week.$i);
print date("m/d/Y l", $ts) . "\n";
}
All of which, alongside more information, can be found on this website and credit goes to the author of that post.
I get this outcome when I do the week of each year
week of45 date:2017-11-06
week of46 date:2017-11-13
week of47 date:2017-11-20
week of48 date:2017-11-27
week of49 date:2017-12-04
week of50 date:2017-12-11
week of51 date:2017-12-18
week of52 date:2017-12-25
week of1 date:1969-12-31
week of2 date:1969-12-31
week of3 date:1969-12-31
week of4 date:1969-12-31
week of5 date:1969-12-31
As you can see when it starts from 1 again, the date gets messed up,
here is the code:
for($i=0;$i< 13;$i++) {
$weekNumnew = $weekNum + $i;
$week_date = date('Y-m-d', strtotime("$thisYear-W$weekNumnew-1"));
if($weekNumnew > '52'){
$weekNumnew = $weekNumnew - 52;
$week_date = date('Y-m-d', strtotime("$nextyear-W$weekNumnew-1"));
}
echo "week of" . $weekNumnew . " date:" .$week_date . "<br>";
}
$weekNumnew starts from 45 it increase each week depending on the week of year date. Also $thisYear = '2017' & $nextyear = '2018'
Is there a way I can fix this? I thought it would be fixed when I added next year but it did not work, can anyone help?
You can use a combination of DateInterval and DatePeriod to generate these data for you:
<?php
$start = new DateTime('now');
$end = new DateTime('+3 years');
$interval = DateInterval::createFromDateString('1 week');
$period = new DatePeriod($start, $interval, $end);
foreach ($period as $week) {
$monday = $week->modify('monday this week');
printf("Week %d. Date: %s \n", $monday->format('W'), $monday->format('Y-m-d'));
}
EDITED directly to the problem :
The code :
<?php
$date = new DateTime('2000-01-31'); // or whatever
for ($i = 0; $i < 100; $i++) {
$currentDay = $date->format('d');
if ($currentDay < $date->format('t')) {
$date->modify('+1 month');
if ($date->format('d') < $currentDay) {
$date->modify('last day of previous month');
}
} else {
$date->modify('last day of next month');
}
echo $date->format('Y-m-d') . "<br>";
}
So, if starting date is 2000-01-31, it works fine. That's just because 31 is the last day of january, so, any other month it will put the last date of the month.
But, if u change starting date to 2000-01-30, it's broken. That's because 30 january is not the last day in january. But anyway, 30 january is greater than days in february, so it transform date to 28/29 february. Since 28/29 february is the last day in february, it proceed the code like when this date == number of days in the month, and on the next iteration instead of putting 30 march, it puts 'last day of next month' (31 of march).
And that's not the unique case. Same thing if u put starting date for example 30-08-2000. 30 is not the last day of august, so it change the date to 30 of september, 30 september is the last day of the september, so it change the date to 31 of octomber, but it's not what I expect.
If I've understood your question correctly then this should be what you're after:
$date = new DateTime('2000-01-31'); // or whatever
$day = $date->format('d');
$date->setDate($date->format('Y'), $date->format('m'), 1);
for ($i = 0; $i < 100; $i++) {
$date->modify('+1 month');
echo echo $date->format('t') < $day ? $date->format('Y-m-t') : $date->format('Y-m-' . $day);
echo '<br />';
}
Hope this helps!
Do I understand correctly that
you want to print the same day for all following months
in case it's higher than the maximum days in the month, last day of that month should be used instead
If yes, this could work:
<?php
$date = new DateTime('2000-01-28'); // or whatever
#echo $date->format('d')." ".$date->format('t');
$expectedDay = $date->format('d');
$month = $date->format('m');
$year = $date->format('Y');
for ($i = 0; $i < 100; $i++) {
echo $date->format('Y-m-d') . "<br>";
if ($month++ == 12) {
$year++;
$month = 1;
}
$date->modify("${year}-${month}-1");
if ($expectedDay > $date->format('t')) {
$day = $date->format('t');
} else {
$day = $expectedDay;
}
$date->modify("${year}-${month}-${day}");
}
I'm having trouble getting "weeks" in DateTime::diff function
Here's my code:
$date1 = new DateTime("2017-05-14");
$date2 = new DateTime("2017-06-14");
$interval = $date1->diff($date2);
echo $interval->m.' '.($interval->m > 1 ? 'months' : 'month');
It worked if I'm going to get the "month" count, but I want to get the weeks before turning it into a month:
We have 4 weeks in a month (4.34524 to be exact from Google Unit Converter), if the difference between start date and the date today exceeds 4 weeks, it should output "1 month" and so on..
Code (Demo):
$date1 = new DateTime("2017-06-1");
$date2 = new DateTime("2017-06-15");
$interval = $date1->diff($date2);
//var_export($interval);
if($interval->m>0){ // check if >= 1 month
echo "{$interval->m} month",($interval->m>1?'s':'');
}else{
$weeks=floor($interval->days/7); // if not yet 1 month, calc weeks
echo "$weeks week",$weeks!=1?'s':'';
}
// output: 2 weeks
Calculate days and then divide by 7 for week.
Try this code :
$date1 = new DateTime("2017-05-14");
$date2 = new DateTime("2017-06-14");
$interval = $date1->diff($date2);
$week = floor($date1->diff($date2)->days/7);
echo $week;
if($week > 4)
{
echo $interval->m.' '.($interval->m > 1 ? 'months' : 'month');
}
you could do this to get weeks and then make the condition:
$daysInAweek = 7;
$weeks = ($interval->days)/$daysInAweek;
if($weeks >= 4) {
echo 'is a month';
}
because a week have 7 days.
I'd like to work with PHP DateInterval to iterate through months:
$from = new DateTime();
$from->setDate(2014, 1, 31);
$period = new DatePeriod($from, new DateInterval('P1M'), 12);
I'd expect it to returns 31 January, 28 February (as the DateInterval is 1 month), but it actually returns 31 January, 3 March, 3 of April... hence skipping February.
Is there any way to do this simply?
Thanks!
EDIT : as a refernece, here is a solution that seems to cover most use cases:
$date = new DateTime('2014-01-31');
$start = $date->format('n');
for ($i = 0; $i < 28; $i++) {
$current = clone $date;
$current->modify('+'.$i.' month');
if ($current->format('n') > ($start % 12) && $start !== 12) {
$current->modify('last day of last month');
}
$start++;
echo $current->format('Y-m-d').PHP_EOL;
}
You can use DateTime::modify():
$date = new DateTime('last day of january');
echo $date->format('Y-m-d').PHP_EOL;
for ($i = 1; $i < 12; $i++) {
$date->modify('last day of next month');
echo $date->format('Y-m-d').PHP_EOL;
}
EDIT: I think I didn't understand your question clearly. Here is a new version:
$date = new DateTime('2014-01-31');
for ($i = 0; $i < 12; $i++) {
$current = clone $date;
$current->modify('+'.$i.' month');
if ($current->format('n') > $i + 1) {
$current->modify('last day of last month');
}
echo $current->format('Y-m-d').PHP_EOL;
}
The issue is cause by the variance between the last day in each of the months within the range. ie. February ending on 28 instead of 31 and the addition of 1 month from the last day 2014-01-31 + 1 month = 2014-03-03 https://3v4l.org/Y42QJ
To resolve the issue with DatePeriod and simplify it a bit, adjust the initial date by resetting the specified date to the first day of the specified month, by using first day of this month.
Then during iteration, you can modify the date period date by using last day of this month to retrieve the bounds of the currently iterated month.
Example: https://3v4l.org/889mB
$from = new DateTime('2014-01-31');
$from->modify('first day of this month'); //2014-01-01
$period = new DatePeriod($from, new DateInterval('P1M'), 12);
foreach ($period as $date) {
echo $date->modify('last day of this month')->format('Y-m-d');
}
Result:
2014-01-31
2014-02-28
2014-03-31
2014-04-30
2014-05-31
2014-06-30
2014-07-31
2014-08-31
2014-09-30
2014-10-31
2014-11-30
2014-12-31
2015-01-31
Then to expand on this approach, in order to retrieve the desired day from the specified date, such as the 29th. You can extract the specified day and adjust the currently iterated month as needed when the day is out of bounds for that month.
Example: https://3v4l.org/SlEJc
$from = new DateTime('2014-01-29');
$day = $from->format('j');
$from->modify('first day of this month'); //2014-01-01
$period = new DatePeriod($from, new DateInterval('P1M'), 12);
foreach ($period as $date) {
$lastDay = clone $date;
$lastDay->modify('last day of this month');
$date->setDate($date->format('Y'), $date->format('n'), $day);
if ($date > $lastDay) {
$date = $lastDay;
}
echo $date->format('Y-m-d');
}
Result:
2014-01-29
2014-02-28 #notice the last day of february is used
2014-03-29
2014-04-29
2014-05-29
2014-06-29
2014-07-29
2014-08-29
2014-09-29
2014-10-29
2014-11-29
2014-12-29
2015-01-29
You may try like this:
$date = new DateTime();
$lastDayOfMonth = $date->modify(
sprintf('+%d days', $date->format('t') - $date->format('j'))
);
I would do it probably like this
$max = array (
31,28,31,30,31,30,31,31,30,31,30,31
); //days in month
$month = 1;
$year = 2014;
$day = 31;
$iterate = 12;
$dates = array();
for ($i = 0;$i < $iterate;$i++) {
$tmp_month = ($month + $i) % 12;
$tmp_year = $year + floor($month+$i)/12;
$tmp_day = min($day, $max[$tmp_month]);
$tmp = new DateTime();
$tmp->setDate($tmp_year, $tmp_month + 1, $tmp_day);
$dates[] = $tmp;
}
var_dump($dates);
This keeps to the same day each month if possible