. support for diffing date/times through date_diff() / DateTime::diff().
. added DateInterval class to represent the difference between two date/times.
. support for parsing ISO intervals for use with DateInterval.
. date_add() / DateTime::add(), date_sub() / DateTime::sub() for applying an
interval to an existing date/time.
- MFH: Fixed bug #44742 (timezone_offset_get() causes segmentation faults).
. support for "first/last day of <month>" style texts.
. support for date/time strings returned by MS SQL.
. support for serialization and unserialization of DateTime objects.
+ . support for diffing date/times through date_diff() / DateTime::diff().
+ . added DateInterval class to represent the difference between two date/times.
+ . support for parsing ISO intervals for use with DateInterval.
+ . date_add() / DateTime::add(), date_sub() / DateTime::sub() for applying an
+ interval to an existing date/time.
- Added functionality to SPL extension:
. Added SPL to list of standard extensions that cannot be disabled. (Marcus)
. Added ability to store associative information with objects in
- Fixed PECL bug #12431 (OCI8 ping functionality is broken). (Oracle Corp.)
- Fixed bug #44805 (rename() function is not portable to Windows). (Pierre)
+- Fixed bug #44742 (timezone_offset_get() causes segmentation faults). (Derick)
- Fixed bug #44648 (Attribute names not checked for wellformedness). (Rob)
- Fixed bug #44414 (Incomplete reporting about abstract methods). (Dmitry)
- Fixed bug #44390 (mysqli_bind_param/bind_result and Object member variables)
PHP_DATE_CFLAGS="-I@ext_builddir@/lib"
timelib_sources="lib/astro.c lib/dow.c lib/parse_date.c lib/parse_tz.c
- lib/timelib.c lib/tm2unixtime.c lib/unixtime2tm.c"
+ lib/timelib.c lib/tm2unixtime.c lib/unixtime2tm.c lib/parse_iso_intervals.c lib/interval.c"
PHP_NEW_EXTENSION(date, php_date.c $timelib_sources, no,, $PHP_DATE_CFLAGS)
Make sure you use re2c 0.9.10 or higher:
-/dat/dev/sf/re2c/re2c -d -b -o ext/date/lib/parse_date.c ext/date/lib/parse_date.re
+re2c -d -b -o ext/date/lib/parse_date.c ext/date/lib/parse_date.re
+re2c -d -b -o ext/date/lib/parse_iso_intervals.c ext/date/lib/parse_iso_intervals.re
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2008 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Derick Rethans <derick@derickrethans.nl> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#include "timelib.h"
+
+timelib_rel_time *timelib_diff(timelib_time *one, timelib_time *two)
+{
+ timelib_rel_time *rt;
+ timelib_time *swp;
+ timelib_sll dst_h_corr = 0, dst_m_corr = 0;
+
+ rt = timelib_rel_time_ctor();
+ rt->invert = 0;
+ if (one->sse > two->sse) {
+ swp = two;
+ two = one;
+ one = swp;
+ rt->invert = 1;
+ }
+
+ /* Calculate correction for DST change over, but only if the TZ type is ID
+ * and it's the same */
+ if (one->zone_type == 3 && two->zone_type == 3
+ && (strcmp(one->tz_info->name, two->tz_info->name) == 0)
+ && (one->z != two->z))
+ {
+ dst_h_corr = (two->z - one->z) / 3600;
+ dst_m_corr = ((two->z - one->z) % 3600) / 60;
+ }
+
+ timelib_apply_localtime(one, 0);
+ timelib_apply_localtime(two, 0);
+
+ rt->y = two->y - one->y;
+ rt->m = two->m - one->m;
+ rt->d = two->d - one->d;
+ rt->h = two->h - one->h + dst_h_corr;
+ rt->i = two->i - one->i + dst_m_corr;
+ rt->s = two->s - one->s;
+ rt->days = abs(floor((one->sse - two->sse - (dst_h_corr * 3600) - (dst_m_corr * 60)) / 86400));
+
+ timelib_do_rel_normalize(one, rt);
+
+ timelib_apply_localtime(one, 1);
+ timelib_apply_localtime(two, 1);
+
+ return rt;
+}
-/* Generated by re2c 0.13.3 on Sun Mar 23 11:46:55 2008 */
+/* Generated by re2c 0.13.3 on Mon Apr 7 19:58:18 2008 */
#line 1 "ext/date/lib/parse_date.re"
/*
+----------------------------------------------------------------------+
--- /dev/null
+/* Generated by re2c 0.13.3 on Mon Apr 7 19:58:19 2008 */
+#line 1 "ext/date/lib/parse_iso_intervals.re"
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Derick Rethans <derick@derickrethans.nl> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#include "timelib.h"
+
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#if defined(_MSC_VER)
+# define strtoll(s, f, b) _atoi64(s)
+#elif !defined(HAVE_STRTOLL)
+# if defined(HAVE_ATOLL)
+# define strtoll(s, f, b) atoll(s)
+# else
+# define strtoll(s, f, b) strtol(s, f, b)
+# endif
+#endif
+
+#define TIMELIB_UNSET -99999
+
+#define TIMELIB_SECOND 1
+#define TIMELIB_MINUTE 2
+#define TIMELIB_HOUR 3
+#define TIMELIB_DAY 4
+#define TIMELIB_MONTH 5
+#define TIMELIB_YEAR 6
+
+#define EOI 257
+
+#define TIMELIB_PERIOD 260
+#define TIMELIB_ISO_DATE 261
+#define TIMELIB_ERROR 999
+
+typedef unsigned char uchar;
+
+#define BSIZE 8192
+
+#define YYCTYPE uchar
+#define YYCURSOR cursor
+#define YYLIMIT s->lim
+#define YYMARKER s->ptr
+#define YYFILL(n) return EOI;
+
+#define RET(i) {s->cur = cursor; return i;}
+
+#define timelib_string_free free
+
+#define TIMELIB_INIT s->cur = cursor; str = timelib_string(s); ptr = str
+#define TIMELIB_DEINIT timelib_string_free(str)
+
+#ifdef DEBUG_PARSER
+#define DEBUG_OUTPUT(s) printf("%s\n", s);
+#define YYDEBUG(s,c) { if (s != -1) { printf("state: %d ", s); printf("[%c]\n", c); } }
+#else
+#define DEBUG_OUTPUT(s)
+#define YYDEBUG(s,c)
+#endif
+
+#include "timelib_structs.h"
+
+typedef struct Scanner {
+ int fd;
+ uchar *lim, *str, *ptr, *cur, *tok, *pos;
+ unsigned int line, len;
+ struct timelib_error_container *errors;
+
+ struct timelib_time *begin;
+ struct timelib_time *end;
+ struct timelib_rel_time *period;
+ int recurrences;
+
+ int have_period;
+ int have_recurrences;
+ int have_date;
+ int have_begin_date;
+ int have_end_date;
+} Scanner;
+
+#define HOUR(a) (int)(a * 60)
+
+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 char *timelib_string(Scanner *s)
+{
+ char *tmp = calloc(1, s->cur - s->tok + 1);
+ memcpy(tmp, s->tok, s->cur - s->tok);
+
+ return tmp;
+}
+
+static timelib_sll timelib_get_nr(char **ptr, int max_length)
+{
+ char *begin, *end, *str;
+ timelib_sll tmp_nr = TIMELIB_UNSET;
+ int len = 0;
+
+ while ((**ptr < '0') || (**ptr > '9')) {
+ if (**ptr == '\0') {
+ return TIMELIB_UNSET;
+ }
+ ++*ptr;
+ }
+ begin = *ptr;
+ while ((**ptr >= '0') && (**ptr <= '9') && len < max_length) {
+ ++*ptr;
+ ++len;
+ }
+ end = *ptr;
+ str = calloc(1, end - begin + 1);
+ memcpy(str, begin, end - begin);
+ tmp_nr = strtoll(str, NULL, 10);
+ free(str);
+ return tmp_nr;
+}
+
+static timelib_ull timelib_get_unsigned_nr(char **ptr, int max_length)
+{
+ timelib_ull dir = 1;
+
+ while (((**ptr < '0') || (**ptr > '9')) && (**ptr != '+') && (**ptr != '-')) {
+ if (**ptr == '\0') {
+ return TIMELIB_UNSET;
+ }
+ ++*ptr;
+ }
+
+ while (**ptr == '+' || **ptr == '-')
+ {
+ if (**ptr == '-') {
+ dir *= -1;
+ }
+ ++*ptr;
+ }
+ return dir * timelib_get_nr(ptr, max_length);
+}
+
+static long timelib_parse_tz_cor(char **ptr)
+{
+ char *begin = *ptr, *end;
+ long tmp;
+
+ while (**ptr != '\0') {
+ ++*ptr;
+ }
+ end = *ptr;
+ switch (end - begin) {
+ case 1:
+ case 2:
+ return HOUR(strtol(begin, NULL, 10));
+ break;
+ case 3:
+ case 4:
+ if (begin[1] == ':') {
+ tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 2, NULL, 10);
+ return tmp;
+ } else if (begin[2] == ':') {
+ tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10);
+ return tmp;
+ } else {
+ tmp = strtol(begin, NULL, 10);
+ return HOUR(tmp / 100) + tmp % 100;
+ }
+ case 5:
+ tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10);
+ return tmp;
+ }
+ return 0;
+}
+
+static void timelib_eat_spaces(char **ptr)
+{
+ while (**ptr == ' ' || **ptr == '\t') {
+ ++*ptr;
+ }
+}
+
+static void timelib_eat_until_separator(char **ptr)
+{
+ while (strchr(" \t.,:;/-0123456789", **ptr) == NULL) {
+ ++*ptr;
+ }
+}
+
+static long timelib_get_zone(char **ptr, int *dst, timelib_time *t, int *tz_not_found, const timelib_tzdb *tzdb)
+{
+ long retval = 0;
+
+ *tz_not_found = 0;
+
+ while (**ptr == ' ' || **ptr == '\t' || **ptr == '(') {
+ ++*ptr;
+ }
+ if ((*ptr)[0] == 'G' && (*ptr)[1] == 'M' && (*ptr)[2] == 'T' && ((*ptr)[3] == '+' || (*ptr)[3] == '-')) {
+ *ptr += 3;
+ }
+ if (**ptr == '+') {
+ ++*ptr;
+ t->is_localtime = 1;
+ t->zone_type = TIMELIB_ZONETYPE_OFFSET;
+ *tz_not_found = 0;
+ t->dst = 0;
+
+ retval = -1 * timelib_parse_tz_cor(ptr);
+ } else if (**ptr == '-') {
+ ++*ptr;
+ t->is_localtime = 1;
+ t->zone_type = TIMELIB_ZONETYPE_OFFSET;
+ *tz_not_found = 0;
+ t->dst = 0;
+
+ retval = timelib_parse_tz_cor(ptr);
+ }
+ while (**ptr == ')') {
+ ++*ptr;
+ }
+ return retval;
+}
+
+#define timelib_split_free(arg) { \
+ int i; \
+ for (i = 0; i < arg.c; i++) { \
+ free(arg.v[i]); \
+ } \
+ if (arg.v) { \
+ free(arg.v); \
+ } \
+}
+
+static int scan(Scanner *s)
+{
+ uchar *cursor = s->cur;
+ char *str, *ptr = NULL;
+
+std:
+ s->tok = cursor;
+ s->len = 0;
+#line 303 "ext/date/lib/parse_iso_intervals.re"
+
+
+
+#line 286 "ext/date/lib/parse_iso_intervals.c"
+{
+ YYCTYPE yych;
+ unsigned int yyaccept = 0;
+ static const unsigned char yybm[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ YYDEBUG(0, *YYCURSOR);
+ if ((YYLIMIT - YYCURSOR) < 20) YYFILL(20);
+ yych = *YYCURSOR;
+ if (yych <= ',') {
+ if (yych <= 0x0A) {
+ if (yych <= 0x00) goto yy9;
+ if (yych <= 0x08) goto yy11;
+ if (yych <= 0x09) goto yy7;
+ goto yy9;
+ } else {
+ if (yych == ' ') goto yy7;
+ if (yych <= '+') goto yy11;
+ goto yy7;
+ }
+ } else {
+ if (yych <= 'O') {
+ if (yych <= '-') goto yy11;
+ if (yych <= '/') goto yy7;
+ if (yych <= '9') goto yy4;
+ goto yy11;
+ } else {
+ if (yych <= 'P') goto yy5;
+ if (yych != 'R') goto yy11;
+ }
+ }
+ YYDEBUG(2, *YYCURSOR);
+ ++YYCURSOR;
+ if ((yych = *YYCURSOR) <= '/') goto yy3;
+ if (yych <= '9') goto yy74;
+yy3:
+ YYDEBUG(3, *YYCURSOR);
+#line 396 "ext/date/lib/parse_iso_intervals.re"
+ {
+ add_error(s, "Unexpected character");
+ goto std;
+ }
+#line 361 "ext/date/lib/parse_iso_intervals.c"
+yy4:
+ YYDEBUG(4, *YYCURSOR);
+ yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych <= '/') goto yy3;
+ if (yych <= '9') goto yy35;
+ goto yy3;
+yy5:
+ YYDEBUG(5, *YYCURSOR);
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yybm[0+yych] & 128) {
+ goto yy12;
+ }
+ if (yych == 'T') goto yy15;
+yy6:
+ YYDEBUG(6, *YYCURSOR);
+#line 343 "ext/date/lib/parse_iso_intervals.re"
+ {
+ timelib_sll nr;
+ int in_time = 0;
+ DEBUG_OUTPUT("period");
+ TIMELIB_INIT;
+ ptr++;
+ do {
+ if ( *ptr == 'T' ) {
+ in_time = 1;
+ ptr++;
+ }
+ if ( *ptr == '\0' ) {
+ add_error(s, "Missing expected time part");
+ break;
+ }
+
+ nr = timelib_get_unsigned_nr((char **) &ptr, 4);
+ switch (*ptr) {
+ case 'Y': s->period->y = nr; break;
+ case 'W': s->period->d = nr * 7; break;
+ case 'D': s->period->d = nr; break;
+ case 'H': s->period->h = nr; break;
+ case 'S': s->period->s = nr; break;
+ case 'M':
+ if (in_time) {
+ s->period->i = nr;
+ } else {
+ s->period->m = nr;
+ }
+ break;
+ default:
+ add_error(s, "Undefined period specifier");
+ break;
+ }
+ ptr++;
+ } while (*ptr);
+ s->have_period = 1;
+ TIMELIB_DEINIT;
+ return TIMELIB_PERIOD;
+ }
+#line 420 "ext/date/lib/parse_iso_intervals.c"
+yy7:
+ YYDEBUG(7, *YYCURSOR);
+ ++YYCURSOR;
+ YYDEBUG(8, *YYCURSOR);
+#line 385 "ext/date/lib/parse_iso_intervals.re"
+ {
+ goto std;
+ }
+#line 429 "ext/date/lib/parse_iso_intervals.c"
+yy9:
+ YYDEBUG(9, *YYCURSOR);
+ ++YYCURSOR;
+ YYDEBUG(10, *YYCURSOR);
+#line 390 "ext/date/lib/parse_iso_intervals.re"
+ {
+ s->pos = cursor; s->line++;
+ goto std;
+ }
+#line 439 "ext/date/lib/parse_iso_intervals.c"
+yy11:
+ YYDEBUG(11, *YYCURSOR);
+ yych = *++YYCURSOR;
+ goto yy3;
+yy12:
+ YYDEBUG(12, *YYCURSOR);
+ ++YYCURSOR;
+ if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
+ yych = *YYCURSOR;
+ YYDEBUG(13, *YYCURSOR);
+ if (yybm[0+yych] & 128) {
+ goto yy12;
+ }
+ if (yych <= 'M') {
+ if (yych == 'D') goto yy25;
+ if (yych >= 'M') goto yy27;
+ } else {
+ if (yych <= 'W') {
+ if (yych >= 'W') goto yy26;
+ } else {
+ if (yych == 'Y') goto yy28;
+ }
+ }
+yy14:
+ YYDEBUG(14, *YYCURSOR);
+ YYCURSOR = YYMARKER;
+ if (yyaccept <= 0) {
+ goto yy3;
+ } else {
+ goto yy6;
+ }
+yy15:
+ YYDEBUG(15, *YYCURSOR);
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych <= '/') goto yy6;
+ if (yych >= ':') goto yy6;
+yy16:
+ YYDEBUG(16, *YYCURSOR);
+ ++YYCURSOR;
+ if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
+ yych = *YYCURSOR;
+ YYDEBUG(17, *YYCURSOR);
+ if (yych <= 'H') {
+ if (yych <= '/') goto yy14;
+ if (yych <= '9') goto yy16;
+ if (yych <= 'G') goto yy14;
+ goto yy20;
+ } else {
+ if (yych <= 'M') {
+ if (yych <= 'L') goto yy14;
+ goto yy19;
+ } else {
+ if (yych != 'S') goto yy14;
+ }
+ }
+yy18:
+ YYDEBUG(18, *YYCURSOR);
+ yych = *++YYCURSOR;
+ goto yy6;
+yy19:
+ YYDEBUG(19, *YYCURSOR);
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych <= '/') goto yy6;
+ if (yych <= '9') goto yy23;
+ goto yy6;
+yy20:
+ YYDEBUG(20, *YYCURSOR);
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych <= '/') goto yy6;
+ if (yych >= ':') goto yy6;
+yy21:
+ YYDEBUG(21, *YYCURSOR);
+ ++YYCURSOR;
+ if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
+ yych = *YYCURSOR;
+ YYDEBUG(22, *YYCURSOR);
+ if (yych <= 'L') {
+ if (yych <= '/') goto yy14;
+ if (yych <= '9') goto yy21;
+ goto yy14;
+ } else {
+ if (yych <= 'M') goto yy19;
+ if (yych == 'S') goto yy18;
+ goto yy14;
+ }
+yy23:
+ YYDEBUG(23, *YYCURSOR);
+ ++YYCURSOR;
+ if (YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(24, *YYCURSOR);
+ if (yych <= '/') goto yy14;
+ if (yych <= '9') goto yy23;
+ if (yych == 'S') goto yy18;
+ goto yy14;
+yy25:
+ YYDEBUG(25, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych == 'T') goto yy15;
+ goto yy6;
+yy26:
+ YYDEBUG(26, *YYCURSOR);
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych <= '/') goto yy6;
+ if (yych <= '9') goto yy33;
+ if (yych == 'T') goto yy15;
+ goto yy6;
+yy27:
+ YYDEBUG(27, *YYCURSOR);
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych <= '/') goto yy6;
+ if (yych <= '9') goto yy31;
+ if (yych == 'T') goto yy15;
+ goto yy6;
+yy28:
+ YYDEBUG(28, *YYCURSOR);
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych <= '/') goto yy6;
+ if (yych <= '9') goto yy29;
+ if (yych == 'T') goto yy15;
+ goto yy6;
+yy29:
+ YYDEBUG(29, *YYCURSOR);
+ ++YYCURSOR;
+ if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
+ yych = *YYCURSOR;
+ YYDEBUG(30, *YYCURSOR);
+ if (yych <= 'D') {
+ if (yych <= '/') goto yy14;
+ if (yych <= '9') goto yy29;
+ if (yych <= 'C') goto yy14;
+ goto yy25;
+ } else {
+ if (yych <= 'M') {
+ if (yych <= 'L') goto yy14;
+ goto yy27;
+ } else {
+ if (yych == 'W') goto yy26;
+ goto yy14;
+ }
+ }
+yy31:
+ YYDEBUG(31, *YYCURSOR);
+ ++YYCURSOR;
+ if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
+ yych = *YYCURSOR;
+ YYDEBUG(32, *YYCURSOR);
+ if (yych <= 'C') {
+ if (yych <= '/') goto yy14;
+ if (yych <= '9') goto yy31;
+ goto yy14;
+ } else {
+ if (yych <= 'D') goto yy25;
+ if (yych == 'W') goto yy26;
+ goto yy14;
+ }
+yy33:
+ YYDEBUG(33, *YYCURSOR);
+ ++YYCURSOR;
+ if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
+ yych = *YYCURSOR;
+ YYDEBUG(34, *YYCURSOR);
+ if (yych <= '/') goto yy14;
+ if (yych <= '9') goto yy33;
+ if (yych == 'D') goto yy25;
+ goto yy14;
+yy35:
+ YYDEBUG(35, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych >= ':') goto yy14;
+ YYDEBUG(36, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych >= ':') goto yy14;
+ YYDEBUG(37, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') {
+ if (yych == '-') goto yy40;
+ goto yy14;
+ } else {
+ if (yych <= '0') goto yy38;
+ if (yych <= '1') goto yy39;
+ goto yy14;
+ }
+yy38:
+ YYDEBUG(38, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '0') goto yy14;
+ if (yych <= '9') goto yy61;
+ goto yy14;
+yy39:
+ YYDEBUG(39, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych <= '2') goto yy61;
+ goto yy14;
+yy40:
+ YYDEBUG(40, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych <= '0') goto yy41;
+ if (yych <= '1') goto yy42;
+ goto yy14;
+yy41:
+ YYDEBUG(41, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '0') goto yy14;
+ if (yych <= '9') goto yy43;
+ goto yy14;
+yy42:
+ YYDEBUG(42, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych >= '3') goto yy14;
+yy43:
+ YYDEBUG(43, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych != '-') goto yy14;
+ YYDEBUG(44, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych <= '0') goto yy45;
+ if (yych <= '2') goto yy46;
+ if (yych <= '3') goto yy47;
+ goto yy14;
+yy45:
+ YYDEBUG(45, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '0') goto yy14;
+ if (yych <= '9') goto yy48;
+ goto yy14;
+yy46:
+ YYDEBUG(46, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych <= '9') goto yy48;
+ goto yy14;
+yy47:
+ YYDEBUG(47, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych >= '2') goto yy14;
+yy48:
+ YYDEBUG(48, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych != 'T') goto yy14;
+ YYDEBUG(49, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych <= '1') goto yy50;
+ if (yych <= '2') goto yy51;
+ goto yy14;
+yy50:
+ YYDEBUG(50, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych <= '9') goto yy52;
+ goto yy14;
+yy51:
+ YYDEBUG(51, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych >= '5') goto yy14;
+yy52:
+ YYDEBUG(52, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych != ':') goto yy14;
+ YYDEBUG(53, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych >= '6') goto yy14;
+ YYDEBUG(54, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych >= ':') goto yy14;
+ YYDEBUG(55, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych != ':') goto yy14;
+ YYDEBUG(56, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych >= '6') goto yy14;
+ YYDEBUG(57, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych >= ':') goto yy14;
+ YYDEBUG(58, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych != 'Z') goto yy14;
+yy59:
+ YYDEBUG(59, *YYCURSOR);
+ ++YYCURSOR;
+ YYDEBUG(60, *YYCURSOR);
+#line 319 "ext/date/lib/parse_iso_intervals.re"
+ {
+ timelib_time *current;
+
+ if (s->have_date || s->have_period) {
+ current = s->end;
+ s->have_end_date = 1;
+ } else {
+ current = s->begin;
+ s->have_begin_date = 1;
+ }
+ DEBUG_OUTPUT("datetimebasic | datetimeextended");
+ TIMELIB_INIT;
+ current->y = timelib_get_nr((char **) &ptr, 4);
+ current->m = timelib_get_nr((char **) &ptr, 2);
+ current->d = timelib_get_nr((char **) &ptr, 2);
+ current->h = timelib_get_nr((char **) &ptr, 2);
+ current->i = timelib_get_nr((char **) &ptr, 2);
+ current->s = timelib_get_nr((char **) &ptr, 2);
+ s->have_date = 1;
+ TIMELIB_DEINIT;
+ return TIMELIB_ISO_DATE;
+ }
+#line 763 "ext/date/lib/parse_iso_intervals.c"
+yy61:
+ YYDEBUG(61, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych <= '0') goto yy62;
+ if (yych <= '2') goto yy63;
+ if (yych <= '3') goto yy64;
+ goto yy14;
+yy62:
+ YYDEBUG(62, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '0') goto yy14;
+ if (yych <= '9') goto yy65;
+ goto yy14;
+yy63:
+ YYDEBUG(63, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych <= '9') goto yy65;
+ goto yy14;
+yy64:
+ YYDEBUG(64, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych >= '2') goto yy14;
+yy65:
+ YYDEBUG(65, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych != 'T') goto yy14;
+ YYDEBUG(66, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych <= '1') goto yy67;
+ if (yych <= '2') goto yy68;
+ goto yy14;
+yy67:
+ YYDEBUG(67, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych <= '9') goto yy69;
+ goto yy14;
+yy68:
+ YYDEBUG(68, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych >= '5') goto yy14;
+yy69:
+ YYDEBUG(69, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych >= '6') goto yy14;
+ YYDEBUG(70, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych >= ':') goto yy14;
+ YYDEBUG(71, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych >= '6') goto yy14;
+ YYDEBUG(72, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych <= '/') goto yy14;
+ if (yych >= ':') goto yy14;
+ YYDEBUG(73, *YYCURSOR);
+ yych = *++YYCURSOR;
+ if (yych == 'Z') goto yy59;
+ goto yy14;
+yy74:
+ YYDEBUG(74, *YYCURSOR);
+ ++YYCURSOR;
+ if (YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+ YYDEBUG(75, *YYCURSOR);
+ if (yych <= '/') goto yy76;
+ if (yych <= '9') goto yy74;
+yy76:
+ YYDEBUG(76, *YYCURSOR);
+#line 308 "ext/date/lib/parse_iso_intervals.re"
+ {
+ DEBUG_OUTPUT("recurrences");
+ TIMELIB_INIT;
+ ptr++;
+ s->recurrences = timelib_get_unsigned_nr((char **) &ptr, 9);
+ TIMELIB_DEINIT;
+ s->have_recurrences = 1;
+ return TIMELIB_PERIOD;
+ }
+#line 851 "ext/date/lib/parse_iso_intervals.c"
+}
+#line 400 "ext/date/lib/parse_iso_intervals.re"
+
+}
+
+#define YYMAXFILL 20
+
+void timelib_strtointerval(char *s, int len,
+ timelib_time **begin, timelib_time **end,
+ timelib_rel_time **period, int *recurrences,
+ struct timelib_error_container **errors)
+{
+ 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;
+
+ if (len > 0) {
+ while (isspace(*s) && s < e) {
+ s++;
+ }
+ while (isspace(*e) && e > s) {
+ e--;
+ }
+ }
+ if (e - s < 0) {
+ add_error(&in, "Empty string");
+ if (errors) {
+ *errors = in.errors;
+ } else {
+ timelib_error_container_dtor(in.errors);
+ }
+ return;
+ }
+ e++;
+
+ /* init cursor */
+ in.str = malloc((e - s) + YYMAXFILL);
+ memset(in.str, 0, (e - s) + YYMAXFILL);
+ memcpy(in.str, s, (e - s));
+ in.lim = in.str + (e - s) + YYMAXFILL;
+ in.cur = in.str;
+
+ /* init value containers */
+ in.begin = timelib_time_ctor();
+ in.begin->y = TIMELIB_UNSET;
+ in.begin->d = TIMELIB_UNSET;
+ in.begin->m = TIMELIB_UNSET;
+ in.begin->h = TIMELIB_UNSET;
+ in.begin->i = TIMELIB_UNSET;
+ in.begin->s = TIMELIB_UNSET;
+ in.begin->f = TIMELIB_UNSET;
+ in.begin->z = TIMELIB_UNSET;
+ in.begin->dst = TIMELIB_UNSET;
+ in.begin->is_localtime = 0;
+ in.begin->zone_type = 0;
+
+ in.end = timelib_time_ctor();
+ in.end->y = TIMELIB_UNSET;
+ in.end->d = TIMELIB_UNSET;
+ in.end->m = TIMELIB_UNSET;
+ in.end->h = TIMELIB_UNSET;
+ in.end->i = TIMELIB_UNSET;
+ in.end->s = TIMELIB_UNSET;
+ in.end->f = TIMELIB_UNSET;
+ in.end->z = TIMELIB_UNSET;
+ in.end->dst = TIMELIB_UNSET;
+ in.end->is_localtime = 0;
+ in.end->zone_type = 0;
+
+ in.period = timelib_rel_time_ctor();
+ in.period->y = 0;
+ in.period->d = 0;
+ in.period->m = 0;
+ in.period->h = 0;
+ in.period->i = 0;
+ in.period->s = 0;
+ in.period->weekday = 0;
+ in.period->weekday_behavior = 0;
+ in.period->first_last_day_of = 0;
+
+ in.recurrences = 1;
+
+ do {
+ t = scan(&in);
+#ifdef DEBUG_PARSER
+ printf("%d\n", t);
+#endif
+ } while(t != EOI);
+
+ free(in.str);
+ if (errors) {
+ *errors = in.errors;
+ } else {
+ timelib_error_container_dtor(in.errors);
+ }
+ if (in.have_begin_date) {
+ *begin = in.begin;
+ } else {
+ timelib_time_dtor(in.begin);
+ }
+ if (in.have_end_date) {
+ *end = in.end;
+ } else {
+ timelib_time_dtor(in.end);
+ }
+ if (in.have_period) {
+ *period = in.period;
+ } else {
+ timelib_rel_time_dtor(in.period);
+ }
+ if (in.have_recurrences) {
+ *recurrences = in.recurrences;
+ }
+}
+
+
+/*
+ * vim: syntax=c
+ */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Derick Rethans <derick@derickrethans.nl> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#include "timelib.h"
+
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#if defined(_MSC_VER)
+# define strtoll(s, f, b) _atoi64(s)
+#elif !defined(HAVE_STRTOLL)
+# if defined(HAVE_ATOLL)
+# define strtoll(s, f, b) atoll(s)
+# else
+# define strtoll(s, f, b) strtol(s, f, b)
+# endif
+#endif
+
+#define TIMELIB_UNSET -99999
+
+#define TIMELIB_SECOND 1
+#define TIMELIB_MINUTE 2
+#define TIMELIB_HOUR 3
+#define TIMELIB_DAY 4
+#define TIMELIB_MONTH 5
+#define TIMELIB_YEAR 6
+
+#define EOI 257
+
+#define TIMELIB_PERIOD 260
+#define TIMELIB_ISO_DATE 261
+#define TIMELIB_ERROR 999
+
+typedef unsigned char uchar;
+
+#define BSIZE 8192
+
+#define YYCTYPE uchar
+#define YYCURSOR cursor
+#define YYLIMIT s->lim
+#define YYMARKER s->ptr
+#define YYFILL(n) return EOI;
+
+#define RET(i) {s->cur = cursor; return i;}
+
+#define timelib_string_free free
+
+#define TIMELIB_INIT s->cur = cursor; str = timelib_string(s); ptr = str
+#define TIMELIB_DEINIT timelib_string_free(str)
+
+#ifdef DEBUG_PARSER
+#define DEBUG_OUTPUT(s) printf("%s\n", s);
+#define YYDEBUG(s,c) { if (s != -1) { printf("state: %d ", s); printf("[%c]\n", c); } }
+#else
+#define DEBUG_OUTPUT(s)
+#define YYDEBUG(s,c)
+#endif
+
+#include "timelib_structs.h"
+
+typedef struct Scanner {
+ int fd;
+ uchar *lim, *str, *ptr, *cur, *tok, *pos;
+ unsigned int line, len;
+ struct timelib_error_container *errors;
+
+ struct timelib_time *begin;
+ struct timelib_time *end;
+ struct timelib_rel_time *period;
+ int recurrences;
+
+ int have_period;
+ int have_recurrences;
+ int have_date;
+ int have_begin_date;
+ int have_end_date;
+} Scanner;
+
+#define HOUR(a) (int)(a * 60)
+
+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 char *timelib_string(Scanner *s)
+{
+ char *tmp = calloc(1, s->cur - s->tok + 1);
+ memcpy(tmp, s->tok, s->cur - s->tok);
+
+ return tmp;
+}
+
+static timelib_sll timelib_get_nr(char **ptr, int max_length)
+{
+ char *begin, *end, *str;
+ timelib_sll tmp_nr = TIMELIB_UNSET;
+ int len = 0;
+
+ while ((**ptr < '0') || (**ptr > '9')) {
+ if (**ptr == '\0') {
+ return TIMELIB_UNSET;
+ }
+ ++*ptr;
+ }
+ begin = *ptr;
+ while ((**ptr >= '0') && (**ptr <= '9') && len < max_length) {
+ ++*ptr;
+ ++len;
+ }
+ end = *ptr;
+ str = calloc(1, end - begin + 1);
+ memcpy(str, begin, end - begin);
+ tmp_nr = strtoll(str, NULL, 10);
+ free(str);
+ return tmp_nr;
+}
+
+static timelib_ull timelib_get_unsigned_nr(char **ptr, int max_length)
+{
+ timelib_ull dir = 1;
+
+ while (((**ptr < '0') || (**ptr > '9')) && (**ptr != '+') && (**ptr != '-')) {
+ if (**ptr == '\0') {
+ return TIMELIB_UNSET;
+ }
+ ++*ptr;
+ }
+
+ while (**ptr == '+' || **ptr == '-')
+ {
+ if (**ptr == '-') {
+ dir *= -1;
+ }
+ ++*ptr;
+ }
+ return dir * timelib_get_nr(ptr, max_length);
+}
+
+static long timelib_parse_tz_cor(char **ptr)
+{
+ char *begin = *ptr, *end;
+ long tmp;
+
+ while (**ptr != '\0') {
+ ++*ptr;
+ }
+ end = *ptr;
+ switch (end - begin) {
+ case 1:
+ case 2:
+ return HOUR(strtol(begin, NULL, 10));
+ break;
+ case 3:
+ case 4:
+ if (begin[1] == ':') {
+ tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 2, NULL, 10);
+ return tmp;
+ } else if (begin[2] == ':') {
+ tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10);
+ return tmp;
+ } else {
+ tmp = strtol(begin, NULL, 10);
+ return HOUR(tmp / 100) + tmp % 100;
+ }
+ case 5:
+ tmp = HOUR(strtol(begin, NULL, 10)) + strtol(begin + 3, NULL, 10);
+ return tmp;
+ }
+ return 0;
+}
+
+static void timelib_eat_spaces(char **ptr)
+{
+ while (**ptr == ' ' || **ptr == '\t') {
+ ++*ptr;
+ }
+}
+
+static void timelib_eat_until_separator(char **ptr)
+{
+ while (strchr(" \t.,:;/-0123456789", **ptr) == NULL) {
+ ++*ptr;
+ }
+}
+
+static long timelib_get_zone(char **ptr, int *dst, timelib_time *t, int *tz_not_found, const timelib_tzdb *tzdb)
+{
+ long retval = 0;
+
+ *tz_not_found = 0;
+
+ while (**ptr == ' ' || **ptr == '\t' || **ptr == '(') {
+ ++*ptr;
+ }
+ if ((*ptr)[0] == 'G' && (*ptr)[1] == 'M' && (*ptr)[2] == 'T' && ((*ptr)[3] == '+' || (*ptr)[3] == '-')) {
+ *ptr += 3;
+ }
+ if (**ptr == '+') {
+ ++*ptr;
+ t->is_localtime = 1;
+ t->zone_type = TIMELIB_ZONETYPE_OFFSET;
+ *tz_not_found = 0;
+ t->dst = 0;
+
+ retval = -1 * timelib_parse_tz_cor(ptr);
+ } else if (**ptr == '-') {
+ ++*ptr;
+ t->is_localtime = 1;
+ t->zone_type = TIMELIB_ZONETYPE_OFFSET;
+ *tz_not_found = 0;
+ t->dst = 0;
+
+ retval = timelib_parse_tz_cor(ptr);
+ }
+ while (**ptr == ')') {
+ ++*ptr;
+ }
+ return retval;
+}
+
+#define timelib_split_free(arg) { \
+ int i; \
+ for (i = 0; i < arg.c; i++) { \
+ free(arg.v[i]); \
+ } \
+ if (arg.v) { \
+ free(arg.v); \
+ } \
+}
+
+static int scan(Scanner *s)
+{
+ uchar *cursor = s->cur;
+ char *str, *ptr = NULL;
+
+std:
+ s->tok = cursor;
+ s->len = 0;
+/*!re2c
+
+/* */
+any = [\000-\377];
+number = [0-9]+;
+
+hour24lz = [01][0-9] | "2"[0-4];
+minutelz = [0-5][0-9];
+monthlz = "0" [1-9] | "1" [0-2];
+daylz = "0" [1-9] | [1-2][0-9] | "3" [01];
+secondlz = minutelz;
+year4 = [0-9]{4};
+weekofyear = "0"[1-9] | [1-4][0-9] | "5"[0-3];
+
+space = [ \t]+;
+datetimebasic = year4 monthlz daylz "T" hour24lz minutelz secondlz "Z";
+datetimeextended = year4 "-" monthlz "-" daylz "T" hour24lz ':' minutelz ':' secondlz "Z";
+period = "P" (number "Y")? (number "M")? (number "W")? (number "D")? ("T" (number "H")? (number "M")? (number "S")?)?;
+
+recurrences = "R" number;
+
+isoweekday = year4 "-"? "W" weekofyear "-"? [0-7];
+isoweek = year4 "-"? "W" weekofyear;
+
+*/
+
+/*!re2c
+ /* so that vim highlights correctly */
+ recurrences
+ {
+ DEBUG_OUTPUT("recurrences");
+ TIMELIB_INIT;
+ ptr++;
+ s->recurrences = timelib_get_unsigned_nr((char **) &ptr, 9);
+ TIMELIB_DEINIT;
+ s->have_recurrences = 1;
+ return TIMELIB_PERIOD;
+ }
+
+ datetimebasic| datetimeextended
+ {
+ timelib_time *current;
+
+ if (s->have_date || s->have_period) {
+ current = s->end;
+ s->have_end_date = 1;
+ } else {
+ current = s->begin;
+ s->have_begin_date = 1;
+ }
+ DEBUG_OUTPUT("datetimebasic | datetimeextended");
+ TIMELIB_INIT;
+ current->y = timelib_get_nr((char **) &ptr, 4);
+ current->m = timelib_get_nr((char **) &ptr, 2);
+ current->d = timelib_get_nr((char **) &ptr, 2);
+ current->h = timelib_get_nr((char **) &ptr, 2);
+ current->i = timelib_get_nr((char **) &ptr, 2);
+ current->s = timelib_get_nr((char **) &ptr, 2);
+ s->have_date = 1;
+ TIMELIB_DEINIT;
+ return TIMELIB_ISO_DATE;
+ }
+
+ period
+ {
+ timelib_sll nr;
+ int in_time = 0;
+ DEBUG_OUTPUT("period");
+ TIMELIB_INIT;
+ ptr++;
+ do {
+ if ( *ptr == 'T' ) {
+ in_time = 1;
+ ptr++;
+ }
+ if ( *ptr == '\0' ) {
+ add_error(s, "Missing expected time part");
+ break;
+ }
+
+ nr = timelib_get_unsigned_nr((char **) &ptr, 4);
+ switch (*ptr) {
+ case 'Y': s->period->y = nr; break;
+ case 'W': s->period->d = nr * 7; break;
+ case 'D': s->period->d = nr; break;
+ case 'H': s->period->h = nr; break;
+ case 'S': s->period->s = nr; break;
+ case 'M':
+ if (in_time) {
+ s->period->i = nr;
+ } else {
+ s->period->m = nr;
+ }
+ break;
+ default:
+ add_error(s, "Undefined period specifier");
+ break;
+ }
+ ptr++;
+ } while (*ptr);
+ s->have_period = 1;
+ TIMELIB_DEINIT;
+ return TIMELIB_PERIOD;
+ }
+
+ [ .,\t/]
+ {
+ goto std;
+ }
+
+ "\000"|"\n"
+ {
+ s->pos = cursor; s->line++;
+ goto std;
+ }
+
+ any
+ {
+ add_error(s, "Unexpected character");
+ goto std;
+ }
+*/
+}
+
+/*!max:re2c */
+
+void timelib_strtointerval(char *s, int len,
+ timelib_time **begin, timelib_time **end,
+ timelib_rel_time **period, int *recurrences,
+ struct timelib_error_container **errors)
+{
+ 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;
+
+ if (len > 0) {
+ while (isspace(*s) && s < e) {
+ s++;
+ }
+ while (isspace(*e) && e > s) {
+ e--;
+ }
+ }
+ if (e - s < 0) {
+ add_error(&in, "Empty string");
+ if (errors) {
+ *errors = in.errors;
+ } else {
+ timelib_error_container_dtor(in.errors);
+ }
+ return;
+ }
+ e++;
+
+ /* init cursor */
+ in.str = malloc((e - s) + YYMAXFILL);
+ memset(in.str, 0, (e - s) + YYMAXFILL);
+ memcpy(in.str, s, (e - s));
+ in.lim = in.str + (e - s) + YYMAXFILL;
+ in.cur = in.str;
+
+ /* init value containers */
+ in.begin = timelib_time_ctor();
+ in.begin->y = TIMELIB_UNSET;
+ in.begin->d = TIMELIB_UNSET;
+ in.begin->m = TIMELIB_UNSET;
+ in.begin->h = TIMELIB_UNSET;
+ in.begin->i = TIMELIB_UNSET;
+ in.begin->s = TIMELIB_UNSET;
+ in.begin->f = TIMELIB_UNSET;
+ in.begin->z = TIMELIB_UNSET;
+ in.begin->dst = TIMELIB_UNSET;
+ in.begin->is_localtime = 0;
+ in.begin->zone_type = 0;
+
+ in.end = timelib_time_ctor();
+ in.end->y = TIMELIB_UNSET;
+ in.end->d = TIMELIB_UNSET;
+ in.end->m = TIMELIB_UNSET;
+ in.end->h = TIMELIB_UNSET;
+ in.end->i = TIMELIB_UNSET;
+ in.end->s = TIMELIB_UNSET;
+ in.end->f = TIMELIB_UNSET;
+ in.end->z = TIMELIB_UNSET;
+ in.end->dst = TIMELIB_UNSET;
+ in.end->is_localtime = 0;
+ in.end->zone_type = 0;
+
+ in.period = timelib_rel_time_ctor();
+ in.period->y = 0;
+ in.period->d = 0;
+ in.period->m = 0;
+ in.period->h = 0;
+ in.period->i = 0;
+ in.period->s = 0;
+ in.period->weekday = 0;
+ in.period->weekday_behavior = 0;
+ in.period->first_last_day_of = 0;
+
+ in.recurrences = 1;
+
+ do {
+ t = scan(&in);
+#ifdef DEBUG_PARSER
+ printf("%d\n", t);
+#endif
+ } while(t != EOI);
+
+ free(in.str);
+ if (errors) {
+ *errors = in.errors;
+ } else {
+ timelib_error_container_dtor(in.errors);
+ }
+ if (in.have_begin_date) {
+ *begin = in.begin;
+ } else {
+ timelib_time_dtor(in.begin);
+ }
+ if (in.have_end_date) {
+ *end = in.end;
+ } else {
+ timelib_time_dtor(in.end);
+ }
+ if (in.have_period) {
+ *period = in.period;
+ } else {
+ timelib_rel_time_dtor(in.period);
+ }
+ if (in.have_recurrences) {
+ *recurrences = in.recurrences;
+ }
+}
+
+
+/*
+ * vim: syntax=c
+ */
return t;
}
+timelib_rel_time* timelib_rel_time_ctor(void)
+{
+ timelib_rel_time *t;
+ t = calloc(1, sizeof(timelib_rel_time));
+
+ return t;
+}
+
void timelib_time_tz_abbr_update(timelib_time* tm, char* tz_abbr)
{
unsigned int i;
TIMELIB_TIME_FREE(t);
}
+void timelib_rel_time_dtor(timelib_rel_time* t)
+{
+ TIMELIB_TIME_FREE(t);
+}
+
timelib_time_offset* timelib_time_offset_ctor(void)
{
timelib_time_offset *t;
TIMELIB_TIME_FREE(tz->timezone_abbr);
TIMELIB_TIME_FREE(tz->leap_times);
TIMELIB_TIME_FREE(tz);
+ tz = NULL;
}
char *timelib_get_tz_abbr_ptr(timelib_time *t)
printf("\n");
}
+void timelib_dump_rel_time(timelib_rel_time *d)
+{
+ printf("%3lldY %3lldM %3lldD / %3lldH %3lldM %3lldS (days: %lld)%s",
+ d->y, d->m, d->d, d->h, d->i, d->s, d->days, d->invert ? " inverted" : "");
+ if (d->first_last_day_of != 0) {
+ switch (d->first_last_day_of) {
+ case 1:
+ printf(" / first day of");
+ break;
+ case 2:
+ printf(" / last day of");
+ break;
+ }
+ }
+ printf("\n");
+}
+
char *timelib_timezone_id_from_abbr(const char *abbr, long gmtoffset, int isdst);
const timelib_tz_lookup_table *timelib_timezone_abbreviations_list(void);
+/* From parse_iso_intervals.re */
+void timelib_strtointerval(char *s, int len,
+ timelib_time **begin, timelib_time **end,
+ timelib_rel_time **period, int *recurrences,
+ struct timelib_error_container **errors);
+
+
/* From tm2unixtime.c */
void timelib_update_ts(timelib_time* time, timelib_tzinfo* tzi);
+void timelib_do_rel_normalize(timelib_time *base, timelib_rel_time *rt);
/* From unixtime2tm.c */
int timelib_apply_localtime(timelib_time *t, unsigned int localtime);
void timelib_tzinfo_dtor(timelib_tzinfo *tz);
timelib_tzinfo* timelib_tzinfo_clone(timelib_tzinfo *tz);
+timelib_rel_time* timelib_rel_time_ctor(void);
+void timelib_rel_time_dtor(timelib_rel_time* t);
+
timelib_time* timelib_time_ctor(void);
void timelib_time_set_option(timelib_time* tm, int option, void* option_value);
void timelib_time_dtor(timelib_time* t);
signed long timelib_date_to_int(timelib_time *d, int *error);
void timelib_dump_date(timelib_time *d, int options);
+void timelib_dump_rel_time(timelib_rel_time *d);
void timelib_decimal_hour_to_hms(double h, int *hour, int *min, int *sec);
double timelib_ts_to_juliandate(timelib_sll ts);
int timelib_astro_rise_set_altitude(timelib_time *time, double lon, double lat, double altit, int upper_limb, double *h_rise, double *h_set, timelib_sll *ts_rise, timelib_sll *ts_set, timelib_sll *ts_transit);
+/* from interval.c */
+timelib_rel_time *timelib_diff(timelib_time *one, timelib_time *two);
+
#endif
int weekday_behavior; /* 0: the current day should *not* be counted when advancing forwards; 1: the current day *should* be counted */
int first_last_day_of;
+ int invert; /* Whether the difference should be inverted */
+ timelib_sll days; /* Contains the number of *days*, instead of Y-M-D differences */
} timelib_rel_time;
typedef struct timelib_time_offset {
return 0;
}
+static int do_range_limit_days_relative(timelib_sll *base_y, timelib_sll *base_m, timelib_sll *y, timelib_sll *m, timelib_sll *d)
+{
+ timelib_sll leapyear;
+ timelib_sll days_this_month;
+ timelib_sll next_month, next_year;
+ timelib_sll days_next_month;
+
+ do_range_limit(1, 13, 12, base_m, base_y);
+
+ leapyear = timelib_is_leap(*base_y);
+ days_this_month = leapyear ? days_in_month_leap[*base_m] : days_in_month[*base_m];
+ next_month = (*base_m) + 1;
+
+ if (next_month > 12) {
+ next_month -= 12;
+ next_year = (*base_y) + 1;
+ } else {
+ next_year = (*base_y);
+ }
+ leapyear = timelib_is_leap(next_year);
+ days_next_month = leapyear ? days_in_month_leap[next_month] : days_in_month[next_month];
+
+ if (*d < 0) {
+ *d += days_this_month;
+ (*m)--;
+ return 1;
+ }
+ if (*d > days_next_month) {
+ *d -= days_next_month;
+ (*m)++;
+ return 1;
+ }
+ return 0;
+}
+
static int do_range_limit_days(timelib_sll *y, timelib_sll *m, timelib_sll *d)
{
timelib_sll leapyear;
time->have_weekday_relative = 0;
}
+void timelib_do_rel_normalize(timelib_time *base, timelib_rel_time *rt)
+{
+ do {} while (do_range_limit(0, 60, 60, &rt->s, &rt->i));
+ do {} while (do_range_limit(0, 60, 60, &rt->i, &rt->h));
+ do {} while (do_range_limit(0, 24, 24, &rt->h, &rt->d));
+ do {} while (do_range_limit(0, 12, 12, &rt->m, &rt->y));
+
+ do {} while (do_range_limit_days_relative(&base->y, &base->m, &rt->y, &rt->m, &rt->d));
+ do {} while (do_range_limit(0, 12, 12, &rt->m, &rt->y));
+}
+
static void do_normalize(timelib_time* time)
{
do {} while (do_range_limit(0, 60, 60, &time->s, &time->i));
}
timelib_time_offset_dtor(before);
timelib_time_offset_dtor(after);
-
+
+ {
+ timelib_time_offset *gmt_offset;
+
+ gmt_offset = timelib_get_time_zone_info(tz->sse + tmp, tzi);
+ tz->z = gmt_offset->offset;
+
+ tz->dst = gmt_offset->is_dst;
+ if (tz->tz_abbr) {
+ free(tz->tz_abbr);
+ }
+ tz->tz_abbr = strdup(gmt_offset->abbr);
+ timelib_time_offset_dtor(gmt_offset);
+ }
return tmp;
}
}
PHP_FE(date_get_last_errors, NULL)
PHP_FE(date_format, NULL)
PHP_FE(date_modify, NULL)
+ PHP_FE(date_add, NULL)
+ PHP_FE(date_sub, NULL)
PHP_FE(date_timezone_get, NULL)
PHP_FE(date_timezone_set, NULL)
PHP_FE(date_offset_get, NULL)
+ PHP_FE(date_diff, NULL)
PHP_FE(date_time_set, NULL)
PHP_FE(date_date_set, NULL)
PHP_FE(timezone_identifiers_list, NULL)
PHP_FE(timezone_abbreviations_list, NULL)
+ PHP_FE(date_interval_format, NULL)
+
/* Options and Configuration */
PHP_FE(date_default_timezone_set, arginfo_date_default_timezone_set)
PHP_FE(date_default_timezone_get, arginfo_date_default_timezone_get)
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(add, date_add, NULL, 0)
+ PHP_ME_MAPPING(sub, date_sub, NULL, 0)
PHP_ME_MAPPING(getTimezone, date_timezone_get, NULL, 0)
PHP_ME_MAPPING(setTimezone, date_timezone_set, NULL, 0)
PHP_ME_MAPPING(getOffset, date_offset_get, NULL, 0)
PHP_ME_MAPPING(setISODate, date_isodate_set, NULL, 0)
PHP_ME_MAPPING(setTimestamp, date_timestamp_set, NULL, 0)
PHP_ME_MAPPING(getTimestamp, date_timestamp_get, NULL, 0)
+ PHP_ME_MAPPING(diff, date_diff, NULL, 0)
{NULL, NULL, NULL}
};
{NULL, NULL, NULL}
};
+const zend_function_entry date_funcs_interval[] = {
+ PHP_ME(DateInterval, __construct, NULL, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(format, date_interval_format, NULL, 0)
+ {NULL, NULL, NULL}
+};
+
static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC);
static void date_register_classes(TSRMLS_D);
-static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC);
/* }}} */
ZEND_DECLARE_MODULE_GLOBALS(date)
PHP_INI_END()
/* }}} */
-zend_class_entry *date_ce_date, *date_ce_timezone;
+zend_class_entry *date_ce_date, *date_ce_timezone, *date_ce_interval;
static zend_object_handlers date_object_handlers_date;
static zend_object_handlers date_object_handlers_timezone;
+static zend_object_handlers date_object_handlers_interval;
typedef struct _php_date_obj php_date_obj;
typedef struct _php_timezone_obj php_timezone_obj;
+typedef struct _php_interval_obj php_interval_obj;
struct _php_date_obj {
zend_object std;
} tzi;
};
+struct _php_interval_obj {
+ zend_object std;
+ timelib_rel_time *diff;
+ HashTable *props;
+ int initialized;
+};
+
#define DATE_SET_CONTEXT \
zval *object; \
object = getThis(); \
static void date_object_free_storage_date(void *object TSRMLS_DC);
static void date_object_free_storage_timezone(void *object TSRMLS_DC);
+static void date_object_free_storage_interval(void *object TSRMLS_DC);
+
static zend_object_value date_object_new_date(zend_class_entry *class_type TSRMLS_DC);
static zend_object_value date_object_new_timezone(zend_class_entry *class_type TSRMLS_DC);
+static zend_object_value date_object_new_interval(zend_class_entry *class_type TSRMLS_DC);
+
static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC);
+static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC);
+static zend_object_value date_object_clone_interval(zval *this_ptr TSRMLS_DC);
+
static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC);
static HashTable *date_object_get_properties(zval *object TSRMLS_DC);
-static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC);
+
+zval *date_interval_read_property(zval *object, zval *member, int type TSRMLS_DC);
+void date_interval_write_property(zval *object, zval *member, zval *value TSRMLS_DC);
/* This is need to ensure that session extension request shutdown occurs 1st, because it uses the date extension */
static const zend_module_dep date_deps[] = {
static void date_register_classes(TSRMLS_D)
{
- zend_class_entry ce_date, ce_timezone;
+ zend_class_entry ce_date, ce_timezone, ce_interval;
INIT_CLASS_ENTRY(ce_date, "DateTime", date_funcs_date);
ce_date.create_object = date_object_new_date;
REGISTER_TIMEZONE_CLASS_CONST_STRING("UTC", PHP_DATE_TIMEZONE_GROUP_UTC);
REGISTER_TIMEZONE_CLASS_CONST_STRING("ALL", PHP_DATE_TIMEZONE_GROUP_ALL);
REGISTER_TIMEZONE_CLASS_CONST_STRING("ALL_WITH_BC", PHP_DATE_TIMEZONE_GROUP_ALL_W_BC);
+
+ INIT_CLASS_ENTRY(ce_interval, "DateInterval", date_funcs_interval);
+ ce_interval.create_object = date_object_new_interval;
+ date_ce_interval = zend_register_internal_class_ex(&ce_interval, NULL, NULL TSRMLS_CC);
+ memcpy(&date_object_handlers_interval, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ date_object_handlers_interval.clone_obj = date_object_clone_interval;
+ date_object_handlers_interval.read_property = date_interval_read_property;
+ date_object_handlers_interval.write_property = date_interval_write_property;
}
static inline zend_object_value date_object_new_date_ex(zend_class_entry *class_type, php_date_obj **ptr TSRMLS_DC)
return new_ov;
}
+static inline zend_object_value date_object_new_interval_ex(zend_class_entry *class_type, php_interval_obj **ptr TSRMLS_DC)
+{
+ php_interval_obj *intern;
+ zend_object_value retval;
+ zval *tmp;
+
+ intern = emalloc(sizeof(php_interval_obj));
+ memset(intern, 0, sizeof(php_interval_obj));
+ if (ptr) {
+ *ptr = intern;
+ }
+
+ zend_object_std_init(&intern->std, class_type TSRMLS_CC);
+ zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+
+ retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_interval, NULL TSRMLS_CC);
+ retval.handlers = &date_object_handlers_interval;
+
+ return retval;
+}
+
+static zend_object_value date_object_new_interval(zend_class_entry *class_type TSRMLS_DC)
+{
+ return date_object_new_interval_ex(class_type, NULL TSRMLS_CC);
+}
+
+static zend_object_value date_object_clone_interval(zval *this_ptr TSRMLS_DC)
+{
+ php_interval_obj *new_obj = NULL;
+ php_interval_obj *old_obj = (php_interval_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
+ zend_object_value new_ov = date_object_new_interval_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
+
+ zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
+
+ /** FIX ME ADD CLONE STUFF **/
+ return new_ov;
+}
+
static void date_object_free_storage_date(void *object TSRMLS_DC)
{
php_date_obj *intern = (php_date_obj *)object;
efree(object);
}
+static void date_object_free_storage_interval(void *object TSRMLS_DC)
+{
+ php_interval_obj *intern = (php_interval_obj *)object;
+
+ timelib_rel_time_dtor(intern->diff);
+ zend_object_std_dtor(&intern->std TSRMLS_CC);
+ efree(object);
+}
+
/* Advanced Interface */
static zval * date_instantiate(zend_class_entry *pce, zval *object TSRMLS_DC)
{
}
/* }}} */
+/* {{{ proto void date_add(DateTime object, DateInterval interval)
+ Adds an interval to the current date in object.
+*/
+PHP_FUNCTION(date_add)
+{
+ zval *object, *interval;
+ php_date_obj *dateobj;
+ php_interval_obj *intobj;
+ int bias = 1;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) {
+ RETURN_FALSE;
+ }
+ dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
+ DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
+ intobj = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC);
+ DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval);
+
+ if (intobj->diff->invert) {
+ bias = -1;
+ }
+
+ dateobj->time->relative.y = intobj->diff->y * bias;
+ dateobj->time->relative.m = intobj->diff->m * bias;
+ dateobj->time->relative.d = intobj->diff->d * bias;
+ dateobj->time->relative.h = intobj->diff->h * bias;
+ dateobj->time->relative.i = intobj->diff->i * bias;
+ dateobj->time->relative.s = intobj->diff->s * bias;
+ dateobj->time->relative.weekday = 0;
+ dateobj->time->have_relative = 1;
+ dateobj->time->have_weekday_relative = 0;
+ dateobj->time->sse_uptodate = 0;
+
+ timelib_update_ts(dateobj->time, NULL);
+ timelib_update_from_sse(dateobj->time);
+}
+/* }}} */
+
+/* {{{ proto void date_sub(DateTime object, DateInterval interval)
+ Subtracts an interval to the current date in object.
+*/
+PHP_FUNCTION(date_sub)
+{
+ zval *object, *interval;
+ php_date_obj *dateobj;
+ php_interval_obj *intobj;
+ int bias = 1;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) {
+ RETURN_FALSE;
+ }
+ dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
+ DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
+ intobj = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC);
+ DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval);
+
+ if (intobj->diff->invert) {
+ bias = -1;
+ }
+
+ dateobj->time->relative.y = 0 - (intobj->diff->y * bias);
+ dateobj->time->relative.m = 0 - (intobj->diff->m * bias);
+ dateobj->time->relative.d = 0 - (intobj->diff->d * bias);
+ dateobj->time->relative.h = 0 - (intobj->diff->h * bias);
+ dateobj->time->relative.i = 0 - (intobj->diff->i * bias);
+ dateobj->time->relative.s = 0 - (intobj->diff->s * bias);
+ dateobj->time->relative.weekday = 0;
+ dateobj->time->have_relative = 1;
+ dateobj->time->have_weekday_relative = 0;
+ dateobj->time->sse_uptodate = 0;
+
+ timelib_update_ts(dateobj->time, NULL);
+ timelib_update_from_sse(dateobj->time);
+}
+/* }}} */
+
/* {{{ proto DateTimeZone date_timezone_get(DateTime object)
Return new DateTimeZone object relative to give DateTime
*/
}
/* }}} */
+/* {{{ proto DateInterval date_diff(DateTime object [, bool absolute])
+ Returns the difference between two DateTime objects.
+*/
+PHP_FUNCTION(date_diff)
+{
+ zval *object1, *object2;
+ php_date_obj *dateobj1, *dateobj2;
+ php_interval_obj *interval;
+ long absolute = 0;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO|l", &object1, date_ce_date, &object2, date_ce_date, &absolute) == FAILURE) {
+ RETURN_FALSE;
+ }
+ dateobj1 = (php_date_obj *) zend_object_store_get_object(object1 TSRMLS_CC);
+ dateobj2 = (php_date_obj *) zend_object_store_get_object(object2 TSRMLS_CC);
+ DATE_CHECK_INITIALIZED(dateobj1->time, DateTime);
+ DATE_CHECK_INITIALIZED(dateobj2->time, DateTime);
+ timelib_update_ts(dateobj1->time, NULL);
+ timelib_update_ts(dateobj2->time, NULL);
+
+ date_instantiate(date_ce_interval, return_value TSRMLS_CC);
+ interval = zend_object_store_get_object(return_value TSRMLS_CC);
+ interval->diff = timelib_diff(dateobj1->time, dateobj2->time);
+ if (absolute) {
+ interval->diff->invert = 0;
+ }
+ interval->initialized = 1;
+}
+/* }}} */
+
static int timezone_initialize(timelib_tzinfo **tzi, /*const*/ char *tz TSRMLS_DC)
{
char *tzid;
}
}
+static int date_interval_initialize(timelib_rel_time **rt, /*const*/ char *format, int format_length TSRMLS_DC)
+{
+ timelib_time *b = NULL, *e = NULL;
+ timelib_rel_time *p = NULL;
+ int r = 0;
+ int retval = 0;
+ struct timelib_error_container *errors;
+
+ timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors);
+
+ if (errors->error_count > 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad format (%s)", format);
+ retval = FAILURE;
+ } else {
+ *rt = p;
+ retval = SUCCESS;
+ }
+ timelib_error_container_dtor(errors);
+ return retval;
+}
+
+/* {{{ date_interval_read_property */
+zval *date_interval_read_property(zval *object, zval *member, int type TSRMLS_DC)
+{
+ php_interval_obj *obj;
+ zval *retval;
+ zval tmp_member;
+ timelib_sll value = -1;
+
+ if (member->type != IS_STRING) {
+ tmp_member = *member;
+ zval_copy_ctor(&tmp_member);
+ convert_to_string(&tmp_member);
+ member = &tmp_member;
+ }
+
+ obj = (php_interval_obj *)zend_objects_get_address(object TSRMLS_CC);
+
+#define GET_VALUE_FROM_STRUCT(n,m) \
+ if (strcmp(Z_STRVAL_P(member), m) == 0) { \
+ value = obj->diff->n; \
+ }
+ GET_VALUE_FROM_STRUCT(y, "y");
+ GET_VALUE_FROM_STRUCT(m, "m");
+ GET_VALUE_FROM_STRUCT(d, "d");
+ GET_VALUE_FROM_STRUCT(h, "h");
+ GET_VALUE_FROM_STRUCT(i, "i");
+ GET_VALUE_FROM_STRUCT(s, "s");
+ GET_VALUE_FROM_STRUCT(invert, "invert");
+ GET_VALUE_FROM_STRUCT(days, "days");
+
+ if (value == -1) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unknown property (%s)", Z_STRVAL_P(member));
+ }
+
+ ALLOC_INIT_ZVAL(retval);
+ ZVAL_LONG(retval, value);
+
+ if (member == &tmp_member) {
+ zval_dtor(member);
+ }
+
+ return retval;
+}
+/* }}} */
+
+/* {{{ date_interval_write_property */
+void date_interval_write_property(zval *object, zval *member, zval *value TSRMLS_DC)
+{
+ php_interval_obj *obj;
+ zval tmp_member, tmp_value;
+
+ if (member->type != IS_STRING) {
+ tmp_member = *member;
+ zval_copy_ctor(&tmp_member);
+ convert_to_string(&tmp_member);
+ member = &tmp_member;
+ }
+ obj = (php_interval_obj *)zend_objects_get_address(object TSRMLS_CC);
+
+#define SET_VALUE_FROM_STRUCT(n,m) \
+ if (strcmp(Z_STRVAL_P(member), m) == 0) { \
+ if (value->type != IS_LONG) { \
+ tmp_value = *value; \
+ zval_copy_ctor(&tmp_value); \
+ convert_to_long(&tmp_value); \
+ value = &tmp_value; \
+ } \
+ obj->diff->n = Z_LVAL_P(value); \
+ if (value == &tmp_value) { \
+ zval_dtor(value); \
+ } \
+ }
+
+ SET_VALUE_FROM_STRUCT(y, "y");
+ SET_VALUE_FROM_STRUCT(m, "m");
+ SET_VALUE_FROM_STRUCT(d, "d");
+ SET_VALUE_FROM_STRUCT(h, "h");
+ SET_VALUE_FROM_STRUCT(i, "i");
+ SET_VALUE_FROM_STRUCT(s, "s");
+ SET_VALUE_FROM_STRUCT(invert, "invert");
+
+ if (value == -1) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unknown property (%s)", Z_STRVAL_P(member));
+ }
+
+ if (member == &tmp_member) {
+ zval_dtor(member);
+ }
+}
+/* }}} */
+
+
/* {{{ proto DateTimeZone timezone_open(string timezone)
Returns new DateTimeZone object
*/
dateobj = (php_date_obj *) zend_object_store_get_object(dateobject TSRMLS_CC);
DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
- offset = timelib_get_time_zone_info(dateobj->time->sse, tzobj->tzi.tz);
- RETVAL_LONG(offset->offset);
- timelib_time_offset_dtor(offset);
+ switch (tzobj->type) {
+ case TIMELIB_ZONETYPE_ID:
+ offset = timelib_get_time_zone_info(dateobj->time->sse, tzobj->tzi.tz);
+ RETVAL_LONG(offset->offset);
+ timelib_time_offset_dtor(offset);
+ break;
+ case TIMELIB_ZONETYPE_OFFSET:
+ RETURN_LONG(tzobj->tzi.utc_offset * -60);
+ break;
+ case TIMELIB_ZONETYPE_ABBR:
+ RETURN_LONG((tzobj->tzi.z.utc_offset - (tzobj->tzi.z.dst*60)) * -60);
+ break;
+ }
}
/* }}} */
}
/* }}} */
+/* {{{ proto DateInterval::__construct([string interval_spec])
+ Creates new DateInterval object.
+*/
+PHP_METHOD(DateInterval, __construct)
+{
+ char *interval_string = NULL;
+ int interval_string_length;
+ php_interval_obj *diobj;
+ timelib_rel_time *reltime;
+
+ php_set_error_handling(EH_THROW, NULL TSRMLS_CC);
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &interval_string, &interval_string_length) == SUCCESS) {
+ if (date_interval_initialize(&reltime, interval_string, interval_string_length TSRMLS_CC) == SUCCESS) {
+ diobj = zend_object_store_get_object(getThis() TSRMLS_CC);
+ diobj->diff = reltime;
+ diobj->initialized = 1;
+ } else {
+ ZVAL_NULL(getThis());
+ }
+ }
+ php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ date_interval_format - */
+static char *date_interval_format(char *format, int format_len, timelib_rel_time *t)
+{
+ smart_str string = {0};
+ int i, length, have_format_spec = 0;
+ char buffer[33];
+
+ if (!format_len) {
+ return estrdup("");
+ }
+
+ for (i = 0; i < format_len; i++) {
+ if (have_format_spec) {
+ switch (format[i]) {
+ case 'Y': length = slprintf(buffer, 32, "%02d", (int) t->y); break;
+ case 'y': length = slprintf(buffer, 32, "%d", (int) t->y); break;
+
+ case 'M': length = slprintf(buffer, 32, "%02d", (int) t->m); break;
+ case 'm': length = slprintf(buffer, 32, "%d", (int) t->m); break;
+
+ case 'D': length = slprintf(buffer, 32, "%02d", (int) t->d); break;
+ case 'd': length = slprintf(buffer, 32, "%d", (int) t->d); break;
+
+ case 'H': length = slprintf(buffer, 32, "%02d", (int) t->h); break;
+ case 'h': length = slprintf(buffer, 32, "%d", (int) t->h); break;
+
+ case 'I': length = slprintf(buffer, 32, "%02d", (int) t->i); break;
+ case 'i': length = slprintf(buffer, 32, "%d", (int) t->i); break;
+
+ case 'S': length = slprintf(buffer, 32, "%02d", (int) t->s); break;
+ case 's': length = slprintf(buffer, 32, "%d", (int) t->s); break;
+
+ case 'a': length = slprintf(buffer, 32, "%d", (int) t->days); break;
+ case 'r': length = slprintf(buffer, 32, "%s", t->invert ? "-" : ""); break;
+ case 'R': length = slprintf(buffer, 32, "%c", t->invert ? '-' : '+'); break;
+
+ case '%': length = slprintf(buffer, 32, "%%"); break;
+ default: buffer[0] = '%'; buffer[1] = format[i]; buffer[2] = '\0'; length = 2; break;
+ }
+ smart_str_appendl(&string, buffer, length);
+ have_format_spec = 0;
+ } else {
+ if (format[i] == '%') {
+ have_format_spec = 1;
+ } else {
+ smart_str_appendc(&string, format[i]);
+ }
+ }
+ }
+
+ smart_str_0(&string);
+
+ return string.c;
+}
+/* }}} */
+
+/* {{{ proto string date_interval_format(DateInterval object)
+ Formats the interval.
+*/
+PHP_FUNCTION(date_interval_format)
+{
+ zval *object;
+ php_interval_obj *diobj;
+ char *format;
+ int format_len;
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_interval, &format, &format_len) == FAILURE) {
+ RETURN_FALSE;
+ }
+ diobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC);
+ DATE_CHECK_INITIALIZED(diobj->initialized, DateInterval);
+
+ RETURN_STRING(date_interval_format(format, format_len, diobj->diff), 0);
+}
+/* }}} */
static int check_id_allowed(char *id, long what)
{
if (what & PHP_DATE_TIMEZONE_GROUP_AFRICA && strncasecmp(id, "Africa/", 7) == 0) return 1;
PHP_FUNCTION(date_get_last_errors);
PHP_FUNCTION(date_format);
PHP_FUNCTION(date_modify);
+PHP_FUNCTION(date_add);
+PHP_FUNCTION(date_sub);
PHP_FUNCTION(date_timezone_get);
PHP_FUNCTION(date_timezone_set);
PHP_FUNCTION(date_offset_get);
+PHP_FUNCTION(date_diff);
PHP_FUNCTION(date_time_set);
PHP_FUNCTION(date_date_set);
PHP_FUNCTION(timezone_identifiers_list);
PHP_FUNCTION(timezone_abbreviations_list);
+PHP_METHOD(DateInterval, __construct);
+PHP_FUNCTION(date_interval_format);
+
/* Options and Configuration */
PHP_FUNCTION(date_default_timezone_set);
PHP_FUNCTION(date_default_timezone_get);
--- /dev/null
+--TEST--
+Bug #44742 (timezone_offset_get() causes segmentation faults)
+--FILE--
+<?php
+$dates = array(
+ "2008-04-11 00:00:00+0000",
+ "2008-04-11 00:00:00+0200",
+ "2008-04-11 00:00:00+0330",
+ "2008-04-11 00:00:00-0500",
+ "2008-04-11 00:00:00-1130",
+ "2008-04-11 00:00:00 CEST",
+ "2008-04-11 00:00:00 CET",
+ "2008-04-11 00:00:00 UTC",
+ "2008-04-11 00:00:00 America/New_York",
+ "2008-04-11 00:00:00 Europe/Oslo",
+ "2008-04-11 00:00:00 Asia/Singapore",
+);
+foreach ($dates as $date)
+{
+ $date = date_create($date);
+ var_dump(timezone_offset_get(date_timezone_get($date), $date));
+}
+?>
+--EXPECT--
+int(0)
+int(7200)
+int(12600)
+int(-18000)
+int(-41400)
+int(7200)
+int(3600)
+int(0)
+int(-14400)
+int(7200)
+int(28800)