- Fixed bug #49081 (DateTime::diff() mistake if start in January and interval >

28 days). (Derick)
This commit is contained in:
Derick Rethans 2010-05-04 15:11:41 +00:00
parent ebae62d7c4
commit 7cf3911cb8
5 changed files with 132 additions and 26 deletions

2
NEWS
View File

@ -129,6 +129,8 @@ PHP NEWS
- Fixed bug #49429 (odbc_autocommit doesn't work). (Felipe)
- Fixed bug #49234 (mysqli_ssl_set not found). (Andrey)
- Fixed bug #49192 (PHP crashes when GC invoked on COM object). (Stas)
- Fixed bug #49081 (DateTime::diff() mistake if start in January and interval >
28 days). (Derick)
- Fixed bug #49059 (DateTime::diff() repeats previous sub() operation).
(yoarvi@gmail.com, Derick)
- Fixed bug #48983 (DomDocument : saveHTMLFile wrong charset). (Rob)

View File

@ -56,7 +56,7 @@ timelib_rel_time *timelib_diff(timelib_time *one, timelib_time *two)
rt->s = two->s - one->s;
rt->days = abs(floor((one->sse - two->sse - (dst_h_corr * 3600) - (dst_m_corr * 60)) / 86400));
timelib_do_rel_normalize(one, rt);
timelib_do_rel_normalize(rt->invert ? one : two, rt);
timelib_apply_localtime(one, 1);
timelib_apply_localtime(two, 1);

View File

@ -41,39 +41,64 @@ static int do_range_limit(timelib_sll start, timelib_sll end, timelib_sll adj, t
return 0;
}
static int do_range_limit_days_relative(timelib_sll *base_y, timelib_sll *base_m, timelib_sll *y, timelib_sll *m, timelib_sll *d)
static void inc_month(timelib_sll *y, timelib_sll *m)
{
(*m)++;
if (*m > 12) {
*m -= 12;
(*y)++;
}
}
static void dec_month(timelib_sll *y, timelib_sll *m)
{
(*m)--;
if (*m < 1) {
*m += 12;
(*y)--;
}
}
static void do_range_limit_days_relative(timelib_sll *base_y, timelib_sll *base_m, timelib_sll *y, timelib_sll *m, timelib_sll *d, timelib_sll invert)
{
timelib_sll leapyear;
timelib_sll days_this_month;
timelib_sll next_month, next_year;
timelib_sll days_next_month;
timelib_sll month, year;
timelib_sll days;
do_range_limit(1, 13, 12, base_m, base_y);
leapyear = timelib_is_leap(*base_y);
days_this_month = leapyear ? days_in_month_leap[*base_m] : days_in_month[*base_m];
next_month = (*base_m) + 1;
year = *base_y;
month = *base_m;
if (next_month > 12) {
next_month -= 12;
next_year = (*base_y) + 1;
/*
printf( "S: Y%d M%d %d %d %d %d\n", year, month, *y, *m, *d, days);
*/
if (!invert) {
while (*d < 0) {
dec_month(&year, &month);
leapyear = timelib_is_leap(year);
days = leapyear ? days_in_month_leap[month] : days_in_month[month];
/* printf( "I Y%d M%d %d %d %d %d\n", year, month, *y, *m, *d, days); */
*d += days;
(*m)--;
}
} else {
next_year = (*base_y);
}
leapyear = timelib_is_leap(next_year);
days_next_month = leapyear ? days_in_month_leap[next_month] : days_in_month[next_month];
while (*d < 0) {
leapyear = timelib_is_leap(year);
days = leapyear ? days_in_month_leap[month] : days_in_month[month];
if (*d < 0) {
*d += days_this_month;
(*m)--;
return 1;
/* printf( "I Y%d M%d %d %d %d %d\n", year, month, *y, *m, *d, days); */
*d += days;
(*m)--;
inc_month(&year, &month);
}
}
if (*d > days_next_month) {
*d -= days_next_month;
(*m)++;
return 1;
}
return 0;
/*
printf( "E: Y%d M%d %d %d %d %d\n", year, month, *y, *m, *d, days);
*/
}
static int do_range_limit_days(timelib_sll *y, timelib_sll *m, timelib_sll *d)
@ -150,7 +175,7 @@ void timelib_do_rel_normalize(timelib_time *base, timelib_rel_time *rt)
do {} while (do_range_limit(0, 24, 24, &rt->h, &rt->d));
do {} while (do_range_limit(0, 12, 12, &rt->m, &rt->y));
do {} while (do_range_limit_days_relative(&base->y, &base->m, &rt->y, &rt->m, &rt->d));
do_range_limit_days_relative(&base->y, &base->m, &rt->y, &rt->m, &rt->d, rt->invert);
do {} while (do_range_limit(0, 12, 12, &rt->m, &rt->y));
}

View File

@ -0,0 +1,22 @@
--TEST--
Bug #49081 (DateTime::diff() mistake if start in January and interval > 28 days)
--FILE--
<?php
date_default_timezone_set('Europe/Berlin');
$d1 = new DateTime('2010-01-01 06:00:00');
$d2 = new DateTime('2010-01-31 10:00:00');
$d = $d1->diff($d2);
print_r($d);
?>
--EXPECT--
DateInterval Object
(
[y] => 0
[m] => 0
[d] => 30
[h] => 4
[i] => 0
[s] => 0
[invert] => 0
[days] => 30
)

View File

@ -0,0 +1,57 @@
--TEST--
Extensive test for date_diff().
--FILE--
<?php
$ok = 0;
define( 'COUNT', 120 );
$d0 = new DateTime('2009-11-20');
for ( $i = 0; $i < COUNT * 12; $i++ )
{
$d = clone $d0;
$dates[$i] = $d->add( new DateInterval( "P{$i}D" ) );
}
for ( $i = 0; $i < COUNT; $i++)
{
// echo $dates[$i]->format( "Y-m-d\n" );
for ( $j = 0; $j < COUNT * 12; $j++)
{
$diff = date_diff( $dates[$i], $dates[$j] );
/*
printf( "\t%s %s %3d %s\n",
$dates[$i]->format( 'Y-m-d' ),
$dates[$j]->format( 'Y-m-d' ),
$diff->format( '%a' ),
$diff->format( '%y-%m-%d' )
);
*/
$current = clone $dates[$i];
$int = new DateInterval( $diff->format( 'P%yY%mM%dD' ) );
if ( $current > $dates[$j] )
{
$current->sub( $int );
}
else
{
$current->add( $int );
}
if ( $current != $dates[$j] )
{
echo "FAIL: ",
$dates[$i]->format( 'Y-m-d' ), " + ",
$int->format( '%y-%m-%d' ), " = ",
$current->format( 'Y-m-d' ), " (",
$dates[$j]->format( 'Y-m-d' ), ")\n";
}
else
{
$ok++;
}
}
}
echo $ok, "\n";
?>
--EXPECT--
172800