How do you actually perform datetime operations such as adding date, finding difference, find out how many days excluding weekends in an interval? I personally started to pass some of these operations to my postgresql dbms as typically I would only need to issue one sql statement to obtain an answer, however, to do it in PHP way I would have to write a lot more code that means more chances for errors to occur...
Are there any libraries in PHP that does datetime operation in a way that don't require a lot of code? that beats sql in a situation where 'Given two dates, how many workdays are there between the two dates? Implement in either SQL, or $pet_lang' that is solved by making this query?
SELECT COUNT(*) AS total_days
FROM (SELECT date '2008-8-26' + generate_series(0,
(date '2008-9-1' - date '2008-8-26')) AS all_days) AS calendar
WHERE EXTRACT(isodow FROM all_days) < 6;
While for most datetime operations I would normally convert to Unixtime and perform addition subtraction etc. on the Unixtime integer, you may want to look at the Zend framework Zend_Date class.
This has a lot of the functionality you describe. Although Zend is billed as a "framework" it works exceptionally well as a class library to pick and chose elements from. We routinely include it in projects and then just pull in bits as and when we need them.
PHP5+'s DateTime object is useful because it is leap time and
daylight savings aware, but it needs some extension to really
solve the problem. I wrote the following to solve a similar problem.
The find_WeekdaysFromThisTo() method is brute-force, but it works reasonably quickly if your time span is less than 2 years.
$tryme = new Extended_DateTime('2007-8-26');
$newer = new Extended_DateTime('2008-9-1');
print 'Weekdays From '.$tryme->format('Y-m-d').' To '.$newer->format('Y-m-d').': '.$tryme -> find_WeekdaysFromThisTo($newer) ."\n";
/* Output: Weekdays From 2007-08-26 To 2008-09-01: 265 */
print 'All Days From '.$tryme->format('Y-m-d').' To '.$newer->format('Y-m-d').': '.$tryme -> find_AllDaysFromThisTo($newer) ."\n";
/* Output: All Days From 2007-08-26 To 2008-09-01: 371 */
$timefrom = $tryme->find_TimeFromThisTo($newer);
print 'Between '.$tryme->format('Y-m-d').' and '.$newer->format('Y-m-d').' there are '.
$timefrom['years'].' years, '.$timefrom['months'].' months, and '.$timefrom['days'].
' days.'."\n";
/* Output: Between 2007-08-26 and 2008-09-01 there are 1 years, 0 months, and 5 days. */
class Extended_DateTime extends DateTime {
public function find_TimeFromThisTo($newer) {
$timefrom = array('years'=>0,'months'=>0,'days'=>0);
// Clone because we're using modify(), which will destroy the object that was passed in by reference
$testnewer = clone $newer;
$timefrom['years'] = $this->find_YearsFromThisTo($testnewer);
$mod = '-'.$timefrom['years'].' years';
$testnewer -> modify($mod);
$timefrom['months'] = $this->find_MonthsFromThisTo($testnewer);
$mod = '-'.$timefrom['months'].' months';
$testnewer -> modify($mod);
$timefrom['days'] = $this->find_AllDaysFromThisTo($testnewer);
return $timefrom;
} // end function find_TimeFromThisTo
public function find_YearsFromThisTo($newer) {
/*
If the passed is:
not an object, not of class DateTime or one of its children,
or not larger (after) $this
return false
*/
if (!is_object($newer) || !($newer instanceof DateTime) || $newer->format('U') < $this->format('U'))
return FALSE;
$count = 0;
// Clone because we're using modify(), which will destroy the object that was passed in by reference
$testnewer = clone $newer;
$testnewer -> modify ('-1 year');
while ( $this->format('U') < $testnewer->format('U')) {
$count ++;
$testnewer -> modify ('-1 year');
}
return $count;
} // end function find_YearsFromThisTo
public function find_MonthsFromThisTo($newer) {
/*
If the passed is:
not an object, not of class DateTime or one of its children,
or not larger (after) $this
return false
*/
if (!is_object($newer) || !($newer instanceof DateTime) || $newer->format('U') < $this->format('U'))
return FALSE;
$count = 0;
// Clone because we're using modify(), which will destroy the object that was passed in by reference
$testnewer = clone $newer;
$testnewer -> modify ('-1 month');
while ( $this->format('U') < $testnewer->format('U')) {
$count ++;
$testnewer -> modify ('-1 month');
}
return $count;
} // end function find_MonthsFromThisTo
public function find_AllDaysFromThisTo($newer) {
/*
If the passed is:
not an object, not of class DateTime or one of its children,
or not larger (after) $this
return false
*/
if (!is_object($newer) || !($newer instanceof DateTime) || $newer->format('U') < $this->format('U'))
return FALSE;
$count = 0;
// Clone because we're using modify(), which will destroy the object that was passed in by reference
$testnewer = clone $newer;
$testnewer -> modify ('-1 day');
while ( $this->format('U') < $testnewer->format('U')) {
$count ++;
$testnewer -> modify ('-1 day');
}
return $count;
} // end function find_AllDaysFromThisTo
public function find_WeekdaysFromThisTo($newer) {
/*
If the passed is:
not an object, not of class DateTime or one of its children,
or not larger (after) $this
return false
*/
if (!is_object($newer) || !($newer instanceof DateTime) || $newer->format('U') < $this->format('U'))
return FALSE;
$count = 0;
// Clone because we're using modify(), which will destroy the object that was passed in by reference
$testnewer = clone $newer;
$testnewer -> modify ('-1 day');
while ( $this->format('U') < $testnewer->format('U')) {
// If the calculated day is not Sunday or Saturday, count this day
if ($testnewer->format('w') != '0' && $testnewer->format('w') != '6')
$count ++;
$testnewer -> modify ('-1 day');
}
return $count;
} // end function find_WeekdaysFromThisTo
public function set_Day($newday) {
if (is_int($newday) && $newday > 0 && $newday < 32 && checkdate($this->format('m'),$newday,$this->format('Y')))
$this->setDate($this->format('Y'),$this->format('m'),$newday);
} // end function set_Day
public function set_Month($newmonth) {
if (is_int($newmonth) && $newmonth > 0 && $newmonth < 13)
$this->setDate($this->format('Y'),$newmonth,$this->format('d'));
} // end function set_Month
public function set_Year($newyear) {
if (is_int($newyear) && $newyear > 0)
$this->setDate($newyear,$this->format('m'),$this->format('d'));
} // end function set_Year
} // end class Extended_DateTime
strtotime() is useful but it does have some odd behaviors that can pop-up from time to time if you are not just using it to convert a formatted date/time string.
things like "+1 month" or "-3 days" can sometimes not give you what you expect it to output.
For adding a date, you can use the method DateTime::add (Adds an amount of days, months, years, hours, minutes and seconds to a DateTime object), available from php 5.3.0 onwards.
To find the difference between two dates, there's the DateTime::diff method; but there doesn't seem to be a method for counting the working days between two dates.
PEAR::Date looks like it might have some useful functionality.
PEAR::Calendar might also be useful.
The easiest method is to use a timestamp, representing the number of seconds since January 1, 2008. With a timestamp type, you can do things like...
now = time();
tomorrow = now + 24 * 60 * 60; // 24 hours * 60 minutes * 60 seconds
Check out the documentation for time(), date() and mktime() on the php web pages. Those are the three methods that I tend to use the most frequently.
You can use a combination of strtotime, mktime and date todo the arithmetic
Here is an example which uses a combo todo some arithmetic http://rushi.wordpress.com/2008/04/13/php-print-out-age-of-date-in-words/ I'll reproduce the code here for simplicity
if ($timestamp_diff < (60*60*24*7)) {
echo floor($timestamp_diff/60/60/24)." Days";
} elseif ($timestamp_diff > (60*60*24*7*4)) {
echo floor($timestamp_diff/60/60/24/7)." Weeks";
} else {
$total_months = $months = floor($timestamp_diff/60/60/24/30);
if($months >= 12) {
$months = ($total_months % 12);
$years = ($total_months - $months)/12;
echo $years . " Years ";
}
if($months > 0)
echo $months . " Months";
}
?>
#Rushi I don't like strtotime() personally.. i don't know why but i discovered this morning that passing a string like this '2008-09-11 9:5 AM' to strtotime returns a false...
I don't think the code you provided solve the example problem 'Given two dates, how many workdays are there between the two dates? Implement in either SQL, or $pet_lang' and I haven't consider if I have a list of public holiday...
You can get number of days between two dates like this:
$days = (strtotime("2008-09-10") - strtotime("2008-09-12")) / (60 * 60 * 24);
And you can make function something like that (I don't have php installed in my work computer so i can't guarantee syntax is 100% correct)
function isWorkDay($date)
{
// check if workday and return true if so
}
function numberOfWorkDays($startdate, $enddate)
{
$workdays = 0;
$tmp = strtotime($startdate);
$end = strtotime($enddate);
while($tmp <= $end)
{
if ( isWorkDay( date("Y-m-d",$tmp) ) ) $workdays++;
$tmp += 60*60*24;
}
return $workdays;
}
If you don't like strtotime and you always have date in same format you can use explode function like
list($year, $month, day) = explode("-", $date);
I would strongly recommend using PHP 5.2's DateTime objects, rather than using UNIX timestamps, when doing date calculations. When you use the PHP date functions that return UNIX timestamps, you have a very limited range to work with (e.g. nothing before 1970).
If you have a look at http://php.net/date , you will find some examples of using mktime() to perform operations.
A simple example would be to workout what tomorrows date would be. You can do that by simply adding 1, to the day value in mktime() as follows:
$tomorrow = date("Y-m-d", mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")));
So here, you will receive a date in the form of YYYY-MM-DD containing tomorrows date. You can also subtract days by simply replacing '+' with '-'. mktime() makes life a lot easier, and saves you from having to do nested if statements and other such troublesome coding.
to get working days/holidays, postgresql CTE ftw -- see http://osssmb.wordpress.com/2009/12/02/business-days-working-days-sql-for-postgres-2/
Related
I am using PHP, jQuery AJAX and HTML to create a timesheet system, for this the user needs to select 2 dates within 1 month of each other. The system as yet is working and shows (very limited) data.
BUT! When I actually select a date over the month limit (i.e. 2 months further than the start or another year after the start), it still shows the table with the data.
For this I have this check:
$dt1 = new DateTime($_REQUEST['startdate']);
$dt2 = new DateTime($_REQUEST['enddate']);
$diff = date_diff($dt1, $dt2);
// I have tried this the other way around and get the same result...
if($diff->m > 1 || $diff->y > 1)
{
print("<center><strong>Time between dates it too great<br />Please choose another date or time within a month of each other</strong></center>");
die();
}
The dates are passed by a jQuery datepicker object via AJAX, and the dates I use, for example, are passed as such:
11/14/2015 (start date) && 12/14/2015 (end date) - should show data
09/14/2015 (start date) && 12/14/2015 (end date) - should not show data but does
11/14/2015 (start date) && 12/14/2016 (end date) - should not show data but does
There is a check in place that sees if the dates given start before the other and this works, I have tried the same kind of thing for this check, but without success, this check is as such:
function CountDaysBetween($startDate, $endDate)
{
$begin = strtotime($startDate);
$end = strtotime($endDate);
if ($begin > $end) {
echo "start date is in the future! <br />";
return;
} else {
$no_days = 0;
$weekends = 0;
while ($begin <= $end) {
$no_days++; // no of days in the given interval
$what_day = date("N", $begin);
if ($what_day > 5) { // 6 and 7 are weekend days
$weekends++;
};
$begin += 86400; // +1 day
};
$working_days = $no_days - $weekends;
return $working_days + 1;
}
}
Edit
Dates 2 or more months apart within the same year work, tested again and this is the case, but dates into the next year do not
In your first part of the php code, you have put this operator>, but the problem is it means, everything Smaller than 1, not everything that is smaller than one or equal to 1. The easy solution is to change the operators to >=; which means everything that is equal to 1 or smaller than 1.
The date_diff constructs in PHP suck monkeyballs. Far more practical is to use straight comparisons instead:
$dt1 = new \DateTime($_REQUEST['startdate']);
$dt2 = new \DateTime($_REQUEST['enddate']);
$dt1->add(new \DateInterval('P1M'));
echo ($dt1 < $dt2 ? 'Less' : 'More') . ' than a month';
Also please do not use $_REQUEST, it has potentially terrible security issues. You should use $_GET, $_POST or $_COOKIE according to what you explicitly expect.
***** SOLVED *****
I have a small program where I get a date from a user - (mm/dd/yyy) - then allow them to add x number of days, months, or years. I've been trying to use the 'strtotime' function but I'm not sure if I am understanding it right.
My code is below. Say, for example, $od (original date) was 7/24/2015. The $d, $m, and $y variables are read from the form filled out by the user. These could be 0's or a user-supplied value.
Before spending hours on this one simple task, I thought I'd ask if I should be approaching this in a different fashion and/or using another function.
// Function to determine new date
function newDate($od, $d, $m, $y) {
$newDate = Date($od, strtotime('+ $d days'));
$newDate = Date($od, strtotime('+ $m months'));
$newDate = Date($od, strtotime('+ $y years'));
if ($od != $newDate) {
return $newDate;
}
else if ($od == $newDate ){
return '[no change]';
}
else {
return '[error occurred]';
}
}
EDIT: Trying now with the interval date as suggested. Can you not parse the interval string together? I feel like this should work (results in some 'non-object' error):
$newDate = $od;
$newDate->add(new DateInterval('P'.$m.'M'.$d.'D'.$y.'Y'));
echo $newDate;
if ($od != $newDate) {
return $newDate->format('mm/dd/yyyy');
EDIT: I figured it out - you can't have '0's in the string so the function won't be as clean as I had hoped.
***** SOLVED *****
The right way : DateTime::add -- date_add — Adds an amount of days, months, years, hours, minutes and seconds to a DateTime object
http://php.net/manual/en/datetime.add.php
Using native functions is always fastest, and in your case seems the proper way to go!
Why is today excluded from the returned values?
SELECT DATE(created) AS reg_date,
COUNT(*) AS user_reg_per_day
FROM users
WHERE created > (NOW() - INTERVAL 30 DAY)
GROUP BY reg_date
My query seems to be fine, but I use following PHP to fill in the gaps:
function generate_calendar_days() {
$end = date("Y-m-d");
$today = strtotime($end);
$start = strtotime("-30 day", $today);
$start = date('Y-m-d', $start);
$range = new DatePeriod(
DateTime::createFromFormat('Y-m-d', $start),
new DateInterval('P1D'),
DateTime::createFromFormat('Y-m-d', $end));
$filler = array();
foreach($range as $date) {
$d = $date->format('Y-m-d');
$filler[$d] = 0;
}
return $filler;
}
My guess is $today is not correct.
There is no reason your query should exclude data from the current day unless there is something odd with the way you are writing data to this table. Are you maybe not seeing it because you are not ordering your results (i.e. it is at bottom of result set)?
It would be giving partial day results for the day 30 days ago. As such, you might consider modifying the WHERE condition a bit:
SELECT DATE(created) AS reg_date,
COUNT(*) AS user_reg_per_day
FROM users
WHERE created >= DATE(DATE_SUB(NOW(),INTERVAL 30 DAY))
GROUP BY reg_date
ORDER BY reg_date DESC
The following is comments on update question, since it seems problem is in PHP code.
I do not fully understand why you would mix strtotime functionality with DateTime, DateInterval, DatePeriod. It is good to see that you are using those though as those are drastically underused by many developers.
That being said I might rewrite that function as:
function generate_calendar_days($start = 'today', $days = 30, $days_in_past = true) {
$dates = array();
try {
$current_day = new DateTime($start); // time set to 00:00:00
} catch (Exception $e) {
echo ('Failed with: ' . $e->getMessage());
return false;
}
$interval = new DateInterval('P1D');
if (true === $days_in_past) {
$interval->invert = 1; // make days step back in time
}
$range = new DatePeriod($current_day, $interval, $days);
foreach($range as $date) {
$dates[] = $date->format('Y-m-d');
}
return $dates;
}
Note that here I have added parameters to make your function more flexible. I also only return an array of date strings so as to make the the function more general purpose. You can leave how to work with the array of dates as an implementation detail outside the scope of this function.
Your zero-filled array can easily be constructed outside the function call like this:
$calendar = array_fill_keys(generate_calendar_days(), 0);
Your sentence is perfect, in fact SELECT (NOW() - INTERVAL 30 DAY) returns 2013-12-18 22:33:30. I experimented similar odd problems, and it was because our DDBB server had a different time configuration than our Apache Server, and it gaves us weird results.
Check your servers time configuration, (http://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html)
You can see from the comments in the PHP manual that people have had the trouble including the end date when iterating a DatePeriod. There are various modifications suggested there that can help with that, but for what you're doing you don't really need the end date, since you're always just going back a set number of days from the current date.
You can include the end date by using the "recurrences" form of the DatePeriod constructor.
function generate_calendar_days(int $n): array
{
$range = new DatePeriod(new DateTime("-$n day"), new DateInterval('P1D'), $n);
foreach($range as $date) {
$filler[$date->format('Y-m-d')] = 0;
}
return $filler;
}
$days = generate_calendar_days(30);
I want all next dates with day from specified date for sending mail within cron job file.
right now I m checking for whether its week by calculating like this
$event_from_date = strtotime(date('Y-m-d',strtotime($rs->from_date)));
$today_date = strtotime(date('Y-m-d'));
$event_expire_on = strtotime($rs->to_date);
if($rs->time_zone == "CST")
$current_date=strtotime($cst_date);
elseif($rs->time_zone == "PST")
$current_date=strtotime($pst_date);
elseif($rs->time_zone == "MST")
$current_date=strtotime($est_date);
elseif($rs->time_zone == "EST")
$current_date=strtotime($mst_date);
if($current_date <= $event_expire_on && $current_date >= $event_from_date)
{
$diff=$today_date-$event_from_date;
if($diff%604800 == 0 && $rs->report_cycle=="Weekly")
$flag = 1;
else
$flag = 0;
}
can any body tell me . how can I get all next 7 days for weekly,15 days for biweekly,30 days for monthly with its day like Monday,Tuesday..
I'm not 100% sure I have understood your question. The DateTime classes offer simple ways of manipulating dates and times in all manner of ways.
I think, in your position I would be looking for DatePeriods to represent the various erm, periods I need. A function like this may suit:-
/**
* #param Int $days
* #return DatePeriod
*/
function getNumDays($days)
{
$today = new \DateTime('UTC');
$oneDay = new \DateInterval('P1D');
return new \DatePeriod($today, $oneDay, $days);
}
foreach(getNumDays(7) as $day){
//Do what ever you want with the DateTime instance
//We'll just var_dump() it for now.
var_dump($day);
}
See it working.
From October 1st to March 31 the fee is $1 (season 1). From April 1st to September 30 the fee is $2 (season 2).
How can I calculate the total fee of a given date range (user input) depending on how many days of this date range fall into season 1 and season 2?
The following gives me the number of days of the user´s date range, but I have no idea how to test against season 1 or season 2:
$user_input_start_date = getdate( $a );
$user_input_end_date = getdate( $b );
$start_date_new = mktime( 12, 0, 0, $user_input_start_date['mon'], $user_input_start_date['mday'], $user_input_start_date['year'] );
$end_date_new = mktime( 12, 0, 0, $user_input_end_date['mon'], $user_input_end_date['mday'], $user_input_end_date['year'] );
return round( abs( $start_date_new - $end_date_new ) / 86400 );
Given that a date range starts and ends in 2012 or starts in 2012 and ends in 2013 alone gives me 10 different possibilities of in which season a date range can start and where it can end.
There must be a better solution than iterating if/else and comparing dates over and over again for the following conditions:
Date range is completely within season 1
Date range starts in season 1 and ends in season 2
Date range starts in season 1, spans across season 2 and ends in the second part of season 1
... and so forth with "Starts in season 2", etc
This not a duplicate of How many days until X-Y-Z date? as that only deals with counting the number of days. It does not address the issue of comparing one date range with another.
The key to this problem is to simplify it as much as possible. I think using an array as a lookup table for the cost of each day of the year is the way to go. The first thing to do then, is to generate the array. The array just represents each day of the year and doesn't represent any particular year. I chose to use 2012 to generate the lookup array as it is a leap year and so has every possible day in it.
function getSeasonArray()
{
/**
* I have chosen 2012 as it was a leap year. All we want to do is
* generate an array which has avery day of the year in it.
*/
$startDate = new DateTime('1st January 2012');
//DatePeriod always drops the last day.
$endDate = new DateTime('1st January 2013');
$season2Start = new DateTime('1st April 2012');
$season2End = new DateTime('1st October 2012');
$allDays = new DatePeriod($startDate, new DateInterval('P1D'), $endDate);
$season2Days = new DatePeriod($season2Start, new DateInterval('P1D'), $season2End);
$seasonArray = array();
foreach($allDays as $day){
$seasonArray[] = $day->format('d-M');
$seasonArray[$day->format('d-M')]['season'] = 1;
}
foreach($season2Days as $day){
$seasonArray[$day->format('d-M')]['season'] = 2;
}
return $seasonArray;
}
Once that is done you just need the period over which to calculate:-
$bookingStartDate = new DateTime();//Or wherever you get this from
$bookingEndDate = new DateTime();
$bookingEndDate->setTimestamp(strtotime('+ 7 month'));//Or wherever you get this from
$bookingPeriod = new DatePeriod($bookingStartDate, new DateInterval('P1D'), $bookingEndDate);
Then we can do the calculation:-
$seasons = getSeasonArray();
$totalCost = 0;
foreach($bookingPeriod as $day){
$totalCost += $seasons[$day->format('d-M')]['season'];
var_dump($day->format('d-M') . ' = $' . $seasons[$day->format('d-M')]['season']);
}
var_dump($totalCost);
I have chosen a long booking period, so that you can scan through the var_dump() output and verify the correct price for each day of the year.
This is a quick stab done between distractions at work and I'm sure that with a bit of thought you can mould it into a more elegant solution. I'd like to get rid of the double iteration for example, unfortunately, work pressures prevent me from spending further time on this.
See the PHP DateTime man page for further information on these useful classes.
At first I suggested using the DateTime class that PHP provides, naively assuming that it has some kind of thought-out API that one could use. It turns out that it does not. While it features very basic DateTime functionality, it is mostly unusable because, for most operations, it relies on the DateInterval class. In combination, those classes represent another masterpiece of bad API design.
An interval should be defined like so:
An interval in Joda-Time represents an interval of time from one millisecond instant to another instant. Both instants are fully specified instants in the datetime continuum, complete with time zone.
In PHP, however, an Interval is just a duration:
A date interval stores either a fixed amount of time (in years, months, days, hours etc) or a relative time string [such as "2 days"].
Unfortunately, PHP's DateInterval definition does not allow for intersection/overlap calculation (which the OP needs) because PHP's Intervals have no specific position in the datetime continuum. Therefore, I've implemented a (very rudimentary) class that adheres to JodaTime's definition of an interval. It is not extensively tested, but it should get the work done:
class ProperDateInterval {
private $start = null;
private $end = null;
public function __construct(DateTime $start, DateTime $end) {
$this->start = $start;
$this->end = $end;
}
/**
* Does this time interval overlap the specified time interval.
*/
public function overlaps(ProperDateInterval $other) {
$start = $this->getStart()->getTimestamp();
$end = $this->getEnd()->getTimestamp();
$oStart = $other->getStart()->getTimestamp();
$oEnd = $other->getEnd()->getTimestamp();
return $start < $oEnd && $oStart < $end;
}
/**
* Gets the overlap between this interval and another interval.
*/
public function overlap(ProperDateInterval $other) {
if(!$this->overlaps($other)) {
// I haven't decided what should happen here yet.
// Returning "null" doesn't seem like a good solution.
// Maybe ProperDateInterval::EMPTY?
throw new Exception("No intersection.");
}
$start = $this->getStart()->getTimestamp();
$end = $this->getEnd()->getTimestamp();
$oStart = $other->getStart()->getTimestamp();
$oEnd = $other->getEnd()->getTimestamp();
$overlapStart = NULL;
$overlapEnd = NULL;
if($start === $oStart || $start > $oStart) {
$overlapStart = $this->getStart();
} else {
$overlapStart = $other->getStart();
}
if($end === $oEnd || $end < $oEnd) {
$overlapEnd = $this->getEnd();
} else {
$overlapEnd = $other->getEnd();
}
return new ProperDateInterval($overlapStart, $overlapEnd);
}
/**
* #return long The duration of this interval in seconds.
*/
public function getDuration() {
return $this->getEnd()->getTimestamp() - $this->getStart()->getTimestamp();
}
public function getStart() {
return $this->start;
}
public function getEnd() {
return $this->end;
}
}
It may be used like so:
$seasonStart = DateTime::createFromFormat('j-M-Y', '01-Apr-2012');
$seasonEnd = DateTime::createFromFormat('j-M-Y', '30-Sep-2012');
$userStart = DateTime::createFromFormat('j-M-Y', '01-Jan-2012');
$userEnd = DateTime::createFromFormat('j-M-Y', '02-Apr-2012');
$i1 = new ProperDateInterval($seasonStart, $seasonEnd);
$i2 = new ProperDateInterval($userStart, $userEnd);
$overlap = $i1->overlap($i2);
var_dump($overlap->getDuration());