PHP relative month not producing expected result [duplicate] - php

This question already has answers here:
Removing exactly one month from a date
(2 answers)
Closed 8 years ago.
So, I am working with subtracting relative months. According to the documentation:
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.
I understand why the example when adding months, but I don't understand why 2014-12-31 -1 month produces 2014-12-01. Its 31 days in December, shouldn't the result be the last of November?
Example code. Function 1 produces the result I was expecting from function 2 and 3.
//Func 1
$date = '2014-12-31 23:59:59'; //YYYY-MM-DD
$days = 0;
echo $date.'<br>';
for ($i = 1; $i < 13; $i++) {
$days += cal_days_in_month(CAL_GREGORIAN, (13-$i), 2014);
echo date("Y-m-d H:i:s", strtotime("-$days days", strtotime($date))).'<br>';
}
echo "<br><br>";
//Func 2
$date = '2014-12-31 23:59:59'; //YYYY-MM-DD
echo $date.'<br>';
for ($i = 1; $i < 13; $i++) {
echo date("Y-m-d H:i:s", strtotime("-$i months", strtotime($date))).'<br>';
}
//Func 3
echo "<br><br>";
$dateObj = new DateTime("2014-12-31 23:59:59");
echo $dateObj->format("Y-m-d H:i:s").'<br>';
$dateIntervalObj = new DateInterval("P1M");
for ($i = 0; $i < 12; $i++) {
echo $dateObj->format("Y-m-d H:i:s").'<br>';
$dateObj->sub($dateIntervalObj);
}
Result:
2014-12-31 23:59:59
2014-11-30 23:59:59
2014-10-31 23:59:59
2014-09-30 23:59:59
2014-08-31 23:59:59
2014-07-31 23:59:59
2014-06-30 23:59:59
2014-05-31 23:59:59
2014-04-30 23:59:59
2014-03-31 23:59:59
2014-02-28 23:59:59
2014-01-31 23:59:59
2013-12-31 23:59:59
2014-12-31 23:59:59
2014-12-01 23:59:59
2014-10-31 23:59:59
2014-10-01 23:59:59
2014-08-31 23:59:59
2014-07-31 23:59:59
2014-07-01 23:59:59
2014-05-31 23:59:59
2014-05-01 23:59:59
2014-03-31 23:59:59
2014-03-03 23:59:59
2014-01-31 23:59:59
2013-12-31 23:59:59
2014-12-31 23:59:59
2014-12-31 23:59:59
2014-12-01 23:59:59
2014-11-01 23:59:59
2014-10-01 23:59:59
2014-09-01 23:59:59
2014-08-01 23:59:59
2014-07-01 23:59:59
2014-06-01 23:59:59
2014-05-01 23:59:59
2014-04-01 23:59:59
2014-03-01 23:59:59
2014-02-01 23:59:59

seems to always round up:
2014-10-31 +1 month => 2014-12-01 // this makes sense
2014-12-31 -1 month => 2014-12-01 // this doesn't
in both cases if the day does not exist, it uses the day after it.

Related

Is there an idea to jump Sunday date (the iteration number 7) in this code and show all dates?

I want help to show dates without Sunday(date) and show the day of( 2019-
07-27).
I want result like this : twice (Monday -> Saturday) between 2019-07-15
and 2019-07-27. this exemple is just for 2 iterations ($arrayOfMerchs)
but the number of day is 12(static) without Sunday.
Note : the date change every time. Exp :[2019-07-29 to 2019-08-10],[2019-08-12 to 2019-08-24] ...etc
If there is another way to get this code better I'm so thankful.
I want result like this:
2019-07-15 00:00:00 //Monday
2019-07-16 00:00:00
2019-07-17 00:00:00
2019-07-18 00:00:00
2019-07-19 00:00:00
2019-07-20 00:00:00 //Saturday
2019-07-22 00:00:00 //Monday
2019-07-23 00:00:00
2019-07-24 00:00:00
2019-07-25 00:00:00
2019-07-26 00:00:00
2019-07-27 00:00:00 // Saturday
2019-07-15 00:00:00 //Monday
2019-07-16 00:00:00
2019-07-17 00:00:00
2019-07-18 00:00:00
2019-07-19 00:00:00
2019-07-20 00:00:00 //Saturday
2019-07-22 00:00:00 //Monday
2019-07-23 00:00:00
2019-07-24 00:00:00
2019-07-25 00:00:00
2019-07-26 00:00:00
2019-07-27 00:00:00 //Saturday
This is my script :
<?php
$begin = new DateTime('2019-07-15');
$end = new DateTime('2019-07-27');
$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($begin, $interval, $end);
$arrayOfMerchs = array(1,2);
$arrayofPlannings = array(1,2,3,4,5,6,7,8,9,10,11,12);
$cpt = 0;
foreach ($arrayOfMerchs as $merch) {
foreach ($arrayofPlannings as $planning) {
foreach ($period as $dt) {
$cpt ++;
if($cpt == 7){continue;}
echo $dt->format("Y-m-d H:i:s")."<br>";
}
break;
}
echo " "."<br>";
}
The result of this code like:
2019-07-15 00:00:00
2019-07-16 00:00:00
2019-07-17 00:00:00
2019-07-18 00:00:00
2019-07-19 00:00:00
2019-07-20 00:00:00 //
2019-07-22 00:00:00
2019-07-23 00:00:00
2019-07-24 00:00:00
2019-07-25 00:00:00
2019-07-26 00:00:00
// date of2019-07-27 00:00:00 not showing
2019-07-15 00:00:00
2019-07-16 00:00:00
2019-07-17 00:00:00
2019-07-18 00:00:00
2019-07-19 00:00:00
2019-07-20 00:00:00
2019-07-21 00:00:00 // I dont want to show Sunday
2019-07-22 00:00:00
2019-07-23 00:00:00
2019-07-24 00:00:00
2019-07-25 00:00:00
2019-07-26 00:00:00
// date of2019-07-27 00:00:00 not showing
You can do something like:
$start = new DateTime('2019-06-01');
$end = new DateTime('2019-06-30');
$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($start, $interval, $end);
$notSundayDates = [];
foreach ($period as $day) {
//check if day of the week is sunday
if ($day->format('w') !== "0") {
$notSundayDates[] = $day;
}
}
You can use date() and strtotime()
$date_to_test = "<calculated_date_time_here>";
if(date("w",strtotime($date_to_test)) == 0){
// it's a sunday so skip to the next iteration of the loop
continue;
}
You can use that when looping through the dates, you don't need H:i:s to calculate the day but it doesn't matter if it is included.

PHP DateInterval Jan - June and July - Dec

Trying to create a list or date interval for the past 2 years, divided into ranges of 6 months, i.e. Jan - June 2015, July - Dec 2015, Jan - June 2016 ... until today.
I have looked into DateTime and DateInterval, something like this
$begin = new DateTime( '2015-01-01' );
$end = new DateTime( '2017-12-26' );
$interval = new DateInterval('P6M');
$period = new DatePeriod($begin, $interval, $end);
foreach ( $period as $dt )
echo sprintf("%s\n", $dt->format("Y-m-d"));
Which gives me
2015-01-01
2015-07-01
2016-01-01
2016-07-01
2017-01-01
2017-07-01
Can't figure out how to get start and end (Jan 1 - June 30 and July 1 - Dec 31) for each period.
After adding an interval, subtract one day from it. Use sub() and new DateInterval('P1D'), which indicates subtraction of one day.
foreach ( $period as $dt )
echo sprintf(
"%s %s\n",
$dt->format("Y-m-d"),
$dt->add($interval)
->sub(new DateInterval('P1D'))
->format("Y-m-d"));
This outputs:
2015-01-01 2015-06-30
2015-07-01 2015-12-31
2016-01-01 2016-06-30
2016-07-01 2016-12-31
2017-01-01 2017-06-30
2017-07-01 2017-12-31
Update: In the comments you also asked how to indicate what half of the year the date represents. The answer is too obvious:
sprintf(
"%s %s %d\n",
$dt->format("Y-m-d"),
$dt->add($interval)
->sub(new DateInterval('P1D'))
->format("Y-m-d"),
$dt->format("n")/6
);
Note %d and corresponding $dt->format("n")/6.
Output for me:
2015-01-01 2015-06-30 1
2015-07-01 2015-12-31 2
2016-01-01 2016-06-30 1
2016-07-01 2016-12-31 2
2017-01-01 2017-06-30 1
2017-07-01 2017-12-31 2
you can just add the interval size '-1' for each start like this:
$begin = new DateTime( '2015-01-01' );
$end = new DateTime( '2017-12-26' );
$interval = new DateInterval('P6M');
$period = new DatePeriod($begin, $interval, $end);
$oneDay = new DateInterval("P1D");
$oneDay->invert=1; #just get the previous day as if("P-1D")
foreach ( $period as $dt ){
echo $dt->format("Y-m-d"); #interval start
$dt->add($interval); #adding the interval size
$dt->add($oneDay); #get the last day of the cur interval
echo "<br>";
echo $dt->format("Y-m-d"); #interval end
echo "<br>";
}

How to get start and end of the week between two dates

I have two dates
$start_date = '2015-09-21';
$end_Date = '2016-09-21';
What i want to get like this
Week = Monday Friday
36 = 2015-09-21 2015-09-25
37 = 2015-09-28 2015-10-02
38 = 2015-10-05 2015-10-09
.
.
38 = 2016-09-19 2016-09-24
The date difference may be of one year or more. What i need to get is exact each week Monday and Friday dates between this time interval.
I used this method
$weeks = array();
while ($start_date < $end_Date )
{
$weeks[] = date('W', $start_date );
$start_date += strtotime('+1 week', 0);
}
function getStartAndEndDate($week, $year)
{
$time = strtotime("1 January $year", time());
$day = date('w', $time);
$time += ((7*$week)+1-$day)*24*3600;
$return[0] = date('Y-m-d', $time);
$time += 6*24*3600;
$return[1] = date('Y-m-d', $time);
return $return;
}
When i call this function, I need to put week number and year to get exact dates. But I cant get year with the particular week. I can managed to get week from the start date or end date.
$current_year = date("Y", strtotime($fromdate));
Any one suggest me to get the exact year with the week number
First of all you need to convert the time into object, after that calculate the difference. Now calculate the weeks between the given dates. Now its time loop through the weeks from start date, I use DateInterval('P4D') to ahead the date by 4 days and then echo two dates then again DateInterval('P3D') to complete the week and this is repeated.
$start_date = '2015-09-21';
$end_Date = '2016-09-21';
$date1 = new DateTime($start_date);
$date2 = new DateTime($end_Date);
$interval = $date1->diff($date2);
$weeks = floor(($interval->days) / 7);
for($i = 1; $i <= $weeks; $i++){
$week = $date1->format("W");
$date1->add(new DateInterval('P4D'));
echo $week." = ".$start_date." - ".$date1->format('Y-m-d')."<br/>";
$date1->add(new DateInterval('P3D'));
$start_date = $date1->format('Y-m-d');
}
Output:
39 = 2015-09-21 - 2015-09-25
40 = 2015-09-28 - 2015-10-02
41 = 2015-10-05 - 2015-10-09
42 = 2015-10-12 - 2015-10-16
43 = 2015-10-19 - 2015-10-23
44 = 2015-10-26 - 2015-10-30
45 = 2015-11-02 - 2015-11-06
46 = 2015-11-09 - 2015-11-13
47 = 2015-11-16 - 2015-11-20
48 = 2015-11-23 - 2015-11-27
49 = 2015-11-30 - 2015-12-04
50 = 2015-12-07 - 2015-12-11
51 = 2015-12-14 - 2015-12-18
52 = 2015-12-21 - 2015-12-25
53 = 2015-12-28 - 2016-01-01
01 = 2016-01-04 - 2016-01-08
02 = 2016-01-11 - 2016-01-15
03 = 2016-01-18 - 2016-01-22
04 = 2016-01-25 - 2016-01-29
05 = 2016-02-01 - 2016-02-05
06 = 2016-02-08 - 2016-02-12
07 = 2016-02-15 - 2016-02-19
08 = 2016-02-22 - 2016-02-26
09 = 2016-02-29 - 2016-03-04
10 = 2016-03-07 - 2016-03-11
11 = 2016-03-14 - 2016-03-18
12 = 2016-03-21 - 2016-03-25
13 = 2016-03-28 - 2016-04-01
14 = 2016-04-04 - 2016-04-08
15 = 2016-04-11 - 2016-04-15
16 = 2016-04-18 - 2016-04-22
17 = 2016-04-25 - 2016-04-29
18 = 2016-05-02 - 2016-05-06
19 = 2016-05-09 - 2016-05-13
20 = 2016-05-16 - 2016-05-20
21 = 2016-05-23 - 2016-05-27
22 = 2016-05-30 - 2016-06-03
23 = 2016-06-06 - 2016-06-10
24 = 2016-06-13 - 2016-06-17
25 = 2016-06-20 - 2016-06-24
26 = 2016-06-27 - 2016-07-01
27 = 2016-07-04 - 2016-07-08
28 = 2016-07-11 - 2016-07-15
29 = 2016-07-18 - 2016-07-22
30 = 2016-07-25 - 2016-07-29
31 = 2016-08-01 - 2016-08-05
32 = 2016-08-08 - 2016-08-12
33 = 2016-08-15 - 2016-08-19
34 = 2016-08-22 - 2016-08-26
35 = 2016-08-29 - 2016-09-02
36 = 2016-09-05 - 2016-09-09
37 = 2016-09-12 - 2016-09-16
$start_date = '2015-09-21';
$end_Date = '2016-09-21';
$startTime = strtotime($start_date);
$endTime = strtotime($end_Date);
$weeks = array();
$date = new DateTime();
$i=0;
while ($startTime < $endTime) {
$weeks[$i]['week'] = date('W', $startTime);
$weeks[$i]['year'] = date('Y', $startTime);
$date->setISODate($weeks[$i]['year'], $weeks[$i]['week']);
$weeks[$i]['Monday']=$date->format('Y-m-d');
$weeks[$i]['Friday'] = date('Y-m-d',strtotime($weeks[$i]['Monday'] . "+4 days"));
$startTime += strtotime('+1 week', 0);
$i++;
}
var_dump($weeks);

Split DateTime interval to single days

I have a PHP script which receives a set of Events from a database with begin/end DateTimes, which represent working times.
Begin | End
2013-08-14 10:00:00 | 2013-08-22 09:30:00
2013-08-08 07:00:00 | 2013-08-08 15:00:00
2013-08-09 07:00:00 | 2013-08-10 07:00:00
Now I want to calculate how much has been worked each single day. For the first row I would want an output like that:
Begin | End
2013-08-14 10:00:00 | 2013-08-14 23:59:59
2013-08-15 00:00:00 | 2013-08-15 23:59:59
2013-08-16 00:00:00 | 2013-08-16 23:59:59
....
2013-08-22 00:00:00 | 2013-08-22 09:30:00
I've seen some things with DatePeriod and DateInterval, but those didn't take time into account.
Thanks for your help.
DatePeriod and DateInterval DO take time into account, so you can use those classes.
Your data :
$intervals = [
['begin' => '2013-08-14 10:00:00', 'end' => '2013-08-22 09:30:00'],
['begin' => '2013-08-08 07:00:00', 'end' => '2013-08-08 15:00:00'],
['begin' => '2013-08-09 07:00:00', 'end' => '2013-08-10 07:00:00'],
];
Quick function I wrote :
function explodePeriodByDays($begin, $end) {
$days = [];
$dayInterval = new DateInterval('P1D');
$begin = new DateTime($begin);
$end = new DateTime($end);
$_end = clone $end;
$_end->modify('+1 day');
foreach ((new DatePeriod($begin, $dayInterval, $_end)) as $i => $period) {
$_begin = $period;
if ($i) $_begin->setTime(0, 0, 0);
if ($_begin > $end) break;
$_end = clone $_begin;
$_end->setTime(23, 59, 59);
if ($end < $_end) $_end = $end;
$days[] = [
'begin' => $_begin,
'end' => $_end,
];
}
return $days;
}
Example of function use :
foreach ($intervals as $interval) {
echo "Day intervals from {$interval['begin']} to {$interval['end']} : \n";
foreach (explodePeriodByDays($interval['begin'], $interval['end']) as $day) {
echo "\t {$day['begin']->format('Y-m-d H:i:s')} | {$day['end']->format('Y-m-d H:i:s')}\n";
}
echo "\n";
}
Output of the example :
Day intervals from 2013-08-14 10:00:00 to 2013-08-22 09:30:00 :
2013-08-14 10:00:00 | 2013-08-14 23:59:59
2013-08-15 00:00:00 | 2013-08-15 23:59:59
2013-08-16 00:00:00 | 2013-08-16 23:59:59
2013-08-17 00:00:00 | 2013-08-17 23:59:59
2013-08-18 00:00:00 | 2013-08-18 23:59:59
2013-08-19 00:00:00 | 2013-08-19 23:59:59
2013-08-20 00:00:00 | 2013-08-20 23:59:59
2013-08-21 00:00:00 | 2013-08-21 23:59:59
2013-08-22 00:00:00 | 2013-08-22 09:30:00
Day intervals from 2013-08-08 07:00:00 to 2013-08-08 15:00:00 :
2013-08-08 07:00:00 | 2013-08-08 15:00:00
Day intervals from 2013-08-09 07:00:00 to 2013-08-10 07:00:00 :
2013-08-09 07:00:00 | 2013-08-09 23:59:59
2013-08-10 00:00:00 | 2013-08-10 07:00:00
If I am understanding this correctly, you want to get the difference between a begin date and an end date.
I would go about converting the time with a strtotime, subtract the timestamps, then output the date.
$begin = strtotime("2013-08-14 10:00:00");
$end = strtotime("2013-08-14 23:59:59");
$difference = ($end - $begin);
echo gmdate("H:i:s", $difference);
This would give you the time in hours, minutes, then seconds.

Getting first day of every week in 6 months

I'm trying to figure out how can I get the the first day of week for the last 6 months and can't get to a working solution.
If I write date("Y-m-d 00:00:00", strtotime("-1 week", date("Y-m-d")); It just subtracts 7 days from the current date; what I want to do is to always return the date of Monday from that week.
Expected result:
2011-8-8 00:00:00
2011-8-1 00:00:00
2011-7-25 00:00:00
2011-7-18 00:00:00
etc
This should do it:
for ($i=0; $i<52/2; $i++)
echo date('Y-m-d', mktime(1, 0, 0, date('m'), date('d')-date('w')-$i*7+1, date('Y'))) . " 00:00:00\n";
it's slightly changed from Mike's Post, who wants the sunday instead of the monday.
I'd recommend DateTime::createFromFormat.
Pre-PHP 5.3, you can use strtotime instead:
<?php
define('NUM_WEEKS', 10);
$dates = Array();
$dates[] = strtotime('Monday');
for ($i = 0; $i < NUM_WEEKS-1; $i++)
$dates[] = strtotime('-1 week', $dates[$i]);
foreach ($dates as $date)
echo strftime('%c', $date) . "\n";
?>
Output:
Mon Aug 22 00:00:00 2011
Mon Aug 15 00:00:00 2011
Mon Aug 8 00:00:00 2011
Mon Aug 1 00:00:00 2011
Mon Jul 25 00:00:00 2011
Mon Jul 18 00:00:00 2011
Mon Jul 11 00:00:00 2011
Mon Jul 4 00:00:00 2011
Mon Jun 27 00:00:00 2011
Mon Jun 20 00:00:00 2011
Live demo.
If you're trying to make Saturday (or any other day for that matter)
the first day of the week to select datasets, here's a good
workaround:
<?php $last_sat=date("z", strtotime("last Saturday"));
$second_last_sat=date("z", strtotime("last Saturday-1 week")); ?>
source: http://www.php.net/manual/en/function.strtotime.php
What you'd probably want is
<?php $last_mon=date("z", strtotime("last Monday "));
$second_last_mon=date("z", strtotime("last Monday-1 week")); ?>
etc..

Categories