Related
Financial years starts from April. So for example:
$startDate='2015-01-28' // Start date
$endDate ='2018-05-28' // End date
Now output I'm looking at is like this FY-14-15(as start date falls before apr2015),FY-15-16, FY-16-17, FY-17-18 , FY-18-19(as end date falls after apr 2018). This format I need to query db(MySql) to get some values which will be based on FY-Year1-Year2.
I have tried this so far..
$startDate='2015-01-28' // Start date
$endDate ='2017-05-28'
function calculateFinancialYears($startdate,$enddate){ // function calculates FY years
$d = date_parse_from_format("Y-m-d", $startdate);
$y1 = $d['year'];
if($d['month']<4){ //checking if startdate month falls before april
$fy1 = "FY-".($d['year']-2001)."-".(($d['year'])-2000);//concat FY- for desired Output
}else {
$fy1 = "FY-".(($d['year'])-2000)."-".($d['year']-1999);
}
echo $fy1;
$d2 = date_parse_from_format("Y-m-d", $enddate);
$y2 = $d2['year'];
if($d2['month']<4){
$fy2 = "FY-".($d2['year']-2001)."-".(($d2['year'])-2000);
}else {
$fy2 = "FY-".(($d2['year'])-2000)."-".($d2['year']-1999);
}
echo $fy2;
return $fy1; return $fy2;
out Put is FY-14-15 FY-16-17 .
My problem is, Missing Fiscal year FY-15-16. Also what i have tried is not a better code to get this for more number of years say startdate ='2015-01-28' and endDate ='2018-01-28',
How about this ?
function calcFY($startDate,$endDate) {
$prefix = 'FY-';
$ts1 = strtotime($startDate);
$ts2 = strtotime($endDate);
$year1 = date('Y', $ts1);
$year2 = date('Y', $ts2);
$month1 = date('m', $ts1);
$month2 = date('m', $ts2);
//get months
$diff = (($year2 - $year1) * 12) + ($month2 - $month1);
/**
* if end month is greater than april, consider the next FY
* else dont consider the next FY
*/
$total_years = ($month2 > 4)?ceil($diff/12):floor($diff/12);
$fy = array();
while($total_years >= 0) {
$prevyear = $year1 - 1;
//We dont need 20 of 20** (like 2014)
$fy[] = $prefix.substr($prevyear,-2).'-'.substr($year1,-2);
$year1 += 1;
$total_years--;
}
/**
* If start month is greater than or equal to april,
* remove the first element
*/
if($month1 >= 4) {
unset($fy[0]);
}
/* Concatenate the array with ',' */
return implode(',',$fy);
}
Output:
echo calcFY('2015-03-28','2018-05-28');
//FY-14-15,FY-15-16,FY-16-17,FY-17-18,FY-18-19
/ was missing before year
<?php
/*
* AUTHOR: http://www.tutorius.com/calculating-a-fiscal-year-in-php
*
* This function figures out what fiscal year a specified date is in.
* $inputDate - the date you wish to find the fiscal year for. (12/4/08)
* $fyStartDate - the month and day your fiscal year starts. (7/1)
* $fyEndDate - the month and day your fiscal year ends. (6/30)
* $fy - returns the correct fiscal year
*/
function calculateFiscalYearForDate($inputDate, $fyStart, $fyEnd){
$date = strtotime($inputDate);
$inputyear = strftime('%Y',$date);
$fystartdate = strtotime("$fyStart/$inputyear");
$fyenddate = strtotime("$fyEnd/$inputyear");
if($date < $fyenddate){
$fy = intval($inputyear);
}else{
$fy = intval(intval($inputyear) + 1);
}
return $fy;
}
// my fiscal year starts on July,1 and ends on June 30, so...
echo calculateFiscalYearForDate("5/15/08","7/1","6/30")."\n";
// returns 2008
echo calculateFiscalYearForDate("12/1/08","7/1","6/30")."\n";
// returns 2009
?>
This question already has answers here:
Elegant way to get the count of months between two dates?
(10 answers)
Closed 3 years ago.
Is there any way to find the month difference in PHP? I have the input of from-date 2003-10-17 and to-date 2004-03-24. I need to find how many months there are within these two days. Say if 6 months, I need the output in months only. Thanks for guiding me for day difference.
I find the solution through MySQL but I need it in PHP. Anyone help me, Thanks in advance.
The easiest way without reinventing the wheel. This'll give you the full months difference. I.e. the below two dates are almost 76 months apart, but the result is 75 months.
date_default_timezone_set('Asia/Tokyo'); // you are required to set a timezone
$date1 = new DateTime('2009-08-12');
$date2 = new DateTime('2003-04-14');
$diff = $date1->diff($date2);
echo (($diff->format('%y') * 12) + $diff->format('%m')) . " full months difference";
After testing tons of solutions, putting all in a unit test, this is what I come out with:
/**
* Calculate the difference in months between two dates (v1 / 18.11.2013)
*
* #param \DateTime $date1
* #param \DateTime $date2
* #return int
*/
public static function diffInMonths(\DateTime $date1, \DateTime $date2)
{
$diff = $date1->diff($date2);
$months = $diff->y * 12 + $diff->m + $diff->d / 30;
return (int) round($months);
}
For example it will return (test cases from the unit test):
01.11.2013 - 30.11.2013 - 1 month
01.01.2013 - 31.12.2013 - 12 months
31.01.2011 - 28.02.2011 - 1 month
01.09.2009 - 01.05.2010 - 8 months
01.01.2013 - 31.03.2013 - 3 months
15.02.2013 - 15.04.2013 - 2 months
01.02.1985 - 31.12.2013 - 347 months
Notice: Because of the rounding it does with the days, even a half of a month will be rounded, which may lead to issue if you use it with some cases. So DO NOT USE it for such cases, it will cause you issues.
For example:
02.11.2013 - 31.12.2013 will return 2, not 1 (as expected).
I just wanted to add this if anyone is looking for a simple solution that counts each touched-upon month in stead of complete months, rounded months or something like that.
// Build example data
$timeStart = strtotime("2003-10-17");
$timeEnd = strtotime("2004-03-24");
// Adding current month + all months in each passed year
$numMonths = 1 + (date("Y",$timeEnd)-date("Y",$timeStart))*12;
// Add/subtract month difference
$numMonths += date("m",$timeEnd)-date("m",$timeStart);
echo $numMonths;
Wow, way to overthink the problem... How about this version:
function monthsBetween($startDate, $endDate) {
$retval = "";
// Assume YYYY-mm-dd - as is common MYSQL format
$splitStart = explode('-', $startDate);
$splitEnd = explode('-', $endDate);
if (is_array($splitStart) && is_array($splitEnd)) {
$difYears = $splitEnd[0] - $splitStart[0];
$difMonths = $splitEnd[1] - $splitStart[1];
$difDays = $splitEnd[2] - $splitStart[2];
$retval = ($difDays > 0) ? $difMonths : $difMonths - 1;
$retval += $difYears * 12;
}
return $retval;
}
NB: unlike several of the other solutions, this doesn't depend on the date functions added in PHP 5.3, since many shared hosts aren't there yet.
http://www.php.net/manual/en/datetime.diff.php
This returns a DateInterval object which has a format method.
$datetime1 = date_create('2009-10-11');
$datetime2 = date_create('2013-1-13');
$interval = date_diff($datetime1, $datetime2);
echo $interval->format('%a day %m month %y year');
// get year and month difference
$a1 = '20170401';
$a2 = '20160101'
$yearDiff = (substr($a1, 0, 4) - substr($a2, 0, 4));
$monthDiff = (substr($a1, 4, 2) - substr($a2, 4, 2));
$fullMonthDiff = ($yearDiff * 12) + $monthDiff;
// fullMonthDiff = 16
This is my enhanced version of #deceze answer:
/**
* #param string $startDate
* Current date is considered if empty string is passed
* #param string $endDate
* Current date is considered if empty string is passed
* #param bool $unsigned
* If $unsigned is true, difference is always positive, otherwise the difference might be negative
* #return int
*/
public static function diffInFullMonths($startDate, $endDate, $unsigned = false)
{
$diff = (new DateTime($startDate))->diff(new DateTime($endDate));
$reverse = $unsigned === true ? '' : '%r';
return ((int) $diff->format("{$reverse}%y") * 12) + ((int) $diff->format("{$reverse}%m"));
}
The best way.
function getIntervals(DateTime $from, DateTime $to)
{
$intervals = [];
$startDate = $from->modify('first day of this month');
$endDate = $to->modify('last day of this month');
while($startDate < $endDate){
$firstDay = $startDate->format('Y-m-d H:i:s');
$startDate->modify('last day of this month')->modify('+1 day');
$intervals[] = [
'firstDay' => $firstDay,
'lastDay' => $startDate->modify('-1 second')->format('Y-m-d H:i:s'),
];
$startDate->modify('+1 second');
}
return $intervals;
}
$dateTimeFirst = new \DateTime('2013-01-01');
$dateTimeSecond = new \DateTime('2013-03-31');
$interval = getIntervals($dateTimeFirst, $dateTimeSecond);
print_r($interval);
Result:
Array
(
[0] => Array
(
[firstDay] => 2013-01-01 00:00:00
[lastDay] => 2013-01-31 23:59:59
)
[1] => Array
(
[firstDay] => 2013-02-01 00:00:00
[lastDay] => 2013-02-28 23:59:59
)
[2] => Array
(
[firstDay] => 2013-03-01 00:00:00
[lastDay] => 2013-03-31 23:59:59
)
)
In my case I needed to count full months and day leftovers as month as well to build a line chart labels.
/**
* Calculate the difference in months between two dates
*
* #param \DateTime $from
* #param \DateTime $to
* #return int
*/
public static function diffInMonths(\DateTime $from, \DateTime $to)
{
// Count months from year and month diff
$diff = $to->diff($from)->format('%y') * 12 + $to->diff($from)->format('%m');
// If there is some day leftover, count it as the full month
if ($to->diff($from)->format('%d') > 0) $diff++;
// The month count isn't still right in some cases. This covers it.
if ($from->format('d') >= $to->format('d')) $diff++;
}
<?php
# end date is 2008 Oct. 11 00:00:00
$_endDate = mktime(0,0,0,11,10,2008);
# begin date is 2007 May 31 13:26:26
$_beginDate = mktime(13,26,26,05,31,2007);
$timestamp_diff= $_endDate-$_beginDate +1 ;
# how many days between those two date
$days_diff = $timestamp_diff/2635200;
?>
Reference: http://au.php.net/manual/en/function.mktime.php#86916
function monthsDif($start, $end)
{
// Assume YYYY-mm-dd - as is common MYSQL format
$splitStart = explode('-', $start);
$splitEnd = explode('-', $end);
if (is_array($splitStart) && is_array($splitEnd)) {
$startYear = $splitStart[0];
$startMonth = $splitStart[1];
$endYear = $splitEnd[0];
$endMonth = $splitEnd[1];
$difYears = $endYear - $startYear;
$difMonth = $endMonth - $startMonth;
if (0 == $difYears && 0 == $difMonth) { // month and year are same
return 0;
}
else if (0 == $difYears && $difMonth > 0) { // same year, dif months
return $difMonth;
}
else if (1 == $difYears) {
$startToEnd = 13 - $startMonth; // months remaining in start year(13 to include final month
return ($startToEnd + $endMonth); // above + end month date
}
else if ($difYears > 1) {
$startToEnd = 13 - $startMonth; // months remaining in start year
$yearsRemaing = $difYears - 2; // minus the years of the start and the end year
$remainingMonths = 12 * $yearsRemaing; // tally up remaining months
$totalMonths = $startToEnd + $remainingMonths + $endMonth; // Monthsleft + full years in between + months of last year
return $totalMonths;
}
}
else {
return false;
}
}
Here's a quick one:
$date1 = mktime(0,0,0,10,0,2003); // m d y, use 0 for day
$date2 = mktime(0,0,0,3,0,2004); // m d y, use 0 for day
echo round(($date2-$date1) / 60 / 60 / 24 / 30);
I have three date ranges in mysql table as follow
from 2013-09-29 to 2013-10-02
from 2013-10-14 to 2013-10-16
from 2013-10-28 to 2013-11-05
I want to count only days that occur in Month of October, for example from first range (2013-09-29 to 2013-10-02) I should get difference of two days (1st and 2nd October) , and it should ignore days from September month, Finally i want to count total days in a given month from above date ranges.
Can it be done from direct mysql query. or any short PHP logic.
here is my table structure
id,employee_id,leave_start,leave_to
I am looking for a method some thing like
function countLeaves($employee_id,$month)
{
// code
return $numberOfLeaves
}
You need to calculate the first day of the month 2013-10-01 and the last day of the month 2013-10-31 and then you could use a query like this:
SELECT
DATEDIFF(
LEAST(d_end, '2013-10-31'),
GREATEST(d_start, '2013-10-01'))+1 days
FROM
ranges
WHERE
d_start<='2013-10-31' AND d_end>='2013-10-01'
Please see fiddle here.
function getAllDates($fromDate, $toDate,$rejectmonth)
{
if(!$fromDate || !$toDate ) {return false;}
$dateMonthYearArr = array();
$fromDateTS = strtotime($fromDate);
$toDateTS = strtotime($toDate);
for ($currentDateTS = $fromDateTS; $currentDateTS <= $toDateTS; $currentDateTS += (60 * 60 * 24))
{
if($rejectmonth == date("m",$currentDateTS))
continue;
$currentDateStr = date("Y-m-d",$currentDateTS);
$dateMonthYearArr[] = $currentDateStr;
}
return $dateMonthYearArr;
}
use this function will return the array dates which are in the date ranges.
getAllDates('2013-09-10','2013-19-10',10);
$month = strtotime(date('Y-m-01', time()));
$daysCount = (int)(time() - $month) / (24 * 3600);
and if you need to check from any date to any date:
/**
* #var $dateFrom string Date to count from,
* you can use date('Y-m-01') as start of current month
* #var $dateTo string End of period date, example: '2013-09-05'
**/
function getDaysCount($dateFrom, $dateTo)
{
return (int)(strtotime($dateTo) - strtotime($dateFrom)) / (24 * 3600);
}
This was the function I made for getting list of leavedays which an employee have taken in a given date range. It's fine if leaves taken are one or two, but its too complicated so that, it takes much time to retrieve results hence causes time out error! Any help?
This is the function:
function dates_between($emp_id, $start_date, $end_date)
{
$day_incrementer = 1;
$count_leaves = 0;
$flag = 0;
// Getting the days from DB where the employee '28' had worked in given date range
$work_res = mysql_query("SELECT DISTINCT date FROM `work_details` WHERE employee_id='28' and date between '2012-02-01' and '2012-02-29'");
do {
while($row = mysql_fetch_array($work_res))
{
while((date("Y-m-d",$start_date) < $row['date']) && ($flag = 0))
// loop to find startdate less than table date! if table date(attendance) is starting from 3, we need to print leaves 1,2 if they are not weekends
{
if(!(date('N', strtotime(date("Y-m-d", $start_date))) >=6))
{
//checking for weekends, prints only weekdays
echo date("Y-m-d", $start_date) . " \n ";
$count_leaves++;
}
$start_date = $start_date + ($day_incrementer * 60 * 60 *24);
}
$flag=1;
while((date("Y-m-d",$start_date) != $row['date']))
// loop to print $start_date,which is not equal to table date
{
if(!(date('N', strtotime(date("Y-m-d", $start_date))) >= 6))
{
echo date("Y-m-d", $start_date) . "\n";
$count_leaves++;
}
$$start_date = $start_date + ($day_incrementer * 60 * 60 * 24);
}
$start_date = $start_date + ($day_incrementer * 60 * 60 * 24);
}
// loop to print $start_date,comes rest after tabledate if tabledate finishes with 28, prints rest of dates 29,30
if(!(date('N', strtotime(date("Y-m-d", $start_date))) >= 6) && ($start_date <= $end_date))
{
echo date("Y-m-d", $start_date) . "\n";
$count_leaves++;
$start_date = $start_date + ($day_incrementer * 60 * 60 * 24);
}
} while($start_date <= $end_date);
return($count_leaves);
}
I noticed that you also asked similar question elsewhere (http://stackoverflow.com/questions/10898293/how-to-get-days-of-leave-taken-in-a-given-month). Now I tried diving into your code to get a basic understanding of what you were attempting. Kindly pardon me if my answer doesn't exactly meet your desire as it is not easy to read another person's mind. Basically, what I have done is to prepare a sample code that does what you want. This code takes an array of dates a specific worker worked in a given month and year. It then proceeds to get all the work dates that were available in that given month, that year. A difference of both arrays gives the dates the worker was absent (due to leave or AWOL). Public holidays have not been accounted for but of course, you can easily modify the code to add that. If you hold public holiday dates in another array and difference it with the first result, the final array will give you what you want.
Now, just a note of warning, this code is basic, array difference will fail you if the two arrays are not exactly in the same date format. Personally, I will write my own comparison callback function to compare individual dates and pass it into array_udiff() for maximum certainty. I'm pretty sure you can handle that. I have only provided the basics. Use freely and extend as appropriate to your situation. Enough talking, see the code sample below.
<?php
/***************************************************************************
* how to get DAYS absent from working days from given date range?
* #Author Prof. No Time - 12th/June/2012
****************************************************************************/
//Leave was 10th, 13th, 23rd, 24th
//Note that 01-02-2012 is NOT exactly same as 1-2-2012; Important for the array_diff fxn used below.
//Note Format is d-m-Y
//Note I am assuming you have pulled this from a database of course
$imaginaryWorkDatesOfWorker1 = array(
'01-02-2012', '02-02-2012', '03-02-2012', '06-02-2012', '07-02-2012', '08-02-2012',
'09-02-2012', '14-02-2012', '15-02-2012', '16-02-2012', '17-02-2012', '20-02-2012',
'21-02-2012', '22-02-2012', '27-02-2012', '28-02-2012', '29-02-2012'
);
$leaveDays1 = getLeaveDays(2, 2012, $imaginaryWorkDatesOfWorker1);
displayWorkersLeaveDays($leaveDays1);
//Leave was 2nd, 16th, 19th, 23rd and 26th
$imaginaryWorkDatesOfWorker2 = array(
'01-03-2012', '05-03-2012', '06-03-2012', '07-03-2012', '08-03-2012', '09-03-2012',
'12-03-2012', '13-03-2012', '14-03-2012', '15-03-2012', '20-03-2012', '21-03-2012',
'22-03-2012', '27-03-2012', '28-03-2012', '29-03-2012', '30-03-2012'
);
$leaveDays2 = getLeaveDays(3, 2012, $imaginaryWorkDatesOfWorker2);
displayWorkersLeaveDays($leaveDays2);
///MAIN FUNCTION TO GET LEAVE DATES///
function getLeaveDays($month, $year, $arrDatesPresent=array()){
$arrAllWorkDatesInMonth = getDatesInTheMonth($month, $year);
//var_dump($arrDatesPresent); var_dump($arrAllWorkDatesInMonth);
$leaveDays = array_diff($arrAllWorkDatesInMonth, $arrDatesPresent);
return $leaveDays;
}
///HELPER FUNCTIONS///
/**
* <p>Gets all the dates in a given month in the specified year. default format d-m-Y<p>
* #param int $month
* #param int $year
* #param boolean $includeWeekends
* #param string $format2Use
* #throws Exception if invalid parameters are given
* #return array: dates in the given month, in the given year
*/
function getDatesInTheMonth($month, $year, $includeWeekends=false, $format2Use='d-m-Y') {
$arrDatesInTheMonth = array();
if (empty($format2Use)) $format2Use = 'm-d-Y';
if (empty($month) || empty($year)){
throw new Exception("Invalid parameters given.");
}
else{
$fauxDate = mktime(0, 0, 0, $month, 1, $year);
$numOfDaysInMonth = date('t', $fauxDate);
if (!empty($numOfDaysInMonth)){
for ($day = 1; $day <= $numOfDaysInMonth; $day++){
$timeStamp = mktime(0, 0, 0, $month, $day, $year);
$cdate = date($format2Use, $timeStamp);
if ($includeWeekends){
$arrDatesInTheMonth[] = $cdate;
}
else{
if (!isWeekend($cdate)) { $arrDatesInTheMonth[] = $cdate; }
}
}
}
}
return $arrDatesInTheMonth;
}
/**
* Checks if given date is a weekend use this if you have PHP greater than v5.1.
* Credit: http://stackoverflow.com/users/298479/thiefmaster
* #param date $date
* #return boolean
*/
function isWeekend($date) {
return (date('N', strtotime($date)) >= 6);
}
/**
* Checks if given date is a weekend use this if you have PHP less than v5.1.
* Credit: http://stackoverflow.com/users/298479/thiefmaster
* #param date $date
* #return boolean
*/
function isWeekend2($date) {
$weekDay = date('w', strtotime($date));
return ($weekDay == 0 || $weekDay == 6);
}
function printDates($arrDates){
foreach ($arrDates as $key => $cdate) {
$display = sprintf( '%s <br />', date('[l] - jS \of F Y', strtotime($cdate)) );
echo $display;
}
}
function displayWorkersLeaveDays($leaveDays){
echo '<div style="background-color:#CCC;margin:10px 0;">';
echo '<div>Your Leave days are as follows: </div>';
printDates($leaveDays);
echo '</div>';
}
Hope this helps.
I have a variable $ node-> field_work_start [0] ['view'] which denotes the date of birth. To follow up I want to do a background check on the fact that this date is included in the next period then 10 days from the current date. If true then x = 1, false x = 0. Help please with code PHP.
It sounds like you are given a DATETIME with $node->field_work_start[0]['view'] correct? If this is the case, we're going to convert it to a UNIX timestamp to make things a little bit easier. In this example we will assume your date is stored in M d, Y form.
This little code should work well for you!
<?php
class Node
{
// For sake of keeping things similar to your environment
var $field_work_start = array();
}
/**
* checkBirthday function
*
* The function will check a birth date
* and see if it is in the range of specified
* days.
*
* #param $birthday
* Birth date parameter. Assumed to be in M d, Y form
* #param $days
* The range of days to check where the birthday is
* #return int
* 0 if the birthday is _NOT_ within the proper range
* 1 if the birthday _IS_ within the proper range
*/
function checkBirthday($birthday,$days)
{
// Parse out the year of the birthday
$pos = strpos($birthday,",")+2; // Find the comma which separates the year
$today = strtotime(date("M, d")); // Check if day is < Dec. 22. If not, we need to account for next year!
// Check if the birthday is within the range and has not passed!
if($today < strtotime("Dec 22")){
$birthday = substr_replace($birthday,date("Y"),$pos,4); // Replace the year with current year
if(strtotime($birthday) <= strtotime("+".$days." days") && strtotime($birthday) >= time()){
return 1;
}
} else { // Less than 10 days left in our year.. check for January birthdays!
if(!strstr($birthday,"December")){
$birthday = substr_replace($birthday,date("Y")+1,$pos,4); // Replace the year with next year
$year = date("Y")+1;
} else { // Still December?
$birthday = substr_replace($birthday,date("Y"),$pos,4); // Replace the year with current year
$year = date("Y");
}
$day = (date("d")+10)-31; // 10 days from now is...
if((strtotime($birthday) <= strtotime("January ".$day.", ".$year)) && strtotime($birthday) >= strtotime("December 25, 2010")){
return 1;
}
}
return 0;
}
$node[] = new Node;
$node[0]->field_work_start[0] = "January 1, 1970"; // First birthday is _NOT_ within range
$node[1]->field_work_start[0] = "July 20, 1970"; // Second birthday _IS_ within range
for($i=0;$i<count($node);$i++){
if(!checkBirthday($node[$i]->field_work_start[0],10)){
print $node[$i]->field_work_start[0]." is not within the 10 day range.<br /><br />";
} else {
print $node[$i]->field_work_start[0]." is within the 10 day range.<br /><br />";
}
}
unset($node);
?>
It should return this output:
January 1, 1970 is not within the 10 day range.
July 20, 1970 is within the 10 day range.
Good luck!
Regards,
Dennis M.