All date combinations between a fixed period (PHP / Loops) - php

This sounds like a silly question but I am struggling to think of how best to tackle it.
I have 2 dates, lets say 15-03-2012 to 19-03-2012. I need to extract all combinations working down from all 4 days together to 4 individual days, output like this (formatting change for simplicity):
15, 16, 17, 18
15,16, 17
16, 17, 18
15, 16
16, 17
17, 18
15
16
17
18
I am looking for the best looping method, the date range will vary in length, the format isn't relevant but it needs to be php dates from which I will extract the exact format required. I will be using each date set to execute code at each iteration so has to be dates/loops.

Create two Date objects of the values you have, write a while loop that runs until the start variable (your start date) is equal to the end variable (your end date) and you should be done.

The general idea:
$day = 24 * 60 * 60;
for($startDate = $dateA; $startDate <= $dateB; $startDate += day)
{
for($endDate = $startDate; $endDate <= $dateB; $endDate += day)
{
for($dateIndex = startDate; $dateIndex <= $endDate; $dateIndex += day)
{
$output = getDate($dateIndex);
echo($output['month'] . $output['day'] . ',');
}
echo '</br>';
}
}

Related

How to get last and next date from a date number in php?

I want to find entries in a month range based on date of a month
like if a user registered on 20th of a month, the script should get entries in a range from last 20th to next 20th of the month.
I.e if the script is running on any day before 20th of April the range should be March 20 - April 20, and if its running on 20th April or after then the range should be April 20 - May 20.
I looked up relative formats but it only lists functions for day names and weeks etc.
Is there any way the relative date format works like last n to next n. where n= 1 to 31.
Can anyone help? Thanks
Based on comment from Cully, here is an implementation (it still feels too messy, maybe there is an easier way to do it). It may explain the question a bit more.
function getFromDate($myDate, $nDate)
{
// sub 1 day till date is $nDate
while(true)
{
if($myDate->format('d')==$nDate)
break;
$myDate->sub(new DateInterval('P1D'));
}
return $myDate;
}
function getToDate($myDate, $nDate)
{
// add 1 day till date is $nDate
while(true)
{
$myDate->add(new DateInterval('P1D'));
if($myDate->format('d')==$nDate)
break;
}
return $myDate;
}
$timestamp = 1602107066; // An example user registration date, 7 October 2021
$nDate = gmdate("d", $timestamp);
$fromDate = getFromDate(new DateTime('now'), $nDate);
$toDate = getToDate(new DateTime('now'), $nDate);
echo $fromDate->format('d M y')."\r\n"; // 7 May 2021 (run on May 22 2021)
echo $toDate->format('d M y'); // 7 June 2021 (run on May 22 2021)
Do you mean something like this? It might not be exactly what you want, but can you use it to create what you want?
<?php
$numberOfDaysIWant = 20;
// March 20th, 2021, but you can use any date you want
$startDate = new DateTimeImmutable('2021-03-20');
$myPastDates = [];
$myFutureDates = [];
$currentDate = $startDate;
for($i = 0; $i < $numberOfDaysIWant; $i++) {
$currentDate = $currentDate->sub('P1D');
$myPastDates []= $currentDate;
}
$currentDate = $startDate;
for($i = 0; $i < $numberOfDaysIWant; $i++) {
$currentDate = $currentDate->add('P1D');
$myFutureDates []= $currentDate;
}
var_dump($myPastDates, $myFutureDates);
It's unclear from your question, but it sounds like maybe you want to get the $numberOfDaysIWant value based on the date of the selected month. If so, you could use this to get it:
<?php
$startDate = new DateTimeImmutable('2021-03-20');
$numberOfDaysIWant = (int) $startDate->format('j'); // "j" gives you the day of the month, without leading zeroes

Complex date format

I am trying to come up with the most efficient and best way to accomplish this somewhat of a complex situation. I know that I could build this solution using probably around 5 if else statements, maybe more - however there must be a better way to accomplish what I want to.
So here's what I am trying to do. I have an events page on my website, and what I want to do is display the dates in a minimalistic way when possible. What I mean is the following:
Say I have 3 dates: May 5, May 6, May 7. I want to display it as: May 5 - 7.
However, there will be situations where the dates may be: May 5, May 7. In this case I would like to display it as: May 5 & 7.
However, there may also be situations where the dates may be: May 25, June 2. In this case I would like to display it as: May 25 & June 2.
However! There also may be situations where the dates may be: May 25, May 26, June 2. In this case it should display as: May 25 - 26 & June 2
Of course, there could just be a single date as well. But one other thing, it could be possible that there could be more than 3 dates as well, so it would be nice if it could work regardless of how many dates there are (IE loop through an array).
I know that we are suppose to make an attempt and show some code to debug, however I don't even know where to start with this, if this is too much for someone to put together - just giving me an idea of how to do something like this efficiently would be a huge help.
Thanks
//input data: sorted list of dates
$dates = array('May 5','May 6','May 7','May 30','Jun 2','Jun 3','Dec 11','Dec 12','Dec 14');
array_push($dates,false); //add an extra value so the last range gets printed
//initialize min & previous date as first date
$min_date = array_shift($dates);
$prev_date = $min_date;
$counter = 0; //keep count of # of days between min and max
$formatted_dates = array();
foreach($dates as $date) {
//if the difference in number of days between current date and min date
//is greater than counted number of days then we capture the current range
//and start a new one by resetting $min_date to $date and $counter to 0
if(!$date || ($counter + 1) < diff_in_days($min_date,$date)) {
if($counter == 0) { //format for 1 date
$formatted_dates[] = $min_date;
}
elseif($counter == 1) { //format for 2 dates
$formatted_dates[] = "$min_date & $prev_date";
}
elseif($counter > 1) { //format for > 2 dates
$formatted_dates[] = "$min_date - $prev_date";
}
$counter = 0;
$min_date = $date;
}
else {
$counter++;
}
$prev_date = $date;
}
//may also want to verify that neither formatted date contains an '&'
//so you don't end up with "May 11 & May 12 & June 1 & June 2" which may be confusing
if(count($formatted_dates) == 2) {
print implode(' & ',$formatted_dates);
}
else {
print implode("\n",$formatted_dates);
}
function diff_in_days($day1,$day2) {
$datetime1 = new DateTime($day1);
$datetime2 = new DateTime($day2);
$interval = $datetime1->diff($datetime2);
$ret = (int) $interval->format('%a');
return $ret;
}
Output
May 5 - May 7
May 30
Jun 2 & Jun 3
Dec 11 & Dec 12
Dec 14

Populate Drop Down with Time using Time Range from Database

I am trying to populate a drop-down menu with time in 30 minute intervals (ability to change to different intervals would be nice too).
I am currently using the following code to populate the drop down (Scrounged this up online from searching around).
$sqlHours = "SELECT Open, Close FROM TimeTable";
$rsSQLHours = odbc_exec($conn, $sqlHours);
$strOpen = trim(odbc_result($rsSQLHours, "Open"));
$strClose = trim(odbc_result($rsSQLHours, "Close"));
$DeliHourOpen = substr($strOpen, 0, 2);
$DeliMinOpen = substr($strOpen, 3, 2);
$DeliHourClose = substr($strClose, 0, 2);
$DeliMinClose = substr($strClose, 3, 2);
for($hours=$DeliHourOpen; $hours<=$DeliHourClose; $hours++)
for($mins=$DeliMinOpen; $mins<60; $mins+=30)
echo '<option value='.$hours.':'.$mins.'>'.date('h:i A', strtotime($hours.':'.$mins)).'</option>'; ?>
Edit: I am storing the times in the database in 24h format, such as 08:00:00 or 22:00:00. I am using the date() just to format the displayed output in an AM/PM fashion for ease of use by users.
I am having issues when the Close Time is 20:00 it will go up to 8:30 PM in the drop-down. If I remove the = from <=$DeliHourClose then it will only display 7:30 PM. I need it to Display up to whatever the Close Time is.
The fields in the database are 'Time' in the in format 'H:i:s'.
Also, although the drop-down can be populated with a range of times from Open to Close, I need it to start at whatever the current time is + 30 minutes.
So if the Open Time is 8:00 AM, and it is 7:00 AM I want to see 8:00 AM as the first time in the drop-down. But if it is 9:00 AM, the first option in the drop-down needs to be 9:30 AM.
I have the general idea that it needs some sort of if/else to compare current time to the times in the drop-down, but I am not sure how to go about it, with the format I am using now for the drop-down.
I would prefer to have a more manageable format if possible.
Is there an easier/better way to generate a range of times with intervals that may be changed? And then populate the drop-down with the appropriate times?
Any help or suggestions would be greatly appreciated.
Using a Microsoft SQL Database.
Edit: There are multiple locations that will be stored in the table. I will add a WHERE Location = XXX clause once I get it working and add more locations to the table. Currently there is only one location, so no WHERE clause.
I am using time datatype instead of datetime as I do not want a y/m/d attached to the open/close times.
You need to generate your time stamp using time() so you can get the unix timestamp and then convert it as you wish, this way you'll be able to do time addition and add seconds straight to the given unix timestamp.
Ressource : http://fr.php.net/time
Edit : Just so we're clear and to explain it further : UNIX timestamp is the number of seconds since the 1st of january 1970, so echo time(); will return 1390934768, you just need to process it from there as the docs shows.
This code whille return this as an array : 8
8.5
9
9.5
10
10.5
11
11.5
12
12.5
13
13.5
14
14.5
15
15.5
16
16.5
17
17.5
18
18.5
19
<?php
//Function returning unix time from simple time stamp (8 or 17.5 or whatever)
function ttounix($t) {
$tunix = $t * 60 * 60;
return $tunix;
}
//Function returning simple timestamp from unix timestamp
function unixtot($u) {
$tt = $u / 60 / 60;
return $tt;
}
$gap = 30 * 60; //gap in seconds
$t1 = 8; //opening time from db
$t2 = 19; //closing time from db
//setting vars
$n = 0;
$count = array();
//Getting processed time stamps into vars
$o = ttounix($t1);
$c = ttounix($t2);
//Populating the array
while ( $o <= $c ) {
$count[$n] = $o;
$o += $gap;
$n++;
}
//Output
foreach ($count as $output) {
echo unixtot(intval($output)) . '<br />';
}
?>

Determine week number based on starting date

I need help to create a function to determine the week number based on these 2 parameters:
Starting date
Specified date
For example, if I specify April 7, 2010 as the starting date & passed April 20, 2010 as the date to lookup, I would like the function to return WEEK 2. Another example, if I set March 6, 2010 as starting date and looked up April 5, 2010 then it should return WEEK 6.
I appreciate your time and help.
=================
UPDATE
For instance:
Starting date: 3/6 - week1
Lookup date: 4/5
Week 2 starts from Mar 7-13.
Week 3 (3/14-3/20).
Week 4 (3/21-3/27). Week 5 (3/28-4/3).
So 4/5 falls under Week 6.
An idea is to use the Sunday of the starting date as the NEW* starting date. So instead of looking up 3/6, the function will use 2/28 as the starting date.
You can find the number of days between the two dates, divide that number by 7 and take the ceil of the result:
$start_date = strtotime("2010-04-07");
$specified_date = strtotime("2010-04-20");
$num_of_days = ($specified_date - $start_date)/(60*60*24);
$week_num = ceil($num_of_days/7);
echo $week_num; // prints 2.
What about?
Determine the number of days since the epoch of the start date
ditto, the specified date
subtract
divide by 7
Since I do not know how you are going to receive your dates, I would do something like:
$starting = mktime(parsedStartingDate);
$lookup = mktime(parsedLookupDate);
$result = $lookup - $starting;
$result = (((($result / 60) / 60) / 24) / 7);
return $result;
Since you're not being very clear this may or may not be what you're looking for:
// Example 1 (returns 2)
date('W', strtotime('April 20, 2010')) - date('W', strtotime('April 7, 2010'));
// Example 2 (returns 5)
date('W', strtotime('April 5, 2010')) - date('W', strtotime('March 6, 2010'));
Figured it out.
$start_date = strtotime("2010-03-06"); // returns 1267862400
$start_date_week = strtotime("last sunday",$start_date); // 02-28
$specified_date = strtotime("2010-04-10"); // returns 1270882800
$specified_date_week = strtotime("next sunday",$specified_date); // 4-11 looking up the Next Sunday was also the key!
$num_of_days = ($specified_date_week - $start_date_week)/(60*60*24); // 41.958
$week_num = ceil($num_of_days/7); //6
echo $week_num;

Working with date ranges in PHP/Oracle

I need to work out how many different instances occur on a different day, from many different ranges. Probably best to explain it with an example.
18-JAN-09 to 21-JAN-09
19-JAN09 to 20-JAN-09
20-JAN-09 to 20-JAN-09
Using the three examples above, I need it to collect this information and display something a little like...
18th Jan: 1
19th Jan: 2
20th Jan: 3
21st Jan: 1
... I'll be grabbing the information from an Oracle database fwiw (hence the format above ^) and there will be hundreds, maybe thousands of records, so my lame attempt to do all sorts of loops and if statements would take forever to run.
Is there any fairly simple and efficient way of doing this? I'm really not too sure where to start unfortunately...
Thanks
You could use the method described in another SO:
SQL> WITH DATA AS (
2 SELECT to_date('18-JAN-09', 'dd-mon-rr') begin_date,
3 to_date('21-JAN-09', 'dd-mon-rr') end_date FROM dual UNION ALL
4 SELECT to_date('19-JAN-09', 'dd-mon-rr'),
5 to_date('20-JAN-09', 'dd-mon-rr') FROM dual UNION ALL
6 SELECT to_date('20-JAN-09', 'dd-mon-rr'),
7 to_date('20-JAN-09', 'dd-mon-rr') FROM dual
8 ),calendar AS (
9 SELECT to_date(:begin_date, 'dd-mon-rr') + ROWNUM - 1 c_date
10 FROM dual
11 CONNECT BY LEVEL <= to_date(:end_date, 'dd-mon-rr')
12 - to_date(:begin_date, 'dd-mon-rr') + 1
13 )
14 SELECT c.c_date, COUNT(d.begin_date)
15 FROM calendar c
16 LEFT JOIN DATA d ON c.c_date BETWEEN d.begin_date AND d.end_date
17 GROUP BY c.c_date
18 ORDER BY c.c_date;
C_DATE COUNT(D.BEGIN_DATE)
----------- -------------------
18/01/2009 1
19/01/2009 2
20/01/2009 3
21/01/2009 1
Either your DB engine or your PHP code is going to have to loop over the date range.
Here's some PHP code to do the summation. The day counts are stored by year-month to avoid having a huge array for a wide date range.
<?php
// Get the date ranges from the database, hardcoded for example
$dateRanges[0][0] = mktime(0, 0, 0, 1, 18, 2009);
$dateRanges[0][1] = mktime(0, 0, 0, 1, 21, 2009);
$dateRanges[1][0] = mktime(0, 0, 0, 1, 19, 2009);
$dateRanges[1][1] = mktime(0, 0, 0, 1, 20, 2009);
$dateRanges[2][0] = mktime(0, 0, 0, 1, 20, 2009);
$dateRanges[2][1] = mktime(0, 0, 0, 1, 20, 2009);
for ($rangeIndex = 0; $rangeIndex < sizeof($dateRanges); $rangeIndex++)
{
$startDate = $dateRanges[$rangeIndex][0];
$endDate = $dateRanges[$rangeIndex][1];
// Add 60 x 60 x 24 = 86400 seconds for each day
for ($thisDate = $startDate; $thisDate <= $endDate; $thisDate += 86400)
{
$yearMonth = date("Y-m", $thisDate);
$day = date("d", $thisDate);
// Store the count by year-month, then by day
$months[$yearMonth][$day]++;
}
}
foreach ($months as $yearMonth => $dayCounts)
{
foreach ($dayCounts as $dayNumber => $dayCount)
{
echo $yearMonth . "-" . $dayNumber . ": " . $dayCount . "<br>";
}
}
?>
You need a table with one row for each day
test_calendar:
Day
16.01.2009
17.01.2009
18.01.2009
19.01.2009
20.01.2009
21.01.2009
22.01.2009
23.01.2009
24.01.2009
25.01.2009
26.01.2009
table test contains bagin and finish of inctance:
DFROM DTILL
18.01.2009 21.01.2009
19.01.2009 20.01.2009
20.01.2009 20.01.2009
Here is a query you need:
select day, (select count(1)
from test where dfrom<=t.day and dtill>=t.day) from test_calendar t
where day>to_date('15.01.2009','DD.MM.YYYY')
order by day
Huge thanks for the solutions guys - managed to get it working using some of the SQL from above and also bits of PHP from the second solution.
Really appreciate it, cheers :)

Categories