cal_days_in_month incorrect for December 1 BCE
| Bug #52744 | cal_days_in_month incorrect for December 1 BCE | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Submitted: | 2010-08-30 18:16 UTC | Modified: | 2010-09-09 08:41 UTC |
|
||||||||||
| From: | gpap at internet dot gr | Assigned: | aharvey (profile) | |||||||||||
| Status: | Closed | Package: | Calendar related | |||||||||||
| PHP Version: | 5.3SVN-2010-08-30 (snap) | OS: | all | |||||||||||
| Private report: | No | CVE-ID: | None | |||||||||||
[2010-08-30 18:16 UTC] gpap at internet dot gr
Description:
------------
Function cal_days_in_month returns wrong result for December 1 BCE:
echo cal_days_in_month(CAL_GREGORIAN, 12, -1) returns -1721395
echo cal_days_in_month(CAL_JULIAN, 12, -1) returns -1721393
The function uses julian day count internally to calculate the day count
difference between the 1st day of the supplied month and the 1st day of the next
month. The next month of December 1 BCE (year -1) is January 1 CE (year 1, there
is no year zero).
But when cal_days_in_month calculates the next year as year+1, it does not check
for year zero, so it tries to calculate the julian day for 1st January 0, which
returns 0 and consequently the wrong result of days in December 1 BCE is
returned.
actual function code taken from latest svn snapshot php5.3-201008301230
(/ext/calendar.c):
-----------------------
PHP_FUNCTION(cal_days_in_month)
{
long cal, month, year;
struct cal_entry_t *calendar;
long sdn_start, sdn_next;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &cal,
&month, &year) == FAILURE) {
RETURN_FALSE;
}
if (cal < 0 || cal >= CAL_NUM_CALS) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid calendar ID
%ld.", cal);
RETURN_FALSE;
}
calendar = &cal_conversion_table[cal];
sdn_start = calendar->to_jd(year, month, 1);
if (sdn_start == 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid date.");
RETURN_FALSE;
}
sdn_next = calendar->to_jd(year, 1 + month, 1);
if (sdn_next == 0) {
/* if invalid, try first month of the next year... */
sdn_next = calendar->to_jd(year + 1, 1, 1);
}
RETURN_LONG(sdn_next - sdn_start);
}
-----------------------
The following correction is proposed:
-----------------------
if (sdn_next == 0) {
/* if invalid, try first month of the next year... */
- sdn_next = calendar->to_jd(year + 1, 1, 1);
+ if (year == -1) {
+ sdn_next = calendar->to_jd(1, 1, 1);
+ } else {
+ sdn_next = calendar->to_jd(year + 1, 1, 1);
+ }
}
-----------------------
Test script:
---------------
<?php
// returns -1721395 instead of 31
echo cal_days_in_month(CAL_GREGORIAN, 12, -1);
// returns -1721393 instead of 31
echo cal_days_in_month(CAL_JULIAN, 12, -1);
?>
Expected result:
----------------
31
31
Actual result:
--------------
-1721395
-1721393
Patches
Pull Requests
History
AllCommentsChangesGit/SVN commits
[2010-09-09 08:02 UTC] aharvey@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: aharvey
[2010-09-09 08:41 UTC] aharvey@php.net
-Summary: cal_days_in_month +Summary: cal_days_in_month incorrect for December 1 BCE -Status: Assigned +Status: Closed
[2010-09-09 08:41 UTC] aharvey@php.net