TalkPHP (http://www.talkphp.com/forums.php)
-   -   Finding the distance between 2 dates... (http://www.talkphp.com/advanced-php-programming/2854-finding-distance-between-2-dates.html)

 may 05-27-2008 10:51 PM

Finding the distance between 2 dates...

Hi all.

Im trying to find a method (if there is any) that can calculate the distance in days, months or years between two dates. Mainly the distance in days. i almost searched the whole datetime object to no afail...

So for example i have 2008-05-29 and 2008-06-01 i would like to find the distance in days for instance which should be 3. or in months wich should be 1 or years that should be 0.

Usually i use mysql to solve this little math problem, but i was wondering if there isnt a php method that could calculate this instead of using de expensive sql connection all the time to solve it...

Hope its kinda clear what i mean...

May

 Wildhoney 05-27-2008 11:03 PM

php Code:
`\$iStartDate = '2008-05-29';\$iEndDate = '2008-06-01';printf(    'Distance between 2 dates is %d days.',    (strtotime(\$iEndDate) - strtotime(\$iStartDate)) / 86400);`

 ReSpawN 05-28-2008 06:07 AM

Although Adam's way is more thorough, you might want to use this.
PHP Code:

``` \$sStartDate = explode('-', '2008-05-29');// \$sEndDate = explode('-', '2008-06-01'); Tanax got mad./*     Now you would have something like \$sStartDate[0]; would be 2008, being 1, 05 and 2, 29th.     Now, you could make a timestamp which I always use, it's more easier on the eyes if you ask me.*/\$iStartDate = mktime(0, 0, 0, \$sStartDate[1], \$sStartDate[2], \$sStartDate[0]);/*     Now, with that b-e-a-utiful function, you would recieve a timestamp which you can use almost anywhere. If you want to push a date onto the screen, use this.*/echo date('H:i:s d-m-Y', \$iStartDate);/*     Note: I didn't try it, scripted it into this quickreply so there MIGHT be some errors - off to school now.*/  ```
Oh yes, \$iStartDate being that it's a TOTAL integer (only numbers), and \$sStartDate, being that it contains a dash which is not a numeric function, if checked with the is_numeric function. :-)

 Tanax 05-28-2008 12:53 PM

@up- So why do you use sEndDate ? You don't even use it anywhere xD

 ReSpawN 05-28-2008 05:29 PM

There you go.

 may 05-28-2008 07:15 PM

Hehe thanks guys for solving this using pure math. Im sure i can put it to use at some point so thx for that :D

But still there isnt a method out there that actually solves this within an php function like Mysql can using DATEDIFF('expr1', 'expr2')?

 Wildhoney 05-28-2008 09:10 PM

I'm unaware of any such function. Maybe there is one in-built though, but I somehow doubt it as it's quite basic mathematics.

 ReSpawN 05-28-2008 09:25 PM

You can use the DATE() function in mySQL though.

 delayedinsanity 05-28-2008 09:43 PM

Wildhoney, I apologize in advance if stealing.. er, borrowing your code is in any way offensive, but just for clarity's sake;

PHP Code:

``` function dateDiff (\$iStartDate, \$iEndDate) {    return sprintf('%d', (strtotime(\$iEndDate) - strtotime(\$iStartDate)) / 86400);}\$iDiff = dateDiff('2008-05-29', '2008-06-01');echo "Distance between two dates is {\$iDiff} days.";  ```
now you have a function that does it. ;-) If it's not built in, but you know how to do it (or somebody shows you), you can make a function and use it as much as you like.
-m

 Wildhoney 05-28-2008 10:50 PM

That's quite OK! How about the following?

php Code:
`class DateDiff{    private \$m_pDates;    private \$m_aConversions;        public function __construct(\$iStartDate, \$iEndDate)    {        \$this->m_aConversions = array        (            'Seconds' => 0,            'Minutes' => 60,            'Hours' => 3600,            'Days' => 86400,            'Weeks' => 604800        );                \$this->m_pDates->start = \$iStartDate;        \$this->m_pDates->end = \$iEndDate;    }        public function __call(\$szCall, \$aArgs)    {        if(!preg_match('~^in(.+)~', \$szCall, \$aMatches))        {            throw new Exception('Invalid conversion format supplied.');        }            \$szCall = \$aMatches[1];                if (!in_array(\$szCall, \$this->m_aConversions))        {            throw new Exception('Specified conversion is not available.');        }                if(\$this->m_aConversions[\$szCall] == 0)        {            return strtotime(\$this->m_pDates->end) - strtotime(\$this->m_pDates->start);        }                return(strtotime(\$this->m_pDates->end) - strtotime(\$this->m_pDates->start)) / \$this->m_aConversions[\$szCall];    }}`

Then we can use it like so:

php Code:
`\$pDate = new DateDiff('2008-05-29', '2008-06-01');    printf('Difference: %d seconds<br />', \$pDate->inSeconds());printf('Difference: %d minutes<br />', \$pDate->inMinutes());printf('Difference: %d hours<br />', \$pDate->inHours());printf('Difference: %d days<br />', \$pDate->inDays());printf('Difference: %d weeks<br />', \$pDate->inWeeks());`

 delayedinsanity 05-28-2008 11:01 PM

Show off.

Excellent example of using __call() though.
-m

 Salathe 05-29-2008 12:07 AM

How about calculating the correct answers when a daylight savings boundary is crossed? For example, at the moment, the code will return 0 days between March 30th and 31st this year (for timezone Europe/London).

 may 05-29-2008 10:16 AM

Hehehe is it me? or are subjects always treated this thurally?

Btw great examples there :)

ow and... :P
When do we cross the point that we are actually discussing how to handle leap years and the so much discussed 4000 Years rule in the gregorian calendar? (not hoping my code wil ever run that long :P) Hehe.

regards,

 sketchMedia 05-29-2008 12:14 PM

i think you can use the date function to output the timezone offset in seconds by using the 'Z' param:
PHP Code:

``` echo date('Z');  ```
or using the DateTime object:
PHP Code:

``` \$dstOffset = new DateTime();echo \$dstOffset->getOffset();  ```

 sketchMedia 05-29-2008 01:43 PM

I think this should do it, there is probably a better way of doing it but it works for me:

PHP Code:

``` \$date = '30-03-2008';\$date2 = '31-03-2008';//get the offset\$dateTime1 = new DateTime(\$date);\$dateTime2 = new DateTime(\$date2);\$dstZone = new DateTimeZone('Europe/London');//change accordinglyecho 'Difference: ',((strtotime(\$date2) + \$dstZone->getOffset(\$dateTime2)) - (strtotime(\$date) + \$dstZone->getOffset(\$dateTime1))) / 86400, ' Days';  ```
outputs: 1 day.

edit: i think this is for php 5.2.x not sure about 5.1.x as i dunno when these classes were added, any1 know?

 Salathe 05-29-2008 02:01 PM

sketch, try that with some other timezone settings applied to the DateTime objects. For example, at the top of the script call `date_default_timezone_set('Asia/Tokyo');`.

 sketchMedia 05-29-2008 02:06 PM

with the date_default_timezone_set('Asia/Tokyo')
set it outputs:

1.04166666667

but if you also change
PHP Code:

``` DateTimeZone('Europe/London')  ```
to
PHP Code:

``` DateTimeZone('Asia/Tokyo')  ```
it calculates the correct offset for Asia/Tokyo instead of Europe/London and thus out puts 1 day correctly.

this should do it automatically:
PHP Code:

``` date_default_timezone_set('Asia/Tokyo');\$date = '05-03-2008';\$date2 = '10-03-2008';\$dstZone = new DateTimeZone(date_default_timezone_get());echo 'Difference: ',((strtotime(\$date2) + \$dstZone->getOffset(new DateTime(\$date2))) - (strtotime(\$date) + \$dstZone->getOffset(new DateTime(\$date)))) / 86400, ' Days';  ```

 sketchMedia 05-29-2008 02:55 PM

Combined into Wildhoney's class (which i have slightly modified, i added 'array_key_exists, instead of 'in_array' and a few small things)

PHP Code:

``` class DateDiff{    private \$m_pDates;    private \$m_aConversions;     public function __construct(\$iStartDate, \$iEndDate, \$szTimeZone = '')    {        \$this->m_aConversions = array        (            'Seconds' => 0,            'Minutes' => 60,            'Hours' => 3600,            'Days' => 86400,            'Weeks' => 604800        );        \$pDateTimezone = new DateTimeZone(            (!empty(\$szTimeZone)) ?                \$szTimeZone :                date_default_timezone_get()        );        //get time and add related offsets(if any)        \$this->m_pDates->start = strtotime(\$iStartDate) + \$pDateTimezone->getOffset(new DateTime(\$iStartDate));        \$this->m_pDates->end = strtotime(\$iEndDate) + \$pDateTimezone->getOffset(new DateTime(\$iEndDate));    }      public function __call(\$szCall, \$aArgs)    {        if(!preg_match('~^in(.+)~', \$szCall, \$aMatches))        {            throw new Exception('Invalid conversion format supplied.');        }          \$szCall = \$aMatches[1];        if (!array_key_exists(\$szCall, \$this->m_aConversions))        {            throw new Exception('Specified conversion is not available.');        }              if(\$this->m_aConversions[\$szCall] == 0)        {            return \$this->m_pDates->end - \$this->m_pDates->start;        }              return (\$this->m_pDates->end - \$this->m_pDates->start) / \$this->m_aConversions[\$szCall];    }}  ```
Now we can:

PHP Code:

``` date_default_timezone_set('Asia/Tokyo');\$pDate = new DateDiff('2008-01-29', '2008-01-30');    printf('Difference: %d seconds<br />', \$pDate->inSeconds());printf('Difference: %d minutes<br />', \$pDate->inMinutes());printf('Difference: %d hours<br />', \$pDate->inHours());printf('Difference: %d days<br />', \$pDate->inDays());printf('Difference: %d weeks<br />', \$pDate->inWeeks());  ```

 Enfernikus 06-08-2008 04:01 AM

I just want to point out something in the above classes

PHP Code:

```  if(\$this->m_aConversions[\$szCall] == 0)        {            return \$this->m_pDates->end - \$this->m_pDates->start;        }  ```
If you just change the seconds in the conversions array to 1 you don't need the above line of code as X/1 = X or if you don't like algebra - a number over one will always be that number.

 All times are GMT. The time now is 09:48 AM.