- MFH: Fixed bug #37017 (strtotime fails before 13:00:00 with some time zones

identifiers). (Derick)
- MFH: Fixed bug #36988 (mktime freezes on long numbers). (Derick)
- MFH: Implemented better error and warning handling that is also used for the
  date_parse() function.
- MFH: Fixed problems with "T" in front of a time string was seen as a time
  zone string.
- MFH: Fixed a problem were 5 and 6 character timezone abbreviations where not
  correctly parsed.

Experimental support (All MFH):
- Added the date_parse() function that returns a parsed date/time string
  including warnings and errors.
- Added the timezone_name_from_abbr() function that exposes the guessing
  mechanism that tries to find a timezone identifier from a timezone
  abbreviation and GMT offset.
This commit is contained in:
Derick Rethans 2006-04-11 18:03:52 +00:00
parent 4bab5226b2
commit 4043f77e36
11 changed files with 13293 additions and 9540 deletions

3
NEWS
View File

@ -19,6 +19,9 @@ PHP NEWS
- Fixed offset/length parameter validation in substr_compare() function. (Ilia)
- Fixed debug_zval_dump() to support private and protected members. (Dmitry)
- Fixed SoapFault::getMessage(). (Dmitry)
- Fixed bug #37017 (strtotime fails before 13:00:00 with some time zones
identifiers). (Derick)
- Fixed bug #36988 (mktime freezes on long numbers). (Derick)
- Fixed bug #36981 (SplFileObject->fgets() ignores max_length). (Tony)
- Fixed bug #36957 (serialize() does not handle recursion). (Ilia)
- Fixed bug #36944 (strncmp & strncasecmp do not return false on negative

File diff suppressed because it is too large Load Diff

View File

@ -97,13 +97,13 @@ typedef unsigned char uchar;
#define timelib_string_free free
#define TIMELIB_HAVE_TIME() { if (s->time->have_time) { return TIMELIB_ERROR; } else { s->time->have_time = 1; s->time->h = 0; s->time->i = 0; s->time->s = 0; s->time->f = 0; } }
#define TIMELIB_HAVE_TIME() { if (s->time->have_time) { add_error(s, "Double time specification"); timelib_string_free(str); return TIMELIB_ERROR; } else { s->time->have_time = 1; s->time->h = 0; s->time->i = 0; s->time->s = 0; s->time->f = 0; } }
#define TIMELIB_UNHAVE_TIME() { s->time->have_time = 0; s->time->h = 0; s->time->i = 0; s->time->s = 0; s->time->f = 0; }
#define TIMELIB_HAVE_DATE() { if (s->time->have_date) { return TIMELIB_ERROR; } else { s->time->have_date = 1; } }
#define TIMELIB_HAVE_DATE() { if (s->time->have_date) { add_error(s, "Double date specification"); timelib_string_free(str); return TIMELIB_ERROR; } else { s->time->have_date = 1; } }
#define TIMELIB_UNHAVE_DATE() { s->time->have_date = 0; s->time->d = 0; s->time->m = 0; s->time->y = 0; }
#define TIMELIB_HAVE_RELATIVE() { s->time->have_relative = 1; s->time->relative.weekday_behavior = 0; }
#define TIMELIB_HAVE_WEEKDAY_RELATIVE() { s->time->have_weekday_relative = 1; }
#define TIMELIB_HAVE_TZ() { s->cur = cursor; if (s->time->have_zone) { return TIMELIB_ERROR; } else { s->time.have_zone = 1; } }
#define TIMELIB_HAVE_TZ() { s->cur = cursor; if (s->time->have_zone) { add_warning(s, "Double timezone specification"); timelib_string_free(str); return TIMELIB_ERROR; } else { s->time->have_zone = 1; } }
#define TIMELIB_INIT s->cur = cursor; str = timelib_string(s); ptr = str
#define TIMELIB_DEINIT timelib_string_free(str)
@ -140,7 +140,7 @@ typedef struct Scanner {
int fd;
uchar *lim, *str, *ptr, *cur, *tok, *pos;
unsigned int line, len;
int errors;
struct timelib_error_container *errors;
struct timelib_time *time;
timelib_tzdb *tzdb;
@ -325,6 +325,24 @@ uchar *fill(Scanner *s, uchar *cursor){
}
#endif
static void add_warning(Scanner *s, char *error)
{
s->errors->warning_count++;
s->errors->warning_messages = realloc(s->errors->warning_messages, s->errors->warning_count * sizeof(timelib_error_message));
s->errors->warning_messages[s->errors->warning_count - 1].position = s->tok ? s->tok - s->str : 0;
s->errors->warning_messages[s->errors->warning_count - 1].character = s->tok ? *s->tok : 0;
s->errors->warning_messages[s->errors->warning_count - 1].message = strdup(error);
}
static void add_error(Scanner *s, char *error)
{
s->errors->error_count++;
s->errors->error_messages = realloc(s->errors->error_messages, s->errors->error_count * sizeof(timelib_error_message));
s->errors->error_messages[s->errors->error_count - 1].position = s->tok ? s->tok - s->str : 0;
s->errors->error_messages[s->errors->error_count - 1].character = s->tok ? *s->tok : 0;
s->errors->error_messages[s->errors->error_count - 1].message = strdup(error);
}
static timelib_sll timelib_meridian(char **ptr, timelib_sll h)
{
timelib_sll retval = 0;
@ -684,9 +702,11 @@ static long timelib_get_zone(char **ptr, int *dst, timelib_time *t, int *tz_not_
char *tz_abbr;
t->is_localtime = 1;
t->zone_type = TIMELIB_ZONETYPE_ABBR;
offset = timelib_lookup_zone(ptr, dst, &tz_abbr, &found);
if (found) {
t->zone_type = TIMELIB_ZONETYPE_ABBR;
}
#if 0
/* If we found a TimeZone identifier, use it */
if (tz_name) {
@ -702,7 +722,7 @@ static long timelib_get_zone(char **ptr, int *dst, timelib_time *t, int *tz_not_
found++;
}
}
if (t->zone_type != TIMELIB_ZONETYPE_ID) {
if (found && t->zone_type != TIMELIB_ZONETYPE_ID) {
timelib_time_tz_abbr_update(t, tz_abbr);
}
free(tz_abbr);
@ -748,8 +768,8 @@ minute = [0-5]?[0-9];
minutelz = [0-5][0-9];
second = minute | "60";
secondlz = minutelz | "60";
meridian = [AaPp] "."? [Mm] "."?;
tz = "("? [A-Za-z]{1,4} ")"? | [A-Z][a-z]+([_/][A-Z][a-z]+)+;
meridian = ([AaPp] "."? [Mm] "."?) [\000\t ];
tz = "("? [A-Za-z]{1,6} ")"? | [A-Z][a-z]+([_/][A-Z][a-z]+)+;
tzcorrection = [+-] hour24 ":"? minute?;
daysuf = "st" | "nd" | "rd" | "th";
@ -780,17 +800,17 @@ timetiny12 = hour12 space? meridian;
timeshort12 = hour12[:.]minutelz space? meridian;
timelong12 = hour12[:.]minute[:.]secondlz space? meridian;
timeshort24 = hour24[:.]minute;
timelong24 = hour24[:.]minute[:.]second;
iso8601long = hour24 [:.] minute [:.] second frac;
timeshort24 = 't'? hour24[:.]minute;
timelong24 = 't'? hour24[:.]minute[:.]second;
iso8601long = 't'? hour24 [:.] minute [:.] second frac;
/* iso8601shorttz = hour24 [:] minutelz space? (tzcorrection | tz); */
iso8601normtz = hour24 [:.] minute [:.] secondlz space? (tzcorrection | tz);
iso8601normtz = 't'? hour24 [:.] minute [:.] secondlz space? (tzcorrection | tz);
/* iso8601longtz = hour24 [:] minute [:] secondlz frac space? (tzcorrection | tz); */
gnunocolon = hour24lz minutelz;
gnunocolon = 't'? hour24lz minutelz;
/* gnunocolontz = hour24lz minutelz space? (tzcorrection | tz); */
iso8601nocolon = hour24lz minutelz secondlz;
iso8601nocolon = 't'? hour24lz minutelz secondlz;
/* iso8601nocolontz = hour24lz minutelz secondlz space? (tzcorrection | tz); */
/* Date formats */
@ -960,7 +980,9 @@ relativetext = reltextnumber space? reltextunit;
if (*ptr != '\0') {
s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb);
s->errors += tz_not_found;
if (tz_not_found) {
add_error(s, "The timezone could not be found in the database");
}
}
TIMELIB_DEINIT;
return TIMELIB_TIME24_WITH_ZONE;
@ -981,6 +1003,7 @@ relativetext = reltextnumber space? reltextunit;
break;
default:
TIMELIB_DEINIT;
add_error(s, "Double time specification");
return TIMELIB_ERROR;
}
s->time->have_time++;
@ -1023,7 +1046,9 @@ relativetext = reltextnumber space? reltextunit;
if (*ptr != '\0') {
s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb);
s->errors += tz_not_found;
if (tz_not_found) {
add_error(s, "The timezone could not be found in the database");
}
}
TIMELIB_DEINIT;
return TIMELIB_ISO_NOCOLON;
@ -1176,7 +1201,9 @@ relativetext = reltextnumber space? reltextunit;
s->time->f = timelib_get_frac_nr((char **) &ptr, 9);
if (*ptr) { /* timezone is optional */
s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb);
s->errors += tz_not_found;
if (tz_not_found) {
add_error(s, "The timezone could not be found in the database");
}
}
}
TIMELIB_DEINIT;
@ -1274,7 +1301,9 @@ relativetext = reltextnumber space? reltextunit;
s->time->i = timelib_get_nr((char **) &ptr, 2);
s->time->s = timelib_get_nr((char **) &ptr, 2);
s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb);
s->errors += tz_not_found;
if (tz_not_found) {
add_error(s, "The timezone could not be found in the database");
}
TIMELIB_DEINIT;
return TIMELIB_CLF;
}
@ -1341,8 +1370,11 @@ relativetext = reltextnumber space? reltextunit;
int tz_not_found;
DEBUG_OUTPUT("tzcorrection | tz");
TIMELIB_INIT;
TIMELIB_HAVE_TZ();
s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb);
s->errors += tz_not_found;
if (tz_not_found) {
add_error(s, "The timezone could not be found in the database");
}
TIMELIB_DEINIT;
return TIMELIB_TIMEZONE;
}
@ -1369,7 +1401,9 @@ relativetext = reltextnumber space? reltextunit;
if (*ptr != '\0') {
s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb);
s->errors += tz_not_found;
if (tz_not_found) {
add_error(s, "The timezone could not be found in the database");
}
}
TIMELIB_DEINIT;
return TIMELIB_SHORTDATE_WITH_TIME;
@ -1404,8 +1438,7 @@ relativetext = reltextnumber space? reltextunit;
any
{
/* printf("unexpected character: #%d, %c ", *s->tok, *s->tok); */
s->errors++;
add_error(s, "Unexpected character");
goto std;
}
*/
@ -1413,12 +1446,19 @@ relativetext = reltextnumber space? reltextunit;
/*!max:re2c */
timelib_time* timelib_strtotime(char *s, int len, int *errors, timelib_tzdb *tzdb)
timelib_time* timelib_strtotime(char *s, int len, struct timelib_error_container **errors, timelib_tzdb *tzdb)
{
Scanner in;
int t;
char *e = s + len - 1;
memset(&in, 0, sizeof(in));
in.errors = malloc(sizeof(struct timelib_error_container));
in.errors->warning_count = 0;
in.errors->warning_messages = NULL;
in.errors->error_count = 0;
in.errors->error_messages = NULL;
while (isspace(*s) && s < e) {
s++;
}
@ -1426,15 +1466,19 @@ timelib_time* timelib_strtotime(char *s, int len, int *errors, timelib_tzdb *tzd
e--;
}
if (e - s < 1) {
*errors = 1;
in.time = timelib_time_ctor();
add_error(&in, "Empty string");
if (errors) {
*errors = in.errors;
} else {
timelib_error_container_dtor(in.errors);
}
in.time->y = in.time->d = in.time->m = in.time->h = in.time->i = in.time->s = in.time->f = in.time->z = in.time->dst = -1;
in.time->is_localtime = in.time->zone_type = 0;
return in.time;
}
e++;
memset(&in, 0, sizeof(in));
in.str = malloc((e - s) + YYMAXFILL);
memset(in.str, 0, (e - s) + YYMAXFILL);
memcpy(in.str, s, (e - s));
@ -1450,7 +1494,6 @@ timelib_time* timelib_strtotime(char *s, int len, int *errors, timelib_tzdb *tzd
in.time->f = -1;
in.time->z = -1;
in.time->dst = -1;
in.errors = 0;
in.tzdb = tzdb;
in.time->is_localtime = 0;
in.time->zone_type = 0;
@ -1463,7 +1506,11 @@ timelib_time* timelib_strtotime(char *s, int len, int *errors, timelib_tzdb *tzd
} while(t != EOI);
free(in.str);
*errors = in.errors;
if (errors) {
*errors = in.errors;
} else {
timelib_error_container_dtor(in.errors);
}
return in.time;
}

View File

@ -122,6 +122,21 @@ char *timelib_get_tz_abbr_ptr(timelib_time *t)
return t->tz_abbr;
}
void timelib_error_container_dtor(timelib_error_container *errors)
{
int i;
for (i = 0; i < errors->warning_count; i++) {
free(errors->warning_messages[i].message);
}
free(errors->warning_messages);
for (i = 0; i < errors->error_count; i++) {
free(errors->error_messages[i].message);
}
free(errors->error_messages);
free(errors);
}
signed long timelib_date_to_int(timelib_time *d, int *error)
{
timelib_sll ts;

View File

@ -51,7 +51,7 @@ timelib_sll timelib_days_in_month(timelib_sll y, timelib_sll m);
void timelib_isoweek_from_date(timelib_sll y, timelib_sll m, timelib_sll d, timelib_sll *iw, timelib_sll *iy);
/* From parse_date.re */
timelib_time *timelib_strtotime(char *s, int len, int *errors, timelib_tzdb *tzdb);
timelib_time *timelib_strtotime(char *s, int len, timelib_error_container **errors, timelib_tzdb *tzdb);
void timelib_fill_holes(timelib_time *parsed, timelib_time *now, int options);
char *timelib_timezone_id_from_abbr(const char *abbr, long gmtoffset, int isdst);
timelib_tz_lookup_table *timelib_timezone_abbreviations_list(void);
@ -90,6 +90,8 @@ void timelib_time_dtor(timelib_time* t);
timelib_time_offset* timelib_time_offset_ctor();
void timelib_time_offset_dtor(timelib_time_offset* t);
void timelib_error_container_dtor(timelib_error_container *errors);
signed long timelib_date_to_int(timelib_time *d, int *error);
void timelib_dump_date(timelib_time *d, int options);

View File

@ -147,6 +147,19 @@ typedef struct timelib_time {
* 2 TimeZone abbreviation */
} timelib_time;
typedef struct timelib_error_message {
int position;
char character;
char *message;
} timelib_error_message;
typedef struct timelib_error_container {
int warning_count;
struct timelib_error_message *warning_messages;
int error_count;
struct timelib_error_message *error_messages;
} timelib_error_container;
typedef struct _timelib_tz_lookup_table {
char *name;
int type;
@ -170,9 +183,10 @@ typedef struct _timelib_tzdb {
#define TIMELIB_ZONETYPE_ABBR 2
#define TIMELIB_ZONETYPE_ID 3
#define SECS_PER_DAY 86400
#define DAYS_PER_YEAR 365
#define DAYS_PER_LYEAR 366
#define SECS_PER_ERA 12622780800L
#define SECS_PER_DAY 86400
#define DAYS_PER_YEAR 365
#define DAYS_PER_LYEAR 366
#define timelib_is_leap(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))

View File

@ -135,6 +135,13 @@ static timelib_sll do_years(timelib_sll year)
{
timelib_sll i;
timelib_sll res = 0;
timelib_sll eras;
eras = (year - 1970) / 400;
if (eras != 0) {
year = year - (eras * 400);
res += (SECS_PER_ERA * eras);
}
if (year >= 1970) {
for (i = year - 1; i >= 1970; i--) {

View File

@ -51,6 +51,7 @@ zend_function_entry date_functions[] = {
#ifdef EXPERIMENTAL_DATE_SUPPORT
/* Advanced Interface */
PHP_FE(date_create, NULL)
PHP_FE(date_parse, NULL)
PHP_FE(date_format, NULL)
PHP_FE(date_modify, NULL)
PHP_FE(date_timezone_get, NULL)
@ -63,6 +64,7 @@ zend_function_entry date_functions[] = {
PHP_FE(timezone_open, NULL)
PHP_FE(timezone_name_get, NULL)
PHP_FE(timezone_name_from_abbr, NULL)
PHP_FE(timezone_offset_get, NULL)
PHP_FE(timezone_transistions_get, NULL)
PHP_FE(timezone_identifiers_list, NULL)
@ -269,6 +271,7 @@ PHP_MINIT_FUNCTION(date)
REGISTER_STRING_CONSTANT("DATE_RFC1036", DATE_FORMAT_RFC1036, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("DATE_RFC1123", DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("DATE_RFC2822", DATE_FORMAT_RFC2822, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("DATE_RFC3339", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("DATE_RSS", DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("DATE_W3C", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
@ -793,14 +796,14 @@ PHPAPI void php_date_set_tzdb(timelib_tzdb *tzdb)
PHPAPI signed long php_parse_date(char *string, signed long *now)
{
timelib_time *parsed_time;
int error1, error2;
int error2;
signed long retval;
parsed_time = timelib_strtotime(string, strlen(string), &error1, DATE_TIMEZONEDB);
parsed_time = timelib_strtotime(string, strlen(string), NULL, DATE_TIMEZONEDB);
timelib_update_ts(parsed_time, NULL);
retval = timelib_date_to_int(parsed_time, &error2);
timelib_time_dtor(parsed_time);
if (error1 || error2) {
if (error2) {
return -1;
}
return retval;
@ -808,12 +811,13 @@ PHPAPI signed long php_parse_date(char *string, signed long *now)
/* }}} */
/* {{{ proto int strtotime(string time, int now)
/* {{{ proto int strtotime(string time [, int now ])
Convert string representation of date and time to a timestamp */
PHP_FUNCTION(strtotime)
{
char *times, *initial_ts;
int time_len, error1, error2;
struct timelib_error_container *error;
long preset_ts, ts;
timelib_time *t, *now;
@ -827,7 +831,7 @@ PHP_FUNCTION(strtotime)
initial_ts = emalloc(25);
snprintf(initial_ts, 24, "@%ld", preset_ts);
t = timelib_strtotime(initial_ts, strlen(initial_ts), &error1, DATE_TIMEZONEDB); /* we ignore the error here, as this should never fail */
t = timelib_strtotime(initial_ts, strlen(initial_ts), NULL, DATE_TIMEZONEDB); /* we ignore the error here, as this should never fail */
timelib_update_ts(t, tzi);
now->tz_info = tzi;
now->zone_type = TIMELIB_ZONETYPE_ID;
@ -844,7 +848,9 @@ PHP_FUNCTION(strtotime)
RETURN_FALSE;
}
t = timelib_strtotime(times, time_len, &error1, DATE_TIMEZONEDB);
t = timelib_strtotime(times, time_len, &error, DATE_TIMEZONEDB);
error1 = error->error_count;
timelib_error_container_dtor(error);
timelib_fill_holes(t, now, 0);
timelib_update_ts(t, tzi);
ts = timelib_date_to_int(t, &error2);
@ -1299,7 +1305,6 @@ PHP_FUNCTION(date_create)
{
php_date_obj *dateobj;
zval *timezone_object = NULL;
int error;
timelib_time *now;
timelib_tzinfo *tzi;
char *time_str;
@ -1311,7 +1316,7 @@ PHP_FUNCTION(date_create)
date_instanciate(date_ce_date, return_value TSRMLS_CC);
dateobj = (php_date_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
dateobj->time = timelib_strtotime(time_str_len ? time_str : "now", time_str_len ? time_str_len : sizeof("now") -1, &error, DATE_TIMEZONEDB);
dateobj->time = timelib_strtotime(time_str_len ? time_str : "now", time_str_len ? time_str_len : sizeof("now") -1, NULL, DATE_TIMEZONEDB);
if (timezone_object) {
php_timezone_obj *tzobj;
@ -1343,6 +1348,101 @@ PHP_FUNCTION(date_create)
timelib_time_dtor(now);
}
PHP_FUNCTION(date_parse)
{
char *date;
int date_len, i;
struct timelib_error_container *error;
timelib_time *parsed_time;
zval *element;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &date, &date_len) == FAILURE) {
RETURN_FALSE;
}
parsed_time = timelib_strtotime(date, date_len, &error, DATE_TIMEZONEDB);
array_init(return_value);
#define PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(name, elem) \
if (parsed_time->elem == -1) { \
add_assoc_bool(return_value, #name, 0); \
} else { \
add_assoc_long(return_value, #name, parsed_time->elem); \
}
PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(year, y);
PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(month, m);
PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(day, d);
PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(hour, h);
PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(minute, i);
PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(second, s);
if (parsed_time->f == -1) {
add_assoc_bool(return_value, "fraction", 0);
} else {
add_assoc_double(return_value, "fraction", parsed_time->f);
}
add_assoc_long(return_value, "warning_count", error->warning_count);
MAKE_STD_ZVAL(element);
array_init(element);
for (i = 0; i < error->warning_count; i++) {
add_index_string(element, error->warning_messages[i].position, error->warning_messages[i].message, 1);
}
add_assoc_zval(return_value, "warnings", element);
add_assoc_long(return_value, "error_count", error->error_count);
MAKE_STD_ZVAL(element);
array_init(element);
for (i = 0; i < error->error_count; i++) {
add_index_string(element, error->error_messages[i].position, error->error_messages[i].message, 1);
}
add_assoc_zval(return_value, "errors", element);
timelib_error_container_dtor(error);
add_assoc_bool(return_value, "is_localtime", parsed_time->is_localtime);
if (parsed_time->is_localtime) {
PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone_type, zone_type);
switch (parsed_time->zone_type) {
case TIMELIB_ZONETYPE_OFFSET:
PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone, z);
add_assoc_bool(return_value, "is_dst", parsed_time->dst);
break;
case TIMELIB_ZONETYPE_ID:
if (parsed_time->tz_abbr) {
add_assoc_string(return_value, "tz_abbr", parsed_time->tz_abbr, 1);
}
if (parsed_time->tz_info) {
add_assoc_string(return_value, "tz_id", parsed_time->tz_info->name, 1);
}
break;
case TIMELIB_ZONETYPE_ABBR:
PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone, z);
add_assoc_bool(return_value, "is_dst", parsed_time->dst);
add_assoc_string(return_value, "tz_abbr", parsed_time->tz_abbr, 1);
break;
}
}
if (parsed_time->have_relative || parsed_time->have_weekday_relative) {
MAKE_STD_ZVAL(element);
array_init(element);
}
if (parsed_time->have_relative) {
add_assoc_long(element, "year", parsed_time->relative.y);
add_assoc_long(element, "month", parsed_time->relative.m);
add_assoc_long(element, "day", parsed_time->relative.d);
add_assoc_long(element, "hour", parsed_time->relative.h);
add_assoc_long(element, "minute", parsed_time->relative.i);
add_assoc_long(element, "second", parsed_time->relative.s);
}
if (parsed_time->have_weekday_relative) {
add_assoc_long(element, "weekday", parsed_time->relative.weekday);
}
if (parsed_time->have_relative || parsed_time->have_weekday_relative) {
add_assoc_zval(return_value, "relative", element);
}
timelib_time_dtor(parsed_time);
}
PHP_FUNCTION(date_format)
{
zval *object;
@ -1363,7 +1463,6 @@ PHP_FUNCTION(date_modify)
php_date_obj *dateobj;
char *modify;
int modify_len;
int error;
timelib_time *tmp_time;
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &modify, &modify_len) == FAILURE) {
@ -1371,7 +1470,7 @@ PHP_FUNCTION(date_modify)
}
dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
tmp_time = timelib_strtotime(modify, modify_len, &error, DATE_TIMEZONEDB);
tmp_time = timelib_strtotime(modify, modify_len, NULL, DATE_TIMEZONEDB);
dateobj->time->relative.y = tmp_time->relative.y;
dateobj->time->relative.m = tmp_time->relative.m;
dateobj->time->relative.d = tmp_time->relative.d;
@ -1544,6 +1643,26 @@ PHP_FUNCTION(timezone_name_get)
RETURN_STRING(tzobj->tz->name, 1);
}
PHP_FUNCTION(timezone_name_from_abbr)
{
char *abbr;
char *tzname;
int abbr_len;
long gmtoffset = -1;
long isdst = -1;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &abbr, &abbr_len, &gmtoffset, &isdst) == FAILURE) {
RETURN_FALSE;
}
tzname = timelib_timezone_id_from_abbr(abbr, gmtoffset, isdst);
if (tzname) {
RETURN_STRING(tzname, 1);
} else {
RETURN_FALSE;
}
}
PHP_FUNCTION(timezone_offset_get)
{
zval *object, *dateobject;

View File

@ -49,6 +49,7 @@ PHP_FUNCTION(getdate);
#ifdef EXPERIMENTAL_DATE_SUPPORT
/* Advanced Interface */
PHP_FUNCTION(date_create);
PHP_FUNCTION(date_parse);
PHP_FUNCTION(date_format);
PHP_FUNCTION(date_modify);
PHP_FUNCTION(date_timezone_get);
@ -61,6 +62,7 @@ PHP_FUNCTION(date_isodate_set);
PHP_FUNCTION(timezone_open);
PHP_FUNCTION(timezone_name_get);
PHP_FUNCTION(timezone_name_from_abbr);
PHP_FUNCTION(timezone_offset_get);
PHP_FUNCTION(timezone_transistions_get);
PHP_FUNCTION(timezone_identifiers_list);

View File

@ -0,0 +1,10 @@
--TEST--
Bug #36988 (mktime freezes on long numbers)
--FILE--
<?php
$start = microtime(true);
$a = mktime(1, 1, 1, 1, 1, 11111111111);
echo (microtime(true) - $start) < 1 ? "smaller than one second" : "more than a second";
?>
--EXPECT--
smaller than one second

View File

@ -0,0 +1,14 @@
--TEST--
Bug #37017 (strtotime fails before 13:00:00 with some time zones identifiers).
--FILE--
<?php
echo strtotime("2006-05-12 13:00:01 America/New_York"), "\n";
echo strtotime("2006-05-12 13:00:00 America/New_York"), "\n";
echo strtotime("2006-05-12 12:59:59 America/New_York"), "\n";
echo strtotime("2006-05-12 12:59:59 GMT"), "\n";
?>
--EXPECT--
1147453201
1147453200
1147453199
1147438799