Incrementing days if day is a workday - php

I need your help again.
This should be a function for php. I've got two dates. One is set by myDate and the other one is the date of today. I want to find out the number of days left to myDate, but saturday and sundy should be excluded. The result for this function would be 7...
How can I make it work?
<?php
myDate = "29.07.2010 "
DaysTillmyDate = 0
iterate day to myDate {
if (date/day is a weekday(Monday,Tuesday,Wednesday,Thursday, Friday))
increment DaysTillmyDate by 1
}
?>
A hint or any help would be much appreciated.
Faili

Quick iteration:
$days = 0;
for($i = time(); $i < (strtotime('29.07.2010') + 86400); $i=$i+86400)
{
$weekday = date('w', $i);
if($weekday > 0 && $weekday < 6)
{
$days++;
}
}
echo $days;

date('N', $theDate) gives you the day of the week (6 for Saturday and 7 for Sunday). From there, you can easily implement a function that does only counts workdays. On the other hand, this does not detect holidays.

Related

Loop the days of the month throughout the whole month

I am building multi-calendar, I have a horizontal looking interface:
I am trying to run the days of the week S,M,T,W,T,F,S
throughout the whole month instead of just the first 7 as in the picture.
the function which draw the calendar:
//our case "SUN"
if(AC_START_DAY=="sun"){
for($k=0; $k<7; $k++){
$weekday = mb_substr($lang["day_".$k.""],0,1,'UTF-8');
$list_day_titles.='<li class="cal_weekday"> '.$weekday.'</li>';
}
}
//If we chose Monday as start week.
else{
if ($first_week_day == 0) $first_week_day =7;
for($k=1; $k<=7; $k++){
if($k==7) $weekday = mb_substr($lang["day_0"][0],0,1,'UTF-8');
else $weekday = mb_substr($lang["day_".$k.""],0,1,'UTF-8');
$list_day_titles.='<li title="'.$lang["day_".$k.""].'"> '.$weekday.'</li>';
}
}
The lang file:
$lang["day_0"] = "Sunday";
$lang["day_1"] = "Monday";
$lang["day_2"] = "Tuesday";
$lang["day_3"] = "Wednesday";
$lang["day_4"] = "Thursday";
$lang["day_5"] = "Friday";
$lang["day_6"] = "Saturday";
Already defined
$month=sprintf("%02s",$month);
// define vars
$today_timestamp = mktime(0,0,0,date('m'),date('d'),date('Y')); # current timestamp - used to check if date is in past
$this_month = getDate(mktime(0, 0, 0, $month, 1, $year)); # convert month to timestamp
$first_week_day = $this_month["wday"]; # define first weekday (0-6)
$days_in_this_month = cal_days_in_month(CAL_GREGORIAN,$month,$year); # define number of days in week
$day_counter_tot = 0; # count total number of days showin INCLUDING previous and next months - use to get 6th row of dates
Looks like the $lang["day_".$k.""] is just counting the days from 0 to 6.. how can i make is loop untill the end of the month?
NOTE: I tried increasing the $k<7 just more empty blue boxes appear.
Use the loop to the 30/31 day.
And then change this line
$weekday = mb_substr($lang["day_".$k.""],0,1,'UTF-8');
to
$weekday = mb_substr($lang["day_".$k%7.""],0,1,'UTF-8');
This should give you the day 0 for every sunday.
0 % 7 = 0 (sunday)
1 % 7 = 1 (monday)
...
7 % 7 = 0 (sunday again)
8 % 7 = 1 (monday again)
You can use this code to generate all the days of the current month.
for ($date = strtotime(date('Y-m-01')); $date < strtotime(date('Y-m-t')); $date = strtotime("+1 day", $date)) {
echo date("l-d", $date)."<br>";
}
Will print all the days of the current month as follows.
Thursday-01
Friday-02
Saturday-03
Sunday-04
Monday-05
Tuesday-06
Wednesday-07
Thursday-08
Friday-09
Saturday-10
Sunday-11
Monday-12
Tuesday-13
Wednesday-14
Thursday-15
Friday-16
Saturday-17
Sunday-18
Monday-19
Tuesday-20
Wednesday-21
Thursday-22
Friday-23
Saturday-24
Sunday-25
Monday-26
Tuesday-27
Wednesday-28
Thursday-29
Friday-30
Looks like you almost got it right.
You only need to slightly modify your code to make it work the way you want it to.
You should just change your code to:
$number_of_days_in_the_future = 42; // Here you can put in the number of days for which you want to display the corresponding letter, and based on your screenshot that is 42
//our case "SUN"
if(AC_START_DAY=="sun"){
for($i=0; $i<$number_of_days_in_the_future; $i++){
$k = $i % 7;
$weekday = mb_substr($lang["day_".$k.""],0,1,'UTF-8');
$list_day_titles.='<li class="cal_weekday"> '.$weekday.'</li>';
}
}
//If we chose Monday as start week.
else{
if ($first_week_day == 0) $first_week_day =7;
for($i=1; $i<=$number_of_days_in_the_future; $i++){
$k = $i % 7;
if($k==7) $weekday = mb_substr($lang["day_0"][0],0,1,'UTF-8');
else $weekday = mb_substr($lang["day_".$k.""],0,1,'UTF-8');
$list_day_titles.='<li title="'.$lang["day_".$k.""].'"> '.$weekday.'</li>';
}
}
Please note that I only tried to fix your code so it works as you expect it to.
There's probably a more elegant solution but I don't really know your full code so I would just be guessing if I tried to offer you another approach.
I hope this will help you.
Cheers

PHP: define start date for interval

I am using the following lines to calculate a 4-week interval in PHP.
This uses a fixed date ($calStart) as basis for the calculation and ends the interval with the last day of the selected year ($rangeEnd / $selYear) which works well so far.
Example: If the selected year is 2015 than the first date in my range here should be 2015-01-16 as the first interval date in the selected year.
Can someone here tell me how I can set this so that $rangeDays only starts with the first interval date in the selected year instead of returning all intervals since the $calStart date (which is what it does at the moment) ?
$calStart = new DateTime('2014-01-17');
$interval = DateInterval::createFromDateString('4 weeks');
$rangeEnd = new DateTime($selYear . '-12-31');
$rangeDays = new DatePeriod($calStart, $interval, $rangeEnd);
Many thanks for any help with this, Tim.
You can try with:
$calStart = new \DateTime('2014-01-17');
$calYear = $calStart->format('Y');
if ($selYear !== $calYear) {
$day = (int) $calStart->format('z') + date('z', mktime(0,0,0,12,31,$calYear)) * ($selYear - $calYear);
$calStart->setDate($selYear, 1, $day % 28);
}
Edit:
This one is more complex:
$calStart = new \DateTime('2014-01-17');
$calYear = (int) $calStart->format('Y');
if ($selYear !== $calYear) {
$days = (int) $calStart->format('z') + 1; // get day in a year. +1 is because it starts with 0
for ($i = $calYear; $i < $selYear; $i++) {
$days -= (date('z', mktime(0,0,0,12,31,$i)) + 1) % 28; // remove from start day a modulo of 28 days, every year the date is lower
}
if ($days < 0) {
$days += 28; // if we will finish with value under 0, just add 4 weeks
}
$calStart->setDate($selYear, 1, $days);
}
If you're looking to get $calStart to start in the same year as $rangeEnd this should do it for you:
$calStart = new DateTime('2014-01-17');
if ($selYear !== $calStart->format('Y')) {
$calStart->setDate($selYear , $calStart->format('n'), $calStart->format('j'));
}
$interval = DateInterval::createFromDateString('4 weeks');
$rangeEnd = new DateTime($selYear . '-12-31');
$rangeDays = new DatePeriod($calStart, $interval, $rangeEnd);
I'm not sure how you get 2015-01-16 as the new start date so I wasn't able to address that directly.

How many of a certain week day has passed this month

I have a calendar that I want to allow events to be repeated on a week day of the month. Some examples would be:
Repeat every 4th Tuesday of the month
Repeat every 2nd Friday of the month
And so on...
What I need is the ability to find out how many week days (for example Tuesday's) have passed this month so far.
I found some code that returns how many Monday's have passed.
$now=time() + 86400;
if (($dow = date('w', $now)) == 0) $dow = 7;
$begin = $now - (86400 * ($dow-1));
echo "Mondays: ".ceil(date('d', $begin) / 7)."<br/>";
This works well but how do I make it so that I can determine any week day? I cannot seem to get my head around the code to make this work.
strtotime is really useful for this kind of thing. Here are lists of the supported syntax. Using your example of repeat every 2nd Friday of the month I wrote the following simple snippet for you:
<?php
$noOfMonthsFromNow=12;
$dayCondition="Second Friday of";
$months = array();
$years = array();
$currentMonth = (int)date('m');
for($i = $currentMonth; $i < $currentMonth+$noOfMonthsFromNow; $i++) {
$months[] = date('F', mktime(0, 0, 0, $i, 1));
$years[] = date('Y', mktime(0, 0, 0, $i, 1));
}
for ($i=0;$i<count($months);$i++){
$d = date_create($dayCondition.' '.$months[$i].' '.$years[$i]);
if($d instanceof DateTime) echo $d->format('l F d Y H:i:s').'<br>';
}
?>
This can be tested at: http://www.phpfiddle.org/lite/
$beginningOfMonth = strtotime(date('Y-m-01')); // this will give you the timestamp of the beginning of the month
$numTuesdaysPassed = 0;
for ($i = 0; $i <= date('d'); $i ++) { // 'd' == current day of month might need to change to = from <= depending on your needs
if (date('w', $beginningOfMonth + 3600 * $i) == 2) $numTuesdaysPassed ++; // 3600 being seconds in a day, 2 being tuesday from the 'w' (sunday == 0)
}
Not sure if this will work, and there's probably a better way to do it; don't have the means to test it right now but hopefully this puts you on the right track! (I get tripped up on date math a bit too, especially with timezones)

How do I find date prior to another date in php

I need to find date x such that it is n working days prior to date y.
I could use something like date("Y-m-d",$def_date." -5 days");, but in that case it wont take into consideration the weekend or off-date. Let's assume my working days would be Monday to Saturday, any idea how I can accomplish this?
Try this
<?php
function businessdays($begin, $end) {
$rbegin = is_string($begin) ? strtotime(strval($begin)) : $begin;
$rend = is_string($end) ? strtotime(strval($end)) : $end;
if ($rbegin < 0 || $rend < 0)
return 0;
$begin = workday($rbegin, TRUE);
$end = workday($rend, FALSE);
if ($end < $begin) {
$end = $begin;
$begin = $end;
}
$difftime = $end - $begin;
$diffdays = floor($difftime / (24 * 60 * 60)) + 1;
if ($diffdays < 7) {
$abegin = getdate($rbegin);
$aend = getdate($rend);
if ($diffdays == 1 && ($astart['wday'] == 0 || $astart['wday'] == 6) && ($aend['wday'] == 0 || $aend['wday'] == 6))
return 0;
$abegin = getdate($begin);
$aend = getdate($end);
$weekends = ($aend['wday'] < $abegin['wday']) ? 1 : 0;
} else
$weekends = floor($diffdays / 7);
return $diffdays - ($weekends * 2);
}
function workday($date, $begindate = TRUE) {
$adate = getdate($date);
$day = 24 * 60 * 60;
if ($adate['wday'] == 0) // Sunday
$date += $begindate ? $day : -($day * 2);
return $date;
}
$def_date="";//define your date here
$preDay='5 days';//no of previous days
date_sub($date, date_interval_create_from_date_string($preDay));
echo businessdays($date, $def_date); //date prior to another date
?>
Modified from PHP.net
Thanks for the help guys, but to solve this particular problem I wrote a simple code:
$sh_padding = 5; //No of working days to count backwards
$temp_sh_padding = 1; //A temporary holder
$end_stamp = strtotime(date("Y-m-d", strtotime($date_format)) . " -1 day"); //The date(timestamp) from which to count backwards
$start_stamp = $end_stamp; //start from same as end day
while($temp_sh_padding<$sh_padding)
{
$sh_day = date('w',$start_stamp);
if($sh_day==0){ //Skip if sunday
}
else
{
$temp_sh_padding++;
}
$start_stamp = strtotime(date("Y-m-d",$start_stamp)." -1 day");
}
$sh_st_dte = date("Y-m-d",$start_stamp); //The required start day
A quick bit of googling got me to this page, which includes a function for calculating the number of working days between two dates.
It should be fairly trivial to adjust that concept to suit your needs.
Your problem, however, is that the concept of "working days" being monday to friday is not universal. If your software is only ever being used in-house, then it's okay to make some assumptions, but if it's intended for use by third parties, then you can't assume that they'll have the same working week as you.
In addition, public holidays will throw a big spanner in the works, by removing arbitrary dates from various working weeks throughout the year.
If you want to cater for these, then the only sensible way of doing it is to store the dates of the year in a calendar (ie a big array), and mark them individually as working or non-working days. And if you're going to do that, then you may as well use the same mechanism for weekends too.
The down-side, of course, is that this would need to be kept up-to-date. But for weekends, at least, that would be trivial (loop through the calendar in advance and mark weekend days where date('w')==0 or date('w')==6).

Finding all weekdays in a month

How do I go about getting all the work days (mon-fri) in a given time period (let's say, today till the end of the next month) ?
If you're using PHP 5.2+ you can use the library I wrote in order to handle date recursion in PHP called When.
With the library, the code would be something like:
$r = new When();
$r->recur(<start date here>, 'weekly')
->until(<end date here>)
->wkst('SU')
->byday(array('MO', 'TU', 'WE', 'TH', 'FR'));
while($result = $r->next())
{
echo $result->format('c') . '<br />';
}
This sample does exactly what you need, in an quick and efficient way.
It doesn't do nested loops and uses the totally awesome DateTime object.
$oDateTime = new DateTime();
$oDayIncrease = new DateInterval("P1D");
$aWeekDays = array();
$sStart = $oDateTime->format("m-Y");
while($oDateTime->format("m-Y") == $sStart) {
$iDayInWeek = $oDateTime->format("w");
if ($iDayInWeek > 0 && $iDayInWeek < 6) {
$aWeekDays[] = clone $oDateTime;
}
$oDateTime->add($oDayIncrease);
}
Try it here: http://codepad.org/wuAyAqnF
To use it, simply pass a timestamp to get_weekdays. You'll get back an array of all the weekdays, as timestamps, for the rest of the current month. Optionally, you can pass a $to argument - you will get all weekdays between $from and $to.
function get_weekdays ($from, $to=false) {
if ($to == false)
$to = last_day_of_month($from);
$days = array();
for ($x = $from; $x < $to; $x+=86400 ) {
if (date('w', $x) > 0 && date('w', $x) < 6)
$days[] = $x;
}
return $days;
}
function last_day_of_month($ts=false) {
$m = date('m', $ts);
$y = date('y', $ts);
return mktime(23, 59, 59, ($m+1), 0, $y);
}
I suppose you could loop through the dates and check the day for each one, and increment a counter.
Can't think of anything else off the top of my head.
Pseudocode coming your way:
Calculate the number of days between now and the last day of the month
Get the current day of the week (i.e. Wednesday)
Based on the current day of the week, and the number of days left in the month, it's simple calculation to figure out how many weekend days are left in the month - it's going to be the number of days remaining in the month, minus the number of Sundays/Saturdays left in the month.
I would write a function, something like:
daysLeftInMonth(daysLeftInMonth, startingDayOfWeek, dayOfWeekToCalculate)
where:
daysLeftInMonth is last day of the month (30), minus the current date (15)
startingDayOfWeek is the day of the week you want to start on (for today it would be Wednesday)
dayOfWeekToCalculate is the day of the week you want to count, e.g. Saturday or Sunday. June 2011 currently has 2 Sunday, and 2 Saturdays left 'til the end of the month
So, your algorithm becomes something like:
getWeekdaysLeft(todaysDate)
...getWeekdaysLeft is something like:
sundaysLeft = daysLeftInMonth(lastDayOfMonth - todaysDate, "Wednesday", "Sunday");
saturdaysLeft = daysLeftInMonth(lastDayOfMonth - todaysDate, "Wednesday", "Saturday");
return ((lastDayOfMonth - todaysDate) - (sundaysLeft + saturdaysLeft));
This code does at least one part you ask for. Instead of "end of next month" it simply works with a given number of days.
$dfrom = time();
$fourweeks = 7 * 4;
for ($i = 0; $i < $fourweeks; $i ++) {
$stamp = $dfrom + ($i * 24 * 60 * 60);
$weekday = date("D", $stamp);
if (in_array($weekday, array("Mon", "Tue", "Wed", "Thu", "Fri"))) {
print date(DATE_RSS, $stamp) . "\n";
}
}
// Find today's day of the month (i.e. 15)
$today = intval(date('d'));
// Define the array that will hold the work days.
$work_days = array()
// Find this month's last day. (i.e. 30)
$last = intval(date('d', strtotime('last day of this month')));
// Loop through all of the days between today and the last day of the month (i.e. 15 through 30)
for ( $i = $today; $i <= $last; $i++ )
{
// Create a timestamp.
$timestamp = mktime(null, null, null, null, $i);
// If the day of the week is greater than Sunday (0) but less than Saturday (6), add the timestamp to an array.
if ( intval(date('w', $timestamp)) > 0 && intval(date('w', $timestamp)) < 6 )
$work_days[] = mktime($timestamp);
}
The $work_days array will contain timestamps which you could use this way:
echo date('Y-m-d', $work_days[0]);
The code above with work in PHP 4 as well as PHP 5. It does not rely on the functionality of the DateTime class which was not available until PHP 5.2 and does not require the use of "libraries" created by other people.

Categories