php - list of dates coming up - php

All the users are in the United States. I need to be able to list all weekdays besides today. So say that it's Thursday, October 7. It should start by listing Friday, October 8 and then Monday, October 11.
I know how to make sure I'm only listing weekdays when looping through, but the trouble I have is making sure tomorrow is tomorrow. In the past it's changed at about 8:00 at night eastern time. I'm thinking I'd like to have is so when it's maybe 12:00 pacific time to count it as the next day.

<?php
$current = new DateTime('now');
$last = new DateTime('saturday');
while ($current < $last) {
echo $current->format('l, F j'), "\n";
$current->modify('+1 day');
}
?>

You can use strtotime to get the date of the next days and you can use date to determine if a date is a week day :
<?php
$reference = time(); // We set today as the first day //
for ($i=0, $j=0; $i<5; $i++, $j++) {
$nextDay = strtotime('+' . $j . ' days', $reference);
if (date('w', $nextDay) > 0 && date('w', $nextDay) < 6) {
echo date('r', $nextDay), "\n";
} else {
$i--;
}
}
?>

Related

PHP DateTime Textual Representation

I wonder if it is possible to get this as an ouput using PHP DateTime:
'first thursday of February 2021'
The other way round were
$date = new DateTime('first thursday of February 2021');
What I have to accomplish: I have a given date and want to know, if it is the first thursday or not without building the date and comparing dates after this like:
$date = new DateTime('first thursday of February 2021');
$given_date = new DateTime('2021-02-04');
return ($given_date == $date);
Anyone?
I forgot: my given date can be the second saturday in march or the third friday in june and so on.
I will explain a little further for those who doesn't understand my question. Imaging a time table which says: all thursdays office is open from 8am to 5pm but first thursday in march office will open at 7am and closes at 6pm. Now a customer wants to schedule a meeting and we have only a date but must know: is it the first thursday or not. My database holds such information like day, month and possibly position in month. My solution now is a loop to determine the position in month.
private function getPositionInMonth(DateTime $date)
{
$positions = ['first', 'second', 'third', 'fourth', 'fifth'];
$day_name = $date->format('l');
foreach ($positions as $i => $position) {
$str = $position . ' ' . $day_name . ' ' . $date->format('F') . ' ' . $date->format('Y');
$test_date = new DateTime($str);
if ($test_date->format('d.m.Y') == $date->format('d.m.Y')) {
return ($i + 1);
}
}
}
All other information can be fetched in the sql query.
A DateTime object should be formatted as a string like "first thursday of February 2021".
function formatNoWeekday(Datetime $date){
$no = ['first','second','third','fourth','fifth'];
$day = $date->format('j');
$frm = $date->format(' l \o\f F Y');
foreach($no as $n){
$strDate = $n.$frm;
if(date_create($strDate)->format('j') == $day){
return $strDate;
}
}
return false;
}
$result = formatNoWeekday(date_create('2021-02-16'));
//"third Tuesday of February 2021"
Solved it with a tiny bit of math like CBroe suggested:
private function getPositionInMonth(DateTime $date)
{
$test_date = new DateTime($date->format('Y-m-') . '01');
$diff = round(($date->getTimestamp() - $test_date->getTimestamp()) / 86400, 0);
if($diff < 7) {
return 1;
}
return (int)($diff / 7) + 1;
}
That function will give the position in month.
(Diff calculation fixed, DateTime gives d=0 and m=1 for the 29th of march, now it works. If you find any date which fails please mention it)
DateTime object supports relative formats. For this you can call method modify
<?php
$date = new DateTime('now');
$date->modify('first thursday of February 2021');
$given_date = new DateTime('2021-02-04');
return ($given_date == $date);
DateTime::modify
Relative Formats

PHP script date modify issue when using in loop

EDITED directly to the problem :
The code :
<?php
$date = new DateTime('2000-01-31'); // or whatever
for ($i = 0; $i < 100; $i++) {
$currentDay = $date->format('d');
if ($currentDay < $date->format('t')) {
$date->modify('+1 month');
if ($date->format('d') < $currentDay) {
$date->modify('last day of previous month');
}
} else {
$date->modify('last day of next month');
}
echo $date->format('Y-m-d') . "<br>";
}
So, if starting date is 2000-01-31, it works fine. That's just because 31 is the last day of january, so, any other month it will put the last date of the month.
But, if u change starting date to 2000-01-30, it's broken. That's because 30 january is not the last day in january. But anyway, 30 january is greater than days in february, so it transform date to 28/29 february. Since 28/29 february is the last day in february, it proceed the code like when this date == number of days in the month, and on the next iteration instead of putting 30 march, it puts 'last day of next month' (31 of march).
And that's not the unique case. Same thing if u put starting date for example 30-08-2000. 30 is not the last day of august, so it change the date to 30 of september, 30 september is the last day of the september, so it change the date to 31 of octomber, but it's not what I expect.
If I've understood your question correctly then this should be what you're after:
$date = new DateTime('2000-01-31'); // or whatever
$day = $date->format('d');
$date->setDate($date->format('Y'), $date->format('m'), 1);
for ($i = 0; $i < 100; $i++) {
$date->modify('+1 month');
echo echo $date->format('t') < $day ? $date->format('Y-m-t') : $date->format('Y-m-' . $day);
echo '<br />';
}
Hope this helps!
Do I understand correctly that
you want to print the same day for all following months
in case it's higher than the maximum days in the month, last day of that month should be used instead
If yes, this could work:
<?php
$date = new DateTime('2000-01-28'); // or whatever
#echo $date->format('d')." ".$date->format('t');
$expectedDay = $date->format('d');
$month = $date->format('m');
$year = $date->format('Y');
for ($i = 0; $i < 100; $i++) {
echo $date->format('Y-m-d') . "<br>";
if ($month++ == 12) {
$year++;
$month = 1;
}
$date->modify("${year}-${month}-1");
if ($expectedDay > $date->format('t')) {
$day = $date->format('t');
} else {
$day = $expectedDay;
}
$date->modify("${year}-${month}-${day}");
}

Dummy php date compare

I'm dummy and dont know how to compare date's.
I need to do link unclickable when date is less or equal today.
This is actullay not complete code, full code prints this week monday to sunday. Im try to do calendar what print 1 week each time and each day it print time 9am to 17pm.
$toDay = date("m-d-y");
$first = date('m-d-Y', strtotime('Last Monday +'.$d.' days'));
//This sunday + 1 week
$last = date('m-d-Y', strtotime('Next Sunday +'.$d.' days'));
//print week number
**if($first <= $toDay() && $tomorrow <= $toDay)**
{
echo"<p class='list_header'>". $tomorrow."</p>";
//Looping time 9 to 17
for($time_start = 9; $time_start <= 17; $time_start+=2)
{
echo "<li style='background-color:red'><a href='#'>".$time_start."</a></li>";
}
}
You can use timestamp method to compare the time value in php.

PHP create range of dates

Starting with a date in this format: 2011-05-01 09:00:00, how can I create an array that contains all office hours (09:00 to 17:00) for all working days of the year (so excluding all Saturday and Sundays). What I want to arrive to is something like this:
2011-05-01 09:00:00
2011-05-01 10:00:00
2011-05-01 11:00:00
2011-05-01 12:00:00
2011-05-01 13:00:00
2011-05-01 14:00:00
2011-05-01 15:00:00
2011-05-01 16:00:00
2011-05-01 17:00:00
//next day, starting at 09:00 and ending at 17:00
2011-05-02 09:00:00
...
2011-05-02 17:00:00
//until the last day of the year from 09:00 to 17:00
2011-12-31 09:00:00
...
2011-12-31 17:00:00
The start date will be the first of the current month at with 09:00 as time and the very last date (last element of the array) will always be 17:00 on the last day of the year.
Again, weekends should be excluded.
Pseudocode idea:
I thought of something like strtotime($start, "+1 one hour") with a check for "if smaller than 17:00" but it doesn't seem to be that simple.
How about this:
$start = strtotime('2011-05-01');
$end = strtotime('2011-12-31');
$times = array();
for ($i = $start; $i <= $end; $i += 24 * 3600)
{
if (date("D", $i) == "Sun" || date("D", $i) == "Sat")
{
continue;
}
for ($j = 9; $j <= 17; $j++)
{
$times []= date("Y-m-d $j:00:00", $i);
}
}
The outer loop iterates through all the days in the given time period. In the outer loop, we check to see if the day is either Saturday or Sunday (a weekend), and if it is, we skip that day. If it's not a weekend, we loop through all the valid hours, adding the full date and time to the array as we go.
Some tips:
date("G", $some_timestamp) gives you the hour of the day in 24-hour format
date("N", $some_timestamp) gives you the day of the week, 1 (for Monday) through 7 (for Sunday)
Take a look at the php manual for date.
Edit: You can pick any start timestamp and add 3600 to add one hour, if your hour is greater than 17, you can add a bigger step to go right to the next morning, same for a weekend, and just do a while ($timestamp < $end_timestamp) {}
I'd encourage you to use the wonderful DateTime class and its related classes. Here, you can make good use of DatePeriod:
<?php
$now = new DateTime('today'); // starting time 0.00 this morning
$endOfYear = new DateTime('31 December this year 23:00'); // end time
$interval = new DateInterval('PT1H'); // frequency -- every hour
$times = array();
foreach (new DatePeriod($now, $interval, $endOfYear ) as $datetime) {
// $datetime is a DateTime object for the hour and time in question
$dow = $datetime->format('w'); // 0 is Sunday
if (($dow == '0') || ($dow == '6')) {
continue; // miss Saturday and Sunday out
}
$time = $datetime->format('G'); // hour without leading 0
if (($time < '9') || ($time > '17')) {
continue;
}
$times[] = $datetime->format('r'); // output format
}
var_dump($times);
Obviously there are various aspects of this that you can configure, especially the output format. Depending on your purpose, you may prefer to put the DateTime objects themselves into the array.
$datetime = new DateTime(); // Set your start date here
do { // Iterate over .. dont know, a long time?
do { // Iterate over the week ...
$datetime->setTime(9,0,0);
do { // Iterate over the hours ...
echo $datetime->format('c') . PHP_EOL; // Do something with $datetime here
$datetime->add(new DateInterval('PT1H'));
} while ($datetime->format('G') < 18); // .. till < 18
$datetime->add(new DateInterval('P1D')); // next day
} while (!in_array($datetime->format('w'), array('0','6'))); // until we hit sunday or saturday
$datetime->add(new DateInterval('P2D')); // next monday
} while (true); // replace with your "end" expression
Currently untested.
You can use the common interval-strings (like 1 hour and so on) too http://php.net/dateinterval.createfromdatestring
You could calculate your dates with two nested loops and generate the string with date().
I would just loop through all dates, incremented by hour, from now until the end of the year, as follows (pseudocode, obviously):
for n = now until end of year
if (date(n) is between 9:00 and 17:00) AND (if date(n) is not sat or sun)
add to array
end if
increment n by 1 hour
end
Here is a solution which should be reasonably fast since it uses no string comparisons and has only two function calls inside the loops:
function hours()
{
$start = mktime(0, 0, 0, date('n'), 1, date('Y'));
$end = mktime(0, 0, 0, 1, 1, date('Y') + 1);
$wday = date('w', $start);
$result = array();
for ($t = $start; $t < $end; $t += 3600 * 24) {
if (($wday > 0) && ($wday < 6)) {
for ($hour = 9; $hour <= 17; $hour++) {
$result[] = date('Y-m-d', $t) . sprintf(' %02d:00:00', $hour);
}
}
$wday = ($wday + 1) % 7;
}
return $result;
}

Repeating Events on the "nth" Weekday of Every Month

I've looked at at least 2 dozen topics about this and haven't really found a good answer yet, so I come to you to ask once again for answers regarding the dreaded topic of Repeating Events.
I've got Daily, Weekly, Monthly, and Yearly repeats working out fine for now (I still need to revamp the system with Exception events and whatnot, but it works for the time being). But, we want to be able to add the ability to repeat events on the (1st,2nd,3rd,4th,5th) [Sun|Mon|Tue|Wed|Thu|Fri|Sat] of every month, every other month, and every three months.
Now, if I can just understand the logic for the every month, I can figure out the every other month and the every three months.
Here's a bit of what I have so far (note: I'm not saying I have the best way of doing it or anything, but the system is one we update very slowly over time when we aren't busy with other projects, so I make the code more efficient as I have the time).
First I get the starting and ending dates formatted for date calculations:
$ending = $_POST['end_month'] . "/" . $_POST['end_day'] . "/" . substr($_POST['end_year'], 2, 2);
$starting = $_POST['month'] . "/" . $_POST['day'] . "/" . substr($_POST['year'], 2, 2);
Then I get the difference between those two to know how many times to repeat using a function I'm fairly certain I found on here some time ago and dividing that amount by 28 days to get just about how many TIMES it needs to repeat so that there is one a month:
$repeat_number = date_diff($starting, $ending) / 28;
//find the difference in DAYS between the two dates
function date_diff($old_date, $new_date) {
$offset = strtotime($new_date) - strtotime($old_date);
return $offset/60/60/24;
}
Then I add the (1st,2nd,etc...) part to the [Sun|Mon|etc...] part to figure out what they are looking for giving me somehthing like 'first Sunday' :
$find = $_POST['custom_number']. ' ' . $_POST['custom_day'];
Then I use a loop that runs the number of times this needs to repeat (the $repeat_number from above):
for($m = 0; $m <= $repeat_number; $m++) {
if($m == 0) {
$month = date('F', substr($starting,0,2));
} else {
$month = date('F', strtotime($month . ' + ' . $m . ' months'));
}
$repeat_date = strtotime($find . ' in ' . $month);
}
Now, I'm aware this code doesn't work, I at one time did have code that turned up the correct month and year for the repeat, but wouldn't necessarily find the first tuesday or whatever it was that was being looked for.
If anyone could point me back in the right direction, it would be most appreciated. I've been lurking in the community for some time now, just started trying to actively participate recently.
Thanks in advance for any input or advice you can provide.
Here's a possible alternative for you. strtotime is powerful, and the syntax includes really useful bits like comprehensive relative time and date wording.
You can use it to generate the first through Nth specific weekdays of a specific month by using the format " of ". Here's an example using date_create to invoke a DateTime object, but regular old strtotime works the same way:
php > $d = date_create('Last Friday of March 2011'); if($d instanceof DateTime) echo $d->format('l F d Y H:i:s');
Friday March 25 2011 00:00:00
php > $d = date_create('First Friday of March 2011'); if($d instanceof DateTime) echo $d->format('l F d Y H:i:s');
Friday March 04 2011 00:00:00
php > $d = date_create('First Sunday of March 2011'); if($d instanceof DateTime) echo $d->format('l F d Y H:i:s');
Sunday March 06 2011 00:00:00
php > $d = date_create('Fourth Sunday of March 2011'); if($d instanceof DateTime) echo $d->format('l F d Y H:i:s');
Sunday March 27 2011 00:00:00
php > $d = date_create('Last Sunday of March 2011'); if($d instanceof DateTime) echo $d->format('l F d Y H:i:s');
Sunday March 27 2011 00:00:00
It will also overflow the month, if you ask for an invalid one:
php > $d = date_create('Ninth Sunday of March 2011'); if($d instanceof DateTime) echo $d->format('l F d Y H:i:s');
Sunday May 01 2011 00:00:00
Note that it only works with the ordinal number wording. You can't pass "1st" or "3rd", unfortunately.
Once you use this to grab the proper Nth weekday, you can then simply add the number of needed weekdays to skip (7 for one week, 14 for two, 21 for three, etc) as required until the designated end date or designated number of weeks has passed. Once again, strtotime to the rescue, using the second argument to chain together relativeness:
php > echo date('l F d Y H:i:s', strtotime('+14 days', strtotime('First Thursday of March 2011')));
Thursday March 17 2011 00:00:00
(My local copy also accepted '+14 days First Thursday of March 2011', but that felt kind of weird.)
I have a more simple method, although it may seem hack-ish.
What we can do is take the start date, and infer it's "n" value from it by taking the ceiling of its day divided by 7.
For example, if your start date is the 18th, we divide by 7 and take the ceiling to infer that it is the 3rd "whatever-day" of the month.
From there we can simply repeatedly add 7 days to this to get a new date, and whenever the new date's ceilinged 7-quotient is 3, we've hit the next "nth whatever-day" of the month.
Some code can be seen below:
$day_nth = ceil(date("j", strtotime($date))/7);
for ($i = 0; $i < $number_of_repeats; $i++) {
while (ceil(date("j", strtotime($date))/7) != $day_nth)
$date = date("Y-m-d", strtotime("+7 days", strtotime($date)));
/* Add your event, or whatever */
/* Now we increment date by 7 days before the loop starts again,
** otherwise the while loop would never execute and we'd just be
** adding to the same date repeatedly. */
$date = date("Y-m-d", strtotime("+7 days", strtotime($date)));
}
What's nice about this method is that we don't even have to concern ourselves with which day of the week we're dealing with. We just infer everything from the start date and away we go.
I make it like that:
//$typeOfDate = 0;
$typeOfDate = 1;
$day = strtotime("2013-02-01");
$to = strtotime(date("Y-m-d", $day) . " +6 month");
if ($typeOfDate == 0) { //use the same day (number) of the month
$dateArray[] = date("Y-m-d", $day);
$event_day_number = date("d", $day);
while ($day <= $to) {
$nextMonth = date("m", get_x_months_to_the_future($day));
$day = strtotime(date("Y-" . $nextMonth . "-d", $day));
$dateArray[] = date("Y-m-d", $day);
}
}
if ($typeOfDate == 0) { //use the same day (like friday) of the month
$dateArray[] = date("Y-m-d", $day);
$monthEvent = date("m", $day);
$day = strtotime(date("Y-m-d", $day) . " +4 weeks");
$newMonthEvent = date("m", $day);
if ($monthEvent == $newMonthEvent) {
$day = strtotime(date("Y-m-d", $day) . " +7 days");
}
while ($day <= $to) {
$dateArray[] = date("Y-m-d", $day);
$monthEvent = date("m", $day);
$day = strtotime(date("Y-m-d", $day) . " +4 weeks");
$newMonthEvent = date("m", $day);
if ($monthEvent == $newMonthEvent) {
$day = strtotime(date("Y-m-d", $day) . " +7 days");
}
}
}

Categories