derick          Sun Jan 13 15:16:48 2008 UTC

  Modified files:              
    /php-src/ext/date   php_date.c php_date.h 
    /php-src/ext/date/lib       parse_date.c parse_date.re timelib.h 
  Log:
  - MF53: Added new date/time functionality:
  
    * date_parse_from_format(): Parse date/time strings according to a format. 
    * date_create_from_format()/DateTime::createFromFormat(): Create a date/time
      object by parsing a date/time string according to a given format.
    * date_get_last_errors()/DateTime::getLastErrors(): Return a list of 
warnings
      and errors that were found while parsing a date/time string through:
      - strtotime() / new DateTime
      - date_create_from_format() / DateTime::createFromFormat()
      - date_parse_from_format()
  
  
http://cvs.php.net/viewvc.cgi/php-src/ext/date/php_date.c?r1=1.151&r2=1.152&diff_format=u
Index: php-src/ext/date/php_date.c
diff -u php-src/ext/date/php_date.c:1.151 php-src/ext/date/php_date.c:1.152
--- php-src/ext/date/php_date.c:1.151   Mon Dec 31 07:12:08 2007
+++ php-src/ext/date/php_date.c Sun Jan 13 15:16:47 2008
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: php_date.c,v 1.151 2007/12/31 07:12:08 sebastian Exp $ */
+/* $Id: php_date.c,v 1.152 2008/01/13 15:16:47 derick Exp $ */
 
 #include "php.h"
 #include "php_streams.h"
@@ -169,7 +169,10 @@
 
        /* Advanced Interface */
        PHP_FE(date_create, NULL)
+       PHP_FE(date_create_from_format, NULL)
        PHP_FE(date_parse, NULL)
+       PHP_FE(date_parse_from_format, NULL)
+       PHP_FE(date_get_last_errors, NULL)
        PHP_FE(date_format, NULL)
        PHP_FE(date_format_locale, NULL)
        PHP_FE(date_modify, NULL)
@@ -204,6 +207,8 @@
 
 const zend_function_entry date_funcs_date[] = {
        PHP_ME(DateTime,            __construct,       NULL, 
ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
+       PHP_ME_MAPPING(createFromFormat, date_create_from_format,       NULL, 
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+       PHP_ME_MAPPING(getLastErrors, date_get_last_errors,     NULL, 
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
        PHP_ME_MAPPING(format,      date_format,       NULL, 0)
        PHP_ME_MAPPING(modify,      date_modify,       NULL, 0)
        PHP_ME_MAPPING(getTimezone, date_timezone_get, NULL, 0)
@@ -515,7 +520,8 @@
 
        php_date_global_timezone_db = NULL;
        php_date_global_timezone_db_enabled = 0;
-       
+
+       DATEG(last_errors) = NULL;
        return SUCCESS;
 }
 /* }}} */
@@ -525,6 +531,10 @@
 {
        UNREGISTER_INI_ENTRIES();
 
+       if (DATEG(last_errors)) {
+               timelib_error_container_dtor(DATEG(last_errors));
+       }
+
        return SUCCESS;
 }
 /* }}} */
@@ -1764,7 +1774,18 @@
        return object;
 }
 
-static void date_initialize(php_date_obj *dateobj, /*const*/ char *time_str, 
int time_str_len, zval *timezone_object TSRMLS_DC)
+/* Helper function used to store the latest found warnings and errors while
+ * parsing, from either strtotime or parse_from_format. */
+static void update_errors_warnings(timelib_error_container *last_errors)
+{
+       if (DATEG(last_errors)) {
+               timelib_error_container_dtor(DATEG(last_errors));
+               DATEG(last_errors) = NULL;
+       }
+       DATEG(last_errors) = last_errors;
+}
+
+static void date_initialize(php_date_obj *dateobj, /*const*/ char *time_str, 
int time_str_len, char *format, zval *timezone_object TSRMLS_DC)
 {
        timelib_time   *now;
        timelib_tzinfo *tzi;
@@ -1777,16 +1798,15 @@
                }
                timelib_time_dtor(dateobj->time);
        }
-       dateobj->time = timelib_strtotime(time_str_len ? time_str : "now", 
time_str_len ? time_str_len : sizeof("now") -1, &err, DATE_TIMEZONEDB);
-       if (err) {
-               if (err->error_count) {
-                       /* spit out the first library error message, at least */
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to 
parse time string (%s) at position %d (%c): %s", time_str,
-                                                       
err->error_messages[0].position, err->error_messages[0].character, 
err->error_messages[0].message);
-               }
-               timelib_error_container_dtor(err);
+       if (format) {
+               dateobj->time = timelib_parse_from_format(format, time_str_len 
? time_str : "", time_str_len ? time_str_len : 0, &err, DATE_TIMEZONEDB);
+       } else {
+               dateobj->time = timelib_strtotime(time_str_len ? time_str : 
"now", time_str_len ? time_str_len : sizeof("now") -1, &err, DATE_TIMEZONEDB);
        }
 
+       // update last errors and warnings
+       update_errors_warnings(err);
+
        if (timezone_object) {
                php_timezone_obj *tzobj;
 
@@ -1832,7 +1852,25 @@
        }
 
        date_instantiate(date_ce_date, return_value TSRMLS_CC);
-       date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), 
time_str, time_str_len, timezone_object TSRMLS_CC);
+       date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), 
time_str, time_str_len, NULL, timezone_object TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto DateTime date_create(string format, string time[, DateTimeZone 
object])
+   Returns new DateTime object
+*/
+PHP_FUNCTION(date_create_from_format)
+{
+       zval           *timezone_object = NULL;
+       char           *time_str = NULL, *format_str = NULL;
+       int             time_str_len = 0, format_str_len = 0;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|O", 
&format_str, &format_str_len, &time_str, &time_str_len, &timezone_object, 
date_ce_timezone) == FAILURE) {
+               RETURN_FALSE;
+       }
+
+       date_instantiate(date_ce_date, return_value TSRMLS_CC);
+       date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), 
time_str, time_str_len, format_str, timezone_object TSRMLS_CC);
 }
 /* }}} */
 
@@ -1847,28 +1885,53 @@
        
        php_set_error_handling(EH_THROW, NULL TSRMLS_CC);
        if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO", 
&time_str, &time_str_len, &timezone_object, date_ce_timezone)) {
-               date_initialize(zend_object_store_get_object(getThis() 
TSRMLS_CC), time_str, time_str_len, timezone_object TSRMLS_CC);
+               date_initialize(zend_object_store_get_object(getThis() 
TSRMLS_CC), time_str, time_str_len, NULL, timezone_object TSRMLS_CC);
        }
        php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
 }
 /* }}} */
 
-/* {{{ proto array date_parse(string date)
-   Returns associative array with detailed info about given date
+/* Helper function used to add an associative array of warnings and errors to 
a zval */
+void zval_from_error_container(zval *z, timelib_error_container *error)
+{
+       int   i;
+       zval *element;
+
+       add_ascii_assoc_long(z, "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_ascii_assoc_zval(z, "warnings", element);
+
+       add_ascii_assoc_long(z, "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_ascii_assoc_zval(z, "errors", element);
+}
+
+/* {{{ proto array date_get_last_errorse()
+   Returns the warnings and errors found while parsing a date/time string.
 */
-PHP_FUNCTION(date_parse)
+PHP_FUNCTION(date_get_last_errors)
 {
-       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) {
+       array_init(return_value);
+       if (DATEG(last_errors)) {
+               zval_from_error_container(return_value, DATEG(last_errors));
+       } else {
                RETURN_FALSE;
        }
+}
+/* }}} */
+
+void php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAMETERS, timelib_time 
*parsed_time, struct timelib_error_container *error)
+{
+       zval *element;
 
-       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 == -99999) {               \
@@ -1889,21 +1952,8 @@
                add_ascii_assoc_double(return_value, "fraction", 
parsed_time->f);
        }
 
-       add_ascii_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_ascii_assoc_zval(return_value, "warnings", element);
+       zval_from_error_container(return_value, error);
 
-       add_ascii_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_ascii_assoc_zval(return_value, "errors", element);
        timelib_error_container_dtor(error);
 
        add_ascii_assoc_bool(return_value, "is_localtime", 
parsed_time->is_localtime);
@@ -1950,8 +2000,44 @@
        }
        timelib_time_dtor(parsed_time);
 }
+
+/* {{{ proto array date_parse(string date)
+   Returns associative array with detailed info about given date
+*/
+PHP_FUNCTION(date_parse)
+{
+       char                           *date;
+       int                             date_len;
+       struct timelib_error_container *error;
+       timelib_time                   *parsed_time;
+       
+       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);
+       php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
parsed_time, error);
+}
 /* }}} */
 
+/* {{{ proto array date_parse(string date)
+   Returns associative array with detailed info about given date
+*/
+PHP_FUNCTION(date_parse_from_format)
+{
+       char                           *date, *format;
+       int                             date_len, format_len;
+       struct timelib_error_container *error;
+       timelib_time                   *parsed_time;
+       
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &format, 
&format_len, &date, &date_len) == FAILURE) {
+               RETURN_FALSE;
+       }
+
+       parsed_time = timelib_parse_from_format(format, date, date_len, &error, 
DATE_TIMEZONEDB);
+       php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAM_PASSTHRU, 
parsed_time, error);
+}
+
 /* {{{ proto string date_format(DateTime object, string format)
    Returns date formatted according to given format
 */
http://cvs.php.net/viewvc.cgi/php-src/ext/date/php_date.h?r1=1.34&r2=1.35&diff_format=u
Index: php-src/ext/date/php_date.h
diff -u php-src/ext/date/php_date.h:1.34 php-src/ext/date/php_date.h:1.35
--- php-src/ext/date/php_date.h:1.34    Mon Dec 31 07:12:08 2007
+++ php-src/ext/date/php_date.h Sun Jan 13 15:16:47 2008
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: php_date.h,v 1.34 2007/12/31 07:12:08 sebastian Exp $ */
+/* $Id: php_date.h,v 1.35 2008/01/13 15:16:47 derick Exp $ */
 
 #ifndef PHP_DATE_H
 #define PHP_DATE_H
@@ -49,7 +49,10 @@
 /* Advanced Interface */
 PHP_METHOD(DateTime, __construct);
 PHP_FUNCTION(date_create);
+PHP_FUNCTION(date_create_from_format);
 PHP_FUNCTION(date_parse);
+PHP_FUNCTION(date_parse_from_format);
+PHP_FUNCTION(date_get_last_errors);
 PHP_FUNCTION(date_format);
 PHP_FUNCTION(date_format_locale);
 PHP_FUNCTION(date_modify);
@@ -93,6 +96,7 @@
        char      *default_timezone;
        char      *timezone;
        HashTable  tzcache;
+       timelib_error_container *last_errors;
 ZEND_END_MODULE_GLOBALS(date)
 
 #ifdef ZTS
http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/parse_date.c?r1=1.74&r2=1.75&diff_format=u
Index: php-src/ext/date/lib/parse_date.c
diff -u php-src/ext/date/lib/parse_date.c:1.74 
php-src/ext/date/lib/parse_date.c:1.75
--- php-src/ext/date/lib/parse_date.c:1.74      Thu Jul 12 18:59:35 2007
+++ php-src/ext/date/lib/parse_date.c   Sun Jan 13 15:16:47 2008
@@ -1,4 +1,4 @@
-/* Generated by re2c 0.12.1 on Thu Jul 12 20:33:20 2007 */
+/* Generated by re2c 0.12.1 on Sun Jan 13 15:57:11 2008 */
 #line 1 "ext/date/lib/parse_date.re"
 /*
    +----------------------------------------------------------------------+
@@ -18,7 +18,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: parse_date.c,v 1.74 2007/07/12 18:59:35 derick Exp $ */
+/* $Id: parse_date.c,v 1.75 2008/01/13 15:16:47 derick Exp $ */
 
 #include "timelib.h"
 
@@ -351,6 +351,24 @@
        s->errors->error_messages[s->errors->error_count - 1].message = 
strdup(error);
 }
 
+static void add_pbf_warning(Scanner *s, char *error, char *sptr, char *cptr)
+{
+       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 = 
cptr - sptr;
+       s->errors->warning_messages[s->errors->warning_count - 1].character = 
*cptr;
+       s->errors->warning_messages[s->errors->warning_count - 1].message = 
strdup(error);
+}
+
+static void add_pbf_error(Scanner *s, char *error, char *sptr, char *cptr)
+{
+       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 = cptr - 
sptr;
+       s->errors->error_messages[s->errors->error_count - 1].character = *cptr;
+       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;
@@ -374,6 +392,39 @@
        return retval;
 }
 
+static timelib_sll timelib_meridian_with_check(char **ptr, timelib_sll h)
+{
+       timelib_sll retval = 0;
+
+       while (!strchr("AaPp", **ptr)) {
+               ++*ptr;
+       }
+       if (**ptr == 'a' || **ptr == 'A') {
+               if (h == 12) {
+                       retval = -12;
+               }
+       } else if (h != 12) {
+               retval = 12;
+       }
+       ++*ptr;
+       if (**ptr == '.') {
+               ++*ptr;
+               if (**ptr != 'm' && **ptr != 'M') {
+                       return TIMELIB_UNSET;
+               }
+               ++*ptr;
+               if (**ptr != '.' ) {
+                       return TIMELIB_UNSET;
+               }
+               ++*ptr;
+       } else if (**ptr == 'm' || **ptr == 'M') {
+               ++*ptr;
+       } else {
+               return TIMELIB_UNSET;
+       }
+       return retval;
+}
+
 static char *timelib_string(Scanner *s)
 {
        char *tmp = calloc(1, s->cur - s->tok + 1);
@@ -568,6 +619,13 @@
        }
 }
 
+static void timelib_eat_until_seperator(char **ptr)
+{
+       while (strchr(" \t.,:;/-0123456789", **ptr) == NULL) {
+               ++*ptr;
+       }
+}
+
 static const timelib_relunit* timelib_lookup_relunit(char **ptr)
 {
        char *word;
@@ -772,7 +830,7 @@
 std:
        s->tok = cursor;
        s->len = 0;
-#line 889 "ext/date/lib/parse_date.re"
+#line 947 "ext/date/lib/parse_date.re"
 
 
 {
@@ -811,7 +869,7 @@
                  0,   0,   0,   0,   0,   0,   0,   0, 
        };
 
-#line 815 "ext/date/lib/parse_date.c"
+#line 873 "ext/date/lib/parse_date.c"
        {
                YYCTYPE yych;
                unsigned int yyaccept = 0;
@@ -917,7 +975,7 @@
                }
 yy3:
                YYDEBUG(3, *YYCURSOR);
-#line 1443 "ext/date/lib/parse_date.re"
+#line 1501 "ext/date/lib/parse_date.re"
                {
                int tz_not_found;
                DEBUG_OUTPUT("tzcorrection | tz");
@@ -930,7 +988,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_TIMEZONE;
        }
-#line 934 "ext/date/lib/parse_date.c"
+#line 992 "ext/date/lib/parse_date.c"
 yy4:
                YYDEBUG(4, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -1241,12 +1299,12 @@
                if(yych <= '9') goto yy1274;
 yy12:
                YYDEBUG(12, *YYCURSOR);
-#line 1538 "ext/date/lib/parse_date.re"
+#line 1596 "ext/date/lib/parse_date.re"
                {
                add_error(s, "Unexpected character");
                goto std;
        }
-#line 1250 "ext/date/lib/parse_date.c"
+#line 1308 "ext/date/lib/parse_date.c"
 yy13:
                YYDEBUG(13, *YYCURSOR);
                yyaccept = 1;
@@ -2252,11 +2310,11 @@
                if(yych <= '9') goto yy51;
 yy46:
                YYDEBUG(46, *YYCURSOR);
-#line 1527 "ext/date/lib/parse_date.re"
+#line 1585 "ext/date/lib/parse_date.re"
                {
                goto std;
        }
-#line 2260 "ext/date/lib/parse_date.c"
+#line 2318 "ext/date/lib/parse_date.c"
 yy47:
                YYDEBUG(47, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -2265,12 +2323,12 @@
                YYDEBUG(48, *YYCURSOR);
                ++YYCURSOR;
                YYDEBUG(49, *YYCURSOR);
-#line 1532 "ext/date/lib/parse_date.re"
+#line 1590 "ext/date/lib/parse_date.re"
                {
                s->pos = cursor; s->line++;
                goto std;
        }
-#line 2274 "ext/date/lib/parse_date.c"
+#line 2332 "ext/date/lib/parse_date.c"
 yy50:
                YYDEBUG(50, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -2649,7 +2707,7 @@
                if(yych == 's') goto yy70;
 yy69:
                YYDEBUG(69, *YYCURSOR);
-#line 1511 "ext/date/lib/parse_date.re"
+#line 1569 "ext/date/lib/parse_date.re"
                {
                timelib_ull i;
                DEBUG_OUTPUT("relative");
@@ -2664,7 +2722,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_RELATIVE;
        }
-#line 2668 "ext/date/lib/parse_date.c"
+#line 2726 "ext/date/lib/parse_date.c"
 yy70:
                YYDEBUG(70, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -3572,7 +3630,7 @@
                if(yych == 's') goto yy175;
 yy174:
                YYDEBUG(174, *YYCURSOR);
-#line 1416 "ext/date/lib/parse_date.re"
+#line 1474 "ext/date/lib/parse_date.re"
                {
                timelib_sll i;
                int         behavior = 0;
@@ -3588,7 +3646,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_RELATIVE;
        }
-#line 3592 "ext/date/lib/parse_date.c"
+#line 3650 "ext/date/lib/parse_date.c"
 yy175:
                YYDEBUG(175, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -4763,7 +4821,7 @@
                }
 yy276:
                YYDEBUG(276, *YYCURSOR);
-#line 1400 "ext/date/lib/parse_date.re"
+#line 1458 "ext/date/lib/parse_date.re"
                {
                const timelib_relunit* relunit;
                DEBUG_OUTPUT("daytext");
@@ -4778,7 +4836,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_WEEKDAY;
        }
-#line 4782 "ext/date/lib/parse_date.c"
+#line 4840 "ext/date/lib/parse_date.c"
 yy277:
                YYDEBUG(277, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -5255,7 +5313,7 @@
                }
 yy303:
                YYDEBUG(303, *YYCURSOR);
-#line 1433 "ext/date/lib/parse_date.re"
+#line 1491 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("monthtext");
                TIMELIB_INIT;
@@ -5264,7 +5322,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_DATE_TEXT;
        }
-#line 5268 "ext/date/lib/parse_date.c"
+#line 5326 "ext/date/lib/parse_date.c"
 yy304:
                YYDEBUG(304, *YYCURSOR);
                ++YYCURSOR;
@@ -5315,7 +5373,7 @@
                }
 yy308:
                YYDEBUG(308, *YYCURSOR);
-#line 1212 "ext/date/lib/parse_date.re"
+#line 1270 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("datetextual | datenoyear");
                TIMELIB_INIT;
@@ -5327,7 +5385,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_DATE_TEXT;
        }
-#line 5331 "ext/date/lib/parse_date.c"
+#line 5389 "ext/date/lib/parse_date.c"
 yy309:
                YYDEBUG(309, *YYCURSOR);
                yyaccept = 7;
@@ -5600,7 +5658,7 @@
                }
 yy332:
                YYDEBUG(332, *YYCURSOR);
-#line 1481 "ext/date/lib/parse_date.re"
+#line 1539 "ext/date/lib/parse_date.re"
                {
                int tz_not_found;
                DEBUG_OUTPUT("dateshortwithtimeshort | dateshortwithtimelong | 
dateshortwithtimelongtz");
@@ -5629,7 +5687,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_SHORTDATE_WITH_TIME;
        }
-#line 5633 "ext/date/lib/parse_date.c"
+#line 5691 "ext/date/lib/parse_date.c"
 yy333:
                YYDEBUG(333, *YYCURSOR);
                yyaccept = 8;
@@ -6240,7 +6298,7 @@
                YYDEBUG(385, *YYCURSOR);
                ++YYCURSOR;
                YYDEBUG(386, *YYCURSOR);
-#line 1457 "ext/date/lib/parse_date.re"
+#line 1515 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("dateshortwithtimeshort12 | 
dateshortwithtimelong12");
                TIMELIB_INIT;
@@ -6263,7 +6321,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_SHORTDATE_WITH_TIME;
        }
-#line 6267 "ext/date/lib/parse_date.c"
+#line 6325 "ext/date/lib/parse_date.c"
 yy387:
                YYDEBUG(387, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -6439,7 +6497,7 @@
                if(yych <= '9') goto yy397;
 yy402:
                YYDEBUG(402, *YYCURSOR);
-#line 1186 "ext/date/lib/parse_date.re"
+#line 1244 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("datenoday");
                TIMELIB_INIT;
@@ -6451,7 +6509,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_DATE_NO_DAY;
        }
-#line 6455 "ext/date/lib/parse_date.c"
+#line 6513 "ext/date/lib/parse_date.c"
 yy403:
                YYDEBUG(403, *YYCURSOR);
                yyaccept = 7;
@@ -7687,7 +7745,7 @@
                if(yych <= '9') goto yy474;
 yy473:
                YYDEBUG(473, *YYCURSOR);
-#line 1326 "ext/date/lib/parse_date.re"
+#line 1384 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("pgtextshort");
                TIMELIB_INIT;
@@ -7699,7 +7757,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_PG_TEXT;
        }
-#line 7703 "ext/date/lib/parse_date.c"
+#line 7761 "ext/date/lib/parse_date.c"
 yy474:
                YYDEBUG(474, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -9580,7 +9638,7 @@
                }
 yy558:
                YYDEBUG(558, *YYCURSOR);
-#line 1382 "ext/date/lib/parse_date.re"
+#line 1440 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("ago");
                TIMELIB_INIT;
@@ -9597,7 +9655,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_AGO;
        }
-#line 9601 "ext/date/lib/parse_date.c"
+#line 9659 "ext/date/lib/parse_date.c"
 yy559:
                YYDEBUG(559, *YYCURSOR);
                yyaccept = 6;
@@ -12192,7 +12250,7 @@
                ++YYCURSOR;
 yy660:
                YYDEBUG(660, *YYCURSOR);
-#line 1097 "ext/date/lib/parse_date.re"
+#line 1155 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("iso8601date4 | iso8601date2 | iso8601dateslash | 
dateslash");
                TIMELIB_INIT;
@@ -12203,7 +12261,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_ISO_DATE;
        }
-#line 12207 "ext/date/lib/parse_date.c"
+#line 12265 "ext/date/lib/parse_date.c"
 yy661:
                YYDEBUG(661, *YYCURSOR);
                yyaccept = 0;
@@ -12763,7 +12821,7 @@
                }
 yy681:
                YYDEBUG(681, *YYCURSOR);
-#line 1225 "ext/date/lib/parse_date.re"
+#line 1283 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("datenoyearrev");
                TIMELIB_INIT;
@@ -12774,7 +12832,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_DATE_TEXT;
        }
-#line 12778 "ext/date/lib/parse_date.c"
+#line 12836 "ext/date/lib/parse_date.c"
 yy682:
                YYDEBUG(682, *YYCURSOR);
                yyaccept = 11;
@@ -12915,7 +12973,7 @@
                YYDEBUG(693, *YYCURSOR);
                ++YYCURSOR;
                YYDEBUG(694, *YYCURSOR);
-#line 973 "ext/date/lib/parse_date.re"
+#line 1031 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("timetiny12 | timeshort12 | timelong12");
                TIMELIB_INIT;
@@ -12931,7 +12989,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_TIME12;
        }
-#line 12935 "ext/date/lib/parse_date.c"
+#line 12993 "ext/date/lib/parse_date.c"
 yy695:
                YYDEBUG(695, *YYCURSOR);
                yyaccept = 12;
@@ -12944,7 +13002,7 @@
                }
 yy696:
                YYDEBUG(696, *YYCURSOR);
-#line 990 "ext/date/lib/parse_date.re"
+#line 1048 "ext/date/lib/parse_date.re"
                {
                int tz_not_found;
                DEBUG_OUTPUT("timeshort24 | timelong24 | iso8601long");
@@ -12969,7 +13027,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_TIME24_WITH_ZONE;
        }
-#line 12973 "ext/date/lib/parse_date.c"
+#line 13031 "ext/date/lib/parse_date.c"
 yy697:
                YYDEBUG(697, *YYCURSOR);
                yyaccept = 12;
@@ -13237,7 +13295,7 @@
                if(yych <= '9') goto yy730;
 yy724:
                YYDEBUG(724, *YYCURSOR);
-#line 1147 "ext/date/lib/parse_date.re"
+#line 1205 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("datefull");
                TIMELIB_INIT;
@@ -13250,7 +13308,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_DATE_FULL;
        }
-#line 13254 "ext/date/lib/parse_date.c"
+#line 13312 "ext/date/lib/parse_date.c"
 yy725:
                YYDEBUG(725, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -14006,7 +14064,7 @@
                if(yych <= '9') goto yy797;
 yy796:
                YYDEBUG(796, *YYCURSOR);
-#line 1173 "ext/date/lib/parse_date.re"
+#line 1231 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("pointed date YY");
                TIMELIB_INIT;
@@ -14018,7 +14076,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_DATE_FULL_POINTED;
        }
-#line 14022 "ext/date/lib/parse_date.c"
+#line 14080 "ext/date/lib/parse_date.c"
 yy797:
                YYDEBUG(797, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -14027,7 +14085,7 @@
                YYDEBUG(798, *YYCURSOR);
                ++YYCURSOR;
                YYDEBUG(799, *YYCURSOR);
-#line 1161 "ext/date/lib/parse_date.re"
+#line 1219 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("pointed date YYYY");
                TIMELIB_INIT;
@@ -14038,7 +14096,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_DATE_FULL_POINTED;
        }
-#line 14042 "ext/date/lib/parse_date.c"
+#line 14100 "ext/date/lib/parse_date.c"
 yy800:
                YYDEBUG(800, *YYCURSOR);
                yyaccept = 12;
@@ -14656,7 +14714,7 @@
                }
 yy844:
                YYDEBUG(844, *YYCURSOR);
-#line 1134 "ext/date/lib/parse_date.re"
+#line 1192 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("gnudateshort");
                TIMELIB_INIT;
@@ -14668,7 +14726,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_ISO_DATE;
        }
-#line 14672 "ext/date/lib/parse_date.c"
+#line 14730 "ext/date/lib/parse_date.c"
 yy845:
                YYDEBUG(845, *YYCURSOR);
                yyaccept = 14;
@@ -14774,7 +14832,7 @@
                }
 yy854:
                YYDEBUG(854, *YYCURSOR);
-#line 1082 "ext/date/lib/parse_date.re"
+#line 1140 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("americanshort | american");
                TIMELIB_INIT;
@@ -14788,7 +14846,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_AMERICAN;
        }
-#line 14792 "ext/date/lib/parse_date.c"
+#line 14850 "ext/date/lib/parse_date.c"
 yy855:
                YYDEBUG(855, *YYCURSOR);
                yyaccept = 15;
@@ -15011,7 +15069,7 @@
                if(yych <= ':') goto yy890;
 yy887:
                YYDEBUG(887, *YYCURSOR);
-#line 1352 "ext/date/lib/parse_date.re"
+#line 1410 "ext/date/lib/parse_date.re"
                {
                int tz_not_found;
                DEBUG_OUTPUT("clf");
@@ -15031,7 +15089,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_CLF;
        }
-#line 15035 "ext/date/lib/parse_date.c"
+#line 15093 "ext/date/lib/parse_date.c"
 yy888:
                YYDEBUG(888, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -15526,7 +15584,7 @@
                }
 yy942:
                YYDEBUG(942, *YYCURSOR);
-#line 1109 "ext/date/lib/parse_date.re"
+#line 1167 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("iso8601date2");
                TIMELIB_INIT;
@@ -15538,7 +15596,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_ISO_DATE;
        }
-#line 15542 "ext/date/lib/parse_date.c"
+#line 15600 "ext/date/lib/parse_date.c"
 yy943:
                YYDEBUG(943, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -15577,7 +15635,7 @@
                YYDEBUG(949, *YYCURSOR);
                ++YYCURSOR;
                YYDEBUG(950, *YYCURSOR);
-#line 1339 "ext/date/lib/parse_date.re"
+#line 1397 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("pgtextreverse");
                TIMELIB_INIT;
@@ -15589,7 +15647,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_PG_TEXT;
        }
-#line 15593 "ext/date/lib/parse_date.c"
+#line 15651 "ext/date/lib/parse_date.c"
 yy951:
                YYDEBUG(951, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -15727,7 +15785,7 @@
                }
 yy962:
                YYDEBUG(962, *YYCURSOR);
-#line 1373 "ext/date/lib/parse_date.re"
+#line 1431 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("year4");
                TIMELIB_INIT;
@@ -15735,7 +15793,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_CLF;
        }
-#line 15739 "ext/date/lib/parse_date.c"
+#line 15797 "ext/date/lib/parse_date.c"
 yy963:
                YYDEBUG(963, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -15886,7 +15944,7 @@
                }
 yy972:
                YYDEBUG(972, *YYCURSOR);
-#line 1199 "ext/date/lib/parse_date.re"
+#line 1257 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("datenodayrev");
                TIMELIB_INIT;
@@ -15898,7 +15956,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_DATE_NO_DAY;
        }
-#line 15902 "ext/date/lib/parse_date.c"
+#line 15960 "ext/date/lib/parse_date.c"
 yy973:
                YYDEBUG(973, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -16113,7 +16171,7 @@
                if(yych <= '7') goto yy995;
 yy993:
                YYDEBUG(993, *YYCURSOR);
-#line 1307 "ext/date/lib/parse_date.re"
+#line 1365 "ext/date/lib/parse_date.re"
                {
                timelib_sll w, d;
                DEBUG_OUTPUT("isoweek");
@@ -16131,7 +16189,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_ISO_WEEK;
        }
-#line 16135 "ext/date/lib/parse_date.c"
+#line 16193 "ext/date/lib/parse_date.c"
 yy994:
                YYDEBUG(994, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -16141,7 +16199,7 @@
                YYDEBUG(995, *YYCURSOR);
                ++YYCURSOR;
                YYDEBUG(996, *YYCURSOR);
-#line 1288 "ext/date/lib/parse_date.re"
+#line 1346 "ext/date/lib/parse_date.re"
                {
                timelib_sll w, d;
                DEBUG_OUTPUT("isoweekday");
@@ -16159,7 +16217,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_ISO_WEEK;
        }
-#line 16163 "ext/date/lib/parse_date.c"
+#line 16221 "ext/date/lib/parse_date.c"
 yy997:
                YYDEBUG(997, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -16223,7 +16281,7 @@
                }
 yy1000:
                YYDEBUG(1000, *YYCURSOR);
-#line 1275 "ext/date/lib/parse_date.re"
+#line 1333 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("pgydotd");
                TIMELIB_INIT;
@@ -16235,7 +16293,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_PG_YEARDAY;
        }
-#line 16239 "ext/date/lib/parse_date.c"
+#line 16297 "ext/date/lib/parse_date.c"
 yy1001:
                YYDEBUG(1001, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -16338,7 +16396,7 @@
                ++YYCURSOR;
 yy1021:
                YYDEBUG(1021, *YYCURSOR);
-#line 1249 "ext/date/lib/parse_date.re"
+#line 1307 "ext/date/lib/parse_date.re"
                {
                int tz_not_found;
                DEBUG_OUTPUT("xmlrpc | xmlrpcnocolon | soap | wddx | exif");
@@ -16363,7 +16421,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_XMLRPC_SOAP;
        }
-#line 16367 "ext/date/lib/parse_date.c"
+#line 16425 "ext/date/lib/parse_date.c"
 yy1022:
                YYDEBUG(1022, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -16625,7 +16683,7 @@
                }
 yy1027:
                YYDEBUG(1027, *YYCURSOR);
-#line 1237 "ext/date/lib/parse_date.re"
+#line 1295 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("datenocolon");
                TIMELIB_INIT;
@@ -16636,7 +16694,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_DATE_NOCOLON;
        }
-#line 16640 "ext/date/lib/parse_date.c"
+#line 16698 "ext/date/lib/parse_date.c"
 yy1028:
                YYDEBUG(1028, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -17556,7 +17614,7 @@
                if(yych <= '9') goto yy1174;
 yy1152:
                YYDEBUG(1152, *YYCURSOR);
-#line 1122 "ext/date/lib/parse_date.re"
+#line 1180 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("gnudateshorter");
                TIMELIB_INIT;
@@ -17567,7 +17625,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_ISO_DATE;
        }
-#line 17571 "ext/date/lib/parse_date.c"
+#line 17629 "ext/date/lib/parse_date.c"
 yy1153:
                YYDEBUG(1153, *YYCURSOR);
                yyaccept = 23;
@@ -18558,7 +18616,7 @@
                }
 yy1243:
                YYDEBUG(1243, *YYCURSOR);
-#line 1016 "ext/date/lib/parse_date.re"
+#line 1074 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("gnunocolon");
                TIMELIB_INIT;
@@ -18580,7 +18638,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_GNU_NOCOLON;
        }
-#line 18584 "ext/date/lib/parse_date.c"
+#line 18642 "ext/date/lib/parse_date.c"
 yy1244:
                YYDEBUG(1244, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -18672,7 +18730,7 @@
                }
 yy1251:
                YYDEBUG(1251, *YYCURSOR);
-#line 1062 "ext/date/lib/parse_date.re"
+#line 1120 "ext/date/lib/parse_date.re"
                {
                int tz_not_found;
                DEBUG_OUTPUT("iso8601nocolon");
@@ -18691,7 +18749,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_ISO_NOCOLON;
        }
-#line 18695 "ext/date/lib/parse_date.c"
+#line 18753 "ext/date/lib/parse_date.c"
 yy1252:
                YYDEBUG(1252, *YYCURSOR);
                yyaccept = 26;
@@ -19311,7 +19369,7 @@
                if(yych <= '9') goto yy1274;
 yy1276:
                YYDEBUG(1276, *YYCURSOR);
-#line 949 "ext/date/lib/parse_date.re"
+#line 1007 "ext/date/lib/parse_date.re"
                {
                timelib_ull i;
 
@@ -19334,7 +19392,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_RELATIVE;
        }
-#line 19338 "ext/date/lib/parse_date.c"
+#line 19396 "ext/date/lib/parse_date.c"
 yy1277:
                YYDEBUG(1277, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -19770,7 +19828,7 @@
                ++YYCURSOR;
 yy1306:
                YYDEBUG(1306, *YYCURSOR);
-#line 937 "ext/date/lib/parse_date.re"
+#line 995 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("tomorrow");
                TIMELIB_INIT;
@@ -19781,7 +19839,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_RELATIVE;
        }
-#line 19785 "ext/date/lib/parse_date.c"
+#line 19843 "ext/date/lib/parse_date.c"
 yy1307:
                YYDEBUG(1307, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -19816,7 +19874,7 @@
                }
 yy1309:
                YYDEBUG(1309, *YYCURSOR);
-#line 927 "ext/date/lib/parse_date.re"
+#line 985 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("midnight | today");
                TIMELIB_INIT;
@@ -19825,7 +19883,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_RELATIVE;
        }
-#line 19829 "ext/date/lib/parse_date.c"
+#line 19887 "ext/date/lib/parse_date.c"
 yy1310:
                YYDEBUG(1310, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -21598,7 +21656,7 @@
                }
 yy1387:
                YYDEBUG(1387, *YYCURSOR);
-#line 906 "ext/date/lib/parse_date.re"
+#line 964 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("now");
                TIMELIB_INIT;
@@ -21606,7 +21664,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_RELATIVE;
        }
-#line 21610 "ext/date/lib/parse_date.c"
+#line 21668 "ext/date/lib/parse_date.c"
 yy1388:
                YYDEBUG(1388, *YYCURSOR);
                yych = *++YYCURSOR;
@@ -21745,7 +21803,7 @@
                }
 yy1395:
                YYDEBUG(1395, *YYCURSOR);
-#line 915 "ext/date/lib/parse_date.re"
+#line 973 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("noon");
                TIMELIB_INIT;
@@ -21756,7 +21814,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_RELATIVE;
        }
-#line 21760 "ext/date/lib/parse_date.c"
+#line 21818 "ext/date/lib/parse_date.c"
 yy1396:
                YYDEBUG(1396, *YYCURSOR);
                yyaccept = 0;
@@ -22236,7 +22294,7 @@
                ++YYCURSOR;
 yy1418:
                YYDEBUG(1418, *YYCURSOR);
-#line 894 "ext/date/lib/parse_date.re"
+#line 952 "ext/date/lib/parse_date.re"
                {
                DEBUG_OUTPUT("yesterday");
                TIMELIB_INIT;
@@ -22247,7 +22305,7 @@
                TIMELIB_DEINIT;
                return TIMELIB_RELATIVE;
        }
-#line 22251 "ext/date/lib/parse_date.c"
+#line 22309 "ext/date/lib/parse_date.c"
 yy1419:
                YYDEBUG(1419, *YYCURSOR);
                yyaccept = 0;
@@ -22394,7 +22452,7 @@
                }
        }
 }
-#line 1542 "ext/date/lib/parse_date.re"
+#line 1600 "ext/date/lib/parse_date.re"
 
 }
 
@@ -22470,6 +22528,208 @@
        return in.time;
 }
 
+#define TIMELIB_CHECK_NUMBER                                           \
+               if (strchr("0123456789", *ptr) == NULL)                        \
+               {                                                              \
+                       add_pbf_error(s, "Unexpected data found.", string, 
begin); \
+               }
+
+
+timelib_time *timelib_parse_from_format(char *format, char *string, int len, 
timelib_error_container **errors, const timelib_tzdb *tzdb)
+{
+       char       *fptr = format;
+       char       *ptr = string;
+       char       *begin;
+       timelib_sll tmp;
+       Scanner in;
+       Scanner *s = &in;
+
+       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;
+
+       in.time = timelib_time_ctor();
+       in.time->y = TIMELIB_UNSET;
+       in.time->d = TIMELIB_UNSET;
+       in.time->m = TIMELIB_UNSET;
+       in.time->h = TIMELIB_UNSET;
+       in.time->i = TIMELIB_UNSET;
+       in.time->s = TIMELIB_UNSET;
+       in.time->f = TIMELIB_UNSET;
+       in.time->z = TIMELIB_UNSET;
+       in.time->dst = TIMELIB_UNSET;
+       in.tzdb = tzdb;
+       in.time->is_localtime = 0;
+       in.time->zone_type = 0;
+
+       /* Loop over the format string */
+       while (*fptr && *ptr) {
+               begin = ptr;
+               switch (*fptr) {
+                       case 'd': // two digit day, with leading zero
+                       case 'j': // two digit day, without leading zero
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->d = timelib_get_nr((char **) 
&ptr, 2)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A two digit day could 
not be found", string, begin);
+                               }
+                               break;
+                       case 'S': // day suffix, ignored, nor checked
+                               timelib_skip_day_suffix((char **) &ptr);
+                               break;
+                       case 'z': // day of year - resets month (0 based)
+                               TIMELIB_CHECK_NUMBER;
+                               if ((tmp = timelib_get_nr((char **) &ptr, 3)) 
== TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A three digit 
day-of-year could not be found", string, begin);
+                               } else {
+                                       s->time->m = 1;
+                                       s->time->d = tmp + 1;
+                               }
+                               break;
+
+                       case 'm': // two digit month, with leading zero
+                       case 'n': // two digit month, without leading zero
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->m = timelib_get_nr((char **) 
&ptr, 2)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A two digit month 
could not be found", string, begin);
+                               }
+                               break;
+                       case 'M': // three letter month
+                       case 'F': // full month
+                               tmp = timelib_lookup_month((char **) &ptr);
+                               if (!tmp) {
+                                       add_pbf_error(s, "A textual month could 
not be found", string, begin);
+                               } else {
+                                       s->time->m = tmp;
+                               }
+                               break;
+                       case 'y': // two digit year
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->y = timelib_get_nr((char **) 
&ptr, 2)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A two digit year 
could not be found", string, begin);
+                               }
+                               TIMELIB_PROCESS_YEAR(s->time->y);
+                               break;
+                       case 'Y': // four digit year
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->y = timelib_get_nr((char **) 
&ptr, 4)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A four digit year 
could not be found", string, begin);
+                               }
+                               break;
+                       case 'g': // two digit hour, with leading zero
+                       case 'h': // two digit hour, without leading zero
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->h = timelib_get_nr((char **) 
&ptr, 2)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A two digit hour 
could not be found", string, begin);
+                               }
+                               if (s->time->h > 12) {
+                                       add_pbf_error(s, "Hour can not be 
higher than 12", string, begin);
+                               }
+                               break;
+                       case 'G': // two digit hour, with leading zero
+                       case 'H': // two digit hour, without leading zero
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->h = timelib_get_nr((char **) 
&ptr, 2)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A two digit hour 
could not be found", string, begin);
+                               }
+                               break;
+                       case 'a': // am/pm/a.m./p.m.
+                       case 'A': // AM/PM/A.M./P.M.
+                               if (s->time->h == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "Meridian can only 
come after an hour has been found", string, begin);
+                               } else if ((tmp = 
timelib_meridian_with_check((char **) &ptr, s->time->h)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A meridian could no 
tbe found", string, begin);
+                               } else {
+                                       s->time->h += tmp;
+                               }
+                               break;
+                       case 'i': // two digit minute, with leading zero
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->i = timelib_get_nr((char **) 
&ptr, 2)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A two digit minute 
could not be found", string, begin);
+                               }
+                               break;
+                       case 's': // two digit second, with leading zero
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->s = timelib_get_nr((char **) 
&ptr, 2)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A two digit second 
could not be found", string, begin);
+                               }
+                               break;
+                       case 'u': // five digit millisecond, with leading zero
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->f = timelib_get_nr((char **) 
&ptr, 5)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A five digit 
millisecond could not be found", string, begin);
+                               }
+                               break;
+                       case ' ': // any sort of whitespace (' ' and \t)
+                               timelib_eat_spaces((char **) &ptr);
+                               break;
+                       case 'U': // epoch seconds
+                               TIMELIB_CHECK_NUMBER;
+                               TIMELIB_HAVE_RELATIVE();
+                               tmp = timelib_get_unsigned_nr((char **) &ptr, 
24);
+                               s->time->y = 1970;
+                               s->time->m = 1;
+                               s->time->d = 1;
+                               s->time->h = s->time->i = s->time->s = 0;
+                               s->time->f = 0.0;
+                               s->time->relative.s += tmp;
+                               s->time->is_localtime = 1;
+                               s->time->zone_type = TIMELIB_ZONETYPE_OFFSET;
+                               s->time->z = 0;
+                               break;
+
+                       case 'e': // timezone
+                               {
+                                       int tz_not_found;
+                                       s->time->z = timelib_get_zone((char **) 
&ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb);
+                                       if (tz_not_found) {
+                                               add_pbf_error(s, "The timezone 
could not be found in the database", string, begin);
+                                       }
+                               }
+                               break;
+
+                       case '#': // separation symbol
+                               if (*ptr == ';' || *ptr == ':' || *ptr == '/' 
|| *ptr == '.' || *ptr == ',' || *ptr == '-') {
+                                       ++ptr;
+                               } else {
+                                       add_pbf_error(s, "The seperation symbol 
([;:/.,-]) could not be found", string, begin);
+                               }
+                               break;
+
+                       case '?': // random char
+                               ++ptr;
+                               break;
+
+                       case '*': // random chars until a seperator or number 
([ \t.,:;/-0123456789])
+                               timelib_eat_until_seperator((char **) &ptr);
+                               break;
+
+                       default:
+                               if (*fptr != *ptr) {
+                                       add_pbf_error(s, "The format seperator 
does not match", string, begin);
+                               }
+                               ptr++;
+               }
+               fptr++;
+       }
+       if (*ptr) {
+               add_pbf_error(s, "Trailing data", string, ptr);
+       }
+       if (*fptr) {
+               add_pbf_error(s, "Data missing", string, ptr);
+       }
+
+       if (errors) {
+               *errors = in.errors;
+       } else {
+               timelib_error_container_dtor(in.errors);
+       }
+       return in.time;
+}
+
 void timelib_fill_holes(timelib_time *parsed, timelib_time *now, int options)
 {
        if (!(options && TIMELIB_OVERRIDE_TIME) && parsed->have_date && 
!parsed->have_time) {
http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/parse_date.re?r1=1.65&r2=1.66&diff_format=u
Index: php-src/ext/date/lib/parse_date.re
diff -u php-src/ext/date/lib/parse_date.re:1.65 
php-src/ext/date/lib/parse_date.re:1.66
--- php-src/ext/date/lib/parse_date.re:1.65     Thu Jul 12 18:56:41 2007
+++ php-src/ext/date/lib/parse_date.re  Sun Jan 13 15:16:48 2008
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: parse_date.re,v 1.65 2007/07/12 18:56:41 derick Exp $ */
+/* $Id: parse_date.re,v 1.66 2008/01/13 15:16:48 derick Exp $ */
 
 #include "timelib.h"
 
@@ -349,6 +349,24 @@
        s->errors->error_messages[s->errors->error_count - 1].message = 
strdup(error);
 }
 
+static void add_pbf_warning(Scanner *s, char *error, char *sptr, char *cptr)
+{
+       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 = 
cptr - sptr;
+       s->errors->warning_messages[s->errors->warning_count - 1].character = 
*cptr;
+       s->errors->warning_messages[s->errors->warning_count - 1].message = 
strdup(error);
+}
+
+static void add_pbf_error(Scanner *s, char *error, char *sptr, char *cptr)
+{
+       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 = cptr - 
sptr;
+       s->errors->error_messages[s->errors->error_count - 1].character = *cptr;
+       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;
@@ -372,6 +390,39 @@
        return retval;
 }
 
+static timelib_sll timelib_meridian_with_check(char **ptr, timelib_sll h)
+{
+       timelib_sll retval = 0;
+
+       while (!strchr("AaPp", **ptr)) {
+               ++*ptr;
+       }
+       if (**ptr == 'a' || **ptr == 'A') {
+               if (h == 12) {
+                       retval = -12;
+               }
+       } else if (h != 12) {
+               retval = 12;
+       }
+       ++*ptr;
+       if (**ptr == '.') {
+               ++*ptr;
+               if (**ptr != 'm' && **ptr != 'M') {
+                       return TIMELIB_UNSET;
+               }
+               ++*ptr;
+               if (**ptr != '.' ) {
+                       return TIMELIB_UNSET;
+               }
+               ++*ptr;
+       } else if (**ptr == 'm' || **ptr == 'M') {
+               ++*ptr;
+       } else {
+               return TIMELIB_UNSET;
+       }
+       return retval;
+}
+
 static char *timelib_string(Scanner *s)
 {
        char *tmp = calloc(1, s->cur - s->tok + 1);
@@ -566,6 +617,13 @@
        }
 }
 
+static void timelib_eat_until_seperator(char **ptr)
+{
+       while (strchr(" \t.,:;/-0123456789", **ptr) == NULL) {
+               ++*ptr;
+       }
+}
+
 static const timelib_relunit* timelib_lookup_relunit(char **ptr)
 {
        char *word;
@@ -1614,6 +1672,208 @@
        return in.time;
 }
 
+#define TIMELIB_CHECK_NUMBER                                           \
+               if (strchr("0123456789", *ptr) == NULL)                        \
+               {                                                              \
+                       add_pbf_error(s, "Unexpected data found.", string, 
begin); \
+               }
+
+
+timelib_time *timelib_parse_from_format(char *format, char *string, int len, 
timelib_error_container **errors, const timelib_tzdb *tzdb)
+{
+       char       *fptr = format;
+       char       *ptr = string;
+       char       *begin;
+       timelib_sll tmp;
+       Scanner in;
+       Scanner *s = &in;
+
+       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;
+
+       in.time = timelib_time_ctor();
+       in.time->y = TIMELIB_UNSET;
+       in.time->d = TIMELIB_UNSET;
+       in.time->m = TIMELIB_UNSET;
+       in.time->h = TIMELIB_UNSET;
+       in.time->i = TIMELIB_UNSET;
+       in.time->s = TIMELIB_UNSET;
+       in.time->f = TIMELIB_UNSET;
+       in.time->z = TIMELIB_UNSET;
+       in.time->dst = TIMELIB_UNSET;
+       in.tzdb = tzdb;
+       in.time->is_localtime = 0;
+       in.time->zone_type = 0;
+
+       /* Loop over the format string */
+       while (*fptr && *ptr) {
+               begin = ptr;
+               switch (*fptr) {
+                       case 'd': // two digit day, with leading zero
+                       case 'j': // two digit day, without leading zero
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->d = timelib_get_nr((char **) 
&ptr, 2)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A two digit day could 
not be found", string, begin);
+                               }
+                               break;
+                       case 'S': // day suffix, ignored, nor checked
+                               timelib_skip_day_suffix((char **) &ptr);
+                               break;
+                       case 'z': // day of year - resets month (0 based)
+                               TIMELIB_CHECK_NUMBER;
+                               if ((tmp = timelib_get_nr((char **) &ptr, 3)) 
== TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A three digit 
day-of-year could not be found", string, begin);
+                               } else {
+                                       s->time->m = 1;
+                                       s->time->d = tmp + 1;
+                               }
+                               break;
+
+                       case 'm': // two digit month, with leading zero
+                       case 'n': // two digit month, without leading zero
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->m = timelib_get_nr((char **) 
&ptr, 2)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A two digit month 
could not be found", string, begin);
+                               }
+                               break;
+                       case 'M': // three letter month
+                       case 'F': // full month
+                               tmp = timelib_lookup_month((char **) &ptr);
+                               if (!tmp) {
+                                       add_pbf_error(s, "A textual month could 
not be found", string, begin);
+                               } else {
+                                       s->time->m = tmp;
+                               }
+                               break;
+                       case 'y': // two digit year
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->y = timelib_get_nr((char **) 
&ptr, 2)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A two digit year 
could not be found", string, begin);
+                               }
+                               TIMELIB_PROCESS_YEAR(s->time->y);
+                               break;
+                       case 'Y': // four digit year
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->y = timelib_get_nr((char **) 
&ptr, 4)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A four digit year 
could not be found", string, begin);
+                               }
+                               break;
+                       case 'g': // two digit hour, with leading zero
+                       case 'h': // two digit hour, without leading zero
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->h = timelib_get_nr((char **) 
&ptr, 2)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A two digit hour 
could not be found", string, begin);
+                               }
+                               if (s->time->h > 12) {
+                                       add_pbf_error(s, "Hour can not be 
higher than 12", string, begin);
+                               }
+                               break;
+                       case 'G': // two digit hour, with leading zero
+                       case 'H': // two digit hour, without leading zero
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->h = timelib_get_nr((char **) 
&ptr, 2)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A two digit hour 
could not be found", string, begin);
+                               }
+                               break;
+                       case 'a': // am/pm/a.m./p.m.
+                       case 'A': // AM/PM/A.M./P.M.
+                               if (s->time->h == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "Meridian can only 
come after an hour has been found", string, begin);
+                               } else if ((tmp = 
timelib_meridian_with_check((char **) &ptr, s->time->h)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A meridian could no 
tbe found", string, begin);
+                               } else {
+                                       s->time->h += tmp;
+                               }
+                               break;
+                       case 'i': // two digit minute, with leading zero
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->i = timelib_get_nr((char **) 
&ptr, 2)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A two digit minute 
could not be found", string, begin);
+                               }
+                               break;
+                       case 's': // two digit second, with leading zero
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->s = timelib_get_nr((char **) 
&ptr, 2)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A two digit second 
could not be found", string, begin);
+                               }
+                               break;
+                       case 'u': // five digit millisecond, with leading zero
+                               TIMELIB_CHECK_NUMBER;
+                               if ((s->time->f = timelib_get_nr((char **) 
&ptr, 5)) == TIMELIB_UNSET) {
+                                       add_pbf_error(s, "A five digit 
millisecond could not be found", string, begin);
+                               }
+                               break;
+                       case ' ': // any sort of whitespace (' ' and \t)
+                               timelib_eat_spaces((char **) &ptr);
+                               break;
+                       case 'U': // epoch seconds
+                               TIMELIB_CHECK_NUMBER;
+                               TIMELIB_HAVE_RELATIVE();
+                               tmp = timelib_get_unsigned_nr((char **) &ptr, 
24);
+                               s->time->y = 1970;
+                               s->time->m = 1;
+                               s->time->d = 1;
+                               s->time->h = s->time->i = s->time->s = 0;
+                               s->time->f = 0.0;
+                               s->time->relative.s += tmp;
+                               s->time->is_localtime = 1;
+                               s->time->zone_type = TIMELIB_ZONETYPE_OFFSET;
+                               s->time->z = 0;
+                               break;
+
+                       case 'e': // timezone
+                               {
+                                       int tz_not_found;
+                                       s->time->z = timelib_get_zone((char **) 
&ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb);
+                                       if (tz_not_found) {
+                                               add_pbf_error(s, "The timezone 
could not be found in the database", string, begin);
+                                       }
+                               }
+                               break;
+
+                       case '#': // separation symbol
+                               if (*ptr == ';' || *ptr == ':' || *ptr == '/' 
|| *ptr == '.' || *ptr == ',' || *ptr == '-') {
+                                       ++ptr;
+                               } else {
+                                       add_pbf_error(s, "The seperation symbol 
([;:/.,-]) could not be found", string, begin);
+                               }
+                               break;
+
+                       case '?': // random char
+                               ++ptr;
+                               break;
+
+                       case '*': // random chars until a seperator or number 
([ \t.,:;/-0123456789])
+                               timelib_eat_until_seperator((char **) &ptr);
+                               break;
+
+                       default:
+                               if (*fptr != *ptr) {
+                                       add_pbf_error(s, "The format seperator 
does not match", string, begin);
+                               }
+                               ptr++;
+               }
+               fptr++;
+       }
+       if (*ptr) {
+               add_pbf_error(s, "Trailing data", string, ptr);
+       }
+       if (*fptr) {
+               add_pbf_error(s, "Data missing", string, ptr);
+       }
+
+       if (errors) {
+               *errors = in.errors;
+       } else {
+               timelib_error_container_dtor(in.errors);
+       }
+       return in.time;
+}
+
 void timelib_fill_holes(timelib_time *parsed, timelib_time *now, int options)
 {
        if (!(options && TIMELIB_OVERRIDE_TIME) && parsed->have_date && 
!parsed->have_time) {
http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/timelib.h?r1=1.25&r2=1.26&diff_format=u
Index: php-src/ext/date/lib/timelib.h
diff -u php-src/ext/date/lib/timelib.h:1.25 php-src/ext/date/lib/timelib.h:1.26
--- php-src/ext/date/lib/timelib.h:1.25 Mon Dec 31 07:12:08 2007
+++ php-src/ext/date/lib/timelib.h      Sun Jan 13 15:16:48 2008
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: timelib.h,v 1.25 2007/12/31 07:12:08 sebastian Exp $ */
+/* $Id: timelib.h,v 1.26 2008/01/13 15:16:48 derick Exp $ */
 
 #ifndef __TIMELIB_H__
 #define __TIMELIB_H__
@@ -54,6 +54,7 @@
 
 /* From parse_date.re */
 timelib_time *timelib_strtotime(char *s, int len, timelib_error_container 
**errors, const timelib_tzdb *tzdb);
+timelib_time *timelib_parse_from_format(char *format, char *s, int len, 
timelib_error_container **errors, const 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);
 const timelib_tz_lookup_table *timelib_timezone_abbreviations_list(void);

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to