I'm using php and mysqli for my project.
My question is about calculating next available shipping dates.
On my checkout page, my website displays the next available shipping date according to the following rules:
I can ship monday - saturday before 4pm.
I have a table "cantship" containing dates in the format d/m/Y that I cannot ship on because im at work.
So, the next available shipping date displayed should be a monday-saturday unless its past 4pm or todays date matches a date in the cantship table.
So, what I need shown:
If the time now is before 4pm and today is a monday-saturday, I can ship today so show todays date (as long as todays date is not in the cantship table)
If the time now is after 4pm, I cannot ship today so the next shipping date should be a mon-sat thats not in the cantship table.
If the calculated shipping date is in the cantship table, I cant ship on that day, so the next shipping date would have to be the next day thats between mon-sat, thats not in the cantship table.
Here is my code so far: Sorry its messy.
<?php
function nextshipdate ($db)
{
// ========================================================================
// find next available date for despatch
// ========================================================================
$i = 0;
$cutoff = strtotime('today 16:00');
$today1 = strtotime('today');
if ($cutoff >strtotime($today1 ))
{
echo "<p>its after 4pm!<p>";
$i = 1;
}
$tmpDate =date('d-m-Y H:i:s');
$nextBusinessDay = date('d-m-Y ', strtotime($tmpDate . ' +' . $i . ' Weekday'));
$nextavail= date('d-m-Y H:i:s', strtotime($tmpDate . ' +' . $i . ' Weekday'));
$dontuse = array();
$getbiz = $db->get_results("SELECT * from cantship ");
$nowcheck = new DateTime();
// =======================================================
// remove past dates from cantship table
// =======================================================
foreach ($getbiz as $inpast)
{
if (strtotime($inpast->csdate)<= time())
{
//echo $inpast->csdate." has passed!<p>";
$removeold = $db->query("DELETE from cantship where csdate='". $inpast->csdate."'" );
}
}
// =======================================================
// create array of unavailable shipping dates
// =======================================================
if ($getbiz)
{
foreach ($getbiz as $na)
{
$dontuse[]=$na->csdate;
}
}
while (in_array($nextBusinessDay, $dontuse))
{
$i++;
$nextBusinessDay = date('d-m-Y', strtotime($tmpDate . ' +' . $i . ' Weekday'));
}
if(!empty($dontuse))
{
$nbd=$nextBusinessDay;
}
else
{
$nbd=' please contact us.';
}
return $nbd;
}
// ==========================================================================================
Beginning from a Date with the current time you must modify the dateto the next day if
The time is >= 4 pm or
The day is a Sunday or
The day is in the nonshipping list
The nonshiiping list is given as array:
$noShipDates = [
'2020-10-28',
'2020-12-24'
];
The logic can be implemented as a small function.
function nextShipDate(array $noShipDates, $curTime = "now"){
$date = date_create($curTime);
$max = 1000; //protection endless loop
while($max--){
if($date->format('H') >= 16
OR $date->format('w') == 0
OR in_array($date->format('Y-m-d'),$noShipDates)
) {
$date->modify('next Day 00:00');
}
else {
return $date->format('Y-m-d');
}
}
return false;
}
The function returns a string of the form 'yyyy-mm-dd' or false for an error. For test purposes, a date can be specified with the 2nd parameter.
echo nextShipDate($noShipDates, '2020-10-27 16:01');
//2020-10-29
Related
I want to update my data if the current date is equal to last day of the month leave variable will update +1 once every month only, but it seems that when I refresh the homepage it keeps on adding.
function get_leave() {
$current_date = date('d'); // current date
$lastDayOfMonth = date('t'); // last day of the month
$leave = 1;
$total_add_leave = 0;
$query = $this->db->query('SELECT total_leave,user_id FROM user');
foreach ($query->result_array() as $row) {
if($current_date == $lastDayOfMonth) { //if current day is equal to last day of the month ADD 1
$total_add_leave = $row['total_leave'] + $leave;
}
$this->db->set('total_leave',$total_add_leave);
$this->db->where('user_id', $row['user_id']);
$this->db->update('user');
}
}
You can do this as below:
$current_date = date("y-m-d");
$last_day_of_the_month = date("y-m-t", strtotime($current_date));
if($current_date == $last_day_of_the_month) {
$total_add_leave = $row['total_leave'] + 1;
// database updating query must be placed in this condition
}
With this function you will find last date of month "t gives you last date of month"
date("Y-m-t");
then compare with current date
if(date("Y-m-d") == date("Y-m-t"))
{
// write your logic here
}
I want to define SLA for given task excluding weekends, holidays and non working hours in PHP .Workdays Mon-Fri and Worktime 9AM to 5PM.
How can i define SLA and calculate time taken to complete the task in PHP?
Edit Question :
Here the code that I tried, i can exclude the weekends and holidays. But want exclude non working time as well
function _getBusinessDayOfMonth($startDate,$businessDays,$holidays)
{
$date = strtotime($startDate);
$i = 0;
while($i < $businessDays)
{
//get number of week day (1-7)
$day = date('N',$date);
//get just Y-m-d date
$dateYmd = date("Y-m-d",$date);
$datehis=date("H:i:s",$date);
if($day < 6 && !in_array($dateYmd, $holidays)){
$i++;
}
$date = strtotime($dateYmd . ' +1 day'.$datehis);
}
$day = date('N',$date);
$d=date("Y-m-d",$date);
if( $day==7||in_array($d, $holidays))
{
$date = strtotime($d . ' +1 day'.$datehis);
}
elseif($day==6)
{
$date = strtotime($d . ' +2 day'.$datehis);
}
//return date('Y-m-d H:i:s',$date);
return date('Y-m-d H:i:s',$date);
}
I have got strange issue with dates of events and I have tried hard to get it fixed but unable to do it.
I am attaching a screenshot of how I want to display the dates on the page :
In the picture the first event Deine Energie in Aktion! is a combination of 5 events with each event having its start date and end date.
The first part of the event is 1 day event which starts on 4th April and ends on 4th April. Similarly the second part is on 7th April, 3rd part on 9th April and 4th part on 20th April
The last part starts on 5th May and ends on 10th May.
The dates are stored in database in this format :
I am showing the dates for last part of event.
Event Start Date : 2013-05-05 00:00:00
Event End Date : 2013-05-10 00:00:00
So I want to display dates in the format shown in the picture.
There are multiple cases:
First is if all the dates are coming within a single month then we display the month name at the end only once.
Second is if months are changed then the month name will be shown after the date when the month is changed.
I am getting events dates in a while loop, so how do I compare the current event date with the coming event date in a loop.
This is the code I have used so far to get the dates from the database..
$nid = $row->nid;
$get_product_id = "SELECT product_id from {uc_product_kits} where nid='$nid'";
$res = db_query($get_product_id);
while ($get_product_id_array_value = db_fetch_array($res)) {
$prductid = $get_product_id_array_value['product_id'];
$start_date = db_query("select event_start,event_end from {event} where nid=%d",$prductid);
$start_date_value = db_fetch_object($start_date);
$end_value = $start_date_value->event_start;
$event_end_date = $start_date_value->event_end;
$TotalStart = date("d M Y", strtotime($end_value));
$TotalEnd = date("d M Y", strtotime($event_end_date));
$onlyMonthStart = date("M", strtotime($end_value));
$onlyMonthEnd = date("M", strtotime($event_end_date));
//$groupMonth = db_query("select event_start,event_end, month from {event} where nid=%d group by ",$prductid);
if($TotalStart == $TotalEnd ){
$startDay = date("d", strtotime($end_value));
$startMonth = date("M", strtotime($end_value));
if(in_array($startMonth,$newMonth)) {
echo $onlstartdate;
}
else {
$onlstartdate = date("d", strtotime($end_value));
echo $onlstartdate;
$tempStorage[] = $startMonth
}
//$newMonth[] = $startMonth;
}
}
Easiest would be to first collect all data from your query into e.g. array.
Only then iterate over the array. Having all data together will allow you to compare two consecutive date ranges to decide level of details you need to print for each.
Commented example:
// collect data from SQL query into structure like this:
$events = array(
array("event_start" => "2013-4-4", "event_end" => "2013-4-4"),
array("event_start" => "2013-4-7", "event_end" => "2013-4-7"),
array("event_start" => "2013-4-9", "event_end" => "2013-4-9"),
array("event_start" => "2013-4-20", "event_end" => "2013-4-20"),
array("event_start" => "2013-5-5", "event_end" => "2013-5-10"),
array("event_start" => "2014-1-1", "event_end" => "2014-1-2"),
);
// the actual code for range list generation:
for ($i = 0; $i < count($events); $i++)
{
// parse start and end of this range
$this_event = $events[$i];
$this_start_date = strtotime($this_event["event_start"]);
$this_end_date = strtotime($this_event["event_end"]);
// extract months and years
$this_start_month = date("M", $this_start_date);
$this_end_month = date("M", $this_end_date);
$this_start_year = date("Y", $this_start_date);
$this_end_year = date("Y", $this_end_date);
$last = ($i == count($events) - 1);
// parse start and end of next range, if any
if (!$last)
{
$next_event = $events[$i + 1];
$next_start_date = strtotime($next_event["event_start"]);
$next_end_date = strtotime($next_event["event_end"]);
$next_start_month = date("M", $next_start_date);
$next_end_month = date("M", $next_end_date);
$next_start_year = date("Y", $next_start_date);
$next_end_year = date("Y", $next_end_date);
}
// ranges with different starting and ending months always go
// on their own line
if (($this_start_month != $this_end_month) ||
($this_start_year != $this_end_year))
{
echo date("j M", $this_start_date);
// print starting year only if it differs from ending year
if ($this_start_year != $this_end_year)
{
echo " ".date("Y", $this_start_date);
}
echo "-".date("j M Y", $this_end_year)." <br/>\n";
}
else
{
// this is range starting and ending in the same month
echo date("j", $this_start_date);
// different starting and ending day
if ($this_start_date != $this_end_date)
{
echo "-".date("j", $this_end_date);
}
$newline = false;
// print month for the last range;
// and for any range that starts(=ends) in different month
// than the next range ends
if ($last ||
($this_start_month != $next_end_month))
{
echo " ".date("M", $this_start_date);
$newline = true;
}
// print year for the last range;
// and for any range that starts(=ends) in different year
// than next range ends
if ($last ||
($this_start_year != $next_end_year) ||
($next_start_month != $next_end_month))
{
echo " ".date("Y", $this_start_date);
$newline = true;
}
if ($newline)
{
echo " <br/>\n";
}
else
{
// month (and year) will be printed for some future range
// on the same line
echo ", ";
}
}
}
This outputs:
4, 7, 9, 20 Apr <br/>
5-10 May 2013 <br/>
1-2 Jan 2014 <br/>
A possibility to check if you need to print the month for the current date item is actually to check in the next item. Let me try to explain with pseudocode:
<?php
$month = 0; // Initialize $month variable to unset
// Loop over all your events
foreach($dates as $date) {
// Convert $date to a timestamp
// If the 'month' of the current $timestamp is unequal to $month
// it means we switch months and we have to print the $month first
if(date('m', $timestamp) != $month) {
echo $month; // Of course format how you want it to be displayed
// Set $month to the new month
$month = date('m', $timestamp);
}
// Print the rest of the event, like day numbers here
}
?>
Well, since you need to compare value from one loop to another, you won't be able to use echo directly.
You need to use temp variables. So with the first loop for the start date, you store $tmp_day_1 and $tmp_month_1 then with the end date loop you can compare both months and check if they are diferents. Then you can use echo. I hope I make my point :)
I would like validate the current date with question posted date if date difference is greater then 1 day then it needs to show in over due question also this will not consider the array of dates which are already i having in my array.
Like if a question posted on 20-July-11.
exemption date array {'21-July-11', ... etc}
current date is 22-July-11
then the output needs to be shown like question is waiting for 1 day instead of 2 days.
can any one help on it.
That is some example code I have created for you to calculate the due date. When you submit a question, calculate the due date that way and store it in the database with entry for that question...
<?php
$daysDue = 2;
$exDatesArray = array("2011-07-21", "2011-07-23"); //array with all your holiday dates.
$question_1_Date = "2011-07-21";
$question_2_Date = "2011-07-18";
$question_3_Date = "2011-07-20";
echo "Holidays on: ";
foreach( $exDatesArray AS $exdate )
{
echo $exdate . ", ";
}
echo "<br/><br/>";
echo "submit date -> due date<br/>";
echo $question_1_Date . " -> " . calculateDueDate( $question_1_Date, $exDatesArray, $daysDue ) . "<br/>";
echo $question_2_Date . " -> " . calculateDueDate( $question_2_Date, $exDatesArray, $daysDue ) . "<br/>";
echo $question_3_Date . " -> " . calculateDueDate( $question_3_Date, $exDatesArray, $daysDue );
function calculateDueDate( $date, $exDates, $daysDue )
{
//start with day 1
$count = 1;
//now we loop from day one to due days
while( $count <= $daysDue )
{
//add one day to start date
$date = add_date( $date, 1 );
//check if that new date is a holiday
if( !in_array($date , $exDates) )
{
//only if it is not a holiday we increase counter, otherwise we dont count that day towards due period
$count++;
}
}
//return calculated due date
return $date;
}
function add_date($date,$days)
{
$cd = strtotime($date);
return date('Y-m-d', mktime(0,0,0,date('m',$cd),date('d',$cd) + $days, date('Y',$cd)));
}
?>
Output:
Holidays on: 2011-07-21, 2011-07-23,
submit date -> due date
2011-07-21 -> 2011-07-24
2011-07-18 -> 2011-07-20
2011-07-20 -> 2011-07-24
//convert date to unixtime (seconds)
$question_sec = strtotime($question);
//subtract
$diff = time() - $question_sec;
$days = $diff / 60*60*24;
echo "$days old";
Does anyone have a PHP snippet to calculate the next business day for a given date?
How does, for example, YYYY-MM-DD need to be converted to find out the next business day?
Example:
For 03.04.2011 (DD-MM-YYYY) the next business day is 04.04.2011.
For 08.04.2011 the next business day is 11.04.2011.
This is the variable containing the date I need to know the next business day for
$cubeTime['time'];
Variable contains: 2011-04-01
result of the snippet should be: 2011-04-04
Next Weekday
This finds the next weekday from a specific date (not including Saturday or Sunday):
echo date('Y-m-d', strtotime('2011-04-05 +1 Weekday'));
You could also do it with a date variable of course:
$myDate = '2011-04-05';
echo date('Y-m-d', strtotime($myDate . ' +1 Weekday'));
UPDATE: Or, if you have access to PHP's DateTime class (very likely):
$date = new DateTime('2018-01-27');
$date->modify('+7 weekday');
echo $date->format('Y-m-d');
Want to Skip Holidays?:
Although the original poster mentioned "I don't need to consider holidays", if you DO happen to want to ignore holidays, just remember - "Holidays" is just an array of whatever dates you don't want to include and differs by country, region, company, person...etc.
Simply put the above code into a function that excludes/loops past the dates you don't want included. Something like this:
$tmpDate = '2015-06-22';
$holidays = ['2015-07-04', '2015-10-31', '2015-12-25'];
$i = 1;
$nextBusinessDay = date('Y-m-d', strtotime($tmpDate . ' +' . $i . ' Weekday'));
while (in_array($nextBusinessDay, $holidays)) {
$i++;
$nextBusinessDay = date('Y-m-d', strtotime($tmpDate . ' +' . $i . ' Weekday'));
}
I'm sure the above code can be simplified or shortened if you want. I tried to write it in an easy-to-understand way.
For UK holidays you can use
https://www.gov.uk/bank-holidays#england-and-wales
The ICS format data is easy to parse. My suggestion is...
# $date must be in YYYY-MM-DD format
# You can pass in either an array of holidays in YYYYMMDD format
# OR a URL for a .ics file containing holidays
# this defaults to the UK government holiday data for England and Wales
function addBusinessDays($date,$numDays=1,$holidays='') {
if ($holidays==='') $holidays = 'https://www.gov.uk/bank-holidays/england-and-wales.ics';
if (!is_array($holidays)) {
$ch = curl_init($holidays);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
$ics = curl_exec($ch);
curl_close($ch);
$ics = explode("\n",$ics);
$ics = preg_grep('/^DTSTART;/',$ics);
$holidays = preg_replace('/^DTSTART;VALUE=DATE:(\\d{4})(\\d{2})(\\d{2}).*/s','$1-$2-$3',$ics);
}
$addDay = 0;
while ($numDays--) {
while (true) {
$addDay++;
$newDate = date('Y-m-d', strtotime("$date +$addDay Days"));
$newDayOfWeek = date('w', strtotime($newDate));
if ( $newDayOfWeek>0 && $newDayOfWeek<6 && !in_array($newDate,$holidays)) break;
}
}
return $newDate;
}
function next_business_day($date) {
$add_day = 0;
do {
$add_day++;
$new_date = date('Y-m-d', strtotime("$date +$add_day Days"));
$new_day_of_week = date('w', strtotime($new_date));
} while($new_day_of_week == 6 || $new_day_of_week == 0);
return $new_date;
}
This function should ignore weekends (6 = Saturday and 0 = Sunday).
This function will calculate the business day in the future or past. Arguments are number of days, forward (1) or backwards(0), and a date. If no date is supplied todays date will be used:
// returned $date Y/m/d
function work_days_from_date($days, $forward, $date=NULL)
{
if(!$date)
{
$date = date('Y-m-d'); // if no date given, use todays date
}
while ($days != 0)
{
$forward == 1 ? $day = strtotime($date.' +1 day') : $day = strtotime($date.' -1 day');
$date = date('Y-m-d',$day);
if( date('N', strtotime($date)) <= 5) // if it's a weekday
{
$days--;
}
}
return $date;
}
What you need to do is:
Convert the provided date into a timestamp.
Use this along with the or w or N formatters for PHP's date command to tell you what day of the week it is.
If it isn't a "business day", you can then increment the timestamp by a day (86400 seconds) and check again until you hit a business day.
N.B.: For this is really work, you'd also need to exclude any bank or public holidays, etc.
I stumbled apon this thread when I was working on a Danish website where I needed to code a "Next day delivery" PHP script.
Here is what I came up with (This will display the name of the next working day in Danish, and the next working + 1 if current time is more than a given limit)
$day["Mon"] = "Mandag";
$day["Tue"] = "Tirsdag";
$day["Wed"] = "Onsdag";
$day["Thu"] = "Torsdag";
$day["Fri"] = "Fredag";
$day["Sat"] = "Lørdag";
$day["Sun"] = "Søndag";
date_default_timezone_set('Europe/Copenhagen');
$date = date('l');
$checkTime = '1400';
$date2 = date(strtotime($date.' +1 Weekday'));
if( date( 'Hi' ) >= $checkTime) {
$date2 = date(strtotime($date.' +2 Weekday'));
}
if (date('l') == 'Saturday'){
$date2 = date(strtotime($date.' +2 Weekday'));
}
if (date('l') == 'Sunday') {
$date2 = date(strtotime($date.' +2 Weekday'));
}
echo '<p>Næste levering: <span>'.$day[date("D", $date2)].'</span></p>';
As you can see in the sample code $checkTime is where I set the time limit which determines if the next day delivery will be +1 working day or +2 working days.
'1400' = 14:00 hours
I know that the if statements can be made more compressed, but I show my code for people to easily understand the way it works.
I hope someone out there can use this little snippet.
Here is the best way to get business days (Mon-Fri) in PHP.
function days()
{
$week=array();
$weekday=["Monday","Tuesday","Wednesday","Thursday","Friday"];
foreach ($weekday as $key => $value)
{
$sort=$value." this week";
$day=date('D', strtotime($sort));
$date=date('d', strtotime($sort));
$year=date('Y-m-d', strtotime($sort));
$weeks['day']= $day;
$weeks['date']= $date;
$weeks['year']= $year;
$week[]=$weeks;
}
return $week;
}
Hope this will help you guys.
Thanks,.
See the example below:
$startDate = new DateTime( '2013-04-01' ); //intialize start date
$endDate = new DateTime( '2013-04-30' ); //initialize end date
$holiday = array('2013-04-11','2013-04-25'); //this is assumed list of holiday
$interval = new DateInterval('P1D'); // set the interval as 1 day
$daterange = new DatePeriod($startDate, $interval ,$endDate);
foreach($daterange as $date){
if($date->format("N") <6 AND !in_array($date->format("Y-m-d"),$holiday))
$result[] = $date->format("Y-m-d");
}
echo "<pre>";print_r($result);
For more info: http://goo.gl/YOsfPX
You could do something like this.
/**
* #param string $date
* #param DateTimeZone|null|null $DateTimeZone
* #return \NavigableDate\NavigableDateInterface
*/
function getNextBusinessDay(string $date, ? DateTimeZone $DateTimeZone = null):\NavigableDate\NavigableDateInterface
{
$Date = \NavigableDate\NavigableDateFacade::create($date, $DateTimeZone);
$NextDay = $Date->nextDay();
while(true)
{
$nextDayIndexInTheWeek = (int) $NextDay->format('N');
// check if the day is between Monday and Friday. In DateTime class php, Monday is 1 and Friday is 5
if ($nextDayIndexInTheWeek >= 1 && $nextDayIndexInTheWeek <= 5)
{
break;
}
$NextDay = $NextDay->nextDay();
}
return $NextDay;
}
$date = '2017-02-24';
$NextBussinessDay = getNextBusinessDay($date);
var_dump($NextBussinessDay->format('Y-m-d'));
Output:
string(10) "2017-02-27"
\NavigableDate\NavigableDateFacade::create($date, $DateTimeZone), is provided by php library available at https://packagist.org/packages/ishworkh/navigable-date. You need to first include this library in your project with composer or direct download.
I used below methods in PHP, strtotime() does not work specially in leap year February month.
public static function nextWorkingDay($date, $addDays = 1)
{
if (strlen(trim($date)) <= 10) {
$date = trim($date)." 09:00:00";
}
$date = new DateTime($date);
//Add days
$date->add(new DateInterval('P'.$addDays.'D'));
while ($date->format('N') >= 5)
{
$date->add(new DateInterval('P1D'));
}
return $date->format('Y-m-d H:i:s');
}
This solution for 5 working days (you can change if you required for 6 or 4 days working). if you want to exclude more days like holidays then just check another condition in while loop.
//
while ($date->format('N') >= 5 && !in_array($date->format('Y-m-d'), self::holidayArray()))