Weird PHP date incrementation - php

I was trying to do a loop to find the weekends between two dates and something was really damn strange.
I have to following code which in my opinion should be working fine.
$weekends = array();
// yyyy-mm-dd
$firstWeekend = '2015-09-04';
$lastWeekend = '2015-12-25';
$firstWeekendTime = strtotime($firstWeekend);
$lastWeekendTime = strtotime($lastWeekend);
$totalWeekends = 0;
for ($i = $firstWeekendTime; $i <= $lastWeekendTime; $i += (7 * 86400)) {
$totalWeekends++;
$weekends[date('Y-m-d', $i)] = array(
date('Y-m-d', $i),
date('Y-m-d', strtotime(date('Y-m-d', $i) . '+ 2 days'))
);
}
Eg. output:
[2015-10-16] => Array
(
[0] => 2015-10-16
[1] => 2015-10-18
)
[2015-10-23] => Array
(
[0] => 2015-10-23
[1] => 2015-10-25
)
[2015-10-29] => Array
(
[0] => 2015-10-29
[1] => 2015-10-31
)
[2015-11-05] => Array
(
[0] => 2015-11-05
[1] => 2015-11-07
)
But this is not correct cause the next weekend after 2015-10-23 is 2015-10-30.
So the output should be this:
[2015-10-16] => Array
(
[0] => 2015-10-16
[1] => 2015-10-18
)
[2015-10-23] => Array
(
[0] => 2015-10-23
[1] => 2015-10-25
)
[2015-10-30] => Array
(
[0] => 2015-10-30
[1] => 2015-11-01
)
[2015-11-05] => Array
(
[0] => 2015-11-05
[1] => 2015-11-07
)
I finally made it work by putting a default timezone and without chaning anything else, it worked.
date_default_timezone_set('America/Los_Angeles');
Can someone understand why does this incrementation fail without the timezone?
And the weirdest thing is that it only fails around ~2015-10-25
I don't want other options to find the weekend... i just want to understand why it acts like this.
Thank you.

Just you have to change the for loop condition with increment value like this
for ($i = $firstWeekendTime; $i <= $lastWeekendTime; $i = strtotime(date('Y-m-d', strtotime(date('Y-m-d', $i) . '+ 7 days'))))
instead of
for ($i = $firstWeekendTime; $i <= $lastWeekendTime; $i += (7 * 86400))

Related

Apply a function on value multidimentionnal array PHP

I have an array with the hours of production like this (the number of array is not fixed, somethimes we can have production in January, not in february, and restart in March etc...) :
Array
(
[0] => Array
(
[Month] => 8
[HoursProd] => 181.37
)
[1] => Array
(
[Month] => 9
[HoursProd] => 699.35
)
[2] => Array
(
[Month] => 10
[HoursProd] => 500.25
)
[3] => Array
(
[Month] => 11
[HoursProd] => 350.61
)
)
I want to divide the hours in my array by the number of hours in the month. Get the month key (number of th month), calculate the number of hours in this month, and divide my Hours value by this number.
For the number of hours, i write this code for try to have the total of hours in a month.:
$m = 1;
$a = date('m');
$y = date("y");
$result2 = array();
for($m; $m <= 12; $m++){
$d=cal_days_in_month(CAL_GREGORIAN,$m,$y);
$result2[]["HoursTotalMonth"] = $d * 24;
$result2[]["Month"] = $m;
$t = $d * 24;
//To simplify the problem, i try to convert Hours of the month in the same array of production, and wheen the value of month is the same, divise value hours prod by value of hours total month
$test[] = array("Month" => $m, "HoursTotalMonth" => $t);
};
I try lot of things whithout success. The goal being at the end to be able to create a Json file to create a chart with ChartJS, The goal being at the end to be able to create a Json file to create a graph with ChartJS, with the production hour / hour ratio of the month in percentage. I succeed with a simple array but not with an associative multidimentional array.
Ex : [Month] => 8
[RatioHoursProdOnHoursTotalMonth] => 24.37 // (181.37 / (31j*24h))
I want this array :
Array
(
[0] => Array
(
[Month] => 8
[RatioHoursProdOnHoursTotalMonth] => 24.37
)
[1] => Array
(
[Month] => 9
[RatioHoursProdOnHoursTotalMonth] => 97.13
)
[2] => Array
(
[Month] => 10
[RatioHoursProdOnHoursTotalMonth] => 67.23
)
[3] => Array
(
[Month] => 11
[RatioHoursProdOnHoursTotalMonth] => 48.69
)
)
To be able to use the Json encoder, like this one:
[{"Month":8,"RatioHoursProdOnHoursTotalMonth":24.37},{"Month":9,"RatioHoursProdOnHoursTotalMonth":97.13},{"Month":10,"RatioHoursProdOnHoursTotalMonth":67.23},{"Month":11,"RatioHoursProdOnHoursTotalMonth":48.69}]
Is it what you expect as output ?
$a = date('m');
$y = date("y");
$result = array();
$data = array(100,60,75,90,58,98,105,85,74,685,700,550);
for ($m = 1; $m <= 12; $m++){
$d = cal_days_in_month(CAL_GREGORIAN, $m, $y);
$result[] = [
"Heure" => $d * 24,
"Mois" => $m,
"ratio" => $data[$m - 1] * 100 / ($d * 24),
];
};
print_r($result);
With the help of #Melvyn Marigny, the code below make the output i want.
$m = 1;
$a = date('m');
$y = date("y");
$nb = count($result);
for ($m = 1; $m <= $nb; $m++){
$d = cal_days_in_month(CAL_GREGORIAN, $m, $y);
$result3[] = [
"Mois" => $result[$m - 1]["Mois"],
"HeureProd" => $result[$m - 1]["Heure"],
"HeureMois" => $d * 24,
"ratio" => $result[$m - 1]["Heure"] / ($d * 24),
];
}
print_r($result3);
Array
(
[0] => Array
(
[Mois] => 8
[HeureProd] => 181.37
[HeureMois] => 744
[ratio] => 0.24377688172043
)
[1] => Array
(
[Mois] => 9
[HeureProd] => 753.39
[HeureMois] => 696
[ratio] => 1.0824568965517
)
[2] => Array
(
[Mois] => 10
[HeureProd] => 1292.25
[HeureMois] => 744
[ratio] => 1.7368951612903
)
[3] => Array
(
[Mois] => 11
[HeureProd] => 376.11
[HeureMois] => 720
[ratio] => 0.522375
)

Filter multidimensional array and push in new one

I am trying to build a class schedule that takes a .csv with data for the whole semester. I have this multidimensional array, which contains the date, class, instructor, room, and notes for every day of the semester:
Array (
Array (
[0] => 1
[1] => 2019-04-02
[2] => Study Skills
[3] => 371
[4] => Mr Teacher
[5] => 0
[6] =>
)
Array ( ... )
...)
I managed to display the schedule for the whole semester in one table. However, ideally, I would filter out the data for each month and then push in into a new multidimensional array for the whole semester.
I was able to filter out individual months by comparing it a to hardcoded string but I obviously don't want to do that for the whole semester:
$may = "05";
$classMay = [];
foreach ($days as $day){
if (strrpos($day[1], $may, -5)){
array_push($classMay, $day);
}
};
Is there a more efficient solution to this?
Any insight is much appreciated!
Just get the month name from the date of each one and append the day data onto an array indexed by the month:
foreach($days as $day) {
$month = date('F', strtotime($day[1]));
$result[$month][] = $day;
}
Now you should have an array that looks similar to this:
Array
(
[January] => Array
(
[0] => Array
(
[0] => 1
[1] => 2019-01-01
//etc
)
[1] => Array
(
[0] => 3
[1] => 2019-01-02
//etc
)
)
[February] => Array
(
[0] => Array
(
[0] => 10
[1] => 2019-02-01
//etc
)
[1] => Array
(
[0] => 30
[1] => 2019-02-02
//etc
)
)
)
For fun you could loop 12 months and filter on the month:
foreach(range(1, 12) as $m) {
$month = date('F', strtotime($m));
$result[$month] = array_filter($days, function($v) use($month) {
return $month == date('F', strtotime($v[1]));
});
}

Error of index while filling an array in php

The first step is to create an new array with zeros. This is the code:
$amounts = [];
$row = [];
for($a = 0; $a < count($receipts_with_total); $a++){
for($b = 0; $b < count($taxes); $b++){
$row[$b] = 0;
}
$amounts[] = $row;
}
Then, i proceede to fill the array with values. The problem is, for some reason i don't know, it adds some indexs.
The code to fill the array is the next one:
//We calculate all the taxes amounts
for($i = 0; $i < count($receipts_with_total); $i++){
$this_receipt = $receipts_with_total[$i];
//We get all the taxes for each receipt
$taxes = $this_receipt->taxes;
for($j = 0; $j < count($taxes); $j++){
$this_tax = $taxes[$j];
if($this_tax->name == "IVA 21%"){
$amounts[$i][$j] = round((($this_tax->value * $total[$i]) / 100), 2);
}
elseif($this_tax->name == "IVA 10.5%"){
$amounts[$i][$j+1] = round((($this_tax->value * $total[$i]) / 100), 2);
}
else {
$amounts[$i][$j+2] = round((($this_tax->value * $total[$i]) / 100), 2);
}
}
}
And the outputs are:
Creacion
Array ( [0] => Array ( [0] => 0 [1] => 0 [2] => 0 ) [1] => Array ( [0] => 0 [1] => 0 [2] => 0 ) [2] => Array ( [0] => 0 [1] => 0 [2] => 0 ) [3] => Array ( [0] => 0 [1] => 0 [2] => 0 ) )
Modelo
Array ( [0] => Array ( [0] => 0 [1] => 257.46 [2] => 61.3 ) [1] => Array ( [0] => 0 [1] => 40.36 [2] => 9.61 ) [2] => Array ( [0] => 80.73 [1] => 40.36 [2] => 9.61 ) [3] => Array ( [0] => 211.05 [1] => 105.53 [2] => 0 ) )
Lleno
Array ( [0] => Array ( [0] => 0 [1] => 257.46 [2] => 0 [3] => 61.3 ) [1] => Array ( [0] => 0 [1] => 40.37 [2] => 0 [3] => 9.61 ) [2] => Array ( [0] => 80.73 [1] => 0 [2] => 40.37 [4] => 9.61 ) [3] => Array ( [0] => 211.05 [1] => 0 [2] => 105.53 ) )
The first output is the new array with zeros. The second one is an example of as should be the final array with the calculate numbers. The last one is the array really i get.
As you can see, the index in bold represent the errors. For example, the value "61.3" is in fourth position in the first array, instead of third, it would be the correct.
Thanks!
Remove the +1 and +2 from the code.
Just
$amounts[$i][$j]=...
in all cases.
Because if i.e.
$j=2;
it may be become 3 in your code $j+1
My answer just pick that part of your question:
The problem is, for some reason i don't know, it adds some indexs.
I guess you want to show the "IVA 21" always in the 0 index in subarray and "IVA 10.5" always in the 1 index in sub array, and so on...? So you don't have to +1 or +2 in the index...cuz $j has already been increment in the for loop...
Or if you don't know which comes first or maybe you will have more option later, do not use a for loop. Use php foreach and keep +1 manually
$j = 0;
foreach ($taxes as $$this_tax) {
if ($this_tax->name == 'IVA 21%') {
$amounts[$i][$j] = round((($this_tax->value * $total[$i]) / 100), 2);
} elseif ($this_tax->name == 'IVA 10.5%') {
$amounts[$i][$j + 1] = round((($this_tax->value * $total[$i]) / 100), 2);
} else {
$amounts[$i][$j + 2] = round((($this_tax->value * $total[$i]) / 100), 2);
}
//myabe +3 later...
}
Or why not just use a static number like 0,1,2 if you always know the length of $taxes and where you gonna put for your results. You can even create conts like:
define('IVA21', 0); // const IVA21 = 0;
define('IVA105', 1);
// ... more define
//for loop starts
if ($this_tax->name == 'IVA 21%') {
$amounts[$i][IVA21] = round((($this_tax->value * $total[$i]) / 100), 2);
}

Manipulating arrays of dates in PHP

I'm having a lot of difficulty approaching a piece of code in PHP. I have an array of dates and values, for example
dates = (2014-12-01,2014-12-02,2014-12-08,2014-12-09,2014-12-10,2014-12-11)
values = (5,3,7,8,9,2)
You'll note that 12/01 is a Monday, as is 12/08. I'd like to form 4 arrays from these two arrays:
monday = (5,7)
tuesday = (3,8)
wednesday = (0,9)
thursday = (0,2)
You'll note that the arrays are formed by grabbing the values associated with the days of the week. However, in the case that a Wednesday date exists, for example, but the prior Tuesday does not, then the array should have a "0". In other words, the 4 arrays should all be the same length.
Can anyone help me write code in PHP to achieve this? Thanks in advance!
NOTE: So far, I have only determined how to find the day of the week from a date: date('l', strtotime("2014-12-08")); I really can't figure out the general algorithm to solve this.
$dates = array( '2014-12-01','2014-12-02','2014-12-08','2014-12-09',
'2014-12-10','2014-12-11' );
$values = array( 5, 3, 7, 8, 9, 2 );
$date = strtotime(min($dates));
$stop = strtotime(max($dates));
$dates = array_flip($dates);
$out = array();
while($date <= $stop)
{
$tmp = date('Y-m-d', $date);
$out[date('l', $date)][] = isset($dates[$tmp]) && isset($values[$dates[$tmp]]) ?
$values[$dates[$tmp]] : 0;
$date = strtotime('+1 day', $date);
}
print_r($out);
Result:
Array
(
[Monday] => Array
(
[0] => 5
[1] => 7
)
[Tuesday] => Array
(
[0] => 3
[1] => 8
)
[Wednesday] => Array
(
[0] => 0
[1] => 9
)
[Thursday] => Array
(
[0] => 0
[1] => 2
)
[Friday] => Array
(
[0] => 0
)
[Saturday] => Array
(
[0] => 0
)
[Sunday] => Array
(
[0] => 0
)
)
ps: how can I get the an array of all the dates included in the "dates" array associated with only all the Mondays?
Modify the code as, for example:
$tmp = date('Y-m-d', $date);
$exists = isset($dates[$tmp]) && isset($values[$dates[$tmp]]);
$out[date('l', $date)]['numbers'][] = $exists ? $values[$dates[$tmp]] : 0;
if ($exists) $out[date('l', $date)]['dates'][] = $tmp;
$date = strtotime('+1 day', $date);
You'll get an output as (example for monday)
[Monday] => Array
(
[numbers] => Array
(
[0] => 5
[1] => 7
)
[dates] => Array
(
[0] => 2014-12-01
[1] => 2014-12-08
)
)
Might be a better way to get the 0s in there without another loop but I'm headed out:
foreach($dates as $key => $val) {
$day = date('l', strtotime($val));
$result[$day][] = $values[$key];
}
foreach($result as &$val) {
if(count($val) == 1) {
array_unshift($val, 0);
}
}
print_r($result);

Fill in missing elements of an array of date objects in PHP [duplicate]

This question already has answers here:
Push rows with default values into an array containing dates so there are no gaps between dates
(4 answers)
Closed 5 months ago.
I have an array of objects in php which looks like:
Array
(
[0] => Array
(
[day] => 1/23/2013
[executions] => 1
)
[1] => Array
(
[day] => 1/24/2013
[executions] => 1
)
[2] => Array
(
[day] => 1/27/2013
[executions] => 10
)
[3] => Array
(
[day] => 1/29/2013
[executions] => 1
)
[4] => Array
(
[day] => 1/30/2013
[executions] => 3
)
[5] => Array
(
[day] => 2/8/2013
[executions] => 1
)
[6] => Array
(
[day] => 2/11/2013
[executions] => 3
)
)
I am building a graph of this data, and basically it represents the last 30 days. The problem is I don't get the missing days, i.e. when there was no executions from the query. I am looking to fill in these missing days with PHP, simple set the day to the correct date, and executions to 0. Thus the result array should contain 30 elements, assuming start is 1/18/2013 and end is today 2/17/2013.
Any idea of the best algorithm to accomplish this in PHP?
Something like:
$start = '1/18/2013';
$end = '2/17/2013';
$range = new DatePeriod(
DateTime::createFromFormat('m/d/Y', $start),
new DateInterval('P1D'),
DateTime::createFromFormat('m/d/Y', $end));
$filler = array();
foreach($range as $date)
$filler[] = array(
'day' => $date->format('m/d/Y'),
'execution' => 0,
};
$array += $filler;
Loop through each date using DateTime:
$start = new DateTime('2013-01-18');
$end = new DateTime('2013-02-17');
while ($start <= $end)
{
$current_date = $start->format('m/d/Y');
// Right here look in your array and see if that date exists
// and do whatever you need to do if it does/does not
$start->modify("+1 day");
}
You may use this:
$startDate = new DateTime ( "-30 days" );
$dateItter = new DatePeriod (
$startDate,
new DateInterval ('P1D'),
30
);
$original = array (
array (
'days' => '02/16/2013',
'executions' => 5
)
);
$result = array ();
foreach ( $dateItter as $date )
{
$executions = 0;
foreach ( $original as $item ) {
if ( $item['days'] == $date->format ( 'm/d/Y' ) )
$executions = $item['executions'];
}
$result[] = array (
"day" => $date->format ( 'm/d/Y' ),
"executions" => $executions
);
}
var_dump ( $result );
It is slow for large amount of data but for 30 items will be ok!

Categories