Related
I know how to get the previous Quarter number how to turn that into date ranges especially when it goes into the previous year?
$Quarter = floor((date('n') - 1) / 3);
Here you go:
function getQuarter(\DateTime $DateTime) {
$y = $DateTime->format('Y');
$m = $DateTime->format('m');
switch($m) {
case $m >= 1 && $m <= 3:
$start = '01/01/'.$y;
$end = (new DateTime('03/1/'.$y))->modify('Last day of this month')->format('m/d/Y');
$title = 'Q1 '.$y;
break;
case $m >= 4 && $m <= 6:
$start = '04/01/'.$y;
$end = (new DateTime('06/1/'.$y))->modify('Last day of this month')->format('m/d/Y');
$title = 'Q2 '.$y;
break;
case $m >= 7 && $m <= 9:
$start = '07/01/'.$y;
$end = (new DateTime('09/1/'.$y))->modify('Last day of this month')->format('m/d/Y');
$title = 'Q3 '.$y;
break;
case $m >= 10 && $m <= 12:
$start = '10/01/'.$y;
$end = (new DateTime('12/1/'.$y))->modify('Last day of this month')->format('m/d/Y');
$title = 'Q4 '.$y;
break;
}
return array(
'start' => $start,
'end' => $end,
'title'=>$title,
'start_nix' => strtotime($start),
'end_nix' => strtotime($end)
);
}
print_r(getQuarter(new DateTime()));
Output
Array
(
[start] => 10/01/2018
[end] => 12/31/2018
[title] => Q4 2018
[start_nix] => 1538377200
[end_nix] => 1546243200
)
Sandbox
Your in luck I wrote this a wile ago ... This is sort of the brute force way of doing it, but hey it works. There is probably a "fancier" way, but whatever...
UPDATE
Based on some comments using DateTime has many advantages, besides just making the code in the function more concise. For example to get a previous quarter:
print_r(getQuarter((new DateTime())->modify('-3 Months'));
Output
Array
(
[start] => 07/01/2018
[end] => 09/30/2018
[title] => Q3 2018
[start_nix] => 1530428400
[end_nix] => 1538290800
)
Sandbox
Here the extra parentheses are important (around new DateTime)
(new DateTime())->modify('-3 Months');
This causes the constructor to return the instance of the object, which lets you immediately call modify on it. It's equivalent to doing this:
$DateTime = new DateTime();
$DateTime->modify('-3 Months');
But without creating a local variable.
And on the same token you can get the next quarter by doing
print_r(getQuarter((new DateTime())->modify('+3 Months'));
Another example of this is in the function itself (specifically):
(new DateTime('03/1/'.$y))->modify('Last day of this month')
What this does is get the last day of whatever month the DateTime object has, in this case it's 3. So we don't have to even think of how many days that month has, it just returns the correct number. These are Relative Date formats
http://php.net/manual/en/datetime.formats.relative.php
One last one that may be of use to you is this one first day of ? this year where the ? is the month name. For example:
print_r(getQuarter((new DateTime())->modify('first day of january this year')));
print_r(getQuarter((new DateTime())->modify('first day of april this year')));
print_r(getQuarter((new DateTime())->modify('first day of july this year')));
print_r(getQuarter((new DateTime())->modify('first day of october this year')));
Effectively this will give you each quarter this year.
Hope that helps.
A simple one-liner for each start and end date would be:
$start = (new DateTime('first day of -' . (((date('n') - 1) % 3) + 3) . ' month'))->format('Y-m-d'); # first day of previous quarter
$end = (new DateTime('last day of -' . (((date('n') - 1) % 3) + 1) . ' month'))->format('Y-m-d'); # last day of previous quarter
DateTime can work with relative values so you can describe which date you want.
I am using this code. It uses DateTime object and its methods.
The main method is getCurrentQuarterStartDate(), the other 2 methods use it.
You can obtain not only dates of previous quarter, but of any other quarter in the past and in the future.
<?php
echo "Current quarter start: \n";
$dt = getCurrentQuarterStartDate();
var_dump($dt->format('Y-m-d'));
echo "Current quarter end: \n";
$dt = getRelativeQuarterEndDate(0);
var_dump($dt->format('Y-m-d'));
echo "Next quarter start: \n";
$dt = getRelativeQuarterStartDate(1);
var_dump($dt->format('Y-m-d'));
echo "Next quarter end: \n";
$dt = getRelativeQuarterEndDate(1);
var_dump($dt->format('Y-m-d'));
echo "Prev quarter start: \n";
$dt = getRelativeQuarterStartDate(-1);
var_dump($dt->format('Y-m-d'));
echo "Prev quarter end: \n";
$dt = getRelativeQuarterEndDate(-1);
var_dump($dt->format('Y-m-d'));
function getCurrentQuarterStartDate()
{
$dt = new DateTime('now', new DateTimeZone('Europe/Prague'));
$currentMonth = (int)$dt->format('m');
$currentYear = (int)$dt->format('Y');
$currentQuartalNr = ceil($currentMonth / 3); // returns 0.333-4 and it is ceiled to 1-4
$currentQuartalStartMonth = $currentQuartalNr * 3 - 2; // returns 1,4,7 or 10
$dt->setDate($currentYear, $currentQuartalStartMonth, 1);
return $dt;
}
/**
* #param $offset 0 = current quarter, 1 = next, -1 = prev, -2, +5 ...
*/
function getRelativeQuarterStartDate($offset = 0)
{
$currentQStartDate = getCurrentQuarterStartDate();
if ($offset == 0) {
return $currentQStartDate;
}
if ($offset > 0) {
$currentQStartDate->add(new \DateInterval('P' . $offset*3 . 'M'));
return $currentQStartDate;
}
if ($offset < 0) {
$currentQStartDate->sub(new \DateInterval('P' . abs($offset)*3 . 'M'));
return $currentQStartDate;
}
}
/**
* #param $offset 0 = current quarter, 1 = next, -1 = prev, -2, +5 ...
*/
function getRelativeQuarterEndDate($offset = 0)
{
$dt = getCurrentQuarterStartDate();
if ($offset >= 0) {
$dt->add(new \DateInterval('P' . $offset*3 . 'M'));
}
if ($offset < 0) {
$dt->sub(new \DateInterval('P' . abs($offset)*3 . 'M'));
}
$dt->add(new \DateInterval('P3M'));
$dt->sub(new \DateInterval('P1D'));
return $dt;
}
Find Previous Quarter start and end date
function getpreviousQuarterData(\DateTime $DateTime) {
$y = $DateTime->format('Y');
$m = $DateTime->format('m');
switch($m) {
case $m >= 1 && $m <= 3:
$start = '10/01/'.$y-1;
$end = (new DateTime('12/1/'.$y-1))->modify('Last day of this month')->format('m/d/'.$y-1);
$title = 'Q4 '.$y-1;
break;
case $m >= 4 && $m <= 6:
$start = '01/01/'.$y;
$end = (new DateTime('03/1/'.$y))->modify('Last day of this month')->format('m/d/Y');
$title = 'Q1 '.$y;
break;
case $m >= 7 && $m <= 9:
$start = '04/01/'.$y;
$end = (new DateTime('06/1/'.$y))->modify('Last day of this month')->format('m/d/Y');
$title = 'Q2 '.$y;
break;
case $m >= 10 && $m <= 12:
$start = '07/01/'.$y;
$end = (new DateTime('09/1/'.$y))->modify('Last day of this month')->format('m/d/Y');
$title = 'Q3 '.$y;
break;
}
return array(
'start' => $start,
'end' => $end,
'title'=>$title,
'start_nix' => strtotime($start),
'end_nix' => strtotime($end)
);
}
I have an array of random dates (not coming from MySQL). I need to group them by the week as Week1, Week2, and so on upto Week5.
What I have is this:
$dates = array('2015-09-01','2015-09-05','2015-09-06','2015-09-15','2015-09-17');
What I need is a function to get the week number of the month by providing the date.
I know that I can get the weeknumber by doing
date('W',strtotime('2015-09-01'));
but this week number is the number between year (1-52) but I need the week number of the month only, e.g. in Sep 2015 there are 5 weeks:
Week1 = 1st to 5th
Week2 = 6th to 12th
Week3 = 13th to 19th
Week4 = 20th to 26th
Week5 = 27th to 30th
I should be able to get the week Week1 by just providing the date
e.g.
$weekNumber = getWeekNumber('2015-09-01') //output 1;
$weekNumber = getWeekNumber('2015-09-17') //output 3;
I think this relationship should be true and come in handy:
Week of the month = Week of the year - Week of the year of first day of month + 1
We also need to make sure that "overlapping" weeks from the previous year are handeled correctly - if January 1st is in week 52 or 53, it should be counted as week 0. In a similar fashion, if a day in December is in the first week of the next year, it should be counted as 53. (Previous versions of this answer failed to do this properly.)
<?php
function weekOfMonth($date) {
//Get the first day of the month.
$firstOfMonth = strtotime(date("Y-m-01", $date));
//Apply above formula.
return weekOfYear($date) - weekOfYear($firstOfMonth) + 1;
}
function weekOfYear($date) {
$weekOfYear = intval(date("W", $date));
if (date('n', $date) == "1" && $weekOfYear > 51) {
// It's the last week of the previos year.
return 0;
}
else if (date('n', $date) == "12" && $weekOfYear == 1) {
// It's the first week of the next year.
return 53;
}
else {
// It's a "normal" week.
return $weekOfYear;
}
}
// A few test cases.
echo weekOfMonth(strtotime("2020-04-12")) . " "; // 2
echo weekOfMonth(strtotime("2020-12-31")) . " "; // 5
echo weekOfMonth(strtotime("2020-01-02")) . " "; // 1
echo weekOfMonth(strtotime("2021-01-28")) . " "; // 5
echo weekOfMonth(strtotime("2018-12-31")) . " "; // 6
To get weeks that starts with sunday, simply replace date("W", ...) with strftime("%U", ...).
You can use the function below, fully commented:
/**
* Returns the number of week in a month for the specified date.
*
* #param string $date
* #return int
*/
function weekOfMonth($date) {
// estract date parts
list($y, $m, $d) = explode('-', date('Y-m-d', strtotime($date)));
// current week, min 1
$w = 1;
// for each day since the start of the month
for ($i = 1; $i < $d; ++$i) {
// if that day was a sunday and is not the first day of month
if ($i > 1 && date('w', strtotime("$y-$m-$i")) == 0) {
// increment current week
++$w;
}
}
// now return
return $w;
}
The corect way is
function weekOfMonth($date) {
$firstOfMonth = date("Y-m-01", strtotime($date));
return intval(date("W", strtotime($date))) - intval(date("W", strtotime($firstOfMonth)));
}
I have created this function on my own, which seems to work correctly. In case somebody else have a better way of doing this, please share.. Here is what I have done.
function weekOfMonth($qDate) {
$dt = strtotime($qDate);
$day = date('j',$dt);
$month = date('m',$dt);
$year = date('Y',$dt);
$totalDays = date('t',$dt);
$weekCnt = 1;
$retWeek = 0;
for($i=1;$i<=$totalDays;$i++) {
$curDay = date("N", mktime(0,0,0,$month,$i,$year));
if($curDay==7) {
if($i==$day) {
$retWeek = $weekCnt+1;
}
$weekCnt++;
} else {
if($i==$day) {
$retWeek = $weekCnt;
}
}
}
return $retWeek;
}
echo weekOfMonth('2015-09-08') // gives me 2;
function getWeekOfMonth(DateTime $date) {
$firstDayOfMonth = new DateTime($date->format('Y-m-1'));
return ceil(($firstDayOfMonth->format('N') + $date->format('j') - 1) / 7);
}
Goendg solution does not work for 2016-10-31.
function weekOfMonth($strDate) {
$dateArray = explode("-", $strDate);
$date = new DateTime();
$date->setDate($dateArray[0], $dateArray[1], $dateArray[2]);
return floor((date_format($date, 'j') - 1) / 7) + 1;
}
weekOfMonth ('2015-09-17') // returns 3
Given the time_t wday (0=Sunday through 6=Saturday) of the first of the month in firstWday, this returns the (Sunday-based) week number within the month:
weekOfMonth = floor((dayOfMonth + firstWday - 1)/7) + 1
Translated into PHP:
function weekOfMonth($dateString) {
list($year, $month, $mday) = explode("-", $dateString);
$firstWday = date("w",strtotime("$year-$month-1"));
return floor(($mday + $firstWday - 1)/7) + 1;
}
You can also use this simple formula for finding week of the month
$currentWeek = ceil((date("d",strtotime($today_date)) - date("w",strtotime($today_date)) - 1) / 7) + 1;
ALGORITHM :
Date = '2018-08-08' => Y-m-d
Find out day of the month eg. 08
Find out Numeric representation of the day of the week minus 1 (number of days in week) eg. (3-1)
Take difference and store in result
Subtract 1 from result
Divide it by 7 to result and ceil the value of result
Add 1 to result eg. ceil(( 08 - 3 ) - 1 ) / 7) + 1 = 2
My function. The main idea: we would count amount of weeks passed from the month's first date to current. And the current week number would be the next one. Works on rule: "Week starts from monday" (for sunday-based type we need to transform the increasing algorithm)
function GetWeekNumberOfMonth ($date){
echo $date -> format('d.m.Y');
//define current year, month and day in numeric
$_year = $date -> format('Y');
$_month = $date -> format('n');
$_day = $date -> format('j');
$_week = 0; //count of weeks passed
for ($i = 1; $i < $_day; $i++){
echo "\n\n-->";
$_newDate = mktime(0,0,1, $_month, $i, $_year);
echo "\n";
echo date("d.m.Y", $_newDate);
echo "-->";
echo date("N", $_newDate);
//on sunday increasing weeks passed count
if (date("N", $_newDate) == 7){
echo "New week";
$_week += 1;
}
}
return $_week + 1; // as we are counting only passed weeks the current one would be on one higher
}
$date = new DateTime("2019-04-08");
echo "\n\nResult: ". GetWeekNumberOfMonth($date);
$month = 6;
$year = 2021;
$week = date("W", strtotime($year . "-" . $month ."-01"));
$str='';
$str .= date("d-m-Y", strtotime($year . "-" . $month ."-01")) ."to";
$unix = strtotime($year."W".$week ."+1 week");
while(date("m", $unix) == $month){
$str .= date("d-m-Y", $unix-86400) . "|";
$str .= date("d-m-Y", $unix) ."to";
$unix = $unix + (86400*7);
}
$str .= date("d-m-Y", strtotime("last day of ".$year . "-" . $month));
$weeks_ar = explode('|',$str);
echo '<pre>'; print_r($weeks_ar);
working fine.
// Current week of the month starts with Sunday
$first_day_of_the_week = 'Sunday';
$start_of_the_week1 = strtotime("Last $first_day_of_the_week");
if (strtolower(date('l')) === strtolower($first_day_of_the_week)) {
$start_of_the_week1 = strtotime('today');
}
$end_of_the_week1 = $start_of_the_week1 + (60 * 60 * 24 * 7) - 1;
// Get the date format
print date('Y-m-d', $start_of_the_week1) . ' 00:00:00';
print date('Y-m-d', $end_of_the_week1) . ' 23:59:59';
// self::DAYS_IN_WEEK = 7;
function getWeeksNumberOfMonth(): int
{
$currentDate = new \DateTime();
$dayNumberInMonth = (int) $currentDate->format('j');
$dayNumberInWeek = (int) $currentDate->format('N');
$dayNumberToLastSunday = $dayNumberInMonth - $dayNumberInWeek;
$daysCountInFirstWeek = $dayNumberToLastSunday % self::DAYS_IN_WEEK;
$weeksCountToLastSunday = ($dayNumberToLastSunday - $daysCountInFirstWeek) / self::DAYS_IN_WEEK;
$weeks = [];
array_push($weeks, $daysCountInFirstWeek);
for ($i = 0; $i < $weeksCountToLastSunday; $i++) {
array_push($weeks, self::DAYS_IN_WEEK);
}
array_push($weeks, $dayNumberInWeek);
if (array_sum($weeks) !== $dayNumberInMonth) {
throw new Exception('Logic is not valid');
}
return count($weeks);
}
Short variant:
(int) (new \DateTime())->format('W') - (int) (new \DateTime('first day of this month'))->format('W') + 1;
There is a many solutions but here is one my solution that working well in the most cases.
function current_week ($date = NULL) {
if($date) {
if(is_numeric($date) && ctype_digit($date) && strtotime(date('Y-m-d H:i:s',$date)) === (int)$date)
$unix_timestamp = $date;
else
$unix_timestamp = strtotime($date);
} else $unix_timestamp = time();
return (ceil((date('d', $unix_timestamp) - date('w', $unix_timestamp) - 1) / 7) + 1);
}
It accept unix timestamp, normal date or return current week from the time() if you not pass any value.
Enjoy!
I know this an old post but i have an idea!
$datetime0 = date_create("1970-01-01");
$datetime1 = date_create(date("Y-m-d",mktime(0,0,0,$m,"01",$Y)));
$datetime2 = date_create(date("Y-m-d",mktime(0,0,0,$m,$d,$Y)));
$interval1 = date_diff($datetime0, $datetime1);
$daysdiff1= $interval1->format('%a');
$interval2 = date_diff($datetime0, $datetime2);
$daysdiff2= $interval2->format('%a');
$week1=round($daysdiff1/7);
$week2=round($daysdiff2/7);
$WeekOfMonth=$week2-$week1+1;
$date = new DateTime('first Monday of this month');
$thisMonth = $date->format('m');
$mondays_arr = [];
// Get all the Mondays in the current month and store in array
while ($date->format('m') === $thisMonth) {
//echo $date->format('Y-m-d'), "\n";
$mondays_arr[] = $date->format('d');
$date->modify('next Monday');
}
// Get the day of the week (1-7 from monday to sunday)
$day_of_week = date('N') - 1;
// Get the day of month (1 to 31)
$current_week_monday_date = date('j') - $day_of_week;
/*$day_of_week = date('N',mktime(0, 0, 0, 2, 11, 2020)) - 1;
$current_week_monday_date = date('j',mktime(0, 0, 0, 2, 11, 2020)) - $day_of_week;*/
$week_no = array_search($current_week_monday_date,$mondays_arr) + 1;
echo "Week No: ". $week_no;
How about this function making use of PHP's relative dates?
This function assumes the week ends on Saturday. But this can be changed easily.
function get_weekNumMonth($date) {
$CI = &get_instance();
$strtotimedate = strtotime($date);
$firstweekEnd = date('j', strtotime("FIRST SATURDAY OF " . date("F", $strtotimedate) . " " . date("Y", $strtotimedate)));
$cutoff = date('j', strtotime($date));
$weekcount = 1;
while ($cutoff > $firstweekEnd) {
$weekcount++;
$firstweekEnd += 7; // move to next week
}
return $weekcount;
}
This function returns the integer week number of the current month. Weeks always start on Monday and counting always starts with 1.
function weekOfmonth(DateTime $date)
{
$dayFirstMonday = date_create('first monday of '.$date->format('F Y'))->format('j');
return (int)(($date->format('j') - $dayFirstMonday +7)/7) + ($dayFirstMonday == 1 ? 0 : 1);
}
Example of use
echo weekOfmonth(new DateTime("2020-04-12")); //2
A test for all days from 1900-2038 with the accepted solution from #Anders as a reference:
//reference functions
//integer $date (Timestamp)
function weekOfMonthAnders($date) {
//Get the first day of the month.
$firstOfMonth = strtotime(date("Y-m-01", $date));
//Apply above formula.
return weekOfYear($date) - weekOfYear($firstOfMonth) + 1;
}
function weekOfYear($date) {
$weekOfYear = intval(date("W", $date));
if (date('n', $date) == "1" && $weekOfYear > 51) {
// It's the last week of the previos year.
return 0;
}
else if (date('n', $date) == "12" && $weekOfYear == 1) {
// It's the first week of the next year.
return 53;
}
else {
// It's a "normal" week.
return $weekOfYear;
}
}
//this function
function weekOfmonth(DateTime $date)
{
$dayFirstMonday = date_create('first monday of '.$date->format('F Y'))->format('j');
return (int)(($date->format('j') - $dayFirstMonday +7)/7) + ($dayFirstMonday == 1 ? 0 : 1);
}
$dt = date_create('1900-01-01');
$end = date_create('2038-01-02');
$countOk = 0;
$countError = 0;
for(;$dt < $end; $dt->modify('+1 Day')){
$ts = $dt->getTimestamp();
if(weekOfmonth($dt) === weekOfMonthAnders($ts)){
++$countOk;
}
else {
++$countError;
}
}
echo $countOk.' compare ok, '.$countError.' errors';
Result: 50405 compare ok, 0 errors
I took the visual approach (like how we do it in the real world). Instead of using formulas or what not, I solved it (or at least I think I did) by visualizing a literal calendar and then putting the dates in a multidimensional array. The first dimension corresponds to the week.
I hope someone can check if it stands your tests. Or help someone out with a different approach.
# date in this format 2021-08-03
# week_start is either Sunday or Monday
function getWeekOfMonth($date, $week_start = "Sunday"){
list($year, $month, $day) = explode("-", $date);
$dates = array();
$current_week = 1;
$new_week_signal = $week_start == "Sunday" ? 6 : 0;
for($i = 1; $i <= date("t", strtotime($date)); $i++){
$current_date = strtotime("{$year}-{$month}-".$i);
$dates[$current_week][] = $i;
if(date('w', $current_date) == $new_week_signal){
$current_week++;
}
}
foreach($dates as $week => $days){
if(in_array(intval($day), $days)){
return $week;
}
}
return false;
}
//It's easy, no need to use php function
//Let's say your date is 2017-07-02
$Date = explode("-","2017-07-02");
$DateNo = $Date[2];
$WeekNo = $DateNo / 7; // devide it with 7
if(is_float($WeekNo) == true)
{
$WeekNo = ceil($WeekNo); //So answer will be 1
}
//If value is not float then ,you got your answer directly
I have array of week numbers from 1 to 52. how i can convert it to
[week 1 jan],[week 2 jan] .......
using PHP
OK ... I fix it and here is my code
function getWeeks($date, $rollover)
{
$cut = substr($date, 0, 8);
$daylen = 86400;
$timestamp = strtotime($date);
$first = strtotime($cut . "00");
$elapsed = ($timestamp - $first) / $daylen;
$i = 1;
$weeks = 1;
for($i; $i<=$elapsed; $i++)
{
$dayfind = $cut . (strlen($i) < 2 ? '0' . $i : $i);
$daytimestamp = strtotime($dayfind);
$day = strtolower(date("l", $daytimestamp));
if($day == strtolower($rollover)) $weeks ++;
}
return $weeks;
}
and in the foreach I added
$x="1/1/2013 + ".$record->tms." weeks";
$m=date("Y-m-d", strtotime($x));
$first_week_start=getWeeks($m, "sunday");
if($first_week_start == 1){$typo="st";}
if($first_week_start == 2){$typo="nd";}
if($first_week_start == 3){$typo="rd";}
if($first_week_start == 4){$typo="th";}
if($first_week_start == 5){$typo="th";}
$month=date("M", strtotime($m));
$final_format .= "'".$first_week_start.$typo ." week in ".$month."'";
Try a loop, start with 1/jan, use DateInterval::createFromDateString('1 week'); and DateTime::add each time in the loop to add the next week, use DateTime::format to get the month also checking the current year in each iteration to make sure the loop hasn't moved to the next year.
Code:
date_default_timezone_set("UTC");
$weeks = array();
$dt = new DateTime("2013-01-01");
$interval = DateInterval::createFromDateString("1 week");
for($i=1; $i <= 52; $i++)
{
$weeks[$i] = "week " . $i . " " . $dt->format("M");
$dt = $dt->add($interval);
}
print_r($weeks);
If you want a function that will return a month abbreviation from a week:
function weekMonth($week)
{
date_default_timezone_set("UTC");
return (new DateTime("2013-01-01"))->add(DateInterval::createFromDateString($week." week"))->format("M");
}
echo weekMonth(6);
I want to calculate the number of weekdays days in a give month and year. Weekdays means monday to friday. How do i do it ?
You don't need to count every day in the month. You already know the first 28 days contain 20 weekdays no matter what. All you have to do is determine the last few days. Change the start value to 29. Then add 20 weekdays to your return value.
function get_weekdays($m,$y) {
$lastday = date("t",mktime(0,0,0,$m,1,$y));
$weekdays=0;
for($d=29;$d<=$lastday;$d++) {
$wd = date("w",mktime(0,0,0,$m,$d,$y));
if($wd > 0 && $wd < 6) $weekdays++;
}
return $weekdays+20;
}
Some basic code:
$month = 12;
$weekdays = array();
$d = 1;
do {
$mk = mktime(0, 0, 0, $month, $d, date("Y"));
#$weekdays[date("w", $mk)]++;
$d++;
} while (date("m", $mk) == $month);
print_r($weekdays);
Remove the # if your PHP error warning doesn't show notices.
try this one
function getWeekdays($m, $y = NULL){
$arrDtext = array('Mon', 'Tue', 'Wed', 'Thu', 'Fri');
if(is_null($y) || (!is_null($y) && $y == ''))
$y = date('Y');
$d = 1;
$timestamp = mktime(0,0,0,$m,$d,$y);
$lastDate = date('t', $timestamp);
$workingDays = 0;
for($i=$d; $i<=$lastDate; $i++){
if(in_array(date('D', mktime(0,0,0,$m,$i,$y)), $arrDtext)){
$workingDays++;
}
}
return $workingDays;
}
This is the simplest code I could come up with.
You really would need to create an array or a database table to hold the holidays to get a true, "Working Days" count, but that wasn't what was asked, so here you go, hope this helps someone.
function get_weekdays($m,$y) {
$lastday = date("t",mktime(0,0,0,$m,1,$y));
$weekdays=0;
for($d=1;$d<=$lastday;$d++) {
$wd = date("w",mktime(0,0,0,$m,$d,$y));
if($wd > 0 && $wd < 6) $weekdays++;
}
return $weekdays;
}
Get the number of working days without holidays between two dates :
Use example:
echo number_of_working_days('2013-12-23', '2013-12-29');
Output:
3
Link to the function
DateObject method:
function getWorkingDays(DateTime $date) {
$month = clone $date;
$month->modify('last day of this month');
$workingDays = 0;
for ($i = $month->format('t'); $i > 28; --$i) {
if ($month->format('N') < 6) {
++$workingDays;
}
$month->modify('-1 day');
}
return 20 + $workingDays;
}
Calculate working days in a month from any date:
public function getworkd($mday)
{
$dn = new DateTime($mday);
$dfrom = $dn->format('Y-m-01');
$dtill = $dn->format('Y-m-t');
$df = new DateTime($dfrom);
$dt = new DateTime($dtill);
$wdays = 0;
while($df<=$dt)
{
$dof= $df->format('D') ;
if( $dof == 'Sun' || $dof == 'Sat' ) ; else $wdays++;
$df->add(new DateInterval('P1D'));
}
return $wdays;
}
Find the last day and the weekday for the given month
then do a simple while loop like :-
$dates = explode(',', date('t,N', strtotime('2013-11-01')));
$day = $dates[1];
$tot = $dates[0];
$cnt = 0;
while ($tot>1)
{
if ($day < 6)
{
$cnt++;
}
if ($day == 1)
{
$day = 7;
}
else
{
$day--;
}
$tot--;
}
$cnt = total of weekday (Monday to Friday) for a given month
I've come up with a non-loop function. Much better in terms of performance. It might seem messy but it just needs to ask PHP the first day's weekday and the month's number days: the rest are arithmetical operations based on logic.
function countWorkDays($year, $month)
{
$workingWeekdays = 5;
$firstDayTimestamp = mktime(0, 0, 0, $month, 1, $year);
$firstDayWeekDay = (int)date("N", $firstDayTimestamp); //1: monday, 7: saturday
$upToDay = (int)date("t", $firstDayTimestamp);
$firstMonday = 1 === $firstDayWeekDay ? 1 : 9 - $firstDayWeekDay;
$wholeWeeks = $firstMonday < $upToDay ? (int)floor(($upToDay - $firstMonday + 1) / 7) : 0;
$extraDays = ($upToDay - $firstMonday + 1) % 7;
$initialWorkdays = $firstMonday > 1 && $firstDayWeekDay <= $workingWeekdays ? $workingWeekdays - $firstDayWeekDay + 1 : 0;
$workdaysInWholeWeeks = $wholeWeeks * $workingWeekdays;
$extraWorkdays = $extraDays <= $workingWeekdays ? $extraDays : $workingWeekdays;
return $initialWorkdays + $workdaysInWholeWeeks + $extraWorkdays;
}
These functions work Without Loops.
The functions calculate the number of weekdays using:
day-number of first monday in month
number of days in month
// main functions
// weekdays in month of year
function calculateNumberOfWeekDaysAtDate($month, $year)
{
// I'm sorry, I don't know the right format for the $month and $year, I hope this is right.
// PLEASE CORRECT IF WRONG
$firstMondayInCurrentMonth = (int) date("j", strtotime("first monday of 01-$month-$year")); //get first monday in month for calculations
$numberOfDaysOfCurrentMonth = (int) date("t", strtotime("01-$month-$year")); // number of days in month
return calculateNumberOfWeekDaysFromFirstMondayAndNumberOfMonthDays($firstMondayInCurrentMonth, $numberOfDaysOfCurrentMonth);
}
// week days in current month
function calculateNumberOfWeekDaysInCurrentMonth()
{
$firstMondayInCurrentMonth = (int) date("j", strtotime("first monday of this month")); //get first monday in month for calculations
$numberOfDaysOfCurrentMonth = (int) date("t"); // number of days in this month
return calculateNumberOfWeekDaysFromFirstMondayAndNumberOfMonthDays($firstMondayInCurrentMonth, $numberOfDaysOfCurrentMonth);
}
// helper functions
function calculateNumberOfWeekDaysFromFirstMondayAndNumberOfMonthDays($firstMondayInCurrentMonth, $numberOfDaysOfCurrentMonth)
{
return $numberOfWeekDays = (($start = ($firstMondayInCurrentMonth - 3)) < 0 ? 0 : $start) + floor(($numberOfDaysOfCurrentMonth - ($firstMondayInCurrentMonth - 1)) / 7) * 5 + (($rest = (($numberOfDaysOfCurrentMonth - ($firstMondayInCurrentMonth - 1)) % 7)) <= 5 ? $rest : 5);
}
function workingDays($m,$y) {
$days = cal_days_in_month(CAL_GREGORIAN, $m, $y);
$workig_days = 0;
$days_rest = array(5,6); //friday,saturday
for ( $d=1 ; $d < $days+1 ; $d++ ) {
if ( !in_array(date("w",strtotime("{$d}-{$m}-{$y}")),$days_rest) ) {
$workig_days++;
}
}
return $workig_days;
}
I created a simple function that takes the $first_day_of_month (week day like Sunday/Monday etc). You can find out the first day of month like this:
date('N', strtotime(date("01-m-Y")));
And using the $month_last_date which can be procured like this:
date("t");
Here is the function:
function workingDaysInMonth(int $first_day_of_month, int $month_last_date) : array
{
$working_days = [];
$day = $first_day_of_month;
$working_day_count = 0;
for ($i = 1; $i <= $month_last_date; $i++) {
if ($day == 8) {
$day = 1;
}
if (!($day == 6 || $day == 7)) {
$working_day_count++;
$working_days[$i] = $working_day_count;
}
$day++;
}
return $working_days;
}
this will work
// oct. 2013
$month = 10;
// loop through month days
for ($i = 1; $i <= 31; $i++) {
// given month timestamp
$timestamp = mktime(0, 0, 0, $month, $i, 2012);
// to be sure we have not gone to the next month
if (date("n", $timestamp) == $month) {
// current day in the loop
$day = date("N", $timestamp);
// if this is between 1 to 5, weekdays, 1 = Monday, 5 = Friday
if ($day == 1 OR $day <= 5) {
// write it down now
$days[$day][] = date("j", $timestamp);
}
}
}
// to see if it works :)
print_r($days);
If I have two dates - $end_date and $start_date, how can I express the difference between the two in a format such as "2 Years : 4 Months : 2 Days"?
I know that I can get the difference between the two dates like so:
$dif=strtotime($end_date)-strtotime($today);
But how can I convert that result into the human-readable format, like that shown above?
This is how you can format a timestamp:
echo date('d-m-Y', strtotime($end_date)) // for DD-MM-YYYY format
Are you looking to calculate the difference between 2 dates, in number days?
EDIT: code to find the difference between dates in "XXyear YYmonth ZZday". The code assumes that start and end dates are in YYYY-MM-DD format. If that's not the case for you, please either change them to YYYY-MM-DD format, OR change the arguments to mktime() accordingly.
$endDate = '2011-03-01';
$startDate = '2011-02-02';
$daysPerYear = 365;
$daysPerMonth = 30.4;
$diffDay = $diffMonth = $diffYear = 0;
$endDateTs = mktime(0, 0, 0, substr($endDate, 5, 2), substr($endDate, 8, 2), substr($endDate, 0, 4));
$startDateTs = mktime(0, 0, 0, substr($startDate, 5, 2), substr($startDate, 8, 2), substr($startDate, 0, 4));
$diffDay = ($endDateTs - $startDateTs) / 60 / 60/ 24; // difference between 2 dates in number of days
$diffYear = floor($diffDay / $daysPerYear); // difference in years
$diffDay = $diffDay % $daysPerYear; // balance days
$diffMonth = floor($diffDay / $daysPerMonth); // difference in months
$diffDay = ceil($diffDay % $daysPerMonth); // balance days
echo ($diffYear ? $diffYear . 'year ' : '') . ($diffMonth ? $diffMonth . 'month ' : '') . ($diffDay ? $diffDay . 'day' : '');
Note: I haven't tested the code for all possible date combinations, including leap year etc. Please feel free to tweak as needed.
Hope this helps.
If a coarse difference is enough ("2 years ago"), then you might want to try the Date_HumanDiff PEAR package.
The clean, DRY, professional, modern way to do this is to create two datetime objects and call diff(). The generated diff object will automatically populate year, month, day values for you.
Then you only need to iterate through a lookup array containing your desired units and implode any non-zero results into the plain English output string.
Code (Demo)
$startDate = '2001-04-20';
$endDate = '2015-11-29';
$diff = (new DateTime($startDate))->diff(new DateTime($endDate));
$lookup = [
'y' => 'Year',
'm' => 'Month',
'd' => 'Day',
];
$elements = [];
foreach ($lookup as $property => $word) {
if ($diff->$property) {
$elements[] = "{$diff->$property} $word" . ($diff->$property !== 1 ? 's' : '');
}
}
echo implode(' : ', $elements);
// 14 Years : 7 Months : 9 Days
function is_leap_year($year)
{
if($year % 4 == 0)
{
if($year % 100 == 0)
{
if($year % 400 == 0)
{
return true;
}
else
{
return false;
}
}
else
{
return true;
}
}
else
{
return false;
}
}
function calculate_date($now, $end){
$years = date('Y', strtotime($end)) - date('Y', strtotime($now)) ;
if($years < 0)
{
return "Error: year";
}
$mounths = date('m', strtotime($end)) - date('m', strtotime($now)) ;
if($mounths < 0)
{
if($years < 1)
{
return "Error: mounth and year";
}
else
{
$years --;
$mounths += 12;
}
}
$days = date('d', strtotime($end)) - date('d', strtotime($now)) ;
if($days < 0){
if($mounths < 1)
{
if($years < 1)
{
return "Error: day, mounth and year";
}
else
{
$years --;
$mounths += 12;
}
}
else
{
$mounths --;
switch (date('m', strtotime($now)))
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
$days +=31;
break;
case 4:
case 6:
case 9:
case 11:
$days +=30;
break;
case 2:
if(is_leap_year(date('Y', strtotime($now))))
{
$days += 29;
break;
}
else
{
$days += 28;
break;
}
}
}
}
return $years . " Years : " . $mounths . " Months : " . $days . " Days Remaining.";
}
$end_date = new DateTime('2011-08-05');
$end_date = $end_date->format('d-m-Y');
$today = date('d-m-Y');
$remaining = calculate_date($today, $end_date);
echo $remaining;
And if you want to format end_date you can use:
date('d-m-Y', strtotime($end_date))
And after that you can calculate remaining time with calculate_date .