I'm looping through an array of days in the current month to generate another array of days that are on or after the current day. I'm also doing the same for the next month (which will always include all days as they are after the current date).
The complexity is when the next month is in a different year to the current month. The format of the final array is like this:
array("year" => array("month" => array(days)));
When both months are in the same year it might look like this:
$allDays = array("2013" => array( "11" => array(28,29,30), "12" => array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31)));
When the 2 months are in different years (i.e. Dec and Jan) it might look like this:
$allDays = array("2013" => array("12" => array(2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31)), "2014" => array("1" => array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31) )) ;
Here's my code that generates the list of dates for the current month and the next month:
// Set the default timezone
date_default_timezone_set('Australia/Sydney');
// Get days for current month
$day = date("Y-m-d");
$i = strtotime($day);
array("year" => array("month" => array(days)));
$linked_days = array(
date('Y', $i) => array(
date('m') => range(date('d', $i), intval(date('t'))),
),
);
// Get days for next month
$day2 = date("Y-m-d", strtotime('first day of next month')) ;
$i2 = strtotime($day2);
array("year" => array("month" => array(days)));
$linked_days2 = array(
date('Y', $i2) => array(
date('m') => range(date('d', $i2), intval(date('t'))),
),
);
I'm not sure how to go about combining them into the 1 array with a different sytanx if they are in the same year or not?
You can check if there is already an entry for the year in your array with isset function :
Change this
$day2 = date("Y-m-d", strtotime('first day of next month')) ;
$i2 = strtotime($day2);
array("year" => array("month" => array(days)));
$linked_days2 = array(
date('Y', $i2) => array(
date('m') => range(date('d', $i2), intval(date('t'))),
),
);
To
$day2 = date("Y-m-d", strtotime('first day of next month')) ;
$i2 = strtotime($day2);
array("year" => array("month" => array(days))); //useless line ??
if(!isset($linked_days[date('Y', $i2)])){
//if no entry for this year in array, create new entry
$linked_days[date('Y', $i2)] = array(date('m') => range(date('d', $i), intval(date('t'))));
}
else{
//else, just add the month entry
$linked_days[date('Y', $i2)][date('m')] = range(date('d', $i2), intval(date('t'))) ;
}
Related
How can I get the Financial Year date range in PHP like below when I pass year and return date range of every year start and end.
Like Eg.
Input Array = [2017,2018]
Financial Start Month = 04
Output Array =
[
'2017' => [
'start' => '2016-04-01',
'end' => '2017-03-31'
],
'2018' => [
'start' => '2017-04-01',
'end' => '2018-03-31'
]
]
My Effort:-
$year_arr = [2017,2018];
$fn_month = 04;
$date_range_arr = [];
foreach ($year_arr as $key => $value) {
$fn_start_date_year = ($value - 1);
$fn_start_date_month = $fn_month;
$fn_start_date_day = '01';
$fn_start_date_string = $fn_start_date_year.'-'.$fn_start_date_month.'-'.$fn_start_date_day;
$start_date = date('Y-m-d',strtotime($fn_start_date_string));
$fn_end_date_year = ($value);
$fn_end_date_month = (fn_month == 1)?12:(fn_month-1);
$fn_end_date_day = date('t',strtotime($fn_end_date_year.'-'.$fn_end_date_month.'-01'));
$fn_start_date_string = $fn_end_date_year.'-'.$fn_end_date_month.'-'.$fn_end_date_day;
$end_date = date('Y-m-d',strtotime($fn_start_date_string));
$date_range_arr[$value] = [
'start_date' => $start_date,
'end_date' => $end_date
];
}
Above is my effort. It is working perfectly but needs a more robust code.
A good way to manipulate dates in PHP is using the DateTime class. Here's an example of how to get the results you want using it. By using the modify method, we can avoid worries about complications like leap years (see the result for 2016 below).
$year_arr = [2016,2017,2018];
$fn_month = 03;
foreach ($year_arr as $year) {
$end_date = new DateTime($year . '-' . $fn_month . '-01');
$start_date = clone $end_date;
$start_date->modify('-1 year');
$end_date->modify('-1 day');
$date_range_arr[$year] = array('start_date' => $start_date->format('Y-m-d'),
'end_date' => $end_date->format('Y-m-d'));
}
print_r($date_range_arr);
Output:
Array (
[2016] => Array (
[start_date] => 2015-03-01
[end_date] => 2016-02-29
)
[2017] => Array (
[start_date] => 2016-03-01
[end_date] => 2017-02-28
)
[2018] => Array (
[start_date] => 2017-03-01
[end_date] => 2018-02-28
)
)
Demo on 3v4l.org
Maybe this is what you need?
I use strtotime to parse the date strings.
$year_arr = [2017,2018];
$fn_month = 04;
$date_range_arr = [];
foreach($year_arr as $year){
$date_range_arr[$year] =['start' => date("Y-m-d", strtotime($year-1 . "-" .$fn_month . "-01")),
'end' => date("Y-m-d", strtotime($year . "-" .$fn_month . "-01 - 1 day"))];
}
var_dump($date_range_arr);
Output:
array(2) {
[2017]=>
array(2) {
["start"]=>
string(10) "2016-04-01"
["end"]=>
string(10) "2017-03-31"
}
[2018]=>
array(2) {
["start"]=>
string(10) "2017-04-01"
["end"]=>
string(10) "2018-03-31"
}
}
https://3v4l.org/nMUHt
Try this snippet,
function pr($a)
{
echo "<pre>";
print_r($a);
echo "</pre>";
}
$year_arr = [2017, 2018];
$fn_month = 4;
$date_range_arr = [];
foreach ($year_arr as $key => $value) {
$fn_month = str_pad(intval($fn_month),2, 0, STR_PAD_LEFT);
$date = "".($value-1)."-$fn_month-01"; // first day of month
$date_range_arr[$value] = [
'start_date' => $date,
'end_date' => date("Y-m-t", strtotime($date.' 11 months')), // last month minus and last date of month
];
}
pr($date_range_arr);
die;
str_pad - Pad a string to a certain length with another string
Here is working demo.
I am trying to write a script which will display either an open or closed message depending on a businesses operating hours. I tried using the solution found here and adding to this by setting the timezone. However when I try to run this the value of $status is always 'closed' even if the time of day falls within the values in the array.
Here is my code, any advice would be appreciated. Thanks
//setting default timezone
date_default_timezone_set('Europe/Dublin');
//creating array of opening hours
$openingHours = [
'Sun' => ['12:00' => '20:30'],
'Wed' => ['16:00' => '21:00'],
'Thu' => ['16:00' => '21:00'],
'Fri' => ['16:00' => '23:00'],
'Sat' => ['16:00' => '21:00']
];
//current timestamp
$timestamp = time();
//default status
$status = 'closed';
//get time object from timestamp
$currentTime = (new DateTime())->setTimestamp($timestamp);
//loop through time range for current day
foreach ($openingHours[date('D', $timestamp)] as $startTime => $endTime) {
//create time objects from start and end times
$startTime = DateTime::createFromFormat('h:i A', $startTime);
$endTime = DateTime::createFromFormat('h:i A', $endTime);
//check if current time is within range
if (($startTime < $currentTime) && ($currentTime < $endTime)) {
$status = 'open';
break;
}//end off if
}//end off foreach
echo "we are currently :$status";
In your code the currentTime variable is an object so when you try comparing it things aren't going to match. Try this instead which simplifies things a little.
date_default_timezone_set('Europe/Dublin');
//creating array of opening hours
$openingHours = [
'Sun' => ['12:00' => '20:30'],
'Wed' => ['16:00' => '21:00'],
'Thu' => ['16:00' => '21:00'],
'Fri' => ['16:00' => '23:00'],
'Sat' => ['16:00' => '21:00']
];
//default status
$status = 'closed';
$timeNow = date('H:m',time());
//loop through time range for current day
foreach ($openingHours[date('D', time())] as $startTime => $endTime) {
//check if current time is within range
if (($startTime < $timeNow) && ($timeNow < $endTime)) {
$status = 'open';
break;
} //end off if
} //end off foreach
echo "we are currently :$status";
Edit on July 7th:
If you can change you the opening hours array slightly you may avoid multiple calls to date and the foreach loop using the code below.
date_default_timezone_set('Europe/Dublin');
//creating array of opening hours
$openingHours = [
'Sun' => ['Open'=>'12:00','Close' => '20:30'],
'Wed' => ['Open'=>'16:00','Close' => '21:00'],
'Thu' => ['Open'=>'16:00','Close' => '21:00'],
'Fri' => ['Open'=>'16:00','Close' => '23:00'],
'Sat' => ['Open'=>'16:00','Close' => '21:00']
];
$timeNow = date('H:m',time());
$dow = date('D',time());
echo 'We are currently :' . ((($openingHours[$dow]['Open'] < $timeNow) AND
($timeNow < $openingHours[$dow]['Close'])) ? 'open' : 'closed');
I have 2 dates. I want to get all months with total days in each.
How can I do this in PHP?
For example
$date1 = '2013-11-13'; // yy-mm-dd format
$date2 = '2014-02-14';
Output
Months Total Days
-----------------------
11-2013 30
12-2013 31
01-2014 31
02-2014 28
Just try with:
$date1 = '2013-11-15';
$date2 = '2014-02-15';
$output = [];
$time = strtotime($date1);
$last = date('m-Y', strtotime($date2));
do {
$month = date('m-Y', $time);
$total = date('t', $time);
$output[] = [
'month' => $month,
'total' => $total,
];
$time = strtotime('+1 month', $time);
} while ($month != $last);
var_dump($output);
Output:
array (size=4)
0 =>
array (size=2)
'month' => string '11-2013' (length=7)
'total' => string '30' (length=2)
1 =>
array (size=2)
'month' => string '12-2013' (length=7)
'total' => string '31' (length=2)
2 =>
array (size=2)
'month' => string '01-2014' (length=7)
'total' => string '31' (length=2)
3 =>
array (size=2)
'month' => string '02-2014' (length=7)
'total' => string '28' (length=2)
Try the below given code :
$date1 = '2013-11-15'; // yy-mm-dd format
$date2 = '2014-02-15';
$start = new DateTime($date1);
$start->modify('first day of this month');
$end = new DateTime($date2);
$end->modify('first day of next month');
$interval = DateInterval::createFromDateString('1 month');
$period = new DatePeriod($start, $interval, $end);
foreach ($period as $dt) {
echo $dt->format("Y-m") ." " ;
echo cal_days_in_month(CAL_GREGORIAN,$dt->format("m"),$dt->format("Y")) . "<br/>";
}
Also, checkout this link for more
i used timestamp and date:
$date1 = '2013-11-15'; // yy-mm-dd format
$date2 = '2014-02-15';
$d1 = strtotime('2013-11-15');
$d2 = strtotime('2014-02-15');
while ($d1 <= $d2) {
echo date('m-d-Y', $d1)." | ";
echo cal_days_in_month(CAL_GREGORIAN, date('m', $d1), date('Y', $d1)) ."<br>";
$d1 = strtotime("+1 month", $d1);
}
This should help you, Check out,
$date1 = new DateTime('2013-11-15');
$date1->modify('first day of this month');
$date2 = new DateTime('2014-02-15');
$date2->modify('first day of next month');
$interval = DateInterval::createFromDateString('1 month');
$value = new DatePeriod($date1, $interval, $date2);
foreach ($value as $dates) {
echo $dates->format("m- Y")."-->".cal_days_in_month(0,$dates->format("m"),$dates->format("Y"))."<br>\n";
}
This is what i came up with:
$arr_months = array();
$date1 = new DateTime('2013-11-15');
$date2 = new DateTime('2014-02-15');
$month1 = new DateTime($date1->format('Y-m')); //The first day of the month of date 1
while ($month1 < $date2) { //Check if the first day of the next month is still before date 2
$arr_months[$month1->format('Y-m')] = cal_days_in_month(CAL_GREGORIAN, $month1->format('m'), $month1->format('Y')); //Add it to the array
$month1->modify('+1 month'); //Add one month and repeat
}
print_r($arr_months);
It creates an associative array with the month as key and the number of days as value.
The array created from the example would be:
Array
(
[2013-11] => 30
[2013-12] => 31
[2014-01] => 31
[2014-02] => 28
)
With a foreach loop you will be able to scroll trough the array easily.
You can use the DateTime class along with cal_day_in_month() like this
$datetime1 = "2014-02-15";
$datetime2= "2013-03-15";
$date1 = new DateTime($datetime1);
$date2 = new DateTime($datetime2);
while (date_format($date2, 'Y-m') <= date_format($date1, 'Y-m'))
{
$date2 = $date2->add(new DateInterval('P1M'));
echo $date2->format('Y-m')." | ".cal_days_in_month(CAL_GREGORIAN, $date2->format('m'), $date2->format('Y'))."<br>";
}
$dts = new DateTime(AppController::getSetting('event_start'));
$dtf = new DateTime(AppController::getSetting('event_finish'));
//CONTROLLER
...
$weekdays = array(0,1,2,3,4,5,6);
$dates = array();
$today = strtotime(date("Y-m-d", $dts->getTimestamp()));
$end_date = strtotime(date("Y-m-d", $dtf->getTimestamp()));
while($today <= $end_date)
{
$weekday = date("w", $today);
if (in_array($weekday, $weekdays))
{
array_push($dates, date("Y-m-d", $today));
}
$today += 86400;
}
$this->set('dates', $dates);
...
//VIEW
...
echo $this->Form->input('date', array('options'=> $dates));
...
dts and dtf are a start and finish date I get from my database...
When I select a date from my drop box in my view, it submits ok but all i get in my database is 0000-00-00?
What am I doing wrong here?
EDIT
My array out puts this with
Debugger::dump($dates);
array(
(int) 0 => '2013-04-01',
(int) 1 => '2013-04-02',
(int) 2 => '2013-04-03',
(int) 3 => '2013-04-04',
(int) 4 => '2013-04-05',
(int) 5 => '2013-04-06',
(int) 6 => '2013-04-07'
)
EDIT
This is what my query looks like
INSERT INTO cake.tickets (first_name, last_name, email, phone, date, quantity) VALUES ('brbt', 'trbb', 'ver#fvef.com', 765657, //THIS IS THE DATE//2, 2).
It seems to only input the key?
Make your keys and your values the same. The key is what is saved, the value is what is seen by the user.
$dates = array();
$today = strtotime(date("Y-m-d", $dts->getTimestamp()));
$end_date = strtotime(date("Y-m-d", $dtf->getTimestamp()));
while($today <= $end_date)
{
$weekday = date("w", $today);
if (in_array($weekday, $weekdays))
{
$dates[date("Y-m-d", $today)] = date("Y-m-d", $today);
}
$today += 86400;
}
$this->set('dates', $dates);
Your date array should now look something like this:
array(
'2013-04-01' => '2013-04-01',
'2013-04-02' => '2013-04-02',
'2013-04-03' => '2013-04-03',
'2013-04-04' => '2013-04-04',
'2013-04-05' => '2013-04-05',
'2013-04-06' => '2013-04-06',
'2013-04-07'=> '2013-04-07'
)
Which will generate the proper select options.
I just wondered if anybody can point me in the right direction: I'm looking to make a script whereby the logo on my site changes depending on the date; so for instance a haloween style one soon.
I started off by having 2 arrays, 1 of start dates and 1 of end dates(not sure even if this is the best way!):
<?php
$start_dates = array('01/01' => 'New Years',
'14/02' => 'Valentine Day',
'16/02/2010' => 'Pancake Day',
'17/03' => 'St Patricks Day',
'01/04' => 'April Fools',
'02/04/2010' => 'Easter',
'23/04' => 'St Georges Day',
'11/06/2010' => 'World Cup',
'31/10' => 'Halloween',
'05/11' => 'Guy Fawkes',
'11/11' => 'Armistice Day',
'16/10' => 'Today',
'15/12' => 'Christmas');
$end_dates = array( '08/01' => 'New Years',
'15/02' => 'Valentine Day',
'17/02/2010' => 'Pancake Day',
'18/03' => 'St Patricks Day',
'02/04' => 'April Fools',
'06/04/2010' => 'Easter',
'24/04' => 'St Georges Day',
'12/07/2010' => 'World Cup',
'01/11' => 'Halloween',
'06/11' => 'Guy Fawkes',
'12/11' => 'Armistice Day',
'17/10' => 'Today',
'01/01' => 'Christmas');
?>
Easy so far...the problemis that I need a way of working out if todays date falls between the start date and end date, then changing the image file name.
Its a long shot but I hope someone would be kind enough to help.
Thanks,
B.
like this
$events = array(
'New Year' => '01/01 01/08',
'Pancake Day' => '16/02/2010 17/02/2010',
//etc
);
echo find_event($events, '16/02');
where find_event() is
function mdy2time($date) {
$e = explode('/', $date);
if(count($e) < 3)
$e[] = '2010';
return strtotime("$e[1]-$e[0]-$e[2]");
}
function find_event($events, $date = null) {
$date = is_null($date) ? time() : mdy2time($date);
foreach($events as $name => $range) {
list($start, $end) = explode(' ', $range);
if($date >= mdy2time($start) && $date <= mdy2time($end))
return $name;
}
return null;
}
you should use an array more like this:
$dates = array();
$dates[] = array(
'name' => 'New Years'
'start' = '01/14',
'end' => '01/20',
'style' => 'haloween',
);
$dates[] = array(
//...
);
then you can get the style as follows:
$style='default';
// date as number e.g. 130 (january 30th)
$currDate = date('md',time()) * 1;
foreach ($dates AS $k => $v) {
$tmp = explode("/",$v['start'];
$start = ($tmp[1].$tmp[0])*1;
$tmp = explode("/",$v['end'];
$stop = ($tmp[1].$tmp[0])*1;
if ($start <= $currDate && $currDate < $stop) {
$style=$v['style'];
break;
}
}
echo 'style: '.$style;
Didn't check the code yet, so feel free to correct me if iam wrong.