PHP Compound Date Format Bug - php

I am using the following lines of code to get the dates I am trying to generate for some reports and it seems to work fine except in a few instances and I can't see why that would be.
// what week numbers belong to which period
$adminconfig_periods = array(
1=>array(1,2,3,4),
2=>array(5,6,7,8,9),
3=>array(10,11,12,13),
4=>array(14,15,16,17),
5=>array(18,19,20,21,22),
6=>array(23,24,25,26),
7=>array(27,28,29,30),
8=>array(31,32,33,34,35),
9=>array(36,37,38,39),
10=>array(40,41,42,43),
11=>array(44,45,46,47,48),
12=>array(49,50,51,52,53)
);
/**
* Get period no for week no
*
* #param string week the week
* #return int - the period no
*/
function getPeriodForWeek($week) {
global $adminconfig_periods;
$foundperiod = false;
$period = 1;
while(!$foundperiod) {
if(in_array($week, $adminconfig_periods[$period])) {
$foundperiod = true;
} else {
$period ++;
}
}
return $period;
}
$wA = $_GET['wA'];
$yA = $_GET['yA'];
$prev_period = '';
$next_period = '';
if (!isset($wA) || !isset($yA)) {
// period and year aren't set so do it for current period
// period starts on first Sunday of the first week in the period and ends on the last Saturday of the last week in the period
$week = date('W');
$period = getPeriodForWeek($week);
$wA = date('m');
$yA = date('Y');
}
else {
// period and year are set
// period starts on first Sunday of the first week in the period and ends on the last Saturday of the last week in the period
$period = $wA;
}
// get date of first Sunday of the first week in this period
$period_start_week = $adminconfig_periods[$period][0];
// get the Sunday of this week
$period_start = date('Y-m-d', strtotime($yA . 'W' . $period_start_week . '0'));
// get date of last Saturday of the last week in this period
$period_length = count($adminconfig_periods[$period]);
// array indexes start from 0 so we need to take one off this value
$last_element = $period_length - 1;
$period_end_week = $adminconfig_periods[$period][$last_element];
// get the Saturday of this week
$period_end = date('Y-m-d', strtotime($yA . 'W' . $period_end_week . '6'));
On this page I have some select menu controls for changing the period and year number and when it gets to certain periods I get some bizarre dates.
The periods are quite confusing but if anybody has any questions then feel free to ask.
Period | What it Should Be | Actual Result
11 | 28/10/2012 - 01/12/2012 | 28/10/2012 - 01/12/2012
10 | 30/09/2012 - 27/10/2012 | 30/09/2012 - 27/10/2012
09 | 02/09/2012 - 29/09/2012 | 02/09/2012 - 29/09/2012
08 | 29/07/2012 - 01/09/2012 | 29/07/2012 - 01/09/2012
07 | 01/07/2012 - 28/07/2012 | 01/07/2012 - 28/07/2012
06 | 03/06/2012 - 30/06/2012 | 03/06/2012 - 30/06/2012
05 | 29/04/2012 - 02/06/2012 | 29/04/2012 - 02/06/2012
04 | 01/04/2012 - 28/04/2012 | 01/04/2012 - 28/04/2012
03 | 04/03/2012 - 31/03/2012 | 04/03/2012 - 31/03/2012
02 | 29/01/2012 - 03/02/2012 | 10/12/2012 - 01/01/1970
01 | 01/01/2012 - 28/01/2012 | 05/03/2012 - 12/11/2012
As you can see, it seems to go insane for periods 1 and 2 for some reason and I don't understand why.
The parameters are passed in the following way: ?wA=1&yA=2012 and if those are not set it uses the current month and period.
If I was to guess then I'd say it might have something to do with leap years but I thought the code would be able to handle that automatically? Who knows, hopefully a few extra pairs of eyes will spot something stupid I've missed.
Code that echo's the dates
date("d/m/Y", strtotime($period_start)) . ' - ' . date("d/m/Y", strtotime($period_end)) .')';

The error is from those 2 lines
$period_start = date('Y-m-d', strtotime($yA . 'W' . $period_start_week . '0'));
$period_end = date('Y-m-d', strtotime($yA . 'W' . $period_end_week . '6'));
if the week number is 2 for example, adding a 6 to it, it would be 26 (week 26), so you have to add a zero to the left side for the single digit ones. Let's do that with str_pad():
$period_start = date('Y-m-d', strtotime($yA . 'W' . str_pad($period_start_week, 2, 0, STR_PAD_LEFT) . '0'));
$period_end = date('Y-m-d', strtotime($yA . 'W' . str_pad($period_end_week, 2, 0, STR_PAD_LEFT) . '6'));

Related

php maintain date increments in months, weeks, days from past date to present date

I'm struggling to formulate this question correctly.
I have a php time() entry in a mysql table column called renew. I have a second entry in the same row under the column type which decides when to update the row, namely: daily or weekly or monthly from the renew column value (date).
How this script works:
In this example on row id 1; the balance must be updated to reflect the budget monthly. The renew date must also be updated to reflect the next monthly incremented date after the update has taken place.
in row id 2; This will take place weekly. and so on.
for example:
| id | renew | type | budget | balance |
|----| ---------- | ---------| ------ | ------- |
| 1 | 1611214417 | monthly | 10,000.00 | 3,000.00 |
| 2 | 1643614417 | weekly | 4,000.00 | 600,00 |
id 1 = 2021-01-21 07:33:37;
id 2 = 2022-01-31 07:33:37;
in row id 1 how to get the next update date from today?
//the time entry
$now = time():
$today = 28/02/2022
$updatetime = $table['renew'];
$updatetype = $table['type'];
How i did the weekly:
from the $updatetime variable above, I incremented the variable with one week until it just passes the $now time.
// what I've done for weekly and seems to be working
for($i = 0; $i < 1000000000; $i++ ){ //random high number for incrementing
if($updatetime < $now){
$updatetime = $updatetime + (86400 * 7); //add one week
} else {
return;
}
}
// the next update will now be the new $updatetime for weekly
How can i do this for the monthly? there are no fixed days in a month, the renew date could fall on the 31 of the month or 29 of February and then the current month could only have 30 days or 28 days.
This is where my issue lies.
If you can assist me.
I would recommend to use PHP DateTime object that is much simpler to manipulate the date time using relative formats
<?php
$today = new DateTime();
$updatetime = '19/01/2021'; // $table['renew']; //19/01/2021
$updatetype = 'weekly'; //$table['type']; //daily || weekly || monthly
$updatetime = (new DateTime())->createFromFormat('d/m/Y', updatetime);
// what I've done for weekly and seems to be working
if($updatetime < $today){
// $updatetime = $today; // reset to today if needed
$updatetime->modify('next week'); // add one week
} else {
return;
}
echo 'Next time of weekly update '. $updatetime->format('Y-m-d') . PHP_EOL . PHP_EOL;
// Output: Next time of weekly update 2022-03-07
// without time reset: Next time of weekly update 2021-01-25
Other examples of date manipulation using relative formats:
<?php
$today = '2022-02-28';
$t = new DateTime($today);
// print the source date time
echo $t->format('Y-m-d') . PHP_EOL;
// examples of continuously manipulate the date time origin
echo $t->modify('next week')->format('Y-m-d') . PHP_EOL;
echo $t->modify('next month')->format('Y-m-d') . PHP_EOL;
echo $t->modify('next year')->format('Y-m-d') . PHP_EOL;
echo $t->modify('next sunday')->format('Y-m-d') . PHP_EOL;
/*
Output:
2022-02-28
2022-03-07
2022-04-07
2023-04-07
2023-04-09
*/
Live demo Live demo without time reset
TIP:
Convert your daily, weekly, monthly into infinitive day, week, month so you will be able to use its value directly using $table['type'] into the date time manipulation:
<?php
$updatetype = 'week'; //$table['type']; //day || week || month
$updatetime->modify('next ' . $table['type']); // add one xxx dynamically!
TIP2*
Use ISO date format Y-m-d to simplify your codding.
$updatetime = '2021-01-19'; //'19/01/2021'
$updatetime = new DateTime($updatetime); // That's it!
Thanks to Ino's answers i worked it out like this:
$today = time(); // can use DateTime() too.
$updatetime = '1611214417'; // $table['renew']; //19/01/2021
$updatetype = 'weekly'; //$table['type']; //daily || weekly || monthly
echo $updatetime.'<br>';
for($i = 0; $i < 100000; $i++){
if($updatetime < $today){
$updatetime = strtotime("+1 week", $updatetime); // can add week month day
} else {
break;
}
}
echo $updatetime.'<br>'; // just for comparison
echo date('Y-m-d', $updatetime); // 2022-03-03 works out perfectly

Getting records of last week starting from Monday-Sunday from current date in php

Last week is starting from:
13th May 2019(Monday) to 19th May 2019(Sunday)
This week is starting from:
20th May 2019(Monday) to 26th May 2019(Sunday)
In the database, I have records like this:
task_id c_date
1 2019-05-14
2 2019-05-16
3 2019-05-13
4 2019-05-17
5 2019-05-19
6 2019-05-21
7 2019-05-23
8 2019-05-24
9 2019-05-24
the excepted output will be like 1,2,3,4,5 records of the last week
what I have tried:(approach 1st)
$dt = new DateTime;
$dt->setISODate($dt->format('o'), $dt->format('W') - 1);
$year = $dt->format('o');
$week = $dt->format('W');
$this_week = array();
do {
echo '<span>' . $dt->format('l') . " " . $dt->format('d M Y') . "</span></br>\n";
// $date_sheet = $dt->format('Y-m-d');
// array_push($this_week, $date_sheet);
$dt->modify('+1 day');
} while ($week == $dt->format('W'));
Output:
Monday 13 May 2019
Tuesday 14 May 2019
Wednesday 15 May 2019
Thursday 16 May 2019
Friday 17 May 2019
Saturday 18 May 2019
Sunday 19 May 2019
I prefer this but the problem is I can't figure it out how to fetch record from this approach from DB, so I trying to find Alternative and I thought it much better but don't know the how to do that
Alternative Approach (2nd):
$now =date("d-m-Y");
select * from tasks where `c_date` = DATE_SUB('.$now.', INTERVAL 7 DAY )
Don't get anything I am dam sure I am doing totally in the wrong way.
Any help is Appreciated.
You could use something like (warning there are no checks for errors):
$dtFrom = new DateTime; // get current date
$dtTo = new DateTime;
// format for previous week (no previous year check)
$dtFrom->setISODate($dtFrom->format('o'), $dtFrom->format('W') - 1);
// do the same for end date range
$dtTo->setISODate($dtTo->format('o'), $dtTo->format('W') );
// subtract 1 day
$dtTo->sub(new DateInterval('P1D') );
// convert to iso date for database use
$dFrom = $dtFrom->format('y-m-d');
$dTo = $dtTo->format('y-m-d');
The $dFrom and $dTo are date formats that could be used in a query
SELECT * FROM mytable WHERE DateRange between $dFrom AND $dTo;

Filter free day time slot using PHP Codeigniter And Mysql

Please Help !!!
I want free date time slots(data) on new result page in table format associated with the "Search" button so that it outputs the details after the search button has been clicked. Result Image
I know the length of the needed time slot (eg. 1 hour) - Image
An available time slot cannot overlap.
How can this be achieved? What would you think is the best way to approach this?
Process Steps
https://i.stack.imgur.com/FrP09.png
After Hit Seach Button
My DB Structure
Event_ID | dt_start | dt_end
+----------+---------------------+---------------------+
| 3 | 2013-09-21 16:00:00 | 2013-09-21 16:30:00 |
| 21 | 2013-09-21 09:00:00 | 2013-09-21 09:15:00 |
| 5 | 2013-09-21 09:15:00 | 2013-09-21 10:15:00 |
| 64 | 2013-09-21 15:00:00 | 2013-09-21 15:45:00 |
| 32 | 2013-09-21 10:15:00 | 2013-09-21 11:30:00 |
| 6 | 2013-09-21 13:00:00 | 2013-09-21 14:45:00 |
+----------+---------------------+---------------------+
Already thanks for the help,
This answer was based on the ideas from here and here.
The idea of the algorithm is the following:
We create an array where the indexes are all the possible minutes for a date and the values are true.
We fill all the minutes which are included on the existing events to false.
Finally, we look for consecutive time intervals of size $length (in minutes) and once we can traverse the array without finding a false value for $length iterations, we found an empty timeslot for a new event.
<?php
require("database.php");
// Create an array with all the timeslots (in minutes) of a date
// Example: $date = '2018-03-21'
// $timeslots['2018-03-21 00:00:00'] = true;
// $timeslots['2018-03-21 00:01:00'] = true;
// $timeslots['2018-03-21 00:02:00'] = true;
// until
// $timeslots['2018-03-21 23:59:00'] = true;
function getAllTimeslots($date)
{
$currentDate = strtotime($date . " 00:00:00");
$endDate = strtotime($date . " 23:59:59");
$timeslots = [];
while ($currentDate <= $endDate) {
$index = date("Y-m-d H:i:s", $currentDate);
$timeslots[$index] = true;
$currentDate = strtotime("+1 minute", $currentDate);
}
return $timeslots;
}
// Based on the events table registers, fill the intervals of the timeslots array marking them as false, i.e., not available
// Therefore, it will result on an array with trues and falses marking if the specific minute is already filled by an event
function fillUsedTimeslots($date, $timeslots)
{
$queryDate = $date . "%";
$conn = openConnection();
$result = $conn->query("SELECT dt_start, dt_end
FROM events
WHERE dt_start LIKE '" . mysqli_real_escape_string($conn, $queryDate) . "'
OR dt_end LIKE '" . mysqli_real_escape_string($conn, $queryDate) . "'");
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
$start = strtotime($row['dt_start']);
$end = strtotime($row['dt_end']);
// update the timeslots data structure with the information of the events' time usage
while ($start < $end) {
$currentDatetime = date("Y-m-d H:i:s", $start);
$timeslots[$currentDatetime] = false;
$start = strtotime("+1 minute", $start);
}
}
}
return $timeslots;
}
// Finally, we need to find a free an interval of time ($length) where we can place an event
// In short words, it iterates over the array of $timeslots looking for $length consecutives trues, i.e.,
// if $length=60, we iterate over the array looking for 60 times of consecutives falses
function findFreeTimeslots($date, $length, $timeslots)
{
$currentDate = strtotime($date . " 00:00:00");
$endDate = strtotime($date . " 23:59:00");
$timeInterval = 0;
while ($currentDate <= $endDate) {
$index = date("Y-m-d H:i:s", $currentDate);
if ($timeslots[$index]) { // Timeslot is free for use
$timeInterval += 1;
} else { // Reset timeInterval
$timeInterval = 0;
}
// We have $length consecutives true, i.e., an interval of $length minutes available for another event
if ($timeInterval == $length + 1) {
echo "<br/>Timeslot found: " . date("Y-m-d H:i:s", strtotime("-" . $length . " minutes", $currentDate)) . " - " . $index;
$timeInterval = 1;
}
$currentDate = strtotime("+1 minute", $currentDate);
}
}
// Main
$timeslots = getAllTimeslots("2013-09-21");
$filledTimeslots = fillUsedTimeslots("2013-09-21", $timeslots);
findFreeTimeslots("2013-09-21", 180, $filledTimeslots);
I applied your example of 3 hours interval, and the result was:
Timeslot found: 2013-09-21 00:00:00 - 2013-09-21 03:00:00
Timeslot found: 2013-09-21 03:00:00 - 2013-09-21 06:00:00
Timeslot found: 2013-09-21 16:30:00 - 2013-09-21 19:30:00
Timeslot found: 2013-09-21 19:30:00 - 2013-09-21 22:30:00
You can restrict the timeslots data structure size to only working times, or a diferent criteria to adapt on your project. And also, refactor it, it's been a long time since I programmed vanilla PHP

Php calendar by month

I have look at 100 calendar code and thkink there is no good one. So i came up with my own code, but need som help to understans what i am missing. Thinking now that i mixed up the loops or somthing have try this for a while but cant get it right. The result i getting now is in a line from top to bottom. The dont seem to work. Can somone help me understand what i need to do?
<table border="1">
<?php
//counter array
$counter = 0;
//start days array
$list=array();
//current day
$curDay = date("28", $today);
// mktime(0, 0, 0, date("m"), date("d") , date("Y"));
$today = mktime(0, 0, 0, date("m"), '28', date("Y"));
// curent month
$curentmonth = '09';
// curent year
$year = 2018;
// curent month
$month = date('m');
//loop number of days in month and list them in the array
for($d=1; $d<=31; $d++)
{
$datetime=mktime(12, 0, 0, $curentmonth, $d, $year);
if (date('m', $datetime)==$curentmonth)
$list[]=date('d', $datetime);
//try to get the right 7 weeks in a month start monday
for ($day = 1; $day <=7; $day++) {
$datetime = strtotime($year.'W'.$month.$day);
echo "<tr>";
}
// make this day red
if ($curentmonth === $month && $list[$counter] === $curDay) {
echo "<td bgcolor='ff0000'>$list[$counter]</td>";
$counter++;
// all other days in the month
} elseif ($month === $curentmonth) {
echo "<td>$list[$counter]</td>";
$counter++;
// other month
} else {
echo "<td> </td>";
echo "</tr>";
}
}
?>
I've tried coercing your code into doing what you want, but I'm afraid there are so many logical problems that it's better to just go back to the drawing board entirely.
Looking at your code, it seems what you want to accomplish is a table that displays the weeks of the current month below each other, with each week starting on monday. For table cells that don't contain a date (e.g. the month starts or ends in the middle of a week) you want to display only a space in the cell so that it is empty.
Additionally, you want to highlight the current date.
So essentially, your intended end result is something like this for today (September 30th, 2018):
+----+----+----+----+----+----+------+
| | | | | | 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* |
+----+----+----+----+----+----+------+
There are many ways to accomplish this goal. Here's one way of doing it with simple date manipulation, so that there's no need for arrays and multiple loops:
// the month to render and day to highlight
$today = new DateTime();
// we'll need these to check if we're at the day we need to highlight
// or if we're rendering a date that's outside $today's month
$currentDay = $today->format('j');
$currentMonth = $today->format('n');
$daysInCurrentMonth = $today->format('t');
// figure out what Monday needs to kick off our table
$date = (clone $today)->modify('first day of this month');
if ($date->format('w') != 1) {
$date->modify('previous monday');
}
$shouldStopRendering = false;
echo '<table border="1">';
while (!$shouldStopRendering) {
$weekDay = $date->format('w');
$month = $date->format('n');
$day = $date->format('j');
// start a new table row every time we hit a Monday, note that
// since we forced $date to be a Monday above, our table should
// now always start with a <tr>
if ($weekDay == 1) {
echo '<tr>';
}
if ($month != $currentMonth) {
// we're either at the beginning or end of our table
echo '<td> </td>';
} else if ($day == $currentDay) {
// highlight the current date
echo '<td bgcolor="#ff0000">' . $day . '</td>';
} else {
echo '<td>' . $day . '</td>';
}
if ($weekDay == 0) {
// every time we hit a Sunday, close the current table row
echo '</tr>';
// on a Sunday, if we've gone outside the current month **or**
// this Sunday happens to be the last day we need to render,
// stop looping so we can close the table
if ($month != $currentMonth || $day == $daysInCurrentMonth) {
$shouldStopRendering = true;
}
}
// move on to the next day we need to display
$date->modify('+1 day');
}
echo '</table>';
Note this line:
$date = (clone $today)->modify('first day of this month');
The reason I'm cloning $today instead of just creating a new DateTime instance, is that you may wish to change $today to render a different month. Or maybe you're looping over a number of months to render a calendar for a whole year. I don't know which is the case, so I'm basing $date off of whatever $today happens to be.
Don't just do this:
$date = $today->modify('first day of this month');
That'll work, but it will also modify $today which may not be what you want if you want to re-use the current date after rendering the table.
If you're using an older version of PHP, you may not be allowed to do (clone $today)->modify in a single line. If that's the case, just split it up into two lines:
$date = clone $today;
$date->modify('first day of this month');
Here's a demo of this code in action (with some added whitespace for readability of the generated HTML): https://3v4l.org/Z89i8

Creating recurring dates in PHP based on current date, and boolean for done or not

Ello,
I am struggling with some date troubles here in PHP/MySql. I have a form that offers the recurrence of a payment yearly,quarterly,monthly,bi-weekly,or weekly and I need to be able to track when payments are made.
So for example, if something is added on Monday March 8th (that's the date it is being entered), recurring Weekly on Thursdays (the user would only see a dropdown offering days of the week -- as the recurrence is weekly), it would enter the 52 (weekly) due dates into the db (julian/whatever is easiest), and mark the first 9 of them paid (since those days are past); the rest entered but marked unpaid.
I have a table that would have each due_date entry, with a link to the payment detail, and a Boolean field paid/not paid.
So in the above example, the payments table would look something like:
id | pmnt_id | due_date | is_paid
1 | 0023 | 01/07/10 | 1
2 | 0023 | 01/14/10 | 1
3 | 0023 | 01/21/10 | 1
10 | 0023 | 03/25/10 | 0
11 | 0023 | 04/01/10 | 0
etc...
The problem is, well, everything. The calendaring system is so effed up, that there seems no real logical/straightforward way to do this. I've been racking my brain, searching goggle and php date manual all morning, and I'm just getting more confused.
Any ideas/suggestions/pointers would be greatly appreciated.
Cheers.
[snip]
$startDate = strtotime("$currentDay $currentMonthFull $currentYear");
$stTimeFormatted = strftime('%d/%m/%Y',$startDate);
$numPmnts = ($totalWeeks-$currentWeek);
for($i=0;$i<$numPmnts;$i++){
$ddates=array(
'sched_pay_id'=>$pmntID,
'due_date'=>date('m/d/y', strtotime('+'.$i.' week', $startDate)),
'is_paid'=>0,
);
$this->db->insert('sched_payments',$ddates);
}
You might want to look at strtotime: http://php.net/manual/en/function.strtotime.php, you could loop over that until you reach the end of the period (in this case 52 weeks).
for i = 1, i <= 52, i++
insert date(mm / dd / YY, strtotime(+ i week));
/for
The new PHP Date functions have an add method that you can use to generate all these dates.
$startDate = new DateTime();
// "Period of 1 Week
$interval = new DateInterval("P1W");
// Will cycle from 1st week's due date to the end of payment cycle
for($i = 1; $i <= 52; $i++) {
$dueDate = $date->add($interval);
$date = $dueDate;
}
This an example of recurrence days.
This function return a recurrence day per week during a period.
Exemple: All Thurday starting from 06 May 2010 during 52 weeks.
<?php
//function
function nextWeeksDay($date_begin,$nbrweek)
{
$nextweek=array();
for($i = 1; $i <= $nbrweek; $i++) { // 52 week in one year of course
$nextweek[$i]=date('D d M Y', strtotime('+'.$i.' week',$date_begin));
}
return $nextweek;
}
/// end function
/// example of a select date
// var
$date_begin = strtotime('06-05-2010'); //D Day Month Year - like function format.
$nbrweek=52;
// call function
$result=nextWeeksDay($date_begin,$nbrweek);
// Preview
for($i = 1; $i <= $nbrweek; $i++) {
echo '<br> - '.$result[$i];
}
?>

Categories