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).
Related
I am trying to check if the user has been on the site longer then 6 months, if they have to prompt a message.
I cannot get this to work, it keeps thinking 6 weeks has passed even when the date is moved to today.
Currently my code.
$created_at = "2014-12-01 16:58:23";
$sixweek = 604800 * 6;
if(strtotime($created_at) < time() + ($sixweek))
{
$data['needsnewimage'] = 1;
die('6 Weeks has passed ');
}else{
$data['needsnewimage'] = 0;
die('6 Weeks has not passed');
}
Any ideas?
That's not going to work. Consider this: someone signs up for your site TODAY:
$created_at = '2014-12-01 08:00:00'; // "today"
if ($created_at < $today + $sixweek) ...
becomes
if ($today < $today + $sixweek)
if (0 < $sixweek)
and will always be true.
You want
if ($created_at > (time() - $sixweek))
^---------^
Note the changed math
DateTime will make this simple, something like:-
$created_at = new \DateTime("2014-12-01 16:58:23");
$sixWeeks = new \DateInterval('P6W');
if($created_at->add($sixWeeks) < new \DateTime()){
echo "Six weeks has passed!\n";
} else echo "Not yet!\n";
See it working
Reference
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 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.
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.
i am develop a webpage in that i need to calculate x days from a specified date , The problem is we exclude the saturday and sunday . For example $Shipdate = '06/30/2009' and the x is 5 means , i want the answer '7' [ie 30 is tuesday so after 5 days it will be sunday , so there is two holiday(saturday and sunday) so we add 5+2(for saturday and sunday)]=7. Please help me to find out , Thanks in advance.
Generally you will need to be able to specify a calendar with significant days excluded. Consider Christmas Day or public holidays. This appears to be code that will consider public holidays, you need to modify it or parameterise it with your set of holidays.
<?php
// ** Set Beginning and Ending Dates, in YYYY-mm-dd format **
$begin = '2008-01-01';
$end = '2008-03-31';
$begin_mk = strtotime("$begin");
$end_mk = strtotime("$end");
// ** Calculate number of Calendar Days between the two dates
$datediff = ( $end_mk > $begin_mk ? ( $end_mk - $begin_mk ) : ( $begin_mk - $end_mk ) );
$days = ( ( $datediff / 3600 ) / 24 );
$days = $days + 1; // to be inclusive of last date;
// ** Count days excluding Sundays **
$iteration = 0;
$numDaysExSunday = 0;
for ($i=1; $i<=$days; $i++) {
$weekday = date("w", strtotime("$begin + $iteration day"));
echo "$weekday<br>";
**// i change only this line to add saturday**
if ($weekday !== '0' && $weekday !== '6') {
$numDaysExSunday++;
}
$iteration++;
}
// ** Output number of days excluding Sundays **
echo $numDaysExSunday;
?>
i take it from
http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_23499410.html
the solution Excluding Sundays but need to change only one line to exclude saturday i write it in the code
function Weekdays($start,$end){
$days=0;
if ( $end <= $start ) {
// This is invalid data.
// You may consider zero to be valid, up to you.
return; // Or throw an error, whatever.
}
while($start<$end){
$dayofweek = date('w',$start);
if( 6!= $dayofweek && 0 != $dayofweek){
$days++;
}
$start = strtotime('+1 day',$start);
}
return $days;
}
You may want to tweak it a bit depending on whether you want to count it as one day or zero if the start is the same day as the end.