Calculating working hours between two dates - php

I need a PHP method for calculating working hours between two dates based on a 8 hour working day and excluding weekends and bank holidays.
For example the difference between 2012-01-01T08:30:00 AND 2012-01-05T10:30:00 in working hours is actually 26 working hours because the first two days are weekend/bank holiday which just leaves 3 working days and the time differnce of 2 hours i.e. 3*8+2=26.
I have used #flamingLogos excellent answer to a previous question but cannot get it to take into account the time as well as date.

Function below calculates working hours between two dates, provided in text format such as '2013-11-27 13:40', taking work day hours from 9 to 17 (can be changed).
function get_working_hours($from,$to)
{
// timestamps
$from_timestamp = strtotime($from);
$to_timestamp = strtotime($to);
// work day seconds
$workday_start_hour = 9;
$workday_end_hour = 17;
$workday_seconds = ($workday_end_hour - $workday_start_hour)*3600;
// work days beetwen dates, minus 1 day
$from_date = date('Y-m-d',$from_timestamp);
$to_date = date('Y-m-d',$to_timestamp);
$workdays_number = count(get_workdays($from_date,$to_date))-1;
$workdays_number = $workdays_number<0 ? 0 : $workdays_number;
// start and end time
$start_time_in_seconds = date("H",$from_timestamp)*3600+date("i",$from_timestamp)*60;
$end_time_in_seconds = date("H",$to_timestamp)*3600+date("i",$to_timestamp)*60;
// final calculations
$working_hours = ($workdays_number * $workday_seconds + $end_time_in_seconds - $start_time_in_seconds) / 86400 * 24;
return $working_hours;
}
There are two additional functions. One returns work days array...
function get_workdays($from,$to)
{
// arrays
$days_array = array();
$skipdays = array("Saturday", "Sunday");
$skipdates = get_holidays();
// other variables
$i = 0;
$current = $from;
if($current == $to) // same dates
{
$timestamp = strtotime($from);
if (!in_array(date("l", $timestamp), $skipdays)&&!in_array(date("Y-m-d", $timestamp), $skipdates)) {
$days_array[] = date("Y-m-d",$timestamp);
}
}
elseif($current < $to) // different dates
{
while ($current < $to) {
$timestamp = strtotime($from." +".$i." day");
if (!in_array(date("l", $timestamp), $skipdays)&&!in_array(date("Y-m-d", $timestamp), $skipdates)) {
$days_array[] = date("Y-m-d",$timestamp);
}
$current = date("Y-m-d",$timestamp);
$i++;
}
}
return $days_array;
}
and second - returns holidays array
function get_holidays()
{
// arrays
$days_array = array();
// You have to put there your source of holidays and make them as array...
// For example, database in Codeigniter:
// $days_array = $this->my_model->get_holidays_array();
return $days_array;
}

Maybe you can use this function :
function work_hours_diff($date1,$date2) {
if ($date1>$date2) { $tmp=$date1; $date1=$date2; $date2=$tmp; unset($tmp); $sign=-1; } else $sign = 1;
if ($date1==$date2) return 0;
$days = 0;
$working_days = array(1,2,3,4,5); // Monday-->Friday
$working_hours = array(8.5, 17.5); // from 8:30(am) to 17:30
$current_date = $date1;
$beg_h = floor($working_hours[0]); $beg_m = ($working_hours[0]*60)%60;
$end_h = floor($working_hours[1]); $end_m = ($working_hours[1]*60)%60;
// setup the very next first working timestamp
if (!in_array(date('w',$current_date) , $working_days)) {
// the current day is not a working day
// the current timestamp is set at the begining of the working day
$current_date = mktime( $beg_h, $beg_m, 0, date('n',$current_date), date('j',$current_date), date('Y',$current_date) );
// search for the next working day
while ( !in_array(date('w',$current_date) , $working_days) ) {
$current_date += 24*3600; // next day
}
} else {
// check if the current timestamp is inside working hours
$date0 = mktime( $beg_h, $beg_m, 0, date('n',$current_date), date('j',$current_date), date('Y',$current_date) );
// it's before working hours, let's update it
if ($current_date<$date0) $current_date = $date0;
$date3 = mktime( $end_h, $end_m, 59, date('n',$current_date), date('j',$current_date), date('Y',$current_date) );
if ($date3<$current_date) {
// outch ! it's after working hours, let's find the next working day
$current_date += 24*3600; // the day after
// and set timestamp as the begining of the working day
$current_date = mktime( $beg_h, $beg_m, 0, date('n',$current_date), date('j',$current_date), date('Y',$current_date) );
while ( !in_array(date('w',$current_date) , $working_days) ) {
$current_date += 24*3600; // next day
}
}
}
// so, $current_date is now the first working timestamp available...
// calculate the number of seconds from current timestamp to the end of the working day
$date0 = mktime( $end_h, $end_m, 59, date('n',$current_date), date('j',$current_date), date('Y',$current_date) );
$seconds = $date0-$current_date+1;
printf("\nFrom %s To %s : %d hours\n",date('d/m/y H:i',$date1),date('d/m/y H:i',$date0),$seconds/3600);
// calculate the number of days from the current day to the end day
$date3 = mktime( $beg_h, $beg_m, 0, date('n',$date2), date('j',$date2), date('Y',$date2) );
while ( $current_date < $date3 ) {
$current_date += 24*3600; // next day
if (in_array(date('w',$current_date) , $working_days) ) $days++; // it's a working day
}
if ($days>0) $days--; //because we've allready count the first day (in $seconds)
printf("\nFrom %s To %s : %d working days\n",date('d/m/y H:i',$date1),date('d/m/y H:i',$date3),$days);
// check if end's timestamp is inside working hours
$date0 = mktime( $beg_h, 0, 0, date('n',$date2), date('j',$date2), date('Y',$date2) );
if ($date2<$date0) {
// it's before, so nothing more !
} else {
// is it after ?
$date3 = mktime( $end_h, $end_m, 59, date('n',$date2), date('j',$date2), date('Y',$date2) );
if ($date2>$date3) $date2=$date3;
// calculate the number of seconds from current timestamp to the final timestamp
$tmp = $date2-$date0+1;
$seconds += $tmp;
printf("\nFrom %s To %s : %d hours\n",date('d/m/y H:i',$date2),date('d/m/y H:i',$date3),$tmp/3600);
}
// calculate the working days in seconds
$seconds += 3600*($working_hours[1]-$working_hours[0])*$days;
printf("\nFrom %s To %s : %d hours\n",date('d/m/y H:i',$date1),date('d/m/y H:i',$date2),$seconds/3600);
return $sign * $seconds/3600; // to get hours
}
I put printf() to show what it is done (you can remove them)
You call it like that :
date_default_timezone_set("America/Los_Angeles");
$dt2 = strtotime("2012-01-01 05:25:00");
$dt1 = strtotime("2012-01-19 12:40:00");
echo work_hours_diff($dt1 , $dt2 );

The other two proposals don't work if you choose start or end in a non-working day or time. This are the results my code gets using a working day of 9:00 to 20:00 and rest days Saturday and Sunday.
get_working_hours('2016-10-08 08:00:00', '2016-10-08 21:00:00'); //Saturday: 0 hrs
get_working_hours('2016-10-10 08:00:00', '2016-10-10 21:00:00'); //Monday: 11 hrs
get_working_hours('2016-10-10 10:00:00', '2016-10-10 19:00:00'); //Monday: 9 hrs
get_working_hours('2016-10-07 19:00:00', '2016-10-10 10:00:00'); //fri-mon: 2 hrs
get_working_hours('2016-10-08 19:00:00', '2016-10-10 10:00:00'); //sat-mon: 1 hrs
get_working_hours('2016-10-07 19:00:00', '2016-10-09 10:00:00'); //fri-sun: 1 hrs
function get_working_hours($ini_str,$end_str){
//config
$ini_time = [9,0]; //hr, min
$end_time = [20,0]; //hr, min
//date objects
$ini = date_create($ini_str);
$ini_wk = date_time_set(date_create($ini_str),$ini_time[0],$ini_time[1]);
$end = date_create($end_str);
$end_wk = date_time_set(date_create($end_str),$end_time[0],$end_time[1]);
//days
$workdays_arr = get_workdays($ini,$end);
$workdays_count = count($workdays_arr);
$workday_seconds = (($end_time[0] * 60 + $end_time[1]) - ($ini_time[0] * 60 + $ini_time[1])) * 60;
//get time difference
$ini_seconds = 0;
$end_seconds = 0;
if(in_array($ini->format('Y-m-d'),$workdays_arr)) $ini_seconds = $ini->format('U') - $ini_wk->format('U');
if(in_array($end->format('Y-m-d'),$workdays_arr)) $end_seconds = $end_wk->format('U') - $end->format('U');
$seconds_dif = $ini_seconds > 0 ? $ini_seconds : 0;
if($end_seconds > 0) $seconds_dif += $end_seconds;
//final calculations
$working_seconds = ($workdays_count * $workday_seconds) - $seconds_dif;
echo $ini_str.' - '.$end_str.'; Working Hours:'.($working_seconds / 3600).b();
return $working_seconds / 3600; //return hrs
}
function get_workdays($ini,$end){
//config
$skipdays = [6,0]; //saturday:6; sunday:0
$skipdates = []; //eg: ['2016-10-10'];
//vars
$current = clone $ini;
$current_disp = $current->format('Y-m-d');
$end_disp = $end->format('Y-m-d');
$days_arr = [];
//days range
while($current_disp <= $end_disp){
if(!in_array($current->format('w'),$skipdays) && !in_array($current_disp,$skipdates)){
$days_arr[] = $current_disp;
}
$current->add(new DateInterval('P1D')); //adds one day
$current_disp = $current->format('Y-m-d');
}
return $days_arr;
}

Related

calculate night hours between two date

I want to calculate night hours (21PM to 6AM) between two given dates.
I don't have any ideas
public function biss_hours($start, $end){
$startDate = new \DateTime($start);
$endDate = new \DateTime($end);
$periodInterval = new \DateInterval( "PT1H" );
$period = new \DatePeriod( $startDate, $periodInterval, $endDate );
$count = 0;
foreach($period as $date){
$startofday = clone $date;
$startofday->setTime(5,59);
$endofday = clone $date;
$endofday->setTime(20,59);
if($date > $startofday && $date < $endofday){
$count++;
}
}
return $count;
}
I have this fonction but it's don't work :)
Thx any help
There is no need to loop over a period. As already suggested in the comments, start by calculating the hours of the start and end date since these are the ones that can actually contain less than a full nights hours. Once those are calculated, you can simply get the number of days remaining and multiply them by the amount of hours a night has.
Please note that I only consider hours in my example below, so 22:55 to 24:00 would result in 2 full hours of night time counted. Also it does not check cases where the end date is before the start date or whether inputs are valid. It should get the idea across though:
function getHoursForSingleDay ( $startTime, $endTime, $nightStart, $nightEnd ) {
$numHours = 0;
// if the day starts before night ends
if( $startTime < $nightEnd ) {
// e.g. Night ends at 6a.m. - day starts at 5 a.m. = 1 hour
$numHours += $nightEnd - $startTime;
}
// if the day ends after night starts
if( $endTime > $nightStart ) {
// e.g. day ends at 23 - night starts at 21 = 2 hours
$numHours += $endTime - $nightStart;
}
return $numHours;
}
function biss_hours ( $start, $end, $nightStart = 21, $nightEnd = 6 ) {
$startDate = new \DateTime( $start );
$endDate = new \DateTime( $end );
$startTime = intval( $startDate->format( 'H' ) );
$endTime = intval( $endDate->format( 'H' ) );
// Both dates being the same day is an edge case
if( $startDate->format( 'Y-m-d' ) === $endDate->format( 'Y-m-d' ) ) {
return getHoursForSingleDay( $startTime, $endTime, $nightStart, $nightEnd );
}
// get the hours for bot the start and end date, since they can be less than a full night
$numHours = getHoursForSingleDay( $startTime, 24, $nightStart, $nightEnd );
$numHours += getHoursForSingleDay( 0, $endTime, $nightStart, $nightEnd );
// all remaining days in between can be calculated in a rather simple way
$nightHoursPerDay = $nightEnd + ( 24 - $nightStart );
// -1 because diff returns 1 for two adjacent days, but we treat the first and last day specially
$numDaysBetween = intval( $endDate->diff( $startDate )->format( "%a" ) ) - 1;
$numHours += $numDaysBetween * $nightHoursPerDay;
return $numHours;
}

Calculate the weeks between 2 dates manually in PHP

I'm trying to calculate the number of months and weeks since a particular date instead of from the beginning of the year.
It shouldn't follow calendar months but should instead count a month as every 4 weeks, and begin from a specified date. I need to be able to display the number of months, and also what week it is (1, 2, 3 or 4).
I want to put in a start date, and have it then count what month and week is it from that start date e.g if the start date is set to Mon 1st August it should show Month 1, Week 1 and so on.
My code is below. I tested it with some different start dates. Here's a list of what the code below generates and what it should display
Jun-20: Should be Week 2 - Shows as Week 0
Jun-27: Should be Week 1 - Shows as Week 3
Jul-04: Should be Week 4 - Shows as Week 2
Jul-11: Should be Week 3 - Shows as Week 1
Jul-18: Should be Week 2 - Shows as Week 0
$monthNumber = 5;
$monthStartDate = '2016-06-13';
$currentStartWeekDate = date('l') != 'Monday' ? date("Y-m-d", strtotime("last monday")) : date("Y-m-d"); // get the current week's Monday's date
$weekDateCounter = $monthStartDate;
$currentWeekNumber = 0;
while ($weekDateCounter != $currentStartWeekDate){
$currentWeekNumber += 1;
$weekDateCounter = date("Y-m-d", strtotime($weekDateCounter . "+7 days"));
//
if ($currentWeekNumber == 4){
$currentWeekNumber = 0; // reset week number
$monthNumber += 1; // increment month number
}
}
I am really at a loss with this and could use any help!
Your approach seems overly complicated:
function weekCounter($startDate,$endDate=null){
//use today as endDate if no date was supplied
$endDate = $endDate? : date('Y-m-d');
//calculate # of full weeks between dates
$secsPerWeek = 60 * 60 * 24 * 7;
$fullWeeks =
floor((strtotime($endDate) - strtotime($startDate))/$secsPerWeek);
$fullMonths = floor($fullWeeks/4);
$weeksRemainder = $fullWeeks % 4; // weeks that don't fit in a month
//increment from 0-base to 1-base, so first week is Week 1. Same with months
$fullMonths++; $weeksRemainder++;
//return months and weeks in an array
return [$fullMonths,$weeksRemainder];
}
You can call the function this way, and capture months and weeks:
//list() will assign the array members from weekCounter to the vars in list
list($months,$weeks) = weekCounter('2016-06-07'); //no end date, so today is used
//now $months and $weeks can be used as you wish
echo "Month: $months, Week: $weeks"; //outputs Month: 2, Week: 2
Live demo
The DateTime classes could make this much simpler for you. Documentation for them is here: http://php.net/manual/en/book.datetime.php
Try this out:
$date1 = new DateTime('2016-04-01');
$date2 = new DateTime('2016-07-24');
$diff = $date1->diff($date2);
$daysInbetween = $diff->days;
$weeksInbetween = floor($diff->days / 7);
$monthsInbetween = floor($weeksInbetween / 4);
print "Days inbetween = $daysInbetween" . PHP_EOL;
print "Weeks inbetween = $weeksInbetween" . PHP_EOL;
print "Months inbetween = $monthsInbetween" . PHP_EOL;
print "Total difference = $monthsInbetween months and "
. ($weeksInbetween - ($monthsInbetween * 4)) . " weeks" . PHP_EOL;
<?php
/**
* AUTHOR : VEDAVITH RAVULA
* DATE : 13122019
*/
function get_weeks($startDate = NULL,$endDate = NULL)
{
if(is_null($startDate) && is_null($endDate))
{
$startDate = date('Y-m-01');
$endDate = date('Y-m-t');
}
$date1 = new DateTime($startDate);
$date2 = new DateTime($endDate);
$interval = $date1->diff($date2);
$weeks = floor(($interval->days) / 7);
if(($date1->format("N") > 1) && ($date1->format("D") != "Sun"))
{
$diffrence = "-".( $date1->format("N"))." Days";
$date1 = $date1->modify($diffrence);
}
for($i = 0; $i <= $weeks; $i++)
{
if($i == 0)
{
$start_date = $date1->format('Y-m-d');
$date1->add(new DateInterval('P6D'));
}
else
{
$date1->add(new DateInterval('P6D'));
}
echo $start_date." - ".$date1->format('Y-m-d')."\n";
$date1->add(new DateInterval('P1D'));
$start_date = $date1->format('Y-m-d');
}
}
//function call
get_weeks("2021-11-01", "2021-11-14");

Get week number (in the year) from a date PHP

I want to take a date and work out its week number.
So far, I have the following. It is returning 24 when it should be 42.
<?php
$ddate = "2012-10-18";
$duedt = explode("-",$ddate);
$date = mktime(0, 0, 0, $duedt[2], $duedt[1],$duedt[0]);
$week = (int)date('W', $date);
echo "Weeknummer: ".$week;
?>
Is it wrong and a coincidence that the digits are reversed? Or am I nearly there?
Today, using PHP's DateTime objects is better:
<?php
$ddate = "2012-10-18";
$date = new DateTime($ddate);
$week = $date->format("W");
echo "Weeknummer: $week";
It's because in mktime(), it goes like this:
mktime(hour, minute, second, month, day, year);
Hence, your order is wrong.
<?php
$ddate = "2012-10-18";
$duedt = explode("-", $ddate);
$date = mktime(0, 0, 0, $duedt[1], $duedt[2], $duedt[0]);
$week = (int)date('W', $date);
echo "Weeknummer: " . $week;
?>
$date_string = "2012-10-18";
echo "Weeknummer: " . date("W", strtotime($date_string));
Use PHP's date function
http://php.net/manual/en/function.date.php
date("W", $yourdate)
This get today date then tell the week number for the week
<?php
$date=date("W");
echo $date." Week Number";
?>
Just as a suggestion:
<?php echo date("W", strtotime("2012-10-18")); ?>
Might be a little simpler than all that lot.
Other things you could do:
<?php echo date("Weeknumber: W", strtotime("2012-10-18 01:00:00")); ?>
<?php echo date("Weeknumber: W", strtotime($MY_DATE)); ?>
Becomes more difficult when you need year and week.
Try to find out which week is 01.01.2017.
(It is the 52nd week of 2016, which is from Mon 26.12.2016 - Sun 01.01.2017).
After a longer search I found
strftime('%G-%V',strtotime("2017-01-01"))
Result: 2016-52
https://www.php.net/manual/de/function.strftime.php
ISO-8601:1988 week number of the given year, starting with the first week of the year with at least 4 weekdays, with Monday being the start of the week. (01 through 53)
The equivalent in mysql is DATE_FORMAT(date, '%x-%v')
https://www.w3schools.com/sql/func_mysql_date_format.asp
Week where Monday is the first day of the week (01 to 53).
Could not find a corresponding solution with DateTime.
At least not without solutions like "+1day, last monday".
Edit: since strftime is now deprecated, maybe you can also use date.
Didn't verify it though.
date('o-W',strtotime("2017-01-01"));
I have tried to solve this question for years now, I thought I found a shorter solution but had to come back again to the long story. This function gives back the right ISO week notation:
/**
* calcweek("2018-12-31") => 1901
* This function calculates the production weeknumber according to the start on
* monday and with at least 4 days in the new year. Given that the $date has
* the following format Y-m-d then the outcome is and integer.
*
* #author M.S.B. Bachus
*
* #param date-notation PHP "Y-m-d" showing the data as yyyy-mm-dd
* #return integer
**/
function calcweek($date) {
// 1. Convert input to $year, $month, $day
$dateset = strtotime($date);
$year = date("Y", $dateset);
$month = date("m", $dateset);
$day = date("d", $dateset);
$referenceday = getdate(mktime(0,0,0, $month, $day, $year));
$jan1day = getdate(mktime(0,0,0,1,1,$referenceday[year]));
// 2. check if $year is a leapyear
if ( ($year%4==0 && $year%100!=0) || $year%400==0) {
$leapyear = true;
} else {
$leapyear = false;
}
// 3. check if $year-1 is a leapyear
if ( (($year-1)%4==0 && ($year-1)%100!=0) || ($year-1)%400==0 ) {
$leapyearprev = true;
} else {
$leapyearprev = false;
}
// 4. find the dayofyearnumber for y m d
$mnth = array(0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
$dayofyearnumber = $day + $mnth[$month-1];
if ( $leapyear && $month > 2 ) { $dayofyearnumber++; }
// 5. find the jan1weekday for y (monday=1, sunday=7)
$yy = ($year-1)%100;
$c = ($year-1) - $yy;
$g = $yy + intval($yy/4);
$jan1weekday = 1+((((intval($c/100)%4)*5)+$g)%7);
// 6. find the weekday for y m d
$h = $dayofyearnumber + ($jan1weekday-1);
$weekday = 1+(($h-1)%7);
// 7. find if y m d falls in yearnumber y-1, weeknumber 52 or 53
$foundweeknum = false;
if ( $dayofyearnumber <= (8-$jan1weekday) && $jan1weekday > 4 ) {
$yearnumber = $year - 1;
if ( $jan1weekday = 5 || ( $jan1weekday = 6 && $leapyearprev )) {
$weeknumber = 53;
} else {
$weeknumber = 52;
}
$foundweeknum = true;
} else {
$yearnumber = $year;
}
// 8. find if y m d falls in yearnumber y+1, weeknumber 1
if ( $yearnumber == $year && !$foundweeknum) {
if ( $leapyear ) {
$i = 366;
} else {
$i = 365;
}
if ( ($i - $dayofyearnumber) < (4 - $weekday) ) {
$yearnumber = $year + 1;
$weeknumber = 1;
$foundweeknum = true;
}
}
// 9. find if y m d falls in yearnumber y, weeknumber 1 through 53
if ( $yearnumber == $year && !$foundweeknum ) {
$j = $dayofyearnumber + (7 - $weekday) + ($jan1weekday - 1);
$weeknumber = intval( $j/7 );
if ( $jan1weekday > 4 ) { $weeknumber--; }
}
// 10. output iso week number (YYWW)
return ($yearnumber-2000)*100+$weeknumber;
}
I found out that my short solution missed the 2018-12-31 as it gave back 1801 instead of 1901. So I had to put in this long version which is correct.
How about using the IntlGregorianCalendar class?
Requirements: Before you start to use IntlGregorianCalendar make sure that libicu or pecl/intl is installed on the Server.
So run on the CLI:
php -m
If you see intl in the [PHP Modules] list, then you can use IntlGregorianCalendar.
DateTime vs IntlGregorianCalendar:
IntlGregorianCalendar is not better then DateTime. But the good thing about IntlGregorianCalendar is that it will give you the week number as an int.
Example:
$dateTime = new DateTime('21-09-2020 09:00:00');
echo $dateTime->format("W"); // string '39'
$intlCalendar = IntlCalendar::fromDateTime ('21-09-2020 09:00:00');
echo $intlCalendar->get(IntlCalendar::FIELD_WEEK_OF_YEAR); // integer 39
<?php
$ddate = "2012-10-18";
$duedt = explode("-",$ddate);
$date = mktime(0, 0, 0, $duedt[1], $duedt[2],$duedt[0]);
$week = (int)date('W', $date);
echo "Weeknummer: ".$week;
?>
You had the params to mktime wrong - needs to be Month/Day/Year, not Day/Month/Year
To get the week number for a date in North America I do like this:
function week_number($n)
{
$w = date('w', $n);
return 1 + date('z', $n + (6 - $w) * 24 * 3600) / 7;
}
$n = strtotime('2022-12-27');
printf("%s: %d\n", date('D Y-m-d', $n), week_number($n));
and get:
Tue 2022-12-27: 53
for get week number in jalai calendar you can use this:
$weeknumber = date("W"); //number week in year
$dayweek = date("w"); //number day in week
if ($dayweek == "6")
{
$weeknumberint = (int)$weeknumber;
$date2int++;
$weeknumber = (string)$date2int;
}
echo $date2;
result:
15
week number change in saturday
The most of the above given examples create a problem when a year has 53 weeks (like 2020). So every fourth year you will experience a week difference. This code does not:
$thisYear = "2020";
$thisDate = "2020-04-24"; //or any other custom date
$weeknr = date("W", strtotime($thisDate)); //when you want the weeknumber of a specific week, or just enter the weeknumber yourself
$tempDatum = new DateTime();
$tempDatum->setISODate($thisYear, $weeknr);
$tempDatum_start = $tempDatum->format('Y-m-d');
$tempDatum->setISODate($thisYear, $weeknr, 7);
$tempDatum_end = $tempDatum->format('Y-m-d');
echo $tempDatum_start //will output the date of monday
echo $tempDatum_end // will output the date of sunday
Very simple
Just one line:
<?php $date=date("W"); echo "Week " . $date; ?>"
You can also, for example like I needed for a graph, subtract to get the previous week like:
<?php $date=date("W"); echo "Week " . ($date - 1); ?>
Your code will work but you need to flip the 4th and the 5th argument.
I would do it this way
$date_string = "2012-10-18";
$date_int = strtotime($date_string);
$date_date = date($date_int);
$week_number = date('W', $date_date);
echo "Weeknumber: {$week_number}.";
Also, your variable names will be confusing to you after a week of not looking at that code, you should consider reading http://net.tutsplus.com/tutorials/php/why-youre-a-bad-php-programmer/
The rule is that the first week of a year is the week that contains the first Thursday of the year.
I personally use Zend_Date for this kind of calculation and to get the week for today is this simple. They have a lot of other useful functions if you work with dates.
$now = Zend_Date::now();
$week = $now->get(Zend_Date::WEEK);
// 10
To get Correct Week Count for Date 2018-12-31 Please use below Code
$day_count = date('N',strtotime('2018-12-31'));
$week_count = date('W',strtotime('2018-12-31'));
if($week_count=='01' && date('m',strtotime('2018-12-31'))==12){
$yr_count = date('y',strtotime('2018-12-31')) + 1;
}else{
$yr_count = date('y',strtotime('2018-12-31'));
}
function last_monday($date)
{
if (!is_numeric($date))
$date = strtotime($date);
if (date('w', $date) == 1)
return $date;
else
return date('Y-m-d',strtotime('last monday',$date));
}
$date = '2021-01-04'; //Enter custom date
$year = date('Y',strtotime($date));
$date1 = new DateTime($date);
$ldate = last_monday($year."-01-01");
$date2 = new DateTime($ldate);
$diff = $date2->diff($date1)->format("%a");
$diff = $diff/7;
$week = intval($diff) + 1;
echo $week;
//Returns 2.
try this solution
date( 'W', strtotime( "2017-01-01 + 1 day" ) );

Calculate week of a month [duplicate]

So I have a script that returns the number of weeks in a particular month and year. How can I take a specific day from that month and determine if it is part of week 1,2,3,4 or 5 of that month?
The most frustrating thing I have ever tried to get working - but here it is!
<?php
/**
* Returns the amount of weeks into the month a date is
* #param $date a YYYY-MM-DD formatted date
* #param $rollover The day on which the week rolls over
*/
function getWeeks($date, $rollover)
{
$cut = substr($date, 0, 8);
$daylen = 86400;
$timestamp = strtotime($date);
$first = strtotime($cut . "00");
$elapsed = ($timestamp - $first) / $daylen;
$weeks = 1;
for ($i = 1; $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;
}
//
echo getWeeks("2011-06-11", "sunday"); //outputs 2, for the second week of the month
?>
Edit: so much for "single line" - needed variables to avoid recomputation with the conditional. Tossed in a default argument while I was at it.
function weekOfMonth($when = null) {
if ($when === null) $when = time();
$week = date('W', $when); // note that ISO weeks start on Monday
$firstWeekOfMonth = date('W', strtotime(date('Y-m-01', $when)));
return 1 + ($week < $firstWeekOfMonth ? $week : $week - $firstWeekOfMonth);
}
Please note that weekOfMonth(strtotime('Oct 31, 2011')); will return 6; some rare months have 6 weeks in them, contrary to OP's expectation. January 2017 is another month with 6 ISO weeks - Sunday the 1st falls in the last year's week, since ISO weeks start on Monday.
For starshine531, to return a 0 indexed week of the month, change the return 1 + to return 0 + or return (int).
For Justin Stayton, for weeks starting on Sunday instead of Monday I would use strftime('%U' instead of date('W', as follows:
function weekOfMonth($when = null) {
if ($when === null) $when = time();
$week = strftime('%U', $when); // weeks start on Sunday
$firstWeekOfMonth = strftime('%U', strtotime(date('Y-m-01', $when)));
return 1 + ($week < $firstWeekOfMonth ? $week : $week - $firstWeekOfMonth);
}
For this version, 2017-04-30 is now in week 6 of April, while 2017-01-31 is now in week 5.
public function getWeeks($timestamp)
{
$maxday = date("t",$timestamp);
$thismonth = getdate($timestamp);
$timeStamp = mktime(0,0,0,$thismonth['mon'],1,$thismonth['year']); //Create time stamp of the first day from the give date.
$startday = date('w',$timeStamp); //get first day of the given month
$day = $thismonth['mday'];
$weeks = 0;
$week_num = 0;
for ($i=0; $i<($maxday+$startday); $i++) {
if(($i % 7) == 0){
$weeks++;
}
if($day == ($i - $startday + 1)){
$week_num = $weeks;
}
}
return $week_num;
}
Hello all i have been struggling for the whole day trying to figure this code out, i finally figured it out so i thought i would share it with you all.
all you need to do is put a time stamp into the function and it will return the week number back to you.
thanks
there is a problem with this method. if the passing date (Lets say 2012/01/01 which is a Sunday) and "$rollover" day is "Sunday", then this function will return 2. where its actually is 1'st week. i think i have fixed it in following function.
please add comments to make it better.
function getWeeks($date, $rollover)
{
$cut = substr($date, 0, 8);
$daylen = 86400;
$timestamp = strtotime($date);
$first = strtotime($cut . "01");
$elapsed = (($timestamp - $first) / $daylen)+1;
$i = 1;
$weeks = 0;
for($i==1; $i<=$elapsed; $i++)
{
$dayfind = $cut . (strlen($i) < 2 ? '0' . $i : $i);
$daytimestamp = strtotime($dayfind);
$day = strtolower(date("l", $daytimestamp));
if($day == strtolower($rollover))
{
$weeks++;
}
}
if($weeks==0)
{
$weeks++;
}
return $weeks;
}
This is a solution based on sberry's mathematical solution but using the PHP DateTime class instead.
function week_of_month($date) {
$first_of_month = new DateObject($date->format('Y/m/1'));
$day_of_first = $first_of_month->format('N');
$day_of_month = $date->format('j');
return floor(($day_of_first + $day_of_month - 1) / 7) + 1;
}
Just Copy and Past the code and pass month and year.
e.g month=04 year=2013.
That's exactly what You Need.
$mm= $_REQUEST['month'];
$yy= $_REQUEST['year'];
$startdate=date($yy."-".$mm."-01") ;
$current_date=date('Y-m-t');
$ld= cal_days_in_month(CAL_GREGORIAN, $mm, $yy);
$lastday=$yy.'-'.$mm.'-'.$ld;
$start_date = date('Y-m-d', strtotime($startdate));
$end_date = date('Y-m-d', strtotime($lastday));
$end_date1 = date('Y-m-d', strtotime($lastday." + 6 days"));
$count_week=0;
$week_array = array();
for($date = $start_date; $date <= $end_date1; $date = date('Y-m-d', strtotime($date. ' + 7 days')))
{
$getarray=getWeekDates($date, $start_date, $end_date);
echo "<br>";
$week_array[]=$getarray;
echo "\n";
$count_week++;
}
// its give the number of week for the given month and year
echo $count_week;
//print_r($week_array);
function getWeekDates($date, $start_date, $end_date)
{
$week = date('W', strtotime($date));
$year = date('Y', strtotime($date));
$from = date("Y-m-d", strtotime("{$year}-W{$week}+1"));
if($from < $start_date) $from = $start_date;
$to = date("Y-m-d", strtotime("{$year}-W{$week}-6"));
if($to > $end_date) $to = $end_date;
$array1 = array(
"ssdate" => $from,
"eedate" => $to,
);
return $array1;
// echo "Start Date-->".$from."End Date -->".$to;
}
for($i=0;$i<$count_week;$i++)
{
$start= $week_array[$i]['ssdate'];
echo "--";
$week_array[$i]['eedate'];
echo "<br>";
}
OUTPUT:
week( 0 )=>2013-03-01---2013-03-02
week( 1 )=>2013-03-03---2013-03-09
week( 2 )=>2013-03-10---2013-03-16
week( 3 )=>2013-03-17---2013-03-23
week( 4 )=>2013-03-24---2013-03-30
week( 5 )=>2013-03-31---2013-03-31
I think I found an elegant solution
$time = time(); // or whenever
$week_of_the_month = ceil(date('d', $time)/7);
For a Monday-Sunday (ISO 8601) week (or, if you simply don't care), you can do this in one line:
function get_week_of_month($date) {
return date('W', $date) - date('W', strtotime(date("Y-m-01", $date))) + 1;
}
(Source)
For anything else, (e.g. a Sunday-Saturday week), you just need to tweak $date inside the function:
function get_week_of_month($date) {
$date += 86400; //For weeks starting on Sunday
return date('W', $date) - date('W', strtotime(date("Y-m-01", $date))) + 1;
}
(Thanks to these guys/gals)
NOTE: You may run into some issues at the end of the year (e.g. around 12/31, 1/1, etc.). Read more here.
This is the snippet that I made to fulfill my requirements for the same. Hope this will help you.
function getWeek($timestamp) {
$week_year = date('W',$timestamp);
$week = 0;//date('d',$timestamp)/7;
$year = date('Y',$timestamp);
$month = date('m',$timestamp);
$day = date('d',$timestamp);
$prev_month = date('m',$timestamp) -1;
if($month != 1 ){
$last_day_prev = $year."-".$prev_month."-1";
$last_day_prev = date('t',strtotime($last_day_prev));
$week_year_last_mon = date('W',strtotime($year."-".$prev_month."-".$last_day_prev));
$week_year_first_this = date('W',strtotime($year."-".$month."-1"));
if($week_year_first_this == $week_year_last_mon){
$week_diff = 0;
}
else{
$week_diff = 1;
}
if($week_year ==1 && $month == 12 ){
// to handle December's last two days coming in first week of January
$week_year = 53;
}
$week = $week_year-$week_year_last_mon + 1 +$week_diff;
}
else{
// to handle first three days January coming in last week of December.
$week_year_first_this = date('W',strtotime($year."-01-1"));
if($week_year_first_this ==52 || $week_year_first_this ==53){
if($week_year == 52 || $week_year == 53){
$week =1;
}
else{
$week = $week_year + 1;
}
}
else{
$week = $week_year;
}
}
return $week;
}
This is probably not a good way to do this but it's my first thought and I'm really tired.
Put all your dates into an array. The date object must have a day name (Monday). Create a method that searches the array and when ever you hit a Sunday you add 1 to a week counter. Once you find the date you're looking for return the week counter. That is the week the day falls in of the year. For the week in the month you have to reset the week counter every time you get to the last day in each month.
Here comes two liner:
function getWeekOfMonth(DateTime $date) {
$firstDayOfMonth = new DateTime($date->format('Y-m-1'));
return ceil(($firstDayOfMonth->format('N') + $date->format('j') - 1) / 7);
}
And Wtower's solutions doesn't work 100% properly.
Thought I'd share my function as well. This returns an array of weeks. Every week is an array with weeks day (0..6) as key and months day (1..31) as value.
Function assumes that week starts with Sunday.
Enjoy!
function get_weeks($year, $month){
$days_in_month = date("t", mktime(0, 0, 0, $month, 1, $year));
$weeks_in_month = 1;
$weeks = array();
//loop through month
for ($day=1; $day<=$days_in_month; $day++) {
$week_day = date("w", mktime(0, 0, 0, $month, $day, $year));//0..6 starting sunday
$weeks[$weeks_in_month][$week_day] = $day;
if ($week_day == 6) {
$weeks_in_month++;
}
}
return $weeks;
}
My 5 cents:
/**
* calculate number of weeks in a particular month
*/
function weeksInMonth($month=null,$year=null){
if( null==($year) ) {
$year = date("Y",time());
}
if(null==($month)) {
$month = date("m",time());
}
// find number of days in this month
$daysInMonths = date('t',strtotime($year.'-'.$month.'-01'));
$numOfweeks = ($daysInMonths%7==0?0:1) + intval($daysInMonths/7);
$monthEndingDay= date('N',strtotime($year.'-'.$month.'-'.$daysInMonths));
$monthStartDay = date('N',strtotime($year.'-'.$month.'-01'));
if($monthEndingDay<$monthStartDay){
$numOfweeks++;
}
return $numOfweeks;
}
I create this function, from brazil :) I hope it is useful
function weekofmonth($time) {
$firstday = 1;
$lastday = date('j',$time);
$lastdayweek = 6; //Saturday
$week = 1;
for ($day=1;$day<=$lastday;$day++) {
$timetmp = mktime(0, 0, 0, date('n',$time), $day, date('Y',$time));
if (date('N',$timetmp) == $lastdayweek) {
$week++;
}
}
if (date('N',$time)==$lastdayweek) {
$week--;
}
return $week;
}
$time = mktime(0, 0, 0, 9, 30, 2014);
echo weekofmonth($time);
I found a easy way to determine what week of the month today is in, and it would be a small change to have it work on any other date. I'm adding my two cents in here as I think my way is much more compact then the methods listed.
$monthstart = date("N",strtotime(date("n/1/Y")));
$date =( date("j")+$monthstart ) /7;
$ddate= floor( $date );
if($ddate != date) {$ddate++;}
and $ddate contains the week number you could modify it like so
function findweek($indate)
{
$monthstart = date("N",strtotime(date("n/1/Y",strtotime($indate))));
$date =( date("j",strtotime($indate))+$monthstart ) /7;
$ddate= floor( $date );
if($ddate != $date) {$ddate++;}
return $ddate;
}
and it would return what week of the month any date you give it is.
what it does is first find the number of days from the start of the week to the first of the month. then adds that on to the current date then divides the new date by 7 and that will give you how many weeks have passed since the start of the month, including a decimal place for the part of the the current week that has passed. so what I do next is round down that number, then compare the rounded down version to the original if the two match your at the end of the week so it's already in the number. if they don't then just add one to the rounded down number and voila you have the current week number.
Srahul07's solution works perfectly... If you abide by the Monday-Sunday week system! Here in 'murica, non-business folk tend to go by Sunday-Saturday being a week, so May 1, 2011 is week 1 and May 2, 2011 is still week 1.
Adding the following logic to the bottom of his function, right before it returns $week will convert this to a Sunday -> Monday system:
if (!date('w',strtotime("$year-$month-01")) && date('w',$timestamp))
$week--;
elseif (date('w',strtotime("$year-$month-01")) && !date('w',$timestamp))
$week++;
After alot of efoort i found the solution
<?php
function getWeeks($month,$year)
{
$month = intval($month); //force month to single integer if '0x'
$suff = array('st','nd','rd','th','th','th'); //week suffixes
$end = date('t',mktime(0,0,0,$month,1,$year)); //last date day of month: 28 - 31
$start = date('w',mktime(0,0,0,$month,1,$year)); //1st day of month: 0 - 6 (Sun - Sat)
$last = 7 - $start; //get last day date (Sat) of first week
$noweeks = ceil((($end - ($last + 1))/7) + 1); //total no. weeks in month
$output = ""; //initialize string
$monthlabel = str_pad($month, 2, '0', STR_PAD_LEFT);
for($x=1;$x<$noweeks+1;$x++)
{
if($x == 1)
{
$startdate = "$year-$monthlabel-01";
$day = $last - 6;
}
else
{
$day = $last + 1 + (($x-2)*7);
$day = str_pad($day, 2, '0', STR_PAD_LEFT);
$startdate = "$year-$monthlabel-$day";
}
if($x == $noweeks)
{
$enddate = "$year-$monthlabel-$end";
}
else
{
$dayend = $day + 6;
$dayend = str_pad($dayend, 2, '0', STR_PAD_LEFT);
$enddate = "$year-$monthlabel-$dayend";
}
$j=1;
if($j--)
{
$k=getTotalDate($startdate,$enddate);
$j=1;
}
$output .= "Week ".$xyz." week -> Start date=$startdate End date=$enddate <br />";
}
return $output;
}
if(isset($_POST) && !empty($_POST)){
$month = $_POST['m'];
$year = $_POST['y'];
echo getWeeks($month,$year);
}
?>
<form method="post">
M:
<input name="m" value="" />
Y:
<input name="y" value="" />
<input type="submit" value="go" />
</form>
I really liked #michaelc's answer. However, I got stuck on a few points. It seemed that every time Sunday rolled around, there was an offset of one. I think it has to do with what day of the week is the start of the week. In any case, here is my slight alteration to it, expanded a bit for readability:
function wom(\DateTime $date) {
// The week of the year of the current month
$cw = date('W', $date->getTimestamp());
// The week of the year of the first of the given month
$fw = date('W',strtotime(date('Y-m-01',$date->getTimeStamp())));
// Offset
$o = 1;
// If it is a Saturday, offset by two.
if( date('N',$date->getTimestamp()) == 7 ) {
$o = 2;
}
return $cw -$fw + $o;
}
So if the date is Nov. 9, 2013...
$cw = 45
$fw = 44
and with the offset of 1, it correctly returns 2.
If the date is Nov. 10, 2013, $cw and $fw are the same as before, but the offset is 2, and it correctly returns 3.
function get_week_of_month( $timestamp )
{
$week_of_month = 0;
$month = date( 'j', $timestamp );
$test_month = $month;
while( $test_month == $month )
{
$week_of_month++;
$timestamp = strtotime( '-1 week', $timestamp );
$test_month = date( 'j', $timestamp );
}
return $week_of_month;
}
I found this online:
http://kcwebprogrammers.blogspot.de/2009/03/current-week-in-month-php.html
He has a very simple solution which seems to work fine for me.
$currentWeek = ceiling((date("d") - date("w") - 1) / 7) + 1;
So for example:
$now = strtotime("today");
$weekOfMonth = ceil((date("d", $now) - date("w", $now) - 1) / 7) + 1;
you can use W in newer php versions. http://php.net/manual/en/function.date.php
i have used it like so:
function getWeek($date) {
$month_start=strtotime("1 ".date('F Y',$date));
$current_date=strtotime(date('j F Y',$date));
$month_week=date("W",$month_start);
$current_week=date("W",$current_date);
return ($current_week-$month_week);
}//0 is the week of the first.
Short and foolproof:
// Function accepts $date as a string,
// Returns the week number in which the given date falls.
// Assumed week starts on Sunday.
function wom($date) {
$date = strtotime($date);
$weeknoofday = date('w', $date);
$day = date('j', $date);
$weekofmonth = ceil(($day + (7-($weeknoofday+1))) / 7);
return $weekofmonth;
}
// Test
foreach (range(1, 31) as $day) {
$test_date = "2015-01-" . str_pad($day, 2, '0', STR_PAD_LEFT);
echo "$test_date - ";
echo wom($test_date) . "\n";
}
I use this simple function:
function weekNumberInMonth($timestampDate)
{
$firstDayOfMonth = strtotime(date('01-M-Y 00:00:00', $timestampDate));
$firstWeekdayOfMonth = date( 'w', $firstDayOfMonth);
$dayNumberInMonth = date('d', $timestampDate);
$weekNumberInMonth = ceil(($dayNumberInMonth + $firstWeekdayOfMonth) / 7);
return $weekNumberInMonth;
}
if I understand correct, the question is how to identify what number of week within a month of a specific day... I was looking for similar solution. I used some ideas of above answers to develop my own solution. Hope it can be helpful for somebody. If Yes, then UpVote my answer.
function week_number_within_month($datenew){
$year = date("Y",strtotime($datenew));
$month = date("m",strtotime($datenew));
// find number of days in this month
$daysInMonths = date('t',strtotime($year.'-'.$month.'-01'));
$numOfweeks = ($daysInMonths%7==0?0:1) + intval($daysInMonths/7);
$monthEndingDay= date('N',strtotime($year.'-'.$month.'-'.$daysInMonths));
$monthStartDay = date('N',strtotime($year.'-'.$month.'-01'));
if($monthEndingDay<$monthStartDay){
$numOfweeks++;
}
$date=date('Y/m/d', strtotime($year.'-'. $month.'-01'));
$week_array=Array();
for ($i=1; $i<=$numOfweeks; $i++){ /// create an Array of all days of month separated by weeks as a keys
$max = 7;
if ($i ==1){ $max = 8 - $monthStartDay;}
if ($i == $numOfweeks){ $max = $monthEndingDay;}
for ($r=1; $r<=$max; $r++){
$week_array[$i][]=$date;
$date = date('Y/m/d',strtotime($date . "+1 days"));
}
}
$new_datenew = date('Y/m/d', strtotime($datenew));
$week_result='';
foreach ($week_array as $key => $val){ /// finding what week number of my date from week_array
foreach ($val as $kr => $value){
if ($new_datenew == $value){
$week_result = $key;
}
}
}
return $week_result;
}
print week_number_within_month('2016-09-15');
function getWeekOfMonth(\DateTime $date)
{
$firstWeekdayOfMonth = new DateTime("first weekday 0 {$date->format('M')} {$date->format('Y')}");
$offset = $firstWeekdayOfMonth->format('N')-1;
return intval(($date->format('j') + $offset)/7)+1;
}
/**
* In case of Week we can get the week of year. So whenever we will get the week of the month then we have to
* subtract the until last month weeks from it will give us the current month week.
*/
$dateComponents = getdate();
if($dateComponents['mon'] == 1)
$weekOfMonth = date('W', strtotime($dateComponents['year'].'-'.$dateComponents['mon'].'-'.$dateComponents['mday']))-1; // We subtract -1 to map it to the array
else
$weekOfMonth = date('W', strtotime($dateComponents['year'].'-'.$dateComponents['mon'].'-'.$dateComponents['mday']))-date('W', strtotime($dateComponents['year'].'-'.$dateComponents['mon'].'-01'));
Using Carbon:
$date = Carbon::now();
$d1 = $date->startOfMonth();
$d2 = $date->endOfMonth();
$weeks = $d1->diffInWeeks($d2);
If you clearly want to separate a month into 4 Weeks, you can use this function.
This is helpful, if you want
"the first monday of month"
"the third thursday of month" etc.
Here we go
/**
* This Calculates (and returns) the week number within a month, based on date('j') day of month.
* This is useful, if you want to have (for instance) the first Thu in month, regardless of date
* #param $Timestamp
* #return float|int
*/
function getWeekOfMonth($Timestamp)
{
$DayOfMonth=date('j', $Timestamp); // Day of the month without leading zeros 0-31
if($DayOfMonth>21) return 4;
if($DayOfMonth>14) return 3;
if($DayOfMonth>7) return 2;
return 1;
}
From carbon:
return (int) ceil((new Datetime())->format('d') / 7);
As simple as possible :)
Python: Number of the Week in a Month
This is a worked example in Python - should be simple to convert.

Easy way to get day number of current quarter?

PHP provides ways to get the number of the current day of the month (date('j')) as well as the number of the current day of the year (date('z')). Is there a way to get the number of the current day of the current quarter?
So right now, August 5, it is day 36 of the third quarter.
If there is no standard way of calculating this, does anyone have a (prefereably PHP-based) algorithm handy?
How about:
$curMonth = date("m", time());
$curQuarter = ceil($curMonth/3);
I wrote a class with the following methods. Enjoy.
public static function getQuarterByMonth($monthNumber) {
return floor(($monthNumber - 1) / 3) + 1;
}
public static function getQuarterDay($monthNumber, $dayNumber, $yearNumber) {
$quarterDayNumber = 0;
$dayCountByMonth = array();
$startMonthNumber = ((self::getQuarterByMonth($monthNumber) - 1) * 3) + 1;
// Calculate the number of days in each month.
for ($i=1; $i<=12; $i++) {
$dayCountByMonth[$i] = date("t", strtotime($yearNumber . "-" . $i . "-01"));
}
for ($i=$startMonthNumber; $i<=$monthNumber-1; $i++) {
$quarterDayNumber += $dayCountByMonth[$i];
}
$quarterDayNumber += $dayNumber;
return $quarterDayNumber;
}
public static function getCurrentQuarterDay() {
return self::getQuarterDay(date('n'), date('j'), date('Y'));
}
function date_quarter()
{
return ceil(date('n', time()) / 3);
}
or
function date_quarter()
{
$month = date('n');
if ($month <= 3) return 1;
if ($month <= 6) return 2;
if ($month <= 9) return 3;
return 4;
}
You can use Carbon it has easy modifiers for getFirstOf{Month,Year,Quarter}()
<?php
//take current date
$now = Carbon\Carbon::now();
//modify a copy of it to the first day of the current quarter
$firstOfQuarter = $now->copy()->firstOfQuarter();
//calculate the difference in days and add 1 to correct the index
$dayOfQuarter = $now->diffInDays($firstOfQuarter) + 1;
Assuming you mean a calendar-quarter (because a company fiscal year can start in any month of the year), you could rely on the date('z') to determine the day-of-year, and then keep a simple array of the day each quarter starts on:
$quarterStartDays = array( 1 /* Jan 1 */, 90 /* Mar 1, non leap-year */, ... );
Then with the current day-of-year you can first locate the largest start-day that's less than or equal to the day-of-year, then subtract.
Note that you need different numbers depending on the leap year.
<?php
function day_of_quarter($ts=null) {
if( is_null($ts) ) $ts=time();
$d=date('d', $ts);
$m=date('m', $ts)-1;
while($m%3!=0) {
$lastmonth=mktime(0, 0, 0, $m, date("d", $ts), date("Y",$ts));
$d += date('t', $lastmonth);
$m--;
}
return $d;
}
echo day_of_quarter(mktime(0, 0, 0, 1, 1,2009));
echo "\n";
echo day_of_quarter(time());
echo "\n";
?>
We need to calculate the date of the first quarter first
$current_month = date('m');
// Get first month of quarter
$new_month = (3 * floor(($current_month - 1 ) / 3)) + 1;
// Add prefix zero if needed
$new_month = substr('0' . $new_month, -2);
$first_quarter_day_date = date('Y') . '-' . $new_month . '-01';
next we calculate the http://php.net/manual/en/datetime.diff.php
$datetime1 = new DateTime($first_quarter_day_date);
$datetime2 = new DateTime();
$interval = $datetime1->diff($datetime2);
echo $interval->format('%a days');
<?php
function quarter_day($time = "") {
$time = $time ? strtotime($time) : time();
$date = intval(date("j", $time));
$month = intval(date("n", $time));
$year = intval(date("Y", $time));
// get selected quarter as number between 1 and 4
$quarter = ceil($month / 3);
// get first month of current quarter as number between 1 and 12
$fmonth = $quarter + (($quarter - 1) * 2);
// map days in a year by month
$map = [31,28,31,30,31,30,31,31,30,31,30,31];
// check if year is leap
if (((($year % 4) == 0) && ((($year % 100) != 0) || (($year % 400) == 0)))) $map[1] = 29;
// get total number of days in selected quarter, by summing the relative portion of $map array
$total = array_sum(array_slice($map, ($fmonth - 1), 3));
// get number of days passed in selected quarter, by summing the relative portion of $map array
$map[$month-1] = $date;
$day = array_sum(array_slice($map, ($fmonth - 1), ($month - $fmonth + 1)));
return "Day $day on $total of quarter $quarter, $year.";
}
print(quarter_day("2017-01-01")) . "\n"; // prints Day 1 on 90 of quarter 1, 2017.
print(quarter_day("2017-04-01")) . "\n"; // prints Day 1 on 91 of quarter 2, 2017.
print(quarter_day("2017-08-15")) . "\n"; // prints Day 46 on 92 of quarter 3, 2017.
print(quarter_day("2017-12-31")) . "\n"; // prints Day 92 on 92 of quarter 4, 2017.
I've noticed that this thread went a bit beyond the question, and it's the first response to many google searches with "Quarter" & "PHP" in them.
If you're working with the ISO standards of organization, which you should if you're doing a business app, then
$curMonth = date("m", time());
$curQuarter = ceil($curMonth/3);
Is NOT correct, because the first day of a year in the ISO standards, can be 30, or 31 December.
Instead, you should use this :
$current_yearly_cycle_year_number = 2019;
$current_yearly_cycle_start->setISODate( $current_yearly_cycle_year_number, 1, 1 );
$current_yearly_cycle_end->setISODate( $current_yearly_cycle_year_number, 53, 1 );
if( $current_yearly_cycle_end->format("W") !== "53" )
$current_yearly_cycle_end->setISODate( $current_yearly_cycle_year_number, 52, 1 );
$week_number_start = intval( $current_yearly_cycle_start->format( "W" ) );
$timestamp_start_quarter = ( $week_number_start === 1 ? 1 : intval( ceil( $current_yearly_cycle_start->format( "m" ) / 3 ) ) );
var_dump( $timestamp_start_quarter );

Categories