PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/date - php_date.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 1863 2092 89.1 %
Date: 2014-04-16 Functions: 147 162 90.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 5                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2014 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Derick Rethans <derick@derickrethans.nl>                    |
      16             :    +----------------------------------------------------------------------+
      17             :  */
      18             : 
      19             : /* $Id$ */
      20             : 
      21             : #include "php.h"
      22             : #include "php_streams.h"
      23             : #include "php_main.h"
      24             : #include "php_globals.h"
      25             : #include "php_ini.h"
      26             : #include "ext/standard/info.h"
      27             : #include "ext/standard/php_versioning.h"
      28             : #include "ext/standard/php_math.h"
      29             : #include "php_date.h"
      30             : #include "zend_interfaces.h"
      31             : #include "lib/timelib.h"
      32             : #include <time.h>
      33             : 
      34             : #ifdef PHP_WIN32
      35             : static __inline __int64 php_date_llabs( __int64 i ) { return i >= 0? i: -i; }
      36             : #elif defined(__GNUC__) && __GNUC__ < 3
      37             : static __inline __int64_t php_date_llabs( __int64_t i ) { return i >= 0 ? i : -i; }
      38             : #else
      39        6200 : static inline long long php_date_llabs( long long i ) { return i >= 0 ? i : -i; }
      40             : #endif
      41             : 
      42             : #ifdef PHP_WIN32
      43             : #define DATE_I64_BUF_LEN 65
      44             : # define DATE_I64A(i, s, len) _i64toa_s(i, s, len, 10)
      45             : # define DATE_A64I(i, s) i = _atoi64(s)
      46             : #else
      47             : #define DATE_I64_BUF_LEN 65
      48             : # define DATE_I64A(i, s, len) \
      49             :         do { \
      50             :                 int st = snprintf(s, len, "%lld", i); \
      51             :                 s[st] = '\0'; \
      52             :         } while (0);
      53             : # define DATE_A64I(i, s) i = atoll(s)
      54             : #endif
      55             : 
      56             : /* {{{ arginfo */
      57             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date, 0, 0, 1)
      58             :         ZEND_ARG_INFO(0, format)
      59             :         ZEND_ARG_INFO(0, timestamp)
      60             : ZEND_END_ARG_INFO()
      61             : 
      62             : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmdate, 0, 0, 1)
      63             :         ZEND_ARG_INFO(0, format)
      64             :         ZEND_ARG_INFO(0, timestamp)
      65             : ZEND_END_ARG_INFO()
      66             : 
      67             : ZEND_BEGIN_ARG_INFO_EX(arginfo_idate, 0, 0, 1)
      68             :         ZEND_ARG_INFO(0, format)
      69             :         ZEND_ARG_INFO(0, timestamp)
      70             : ZEND_END_ARG_INFO()
      71             : 
      72             : ZEND_BEGIN_ARG_INFO_EX(arginfo_strtotime, 0, 0, 1)
      73             :         ZEND_ARG_INFO(0, time)
      74             :         ZEND_ARG_INFO(0, now)
      75             : ZEND_END_ARG_INFO()
      76             : 
      77             : ZEND_BEGIN_ARG_INFO_EX(arginfo_mktime, 0, 0, 0)
      78             :         ZEND_ARG_INFO(0, hour)
      79             :         ZEND_ARG_INFO(0, min)
      80             :         ZEND_ARG_INFO(0, sec)
      81             :         ZEND_ARG_INFO(0, mon)
      82             :         ZEND_ARG_INFO(0, day)
      83             :         ZEND_ARG_INFO(0, year)
      84             : ZEND_END_ARG_INFO()
      85             : 
      86             : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmmktime, 0, 0, 0)
      87             :         ZEND_ARG_INFO(0, hour)
      88             :         ZEND_ARG_INFO(0, min)
      89             :         ZEND_ARG_INFO(0, sec)
      90             :         ZEND_ARG_INFO(0, mon)
      91             :         ZEND_ARG_INFO(0, day)
      92             :         ZEND_ARG_INFO(0, year)
      93             : ZEND_END_ARG_INFO()
      94             : 
      95             : ZEND_BEGIN_ARG_INFO(arginfo_checkdate, 0)
      96             :         ZEND_ARG_INFO(0, month)
      97             :         ZEND_ARG_INFO(0, day)
      98             :         ZEND_ARG_INFO(0, year)
      99             : ZEND_END_ARG_INFO()
     100             : 
     101             : ZEND_BEGIN_ARG_INFO_EX(arginfo_strftime, 0, 0, 1)
     102             :         ZEND_ARG_INFO(0, format)
     103             :         ZEND_ARG_INFO(0, timestamp)
     104             : ZEND_END_ARG_INFO()
     105             : 
     106             : ZEND_BEGIN_ARG_INFO_EX(arginfo_gmstrftime, 0, 0, 1)
     107             :         ZEND_ARG_INFO(0, format)
     108             :         ZEND_ARG_INFO(0, timestamp)
     109             : ZEND_END_ARG_INFO()
     110             : 
     111             : ZEND_BEGIN_ARG_INFO(arginfo_time, 0)
     112             : ZEND_END_ARG_INFO()
     113             : 
     114             : ZEND_BEGIN_ARG_INFO_EX(arginfo_localtime, 0, 0, 0)
     115             :         ZEND_ARG_INFO(0, timestamp)
     116             :         ZEND_ARG_INFO(0, associative_array)
     117             : ZEND_END_ARG_INFO()
     118             : 
     119             : ZEND_BEGIN_ARG_INFO_EX(arginfo_getdate, 0, 0, 0)
     120             :         ZEND_ARG_INFO(0, timestamp)
     121             : ZEND_END_ARG_INFO()
     122             : 
     123             : ZEND_BEGIN_ARG_INFO(arginfo_date_default_timezone_set, 0)
     124             :         ZEND_ARG_INFO(0, timezone_identifier)
     125             : ZEND_END_ARG_INFO()
     126             : 
     127             : ZEND_BEGIN_ARG_INFO(arginfo_date_default_timezone_get, 0)
     128             : ZEND_END_ARG_INFO()
     129             : 
     130             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sunrise, 0, 0, 1)
     131             :         ZEND_ARG_INFO(0, time)
     132             :         ZEND_ARG_INFO(0, format)
     133             :         ZEND_ARG_INFO(0, latitude)
     134             :         ZEND_ARG_INFO(0, longitude)
     135             :         ZEND_ARG_INFO(0, zenith)
     136             :         ZEND_ARG_INFO(0, gmt_offset)
     137             : ZEND_END_ARG_INFO()
     138             : 
     139             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sunset, 0, 0, 1)
     140             :         ZEND_ARG_INFO(0, time)
     141             :         ZEND_ARG_INFO(0, format)
     142             :         ZEND_ARG_INFO(0, latitude)
     143             :         ZEND_ARG_INFO(0, longitude)
     144             :         ZEND_ARG_INFO(0, zenith)
     145             :         ZEND_ARG_INFO(0, gmt_offset)
     146             : ZEND_END_ARG_INFO()
     147             : 
     148             : ZEND_BEGIN_ARG_INFO(arginfo_date_sun_info, 0)
     149             :         ZEND_ARG_INFO(0, time)
     150             :         ZEND_ARG_INFO(0, latitude)
     151             :         ZEND_ARG_INFO(0, longitude)
     152             : ZEND_END_ARG_INFO()
     153             : 
     154             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_create, 0, 0, 0)
     155             :         ZEND_ARG_INFO(0, time)
     156             :         ZEND_ARG_INFO(0, object)
     157             : ZEND_END_ARG_INFO()
     158             : 
     159             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_create_from_format, 0, 0, 2)
     160             :         ZEND_ARG_INFO(0, format)
     161             :         ZEND_ARG_INFO(0, time)
     162             :         ZEND_ARG_INFO(0, object)
     163             : ZEND_END_ARG_INFO()
     164             : 
     165             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_parse, 0, 0, 1)
     166             :         ZEND_ARG_INFO(0, date)
     167             : ZEND_END_ARG_INFO()
     168             : 
     169             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_parse_from_format, 0, 0, 2)
     170             :         ZEND_ARG_INFO(0, format)
     171             :         ZEND_ARG_INFO(0, date)
     172             : ZEND_END_ARG_INFO()
     173             : 
     174             : ZEND_BEGIN_ARG_INFO(arginfo_date_get_last_errors, 0)
     175             : ZEND_END_ARG_INFO()
     176             : 
     177             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_format, 0, 0, 2)
     178             :         ZEND_ARG_INFO(0, object)
     179             :         ZEND_ARG_INFO(0, format)
     180             : ZEND_END_ARG_INFO()
     181             : 
     182             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_format, 0, 0, 1)
     183             :         ZEND_ARG_INFO(0, format)
     184             : ZEND_END_ARG_INFO()
     185             : 
     186             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_modify, 0, 0, 2)
     187             :         ZEND_ARG_INFO(0, object)
     188             :         ZEND_ARG_INFO(0, modify)
     189             : ZEND_END_ARG_INFO()
     190             : 
     191             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_modify, 0, 0, 1)
     192             :         ZEND_ARG_INFO(0, modify)
     193             : ZEND_END_ARG_INFO()
     194             : 
     195             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_add, 0, 0, 2)
     196             :         ZEND_ARG_INFO(0, object)
     197             :         ZEND_ARG_INFO(0, interval)
     198             : ZEND_END_ARG_INFO()
     199             : 
     200             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_add, 0, 0, 1)
     201             :         ZEND_ARG_INFO(0, interval)
     202             : ZEND_END_ARG_INFO()
     203             : 
     204             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_sub, 0, 0, 2)
     205             :         ZEND_ARG_INFO(0, object)
     206             :         ZEND_ARG_INFO(0, interval)
     207             : ZEND_END_ARG_INFO()
     208             : 
     209             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_sub, 0, 0, 1)
     210             :         ZEND_ARG_INFO(0, interval)
     211             : ZEND_END_ARG_INFO()
     212             : 
     213             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_get, 0, 0, 1)
     214             :         ZEND_ARG_INFO(0, object)
     215             : ZEND_END_ARG_INFO()
     216             : 
     217             : ZEND_BEGIN_ARG_INFO(arginfo_date_method_timezone_get, 0)
     218             : ZEND_END_ARG_INFO()
     219             : 
     220             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_set, 0, 0, 2)
     221             :         ZEND_ARG_INFO(0, object)
     222             :         ZEND_ARG_INFO(0, timezone)
     223             : ZEND_END_ARG_INFO()
     224             : 
     225             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_timezone_set, 0, 0, 1)
     226             :         ZEND_ARG_INFO(0, timezone)
     227             : ZEND_END_ARG_INFO()
     228             : 
     229             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_offset_get, 0, 0, 1)
     230             :         ZEND_ARG_INFO(0, object)
     231             : ZEND_END_ARG_INFO()
     232             : 
     233             : ZEND_BEGIN_ARG_INFO(arginfo_date_method_offset_get, 0)
     234             : ZEND_END_ARG_INFO()
     235             : 
     236             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_diff, 0, 0, 2)
     237             :         ZEND_ARG_INFO(0, object)
     238             :         ZEND_ARG_INFO(0, object2)
     239             :         ZEND_ARG_INFO(0, absolute)
     240             : ZEND_END_ARG_INFO()
     241             : 
     242             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_diff, 0, 0, 1)
     243             :         ZEND_ARG_INFO(0, object)
     244             :         ZEND_ARG_INFO(0, absolute)
     245             : ZEND_END_ARG_INFO()
     246             : 
     247             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_time_set, 0, 0, 3)
     248             :         ZEND_ARG_INFO(0, object)
     249             :         ZEND_ARG_INFO(0, hour)
     250             :         ZEND_ARG_INFO(0, minute)
     251             :         ZEND_ARG_INFO(0, second)
     252             : ZEND_END_ARG_INFO()
     253             : 
     254             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_time_set, 0, 0, 2)
     255             :         ZEND_ARG_INFO(0, hour)
     256             :         ZEND_ARG_INFO(0, minute)
     257             :         ZEND_ARG_INFO(0, second)
     258             : ZEND_END_ARG_INFO()
     259             : 
     260             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_date_set, 0, 0, 4)
     261             :         ZEND_ARG_INFO(0, object)
     262             :         ZEND_ARG_INFO(0, year)
     263             :         ZEND_ARG_INFO(0, month)
     264             :         ZEND_ARG_INFO(0, day)
     265             : ZEND_END_ARG_INFO()
     266             : 
     267             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_date_set, 0, 0, 3)
     268             :         ZEND_ARG_INFO(0, year)
     269             :         ZEND_ARG_INFO(0, month)
     270             :         ZEND_ARG_INFO(0, day)
     271             : ZEND_END_ARG_INFO()
     272             : 
     273             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_isodate_set, 0, 0, 3)
     274             :         ZEND_ARG_INFO(0, object)
     275             :         ZEND_ARG_INFO(0, year)
     276             :         ZEND_ARG_INFO(0, week)
     277             :         ZEND_ARG_INFO(0, day)
     278             : ZEND_END_ARG_INFO()
     279             : 
     280             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_isodate_set, 0, 0, 2)
     281             :         ZEND_ARG_INFO(0, year)
     282             :         ZEND_ARG_INFO(0, week)
     283             :         ZEND_ARG_INFO(0, day)
     284             : ZEND_END_ARG_INFO()
     285             : 
     286             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timestamp_set, 0, 0, 2)
     287             :         ZEND_ARG_INFO(0, object)
     288             :         ZEND_ARG_INFO(0, unixtimestamp)
     289             : ZEND_END_ARG_INFO()
     290             : 
     291             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_timestamp_set, 0, 0, 1)
     292             :         ZEND_ARG_INFO(0, unixtimestamp)
     293             : ZEND_END_ARG_INFO()
     294             : 
     295             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timestamp_get, 0, 0, 1)
     296             :         ZEND_ARG_INFO(0, object)
     297             : ZEND_END_ARG_INFO()
     298             : 
     299             : ZEND_BEGIN_ARG_INFO(arginfo_date_method_timestamp_get, 0)
     300             : ZEND_END_ARG_INFO()
     301             : 
     302             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_method_create_from_mutable, 0, 0, 1)
     303             :         ZEND_ARG_INFO(0, DateTime)
     304             : ZEND_END_ARG_INFO()
     305             : 
     306             : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_open, 0, 0, 1)
     307             :         ZEND_ARG_INFO(0, timezone)
     308             : ZEND_END_ARG_INFO()
     309             : 
     310             : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_name_get, 0, 0, 1)
     311             :         ZEND_ARG_INFO(0, object)
     312             : ZEND_END_ARG_INFO()
     313             : 
     314             : ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_name_get, 0)
     315             : ZEND_END_ARG_INFO()
     316             : 
     317             : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_name_from_abbr, 0, 0, 1)
     318             :         ZEND_ARG_INFO(0, abbr)
     319             :         ZEND_ARG_INFO(0, gmtoffset)
     320             :         ZEND_ARG_INFO(0, isdst)
     321             : ZEND_END_ARG_INFO()
     322             : 
     323             : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_offset_get, 0, 0, 2)
     324             :         ZEND_ARG_INFO(0, object)
     325             :         ZEND_ARG_INFO(0, datetime)
     326             : ZEND_END_ARG_INFO()
     327             : 
     328             : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_method_offset_get, 0, 0, 1)
     329             :         ZEND_ARG_INFO(0, datetime)
     330             : ZEND_END_ARG_INFO()
     331             : 
     332             : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_transitions_get, 0, 0, 1)
     333             :         ZEND_ARG_INFO(0, object)
     334             :         ZEND_ARG_INFO(0, timestamp_begin)
     335             :         ZEND_ARG_INFO(0, timestamp_end)
     336             : ZEND_END_ARG_INFO()
     337             : 
     338             : ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_transitions_get, 0)
     339             :         ZEND_ARG_INFO(0, timestamp_begin)
     340             :         ZEND_ARG_INFO(0, timestamp_end)
     341             : ZEND_END_ARG_INFO()
     342             : 
     343             : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_location_get, 0, 0, 1)
     344             :         ZEND_ARG_INFO(0, object)
     345             : ZEND_END_ARG_INFO()
     346             : 
     347             : ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_location_get, 0)
     348             : ZEND_END_ARG_INFO()
     349             : 
     350             : ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_identifiers_list, 0, 0, 0)
     351             :         ZEND_ARG_INFO(0, what)
     352             :         ZEND_ARG_INFO(0, country)
     353             : ZEND_END_ARG_INFO()
     354             : 
     355             : ZEND_BEGIN_ARG_INFO(arginfo_timezone_abbreviations_list, 0)
     356             : ZEND_END_ARG_INFO()
     357             : 
     358             : ZEND_BEGIN_ARG_INFO(arginfo_timezone_version_get, 0)
     359             : ZEND_END_ARG_INFO()
     360             : 
     361             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_create_from_date_string, 0, 0, 1)
     362             :         ZEND_ARG_INFO(0, time)
     363             : ZEND_END_ARG_INFO()
     364             : 
     365             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_format, 0, 0, 2)
     366             :         ZEND_ARG_INFO(0, object)
     367             :         ZEND_ARG_INFO(0, format)
     368             : ZEND_END_ARG_INFO()
     369             : 
     370             : ZEND_BEGIN_ARG_INFO(arginfo_date_method_interval_format, 0)
     371             :         ZEND_ARG_INFO(0, format)
     372             : ZEND_END_ARG_INFO()
     373             : 
     374             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_period_construct, 0, 0, 3)
     375             :         ZEND_ARG_INFO(0, start)
     376             :         ZEND_ARG_INFO(0, interval)
     377             :         ZEND_ARG_INFO(0, end)
     378             : ZEND_END_ARG_INFO()
     379             : 
     380             : ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_construct, 0, 0, 0)
     381             :         ZEND_ARG_INFO(0, interval_spec)
     382             : ZEND_END_ARG_INFO()
     383             : /* }}} */
     384             : 
     385             : /* {{{ Function table */
     386             : const zend_function_entry date_functions[] = {
     387             :         PHP_FE(strtotime, arginfo_strtotime)
     388             :         PHP_FE(date, arginfo_date)
     389             :         PHP_FE(idate, arginfo_idate)
     390             :         PHP_FE(gmdate, arginfo_gmdate)
     391             :         PHP_FE(mktime, arginfo_mktime)
     392             :         PHP_FE(gmmktime, arginfo_gmmktime)
     393             :         PHP_FE(checkdate, arginfo_checkdate)
     394             : 
     395             : #ifdef HAVE_STRFTIME
     396             :         PHP_FE(strftime, arginfo_strftime)
     397             :         PHP_FE(gmstrftime, arginfo_gmstrftime)
     398             : #endif
     399             : 
     400             :         PHP_FE(time, arginfo_time)
     401             :         PHP_FE(localtime, arginfo_localtime)
     402             :         PHP_FE(getdate, arginfo_getdate)
     403             : 
     404             :         /* Advanced Interface */
     405             :         PHP_FE(date_create, arginfo_date_create)
     406             :         PHP_FE(date_create_immutable, arginfo_date_create)
     407             :         PHP_FE(date_create_from_format, arginfo_date_create_from_format)
     408             :         PHP_FE(date_create_immutable_from_format, arginfo_date_create_from_format)
     409             :         PHP_FE(date_parse, arginfo_date_parse)
     410             :         PHP_FE(date_parse_from_format, arginfo_date_parse_from_format)
     411             :         PHP_FE(date_get_last_errors, arginfo_date_get_last_errors)
     412             :         PHP_FE(date_format, arginfo_date_format)
     413             :         PHP_FE(date_modify, arginfo_date_modify)
     414             :         PHP_FE(date_add, arginfo_date_add)
     415             :         PHP_FE(date_sub, arginfo_date_sub)
     416             :         PHP_FE(date_timezone_get, arginfo_date_timezone_get)
     417             :         PHP_FE(date_timezone_set, arginfo_date_timezone_set)
     418             :         PHP_FE(date_offset_get, arginfo_date_offset_get)
     419             :         PHP_FE(date_diff, arginfo_date_diff)
     420             : 
     421             :         PHP_FE(date_time_set, arginfo_date_time_set)
     422             :         PHP_FE(date_date_set, arginfo_date_date_set)
     423             :         PHP_FE(date_isodate_set, arginfo_date_isodate_set)
     424             :         PHP_FE(date_timestamp_set, arginfo_date_timestamp_set)
     425             :         PHP_FE(date_timestamp_get, arginfo_date_timestamp_get)
     426             : 
     427             :         PHP_FE(timezone_open, arginfo_timezone_open)
     428             :         PHP_FE(timezone_name_get, arginfo_timezone_name_get)
     429             :         PHP_FE(timezone_name_from_abbr, arginfo_timezone_name_from_abbr)
     430             :         PHP_FE(timezone_offset_get, arginfo_timezone_offset_get)
     431             :         PHP_FE(timezone_transitions_get, arginfo_timezone_transitions_get)
     432             :         PHP_FE(timezone_location_get, arginfo_timezone_location_get)
     433             :         PHP_FE(timezone_identifiers_list, arginfo_timezone_identifiers_list)
     434             :         PHP_FE(timezone_abbreviations_list, arginfo_timezone_abbreviations_list)
     435             :         PHP_FE(timezone_version_get, arginfo_timezone_version_get)
     436             : 
     437             :         PHP_FE(date_interval_create_from_date_string, arginfo_date_interval_create_from_date_string)
     438             :         PHP_FE(date_interval_format, arginfo_date_interval_format)
     439             : 
     440             :         /* Options and Configuration */
     441             :         PHP_FE(date_default_timezone_set, arginfo_date_default_timezone_set)
     442             :         PHP_FE(date_default_timezone_get, arginfo_date_default_timezone_get)
     443             : 
     444             :         /* Astronomical functions */
     445             :         PHP_FE(date_sunrise, arginfo_date_sunrise)
     446             :         PHP_FE(date_sunset, arginfo_date_sunset)
     447             :         PHP_FE(date_sun_info, arginfo_date_sun_info)
     448             :         PHP_FE_END
     449             : };
     450             : 
     451             : static const zend_function_entry date_funcs_interface[] = {
     452             :         PHP_ABSTRACT_ME(DateTimeInterface, format, arginfo_date_method_format)
     453             :         PHP_ABSTRACT_ME(DateTimeInterface, getTimezone, arginfo_date_method_timezone_get)
     454             :         PHP_ABSTRACT_ME(DateTimeInterface, getOffset, arginfo_date_method_offset_get)
     455             :         PHP_ABSTRACT_ME(DateTimeInterface, getTimestamp, arginfo_date_method_timestamp_get)
     456             :         PHP_ABSTRACT_ME(DateTimeInterface, diff, arginfo_date_method_diff)
     457             :         PHP_ABSTRACT_ME(DateTimeInterface, __wakeup, NULL)
     458             :         PHP_FE_END
     459             : };
     460             : 
     461             : const zend_function_entry date_funcs_date[] = {
     462             :         PHP_ME(DateTime,                        __construct,            arginfo_date_create, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
     463             :         PHP_ME(DateTime,                        __wakeup,                       NULL, ZEND_ACC_PUBLIC)
     464             :         PHP_ME(DateTime,                        __set_state,            NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     465             :         PHP_ME_MAPPING(createFromFormat, date_create_from_format,       arginfo_date_create_from_format, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     466             :         PHP_ME_MAPPING(getLastErrors, date_get_last_errors,     arginfo_date_get_last_errors, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     467             :         PHP_ME_MAPPING(format,          date_format,            arginfo_date_method_format, 0)
     468             :         PHP_ME_MAPPING(modify,          date_modify,            arginfo_date_method_modify, 0)
     469             :         PHP_ME_MAPPING(add,                     date_add,                       arginfo_date_method_add, 0)
     470             :         PHP_ME_MAPPING(sub,                     date_sub,                       arginfo_date_method_sub, 0)
     471             :         PHP_ME_MAPPING(getTimezone, date_timezone_get,  arginfo_date_method_timezone_get, 0)
     472             :         PHP_ME_MAPPING(setTimezone, date_timezone_set,  arginfo_date_method_timezone_set, 0)
     473             :         PHP_ME_MAPPING(getOffset,       date_offset_get,        arginfo_date_method_offset_get, 0)
     474             :         PHP_ME_MAPPING(setTime,         date_time_set,          arginfo_date_method_time_set, 0)
     475             :         PHP_ME_MAPPING(setDate,         date_date_set,          arginfo_date_method_date_set, 0)
     476             :         PHP_ME_MAPPING(setISODate,      date_isodate_set,       arginfo_date_method_isodate_set, 0)
     477             :         PHP_ME_MAPPING(setTimestamp,    date_timestamp_set, arginfo_date_method_timestamp_set, 0)
     478             :         PHP_ME_MAPPING(getTimestamp,    date_timestamp_get, arginfo_date_method_timestamp_get, 0)
     479             :         PHP_ME_MAPPING(diff,                    date_diff, arginfo_date_method_diff, 0)
     480             :         PHP_FE_END
     481             : };
     482             : 
     483             : const zend_function_entry date_funcs_immutable[] = {
     484             :         PHP_ME(DateTimeImmutable, __construct,   arginfo_date_create, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
     485             :         PHP_ME(DateTime, __wakeup,       NULL, ZEND_ACC_PUBLIC)
     486             :         PHP_ME(DateTimeImmutable, __set_state,   NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     487             :         PHP_ME_MAPPING(createFromFormat, date_create_immutable_from_format, arginfo_date_create_from_format, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     488             :         PHP_ME_MAPPING(getLastErrors,    date_get_last_errors,    arginfo_date_get_last_errors, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     489             :         PHP_ME_MAPPING(format,           date_format,             arginfo_date_method_format, 0)
     490             :         PHP_ME_MAPPING(getTimezone, date_timezone_get,  arginfo_date_method_timezone_get, 0)
     491             :         PHP_ME_MAPPING(getOffset,       date_offset_get,        arginfo_date_method_offset_get, 0)
     492             :         PHP_ME_MAPPING(getTimestamp,    date_timestamp_get, arginfo_date_method_timestamp_get, 0)
     493             :         PHP_ME_MAPPING(diff,                    date_diff, arginfo_date_method_diff, 0)
     494             :         PHP_ME(DateTimeImmutable, modify,        arginfo_date_method_modify, 0)
     495             :         PHP_ME(DateTimeImmutable, add,           arginfo_date_method_add, 0)
     496             :         PHP_ME(DateTimeImmutable, sub,           arginfo_date_method_sub, 0)
     497             :         PHP_ME(DateTimeImmutable, setTimezone,   arginfo_date_method_timezone_set, 0)
     498             :         PHP_ME(DateTimeImmutable, setTime,       arginfo_date_method_time_set, 0)
     499             :         PHP_ME(DateTimeImmutable, setDate,       arginfo_date_method_date_set, 0)
     500             :         PHP_ME(DateTimeImmutable, setISODate,    arginfo_date_method_isodate_set, 0)
     501             :         PHP_ME(DateTimeImmutable, setTimestamp,  arginfo_date_method_timestamp_set, 0)
     502             :         PHP_ME(DateTimeImmutable, createFromMutable, arginfo_date_method_create_from_mutable, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     503             :         PHP_FE_END
     504             : };
     505             : 
     506             : const zend_function_entry date_funcs_timezone[] = {
     507             :         PHP_ME(DateTimeZone,              __construct,                 arginfo_timezone_open, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
     508             :         PHP_ME(DateTimeZone,              __wakeup,                    NULL, ZEND_ACC_PUBLIC)
     509             :         PHP_ME(DateTimeZone,              __set_state,                 NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     510             :         PHP_ME_MAPPING(getName,           timezone_name_get,           arginfo_timezone_method_name_get, 0)
     511             :         PHP_ME_MAPPING(getOffset,         timezone_offset_get,         arginfo_timezone_method_offset_get, 0)
     512             :         PHP_ME_MAPPING(getTransitions,    timezone_transitions_get,    arginfo_timezone_method_transitions_get, 0)
     513             :         PHP_ME_MAPPING(getLocation,       timezone_location_get,       arginfo_timezone_method_location_get, 0)
     514             :         PHP_ME_MAPPING(listAbbreviations, timezone_abbreviations_list, arginfo_timezone_abbreviations_list, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     515             :         PHP_ME_MAPPING(listIdentifiers,   timezone_identifiers_list,   arginfo_timezone_identifiers_list, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     516             :         PHP_FE_END
     517             : };
     518             : 
     519             : const zend_function_entry date_funcs_interval[] = {
     520             :         PHP_ME(DateInterval,              __construct,                 arginfo_date_interval_construct, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
     521             :         PHP_ME(DateInterval,              __wakeup,                    NULL, ZEND_ACC_PUBLIC)
     522             :         PHP_ME(DateInterval,              __set_state,                 NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     523             :         PHP_ME_MAPPING(format,            date_interval_format,        arginfo_date_method_interval_format, 0)
     524             :         PHP_ME_MAPPING(createFromDateString, date_interval_create_from_date_string,     arginfo_date_interval_create_from_date_string, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     525             :         PHP_FE_END
     526             : };
     527             : 
     528             : const zend_function_entry date_funcs_period[] = {
     529             :         PHP_ME(DatePeriod,                __construct,                 arginfo_date_period_construct, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC)
     530             :         PHP_ME(DatePeriod,                __wakeup,                    NULL, ZEND_ACC_PUBLIC)
     531             :         PHP_ME(DatePeriod,                __set_state,                 NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     532             :         PHP_FE_END
     533             : };
     534             : 
     535             : static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC);
     536             : static void date_register_classes(TSRMLS_D);
     537             : /* }}} */
     538             : 
     539             : ZEND_DECLARE_MODULE_GLOBALS(date)
     540             : static PHP_GINIT_FUNCTION(date);
     541             : 
     542             : /* True global */
     543             : timelib_tzdb *php_date_global_timezone_db;
     544             : int php_date_global_timezone_db_enabled;
     545             : 
     546             : #define DATE_DEFAULT_LATITUDE "31.7667"
     547             : #define DATE_DEFAULT_LONGITUDE "35.2333"
     548             : 
     549             : /* on 90'35; common sunset declaration (start of sun body appear) */
     550             : #define DATE_SUNSET_ZENITH "90.583333"
     551             : 
     552             : /* on 90'35; common sunrise declaration (sun body disappeared) */
     553             : #define DATE_SUNRISE_ZENITH "90.583333"
     554             : 
     555             : static PHP_INI_MH(OnUpdate_date_timezone);
     556             : 
     557             : /* {{{ INI Settings */
     558             : PHP_INI_BEGIN()
     559             :         STD_PHP_INI_ENTRY("date.timezone", "", PHP_INI_ALL, OnUpdate_date_timezone, default_timezone, zend_date_globals, date_globals)
     560             :         PHP_INI_ENTRY("date.default_latitude",           DATE_DEFAULT_LATITUDE,        PHP_INI_ALL, NULL)
     561             :         PHP_INI_ENTRY("date.default_longitude",          DATE_DEFAULT_LONGITUDE,       PHP_INI_ALL, NULL)
     562             :         PHP_INI_ENTRY("date.sunset_zenith",              DATE_SUNSET_ZENITH,           PHP_INI_ALL, NULL)
     563             :         PHP_INI_ENTRY("date.sunrise_zenith",             DATE_SUNRISE_ZENITH,          PHP_INI_ALL, NULL)
     564             : PHP_INI_END()
     565             : /* }}} */
     566             : 
     567             : zend_class_entry *date_ce_date, *date_ce_timezone, *date_ce_interval, *date_ce_period;
     568             : zend_class_entry *date_ce_immutable, *date_ce_interface;
     569             : 
     570             : 
     571          60 : PHPAPI zend_class_entry *php_date_get_date_ce(void)
     572             : {
     573          60 :         return date_ce_date;
     574             : }
     575             : 
     576           0 : PHPAPI zend_class_entry *php_date_get_immutable_ce(void)
     577             : {
     578           0 :         return date_ce_immutable;
     579             : }
     580             : 
     581          23 : PHPAPI zend_class_entry *php_date_get_timezone_ce(void)
     582             : {
     583          23 :         return date_ce_timezone;
     584             : }
     585             : 
     586             : static zend_object_handlers date_object_handlers_date;
     587             : static zend_object_handlers date_object_handlers_immutable;
     588             : static zend_object_handlers date_object_handlers_timezone;
     589             : static zend_object_handlers date_object_handlers_interval;
     590             : static zend_object_handlers date_object_handlers_period;
     591             : 
     592             : #define DATE_SET_CONTEXT \
     593             :         zval *object; \
     594             :         object = getThis(); \
     595             :    
     596             : #define DATE_FETCH_OBJECT       \
     597             :         php_date_obj *obj;      \
     598             :         DATE_SET_CONTEXT; \
     599             :         if (object) {   \
     600             :                 if (zend_parse_parameters_none() == FAILURE) {  \
     601             :                         return; \
     602             :                 }       \
     603             :         } else {        \
     604             :                 if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, NULL, "O", &object, date_ce_date) == FAILURE) {       \
     605             :                         RETURN_FALSE;   \
     606             :                 }       \
     607             :         }       \
     608             :         obj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);  \
     609             : 
     610             : #define DATE_CHECK_INITIALIZED(member, class_name) \
     611             :         if (!(member)) { \
     612             :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The " #class_name " object has not been correctly initialized by its constructor"); \
     613             :                 RETURN_FALSE; \
     614             :         }
     615             : 
     616             : static void date_object_free_storage_date(void *object TSRMLS_DC);
     617             : static void date_object_free_storage_timezone(void *object TSRMLS_DC);
     618             : static void date_object_free_storage_interval(void *object TSRMLS_DC);
     619             : static void date_object_free_storage_period(void *object TSRMLS_DC);
     620             : 
     621             : static zend_object_value date_object_new_date(zend_class_entry *class_type TSRMLS_DC);
     622             : static zend_object_value date_object_new_timezone(zend_class_entry *class_type TSRMLS_DC);
     623             : static zend_object_value date_object_new_interval(zend_class_entry *class_type TSRMLS_DC);
     624             : static zend_object_value date_object_new_period(zend_class_entry *class_type TSRMLS_DC);
     625             : 
     626             : static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC);
     627             : static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC);
     628             : static zend_object_value date_object_clone_interval(zval *this_ptr TSRMLS_DC);
     629             : static zend_object_value date_object_clone_period(zval *this_ptr TSRMLS_DC);
     630             : 
     631             : static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC);
     632             : static HashTable *date_object_get_gc(zval *object, zval ***table, int *n TSRMLS_DC);
     633             : static HashTable *date_object_get_properties(zval *object TSRMLS_DC);
     634             : static HashTable *date_object_get_gc_interval(zval *object, zval ***table, int *n TSRMLS_DC);
     635             : static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC);
     636             : static HashTable *date_object_get_gc_period(zval *object, zval ***table, int *n TSRMLS_DC);
     637             : static HashTable *date_object_get_properties_period(zval *object TSRMLS_DC);
     638             : static HashTable *date_object_get_properties_timezone(zval *object TSRMLS_DC);
     639             : static HashTable *date_object_get_gc_timezone(zval *object, zval ***table, int *n TSRMLS_DC);
     640             : 
     641             : zval *date_interval_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC);
     642             : void date_interval_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC);
     643             : static zval *date_period_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC);
     644             : static void date_period_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC);
     645             : 
     646             : /* {{{ Module struct */
     647             : zend_module_entry date_module_entry = {
     648             :         STANDARD_MODULE_HEADER_EX,
     649             :         NULL,
     650             :         NULL,
     651             :         "date",                     /* extension name */
     652             :         date_functions,             /* function list */
     653             :         PHP_MINIT(date),            /* process startup */
     654             :         PHP_MSHUTDOWN(date),        /* process shutdown */
     655             :         PHP_RINIT(date),            /* request startup */
     656             :         PHP_RSHUTDOWN(date),        /* request shutdown */
     657             :         PHP_MINFO(date),            /* extension info */
     658             :         PHP_VERSION,                /* extension version */
     659             :         PHP_MODULE_GLOBALS(date),   /* globals descriptor */
     660             :         PHP_GINIT(date),            /* globals ctor */
     661             :         NULL,                       /* globals dtor */
     662             :         NULL,                       /* post deactivate */
     663             :         STANDARD_MODULE_PROPERTIES_EX
     664             : };
     665             : /* }}} */
     666             : 
     667             : 
     668             : /* {{{ PHP_GINIT_FUNCTION */
     669       21159 : static PHP_GINIT_FUNCTION(date)
     670             : {
     671       21159 :         date_globals->default_timezone = NULL;
     672       21159 :         date_globals->timezone = NULL;
     673       21159 :         date_globals->tzcache = NULL;
     674       21159 :         date_globals->timezone_valid = 0;
     675       21159 : }
     676             : /* }}} */
     677             : 
     678             : 
     679        1705 : static void _php_date_tzinfo_dtor(void *tzinfo)
     680             : {
     681        1705 :         timelib_tzinfo **tzi = (timelib_tzinfo **)tzinfo;
     682             : 
     683        1705 :         timelib_tzinfo_dtor(*tzi);
     684        1705 : }
     685             : 
     686             : /* {{{ PHP_RINIT_FUNCTION */
     687       21116 : PHP_RINIT_FUNCTION(date)
     688             : {
     689       21116 :         if (DATEG(timezone)) {
     690           0 :                 efree(DATEG(timezone));
     691             :         }
     692       21116 :         DATEG(timezone) = NULL;
     693       21116 :         DATEG(tzcache) = NULL;
     694       21116 :         DATEG(last_errors) = NULL;
     695             : 
     696       21116 :         return SUCCESS;
     697             : }
     698             : /* }}} */
     699             : 
     700             : /* {{{ PHP_RSHUTDOWN_FUNCTION */
     701       21151 : PHP_RSHUTDOWN_FUNCTION(date)
     702             : {
     703       21151 :         if (DATEG(timezone)) {
     704         534 :                 efree(DATEG(timezone));
     705             :         }
     706       21151 :         DATEG(timezone) = NULL;
     707       21151 :         if(DATEG(tzcache)) {
     708         641 :                 zend_hash_destroy(DATEG(tzcache));
     709         641 :                 FREE_HASHTABLE(DATEG(tzcache));
     710         641 :                 DATEG(tzcache) = NULL;
     711             :         }
     712       21151 :         if (DATEG(last_errors)) {
     713         239 :                 timelib_error_container_dtor(DATEG(last_errors));
     714         239 :                 DATEG(last_errors) = NULL;
     715             :         }
     716             : 
     717       21151 :         return SUCCESS;
     718             : }
     719             : /* }}} */
     720             : 
     721             : #define DATE_TIMEZONEDB      php_date_global_timezone_db ? php_date_global_timezone_db : timelib_builtin_db()
     722             : 
     723             : /*
     724             :  * RFC822, Section 5.1: http://www.ietf.org/rfc/rfc822.txt
     725             :  *  date-time   =  [ day "," ] date time        ; dd mm yy hh:mm:ss zzz
     726             :  *  day         =  "Mon"  / "Tue" /  "Wed"  / "Thu"  /  "Fri"  / "Sat" /  "Sun"
     727             :  *  date        =  1*2DIGIT month 2DIGIT        ; day month year e.g. 20 Jun 82
     728             :  *  month       =  "Jan"  /  "Feb" /  "Mar"  /  "Apr"  /  "May"  /  "Jun" /  "Jul"  /  "Aug"  /  "Sep"  /  "Oct" /  "Nov"  /  "Dec"
     729             :  *  time        =  hour zone                    ; ANSI and Military
     730             :  *  hour        =  2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59
     731             :  *  zone        =  "UT"  / "GMT"  /  "EST" / "EDT"  /  "CST" / "CDT"  /  "MST" / "MDT"  /  "PST" / "PDT"  /  1ALPHA  / ( ("+" / "-") 4DIGIT )
     732             :  */
     733             : #define DATE_FORMAT_RFC822   "D, d M y H:i:s O"
     734             : 
     735             : /*
     736             :  * RFC850, Section 2.1.4: http://www.ietf.org/rfc/rfc850.txt
     737             :  *  Format must be acceptable both to the ARPANET and to the getdate routine.
     738             :  *  One format that is acceptable to both is Weekday, DD-Mon-YY HH:MM:SS TIMEZONE
     739             :  *  TIMEZONE can be any timezone name (3 or more letters)
     740             :  */
     741             : #define DATE_FORMAT_RFC850   "l, d-M-y H:i:s T"
     742             : 
     743             : /*
     744             :  * RFC1036, Section 2.1.2: http://www.ietf.org/rfc/rfc1036.txt
     745             :  *  Its format must be acceptable both in RFC-822 and to the getdate(3)
     746             :  *  Wdy, DD Mon YY HH:MM:SS TIMEZONE
     747             :  *  There is no hope of having a complete list of timezones.  Universal
     748             :  *  Time (GMT), the North American timezones (PST, PDT, MST, MDT, CST,
     749             :  *  CDT, EST, EDT) and the +/-hhmm offset specifed in RFC-822 should be supported.
     750             :  */
     751             : #define DATE_FORMAT_RFC1036  "D, d M y H:i:s O"
     752             : 
     753             : /*
     754             :  * RFC1123, Section 5.2.14: http://www.ietf.org/rfc/rfc1123.txt
     755             :  *  RFC-822 Date and Time Specification: RFC-822 Section 5
     756             :  *  The syntax for the date is hereby changed to: date = 1*2DIGIT month 2*4DIGIT
     757             :  */
     758             : #define DATE_FORMAT_RFC1123  "D, d M Y H:i:s O"
     759             : 
     760             : /*
     761             :  * RFC2822, Section 3.3: http://www.ietf.org/rfc/rfc2822.txt
     762             :  *  FWS             =       ([*WSP CRLF] 1*WSP) /   ; Folding white space
     763             :  *  CFWS            =       *([FWS] comment) (([FWS] comment) / FWS)
     764             :  *  
     765             :  *  date-time       =       [ day-of-week "," ] date FWS time [CFWS]
     766             :  *  day-of-week     =       ([FWS] day-name)
     767             :  *  day-name        =       "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
     768             :  *  date            =       day month year
     769             :  *  year            =       4*DIGIT
     770             :  *  month           =       (FWS month-name FWS)
     771             :  *  month-name      =       "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
     772             :  *  day             =       ([FWS] 1*2DIGIT)
     773             :  *  time            =       time-of-day FWS zone
     774             :  *  time-of-day     =       hour ":" minute [ ":" second ]
     775             :  *  hour            =       2DIGIT
     776             :  *  minute          =       2DIGIT
     777             :  *  second          =       2DIGIT
     778             :  *  zone            =       (( "+" / "-" ) 4DIGIT)
     779             :  */
     780             : #define DATE_FORMAT_RFC2822  "D, d M Y H:i:s O"
     781             : /*
     782             :  * RFC3339, Section 5.6: http://www.ietf.org/rfc/rfc3339.txt
     783             :  *  date-fullyear   = 4DIGIT
     784             :  *  date-month      = 2DIGIT  ; 01-12
     785             :  *  date-mday       = 2DIGIT  ; 01-28, 01-29, 01-30, 01-31 based on month/year
     786             :  *  
     787             :  *  time-hour       = 2DIGIT  ; 00-23
     788             :  *  time-minute     = 2DIGIT  ; 00-59
     789             :  *  time-second     = 2DIGIT  ; 00-58, 00-59, 00-60 based on leap second rules
     790             :  *  
     791             :  *  time-secfrac    = "." 1*DIGIT
     792             :  *  time-numoffset  = ("+" / "-") time-hour ":" time-minute
     793             :  *  time-offset     = "Z" / time-numoffset
     794             :  *  
     795             :  *  partial-time    = time-hour ":" time-minute ":" time-second [time-secfrac]
     796             :  *  full-date       = date-fullyear "-" date-month "-" date-mday
     797             :  *  full-time       = partial-time time-offset
     798             :  *  
     799             :  *  date-time       = full-date "T" full-time
     800             :  */
     801             : #define DATE_FORMAT_RFC3339  "Y-m-d\\TH:i:sP"
     802             : 
     803             : #define DATE_FORMAT_ISO8601  "Y-m-d\\TH:i:sO"
     804             : 
     805             : /*
     806             :  * This comes from various sources that like to contradict. I'm going with the
     807             :  * format here because of:
     808             :  * http://msdn.microsoft.com/en-us/library/windows/desktop/aa384321%28v=vs.85%29.aspx
     809             :  * and http://curl.haxx.se/rfc/cookie_spec.html
     810             :  */
     811             : #define DATE_FORMAT_COOKIE   "l, d-M-Y H:i:s T"
     812             : 
     813             : #define DATE_TZ_ERRMSG \
     814             :         "It is not safe to rely on the system's timezone settings. You are " \
     815             :         "*required* to use the date.timezone setting or the " \
     816             :         "date_default_timezone_set() function. In case you used any of those " \
     817             :         "methods and you are still getting this warning, you most likely " \
     818             :         "misspelled the timezone identifier. "
     819             : 
     820             : #define SUNFUNCS_RET_TIMESTAMP 0
     821             : #define SUNFUNCS_RET_STRING    1
     822             : #define SUNFUNCS_RET_DOUBLE    2
     823             : 
     824             : /* {{{ PHP_MINIT_FUNCTION */
     825       21159 : PHP_MINIT_FUNCTION(date)
     826             : {
     827       21159 :         REGISTER_INI_ENTRIES();
     828       21159 :         date_register_classes(TSRMLS_C);
     829             : /*
     830             :  * RFC4287, Section 3.3: http://www.ietf.org/rfc/rfc4287.txt
     831             :  *   A Date construct is an element whose content MUST conform to the
     832             :  *   "date-time" production in [RFC3339].  In addition, an uppercase "T"
     833             :  *   character MUST be used to separate date and time, and an uppercase
     834             :  *   "Z" character MUST be present in the absence of a numeric time zone offset.
     835             :  */
     836       21159 :         REGISTER_STRING_CONSTANT("DATE_ATOM",    DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
     837             : /*
     838             :  * Preliminary specification: http://wp.netscape.com/newsref/std/cookie_spec.html
     839             :  *   "This is based on RFC 822, RFC 850,  RFC 1036, and  RFC 1123,
     840             :  *   with the variations that the only legal time zone is GMT
     841             :  *   and the separators between the elements of the date must be dashes."
     842             :  */
     843       21159 :         REGISTER_STRING_CONSTANT("DATE_COOKIE",  DATE_FORMAT_COOKIE,  CONST_CS | CONST_PERSISTENT);
     844       21159 :         REGISTER_STRING_CONSTANT("DATE_ISO8601", DATE_FORMAT_ISO8601, CONST_CS | CONST_PERSISTENT);
     845       21159 :         REGISTER_STRING_CONSTANT("DATE_RFC822",  DATE_FORMAT_RFC822,  CONST_CS | CONST_PERSISTENT);
     846       21159 :         REGISTER_STRING_CONSTANT("DATE_RFC850",  DATE_FORMAT_RFC850,  CONST_CS | CONST_PERSISTENT);
     847       21159 :         REGISTER_STRING_CONSTANT("DATE_RFC1036", DATE_FORMAT_RFC1036, CONST_CS | CONST_PERSISTENT);
     848       21159 :         REGISTER_STRING_CONSTANT("DATE_RFC1123", DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
     849       21159 :         REGISTER_STRING_CONSTANT("DATE_RFC2822", DATE_FORMAT_RFC2822, CONST_CS | CONST_PERSISTENT);
     850       21159 :         REGISTER_STRING_CONSTANT("DATE_RFC3339", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
     851             : /*
     852             :  * RSS 2.0 Specification: http://blogs.law.harvard.edu/tech/rss
     853             :  *   "All date-times in RSS conform to the Date and Time Specification of RFC 822,
     854             :  *   with the exception that the year may be expressed with two characters or four characters (four preferred)"
     855             :  */
     856       21159 :         REGISTER_STRING_CONSTANT("DATE_RSS",     DATE_FORMAT_RFC1123, CONST_CS | CONST_PERSISTENT);
     857       21159 :         REGISTER_STRING_CONSTANT("DATE_W3C",     DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
     858             : 
     859       21159 :         REGISTER_LONG_CONSTANT("SUNFUNCS_RET_TIMESTAMP", SUNFUNCS_RET_TIMESTAMP, CONST_CS | CONST_PERSISTENT);
     860       21159 :         REGISTER_LONG_CONSTANT("SUNFUNCS_RET_STRING", SUNFUNCS_RET_STRING, CONST_CS | CONST_PERSISTENT);
     861       21159 :         REGISTER_LONG_CONSTANT("SUNFUNCS_RET_DOUBLE", SUNFUNCS_RET_DOUBLE, CONST_CS | CONST_PERSISTENT);
     862             : 
     863       21159 :         php_date_global_timezone_db = NULL;
     864       21159 :         php_date_global_timezone_db_enabled = 0;
     865       21159 :         DATEG(last_errors) = NULL;
     866       21159 :         return SUCCESS;
     867             : }
     868             : /* }}} */
     869             : 
     870             : /* {{{ PHP_MSHUTDOWN_FUNCTION */
     871       21192 : PHP_MSHUTDOWN_FUNCTION(date)
     872             : {
     873       21192 :         UNREGISTER_INI_ENTRIES();
     874             : 
     875       21192 :         if (DATEG(last_errors)) {
     876           0 :                 timelib_error_container_dtor(DATEG(last_errors));
     877             :         }
     878             : 
     879       21192 :         return SUCCESS;
     880             : }
     881             : /* }}} */
     882             : 
     883             : /* {{{ PHP_MINFO_FUNCTION */
     884         151 : PHP_MINFO_FUNCTION(date)
     885             : {
     886         151 :         const timelib_tzdb *tzdb = DATE_TIMEZONEDB;
     887             :         
     888         151 :         php_info_print_table_start();
     889         151 :         php_info_print_table_row(2, "date/time support", "enabled");
     890         151 :         php_info_print_table_row(2, "\"Olson\" Timezone Database Version", tzdb->version);
     891         151 :         php_info_print_table_row(2, "Timezone Database", php_date_global_timezone_db_enabled ? "external" : "internal");
     892         151 :         php_info_print_table_row(2, "Default timezone", guess_timezone(tzdb TSRMLS_CC));
     893         151 :         php_info_print_table_end();
     894             : 
     895         151 :         DISPLAY_INI_ENTRIES();
     896         151 : }
     897             : /* }}} */
     898             : 
     899             : /* {{{ Timezone Cache functions */
     900       15366 : static timelib_tzinfo *php_date_parse_tzfile(char *formal_tzname, const timelib_tzdb *tzdb TSRMLS_DC)
     901             : {
     902             :         timelib_tzinfo *tzi, **ptzi;
     903             : 
     904       15366 :         if(!DATEG(tzcache)) {
     905         641 :                 ALLOC_HASHTABLE(DATEG(tzcache));
     906         641 :                 zend_hash_init(DATEG(tzcache), 4, NULL, _php_date_tzinfo_dtor, 0);
     907             :         }
     908             : 
     909       15366 :         if (zend_hash_find(DATEG(tzcache), formal_tzname, strlen(formal_tzname) + 1, (void **) &ptzi) == SUCCESS) {
     910       13658 :                 return *ptzi;
     911             :         }
     912             : 
     913        1708 :         tzi = timelib_parse_tzfile(formal_tzname, tzdb);
     914        1708 :         if (tzi) {
     915        1705 :                 zend_hash_add(DATEG(tzcache), formal_tzname, strlen(formal_tzname) + 1, (void *) &tzi, sizeof(timelib_tzinfo*), NULL);
     916             :         }
     917        1708 :         return tzi;
     918             : }
     919             : 
     920        2261 : timelib_tzinfo *php_date_parse_tzfile_wrapper(char *formal_tzname, const timelib_tzdb *tzdb)
     921             : {
     922             :         TSRMLS_FETCH();
     923        2261 :         return php_date_parse_tzfile(formal_tzname, tzdb TSRMLS_CC);
     924             : }
     925             : /* }}} */
     926             : 
     927             : /* Callback to check the date.timezone only when changed increases performance */
     928             : /* {{{ static PHP_INI_MH(OnUpdate_date_timezone) */
     929       21227 : static PHP_INI_MH(OnUpdate_date_timezone)
     930             : {
     931       21227 :         if (OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC) == FAILURE) {
     932           0 :                 return FAILURE;
     933             :         }
     934             : 
     935       21227 :         DATEG(timezone_valid) = 0;
     936       21227 :         if (stage == PHP_INI_STAGE_RUNTIME) {
     937          34 :                 if (!timelib_timezone_id_is_valid(DATEG(default_timezone), DATE_TIMEZONEDB)) {
     938           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG);
     939             :                 } else {
     940          34 :                         DATEG(timezone_valid) = 1;
     941             :                 }
     942             :         }
     943             : 
     944       21227 :         return SUCCESS;
     945             : }
     946             : /* }}} */
     947             : 
     948             : /* {{{ Helper functions */
     949       13249 : static char* guess_timezone(const timelib_tzdb *tzdb TSRMLS_DC)
     950             : {
     951             :         /* Checking configure timezone */
     952       13249 :         if (DATEG(timezone) && (strlen(DATEG(timezone))) > 0) {
     953       10309 :                 return DATEG(timezone);
     954             :         }
     955             :         /* Check config setting for default timezone */
     956        2940 :         if (!DATEG(default_timezone)) {
     957             :                 /* Special case: ext/date wasn't initialized yet */
     958             :                 zval ztz;
     959             : 
     960           0 :                 if (SUCCESS == zend_get_configuration_directive("date.timezone", sizeof("date.timezone"), &ztz)
     961           0 :                         && Z_TYPE(ztz) == IS_STRING && Z_STRLEN(ztz) > 0 && timelib_timezone_id_is_valid(Z_STRVAL(ztz), tzdb)) {
     962           0 :                         return Z_STRVAL(ztz);
     963             :                 }
     964        2940 :         } else if (*DATEG(default_timezone)) {
     965        2572 :                 if (DATEG(timezone_valid) == 1) {
     966        2454 :                         return DATEG(default_timezone);
     967             :                 }
     968             : 
     969         118 :                 if (!timelib_timezone_id_is_valid(DATEG(default_timezone), tzdb)) {
     970           2 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid date.timezone value '%s', we selected the timezone 'UTC' for now.", DATEG(default_timezone));
     971           2 :                         return "UTC";
     972             :                 }
     973             : 
     974         116 :                 DATEG(timezone_valid) = 1;
     975         116 :                 return DATEG(default_timezone);
     976             :         }
     977             :         /* Fallback to UTC */
     978         368 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, DATE_TZ_ERRMSG "We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone.");
     979         368 :         return "UTC";
     980             : }
     981             : 
     982       13098 : PHPAPI timelib_tzinfo *get_timezone_info(TSRMLS_D)
     983             : {
     984             :         char *tz;
     985             :         timelib_tzinfo *tzi;
     986             : 
     987       13098 :         tz = guess_timezone(DATE_TIMEZONEDB TSRMLS_CC);
     988       13098 :         tzi = php_date_parse_tzfile(tz, DATE_TIMEZONEDB TSRMLS_CC);
     989       13098 :         if (! tzi) {
     990           0 :                 php_error_docref(NULL TSRMLS_CC, E_ERROR, "Timezone database is corrupt - this should *never* happen!");
     991             :         }
     992       13098 :         return tzi;
     993             : }
     994             : /* }}} */
     995             : 
     996             : 
     997             : /* {{{ date() and gmdate() data */
     998             : #include "ext/standard/php_smart_str.h"
     999             : 
    1000             : static char *mon_full_names[] = {
    1001             :         "January", "February", "March", "April",
    1002             :         "May", "June", "July", "August",
    1003             :         "September", "October", "November", "December"
    1004             : };
    1005             : 
    1006             : static char *mon_short_names[] = {
    1007             :         "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    1008             : };
    1009             : 
    1010             : static char *day_full_names[] = {
    1011             :         "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
    1012             : };
    1013             : 
    1014             : static char *day_short_names[] = {
    1015             :         "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
    1016             : };
    1017             : 
    1018          37 : static char *english_suffix(timelib_sll number)
    1019             : {
    1020          37 :         if (number >= 10 && number <= 19) {
    1021          13 :                 return "th";
    1022             :         } else {
    1023          24 :                 switch (number % 10) {
    1024           4 :                         case 1: return "st";
    1025           2 :                         case 2: return "nd";
    1026           2 :                         case 3: return "rd";
    1027             :                 }
    1028             :         }
    1029          16 :         return "th";
    1030             : }
    1031             : /* }}} */
    1032             : 
    1033             : /* {{{ day of week helpers */
    1034         294 : char *php_date_full_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
    1035             : {
    1036         294 :         timelib_sll day_of_week = timelib_day_of_week(y, m, d);
    1037         294 :         if (day_of_week < 0) {
    1038           1 :                 return "Unknown";
    1039             :         } 
    1040         293 :         return day_full_names[day_of_week];     
    1041             : }
    1042             : 
    1043         491 : char *php_date_short_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
    1044             : {
    1045         491 :         timelib_sll day_of_week = timelib_day_of_week(y, m, d);
    1046         491 :         if (day_of_week < 0) {
    1047           1 :                 return "Unknown";
    1048             :         } 
    1049         490 :         return day_short_names[day_of_week];    
    1050             : }
    1051             : /* }}} */
    1052             : 
    1053             : /* {{{ date_format - (gm)date helper */
    1054        9700 : static char *date_format(char *format, int format_len, timelib_time *t, int localtime)
    1055             : {
    1056        9700 :         smart_str            string = {0};
    1057        9700 :         int                  i, length = 0;
    1058             :         char                 buffer[97];
    1059        9700 :         timelib_time_offset *offset = NULL;
    1060             :         timelib_sll          isoweek, isoyear;
    1061             :         int                  rfc_colon;
    1062        9700 :         int                  weekYearSet = 0;
    1063             : 
    1064        9700 :         if (!format_len) {
    1065          41 :                 return estrdup("");
    1066             :         }
    1067             : 
    1068        9659 :         if (localtime) {
    1069        8362 :                 if (t->zone_type == TIMELIB_ZONETYPE_ABBR) {
    1070        1259 :                         offset = timelib_time_offset_ctor();
    1071        1259 :                         offset->offset = (t->z - (t->dst * 60)) * -60;
    1072        1259 :                         offset->leap_secs = 0;
    1073        1259 :                         offset->is_dst = t->dst;
    1074        1259 :                         offset->abbr = strdup(t->tz_abbr);
    1075        7103 :                 } else if (t->zone_type == TIMELIB_ZONETYPE_OFFSET) {
    1076         174 :                         offset = timelib_time_offset_ctor();
    1077         174 :                         offset->offset = (t->z) * -60;
    1078         174 :                         offset->leap_secs = 0;
    1079         174 :                         offset->is_dst = 0;
    1080         174 :                         offset->abbr = malloc(9); /* GMT�xxxx\0 */
    1081         696 :                         snprintf(offset->abbr, 9, "GMT%c%02d%02d", 
    1082         174 :                                                   localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
    1083         174 :                                                   localtime ? abs(offset->offset / 3600) : 0,
    1084         174 :                                                   localtime ? abs((offset->offset % 3600) / 60) : 0 );
    1085             :                 } else {
    1086        6929 :                         offset = timelib_get_time_zone_info(t->sse, t->tz_info);
    1087             :                 }
    1088             :         }
    1089             : 
    1090       92023 :         for (i = 0; i < format_len; i++) {
    1091       82364 :                 rfc_colon = 0;
    1092       82364 :                 switch (format[i]) {
    1093             :                         /* day */
    1094        6125 :                         case 'd': length = slprintf(buffer, 32, "%02d", (int) t->d); break;
    1095         433 :                         case 'D': length = slprintf(buffer, 32, "%s", php_date_short_day_name(t->y, t->m, t->d)); break;
    1096          86 :                         case 'j': length = slprintf(buffer, 32, "%d", (int) t->d); break;
    1097         257 :                         case 'l': length = slprintf(buffer, 32, "%s", php_date_full_day_name(t->y, t->m, t->d)); break;
    1098          37 :                         case 'S': length = slprintf(buffer, 32, "%s", english_suffix(t->d)); break;
    1099          12 :                         case 'w': length = slprintf(buffer, 32, "%d", (int) timelib_day_of_week(t->y, t->m, t->d)); break;
    1100           8 :                         case 'N': length = slprintf(buffer, 32, "%d", (int) timelib_iso_day_of_week(t->y, t->m, t->d)); break;
    1101           6 :                         case 'z': length = slprintf(buffer, 32, "%d", (int) timelib_day_of_year(t->y, t->m, t->d)); break;
    1102             : 
    1103             :                         /* week */
    1104             :                         case 'W':
    1105        1044 :                                 if(!weekYearSet) { timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear); weekYearSet = 1; }
    1106        1044 :                                 length = slprintf(buffer, 32, "%02d", (int) isoweek); break; /* iso weeknr */
    1107             :                         case 'o':
    1108        1030 :                                 if(!weekYearSet) { timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear); weekYearSet = 1; }
    1109        1030 :                                 length = slprintf(buffer, 32, "%d", (int) isoyear); break; /* iso year */
    1110             : 
    1111             :                         /* month */
    1112          65 :                         case 'F': length = slprintf(buffer, 32, "%s", mon_full_names[t->m - 1]); break;
    1113        5982 :                         case 'm': length = slprintf(buffer, 32, "%02d", (int) t->m); break;
    1114         218 :                         case 'M': length = slprintf(buffer, 32, "%s", mon_short_names[t->m - 1]); break;
    1115          18 :                         case 'n': length = slprintf(buffer, 32, "%d", (int) t->m); break;
    1116          20 :                         case 't': length = slprintf(buffer, 32, "%d", (int) timelib_days_in_month(t->y, t->m)); break;
    1117             : 
    1118             :                         /* year */
    1119          10 :                         case 'L': length = slprintf(buffer, 32, "%d", timelib_is_leap((int) t->y)); break;
    1120          64 :                         case 'y': length = slprintf(buffer, 32, "%02d", (int) t->y % 100); break;
    1121        6200 :                         case 'Y': length = slprintf(buffer, 32, "%s%04lld", t->y < 0 ? "-" : "", php_date_llabs((timelib_sll) t->y)); break;
    1122             : 
    1123             :                         /* time */
    1124          39 :                         case 'a': length = slprintf(buffer, 32, "%s", t->h >= 12 ? "pm" : "am"); break;
    1125          10 :                         case 'A': length = slprintf(buffer, 32, "%s", t->h >= 12 ? "PM" : "AM"); break;
    1126             :                         case 'B': {
    1127           6 :                                 int retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);                     
    1128          12 :                                 while (retval < 0) {
    1129           0 :                                         retval += 1000;
    1130             :                                 }
    1131           6 :                                 retval = retval % 1000;
    1132           6 :                                 length = slprintf(buffer, 32, "%03d", retval);
    1133           6 :                                 break;
    1134             :                         }
    1135          38 :                         case 'g': length = slprintf(buffer, 32, "%d", (t->h % 12) ? (int) t->h % 12 : 12); break;
    1136          12 :                         case 'G': length = slprintf(buffer, 32, "%d", (int) t->h); break;
    1137          23 :                         case 'h': length = slprintf(buffer, 32, "%02d", (t->h % 12) ? (int) t->h % 12 : 12); break;
    1138        5901 :                         case 'H': length = slprintf(buffer, 32, "%02d", (int) t->h); break;
    1139        5957 :                         case 'i': length = slprintf(buffer, 32, "%02d", (int) t->i); break;
    1140        5941 :                         case 's': length = slprintf(buffer, 32, "%02d", (int) t->s); break;
    1141        1007 :                         case 'u': length = slprintf(buffer, 32, "%06d", (int) floor(t->f * 1000000 + 0.5)); break;
    1142             : 
    1143             :                         /* timezone */
    1144         123 :                         case 'I': length = slprintf(buffer, 32, "%d", localtime ? offset->is_dst : 0); break;
    1145          28 :                         case 'P': rfc_colon = 1; /* break intentionally missing */
    1146        2602 :                         case 'O': length = slprintf(buffer, 32, "%c%02d%s%02d",
    1147         363 :                                                                                         localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
    1148         363 :                                                                                         localtime ? abs(offset->offset / 3600) : 0,
    1149             :                                                                                         rfc_colon ? ":" : "",
    1150         363 :                                                                                         localtime ? abs((offset->offset % 3600) / 60) : 0
    1151             :                                                           );
    1152        1513 :                                           break;
    1153        3546 :                         case 'T': length = slprintf(buffer, 32, "%s", localtime ? offset->abbr : "GMT"); break;
    1154         376 :                         case 'e': if (!localtime) {
    1155           4 :                                               length = slprintf(buffer, 32, "%s", "UTC");
    1156             :                                           } else {
    1157         372 :                                                   switch (t->zone_type) {
    1158             :                                                           case TIMELIB_ZONETYPE_ID:
    1159         171 :                                                                   length = slprintf(buffer, 32, "%s", t->tz_info->name);
    1160         171 :                                                                   break;
    1161             :                                                           case TIMELIB_ZONETYPE_ABBR:
    1162          98 :                                                                   length = slprintf(buffer, 32, "%s", offset->abbr);
    1163          98 :                                                                   break;
    1164             :                                                           case TIMELIB_ZONETYPE_OFFSET:
    1165         309 :                                                                   length = slprintf(buffer, 32, "%c%02d:%02d",
    1166         103 :                                                                                                 ((offset->offset < 0) ? '-' : '+'),
    1167         103 :                                                                                                 abs(offset->offset / 3600),
    1168         103 :                                                                                                 abs((offset->offset % 3600) / 60)
    1169             :                                                                                    );
    1170             :                                                                   break;
    1171             :                                                   }
    1172             :                                           }
    1173         376 :                                           break;
    1174           5 :                         case 'Z': length = slprintf(buffer, 32, "%d", localtime ? offset->offset : 0); break;
    1175             : 
    1176             :                         /* full date/time */
    1177          40 :                         case 'c': length = slprintf(buffer, 96, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
    1178             :                                                                         (int) t->y, (int) t->m, (int) t->d,
    1179             :                                                                                         (int) t->h, (int) t->i, (int) t->s,
    1180           9 :                                                                                         localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
    1181           9 :                                                                                         localtime ? abs(offset->offset / 3600) : 0,
    1182           9 :                                                                                         localtime ? abs((offset->offset % 3600) / 60) : 0
    1183             :                                                           );
    1184          13 :                                           break;
    1185         260 :                         case 'r': length = slprintf(buffer, 96, "%3s, %02d %3s %04d %02d:%02d:%02d %c%02d%02d",
    1186             :                                                                         php_date_short_day_name(t->y, t->m, t->d),
    1187          58 :                                                                                         (int) t->d, mon_short_names[t->m - 1],
    1188             :                                                                                         (int) t->y, (int) t->h, (int) t->i, (int) t->s,
    1189          48 :                                                                                         localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
    1190          48 :                                                                                         localtime ? abs(offset->offset / 3600) : 0,
    1191          48 :                                                                                         localtime ? abs((offset->offset % 3600) / 60) : 0
    1192             :                                                           );
    1193          58 :                                           break;
    1194          31 :                         case 'U': length = slprintf(buffer, 32, "%lld", (timelib_sll) t->sse); break;
    1195             : 
    1196        1476 :                         case '\\': if (i < format_len) i++; /* break intentionally missing */
    1197             : 
    1198       36150 :                         default: buffer[0] = format[i]; buffer[1] = '\0'; length = 1; break;
    1199             :                 }
    1200       82364 :                 smart_str_appendl(&string, buffer, length);
    1201             :         }
    1202             : 
    1203        9659 :         smart_str_0(&string);
    1204             : 
    1205        9659 :         if (localtime) {
    1206        8362 :                 timelib_time_offset_dtor(offset);
    1207             :         }
    1208             : 
    1209        9659 :         return string.c;
    1210             : }
    1211             : 
    1212        3141 : static void php_date(INTERNAL_FUNCTION_PARAMETERS, int localtime)
    1213             : {
    1214             :         char   *format;
    1215             :         int     format_len;
    1216             :         long    ts;
    1217             :         char   *string;
    1218             : 
    1219        3141 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &ts) == FAILURE) {
    1220          44 :                 RETURN_FALSE;
    1221             :         }
    1222        3097 :         if (ZEND_NUM_ARGS() == 1) {
    1223         170 :                 ts = time(NULL);
    1224             :         }
    1225             : 
    1226        3097 :         string = php_format_date(format, format_len, ts, localtime TSRMLS_CC);
    1227             :         
    1228        3097 :         RETVAL_STRING(string, 0);
    1229             : }
    1230             : /* }}} */
    1231             : 
    1232        4216 : PHPAPI char *php_format_date(char *format, int format_len, time_t ts, int localtime TSRMLS_DC) /* {{{ */
    1233             : {
    1234             :         timelib_time   *t;
    1235             :         timelib_tzinfo *tzi;
    1236             :         char *string;
    1237             : 
    1238        4216 :         t = timelib_time_ctor();
    1239             : 
    1240        4216 :         if (localtime) {
    1241        2903 :                 tzi = get_timezone_info(TSRMLS_C);
    1242        2903 :                 t->tz_info = tzi;
    1243        2903 :                 t->zone_type = TIMELIB_ZONETYPE_ID;
    1244        2903 :                 timelib_unixtime2local(t, ts);
    1245             :         } else {
    1246        1313 :                 tzi = NULL;
    1247        1313 :                 timelib_unixtime2gmt(t, ts);
    1248             :         }
    1249             : 
    1250        4216 :         string = date_format(format, format_len, t, localtime);
    1251             :         
    1252        4216 :         timelib_time_dtor(t);
    1253        4216 :         return string;
    1254             : }
    1255             : /* }}} */
    1256             : 
    1257             : /* {{{ php_idate
    1258             :  */
    1259          83 : PHPAPI int php_idate(char format, time_t ts, int localtime TSRMLS_DC)
    1260             : {
    1261             :         timelib_time   *t;
    1262             :         timelib_tzinfo *tzi;
    1263          83 :         int retval = -1;
    1264          83 :         timelib_time_offset *offset = NULL;
    1265             :         timelib_sll isoweek, isoyear;
    1266             : 
    1267          83 :         t = timelib_time_ctor();
    1268             : 
    1269          83 :         if (!localtime) {
    1270          83 :                 tzi = get_timezone_info(TSRMLS_C);
    1271          83 :                 t->tz_info = tzi;
    1272          83 :                 t->zone_type = TIMELIB_ZONETYPE_ID;
    1273          83 :                 timelib_unixtime2local(t, ts);
    1274             :         } else {
    1275           0 :                 tzi = NULL;
    1276           0 :                 timelib_unixtime2gmt(t, ts);
    1277             :         }
    1278             : 
    1279          83 :         if (!localtime) {
    1280          83 :                 if (t->zone_type == TIMELIB_ZONETYPE_ABBR) {
    1281           0 :                         offset = timelib_time_offset_ctor();
    1282           0 :                         offset->offset = (t->z - (t->dst * 60)) * -60;
    1283           0 :                         offset->leap_secs = 0;
    1284           0 :                         offset->is_dst = t->dst;
    1285           0 :                         offset->abbr = strdup(t->tz_abbr);
    1286          83 :                 } else if (t->zone_type == TIMELIB_ZONETYPE_OFFSET) {
    1287           0 :                         offset = timelib_time_offset_ctor();
    1288           0 :                         offset->offset = (t->z - (t->dst * 60)) * -60;
    1289           0 :                         offset->leap_secs = 0;
    1290           0 :                         offset->is_dst = t->dst;
    1291           0 :                         offset->abbr = malloc(9); /* GMT�xxxx\0 */
    1292           0 :                         snprintf(offset->abbr, 9, "GMT%c%02d%02d", 
    1293           0 :                                                   !localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
    1294           0 :                                                   !localtime ? abs(offset->offset / 3600) : 0,
    1295           0 :                                                   !localtime ? abs((offset->offset % 3600) / 60) : 0 );
    1296             :                 } else {
    1297          83 :                         offset = timelib_get_time_zone_info(t->sse, t->tz_info);
    1298             :                 }
    1299             :         }
    1300             : 
    1301          83 :         timelib_isoweek_from_date(t->y, t->m, t->d, &isoweek, &isoyear);
    1302             : 
    1303          83 :         switch (format) {
    1304             :                 /* day */
    1305           4 :                 case 'd': case 'j': retval = (int) t->d; break;
    1306             : 
    1307           3 :                 case 'w': retval = (int) timelib_day_of_week(t->y, t->m, t->d); break;
    1308           3 :                 case 'z': retval = (int) timelib_day_of_year(t->y, t->m, t->d); break;
    1309             : 
    1310             :                 /* week */
    1311           3 :                 case 'W': retval = (int) isoweek; break; /* iso weeknr */
    1312             : 
    1313             :                 /* month */
    1314           4 :                 case 'm': case 'n': retval = (int) t->m; break;
    1315           3 :                 case 't': retval = (int) timelib_days_in_month(t->y, t->m); break;
    1316             : 
    1317             :                 /* year */
    1318           3 :                 case 'L': retval = (int) timelib_is_leap((int) t->y); break;
    1319           5 :                 case 'y': retval = (int) (t->y % 100); break;
    1320          17 :                 case 'Y': retval = (int) t->y; break;
    1321             : 
    1322             :                 /* Swatch Beat a.k.a. Internet Time */
    1323             :                 case 'B':
    1324           4 :                         retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);                 
    1325           8 :                         while (retval < 0) {
    1326           0 :                                 retval += 1000;
    1327             :                         }
    1328           4 :                         retval = retval % 1000;
    1329           4 :                         break;
    1330             : 
    1331             :                 /* time */
    1332           4 :                 case 'g': case 'h': retval = (int) ((t->h % 12) ? (int) t->h % 12 : 12); break;
    1333           4 :                 case 'H': case 'G': retval = (int) t->h; break;
    1334           3 :                 case 'i': retval = (int) t->i; break;
    1335           3 :                 case 's': retval = (int) t->s; break;
    1336             : 
    1337             :                 /* timezone */
    1338           3 :                 case 'I': retval = (int) (!localtime ? offset->is_dst : 0); break;
    1339           2 :                 case 'Z': retval = (int) (!localtime ? offset->offset : 0); break;
    1340             : 
    1341           3 :                 case 'U': retval = (int) t->sse; break;
    1342             :         }
    1343             : 
    1344          83 :         if (!localtime) {
    1345          83 :                 timelib_time_offset_dtor(offset);
    1346             :         }
    1347          83 :         timelib_time_dtor(t);
    1348             : 
    1349          83 :         return retval;
    1350             : }
    1351             : /* }}} */
    1352             : 
    1353             : /* {{{ proto string date(string format [, long timestamp])
    1354             :    Format a local date/time */
    1355        2920 : PHP_FUNCTION(date)
    1356             : {
    1357        2920 :         php_date(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    1358        2920 : }
    1359             : /* }}} */
    1360             : 
    1361             : /* {{{ proto string gmdate(string format [, long timestamp])
    1362             :    Format a GMT date/time */
    1363         221 : PHP_FUNCTION(gmdate)
    1364             : {
    1365         221 :         php_date(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    1366         221 : }
    1367             : /* }}} */
    1368             : 
    1369             : /* {{{ proto int idate(string format [, int timestamp])
    1370             :    Format a local time/date as integer */
    1371         142 : PHP_FUNCTION(idate)
    1372             : {
    1373             :         char   *format;
    1374             :         int     format_len;
    1375         142 :         long    ts = 0;
    1376             :         int ret; 
    1377             : 
    1378         142 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &ts) == FAILURE) {
    1379          26 :                 RETURN_FALSE;
    1380             :         }
    1381             : 
    1382         116 :         if (format_len != 1) {
    1383          33 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "idate format is one char");
    1384          33 :                 RETURN_FALSE;
    1385             :         }
    1386             : 
    1387          83 :         if (ZEND_NUM_ARGS() == 1) {
    1388          24 :                 ts = time(NULL);
    1389             :         }
    1390             : 
    1391          83 :         ret = php_idate(format[0], ts, 0 TSRMLS_CC);
    1392          83 :         if (ret == -1) {
    1393          12 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unrecognized date format token.");
    1394          12 :                 RETURN_FALSE;
    1395             :         }
    1396          71 :         RETURN_LONG(ret);
    1397             : }
    1398             : /* }}} */
    1399             : 
    1400             : /* {{{ php_date_set_tzdb - NOT THREADSAFE */
    1401           0 : PHPAPI void php_date_set_tzdb(timelib_tzdb *tzdb)
    1402             : {
    1403           0 :         const timelib_tzdb *builtin = timelib_builtin_db();
    1404             :         
    1405           0 :         if (php_version_compare(tzdb->version, builtin->version) > 0) {
    1406           0 :                 php_date_global_timezone_db = tzdb;
    1407           0 :                 php_date_global_timezone_db_enabled = 1;
    1408             :         }
    1409           0 : }
    1410             : /* }}} */
    1411             : 
    1412             : /* {{{ php_parse_date: Backwards compatibility function */
    1413          12 : PHPAPI signed long php_parse_date(char *string, signed long *now)
    1414             : {
    1415             :         timelib_time *parsed_time;
    1416          12 :         timelib_error_container *error = NULL;
    1417             :         int           error2;
    1418             :         signed long   retval;
    1419             : 
    1420          12 :         parsed_time = timelib_strtotime(string, strlen(string), &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    1421          12 :         if (error->error_count) {
    1422           1 :                 timelib_time_dtor(parsed_time);
    1423           1 :                 timelib_error_container_dtor(error);
    1424           1 :                 return -1;
    1425             :         }
    1426          11 :         timelib_error_container_dtor(error);
    1427          11 :         timelib_update_ts(parsed_time, NULL);
    1428          11 :         retval = timelib_date_to_int(parsed_time, &error2);
    1429          11 :         timelib_time_dtor(parsed_time);
    1430          11 :         if (error2) {
    1431           0 :                 return -1;
    1432             :         }
    1433          11 :         return retval;
    1434             : }
    1435             : /* }}} */
    1436             : 
    1437             : /* {{{ proto int strtotime(string time [, int now ])
    1438             :    Convert string representation of date and time to a timestamp */
    1439        4080 : PHP_FUNCTION(strtotime)
    1440             : {
    1441             :         char *times, *initial_ts;
    1442             :         int   time_len, error1, error2;
    1443             :         struct timelib_error_container *error;
    1444        4080 :         long  preset_ts = 0, ts;
    1445             : 
    1446             :         timelib_time *t, *now;
    1447             :         timelib_tzinfo *tzi;
    1448             : 
    1449        4080 :         tzi = get_timezone_info(TSRMLS_C);
    1450             : 
    1451        4080 :         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "sl", &times, &time_len, &preset_ts) != FAILURE) {
    1452             :                 /* We have an initial timestamp */
    1453         189 :                 now = timelib_time_ctor();
    1454             : 
    1455         189 :                 initial_ts = emalloc(25);
    1456         189 :                 snprintf(initial_ts, 24, "@%ld UTC", preset_ts);
    1457         189 :                 t = timelib_strtotime(initial_ts, strlen(initial_ts), NULL, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); /* we ignore the error here, as this should never fail */
    1458         189 :                 timelib_update_ts(t, tzi);
    1459         189 :                 now->tz_info = tzi;
    1460         189 :                 now->zone_type = TIMELIB_ZONETYPE_ID;
    1461         189 :                 timelib_unixtime2local(now, t->sse);
    1462         189 :                 timelib_time_dtor(t);
    1463         189 :                 efree(initial_ts);
    1464        3891 :         } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &times, &time_len, &preset_ts) != FAILURE) {
    1465             :                 /* We have no initial timestamp */
    1466        3891 :                 now = timelib_time_ctor();
    1467        3891 :                 now->tz_info = tzi;
    1468        3891 :                 now->zone_type = TIMELIB_ZONETYPE_ID;
    1469        3891 :                 timelib_unixtime2local(now, (timelib_sll) time(NULL));
    1470             :         } else {
    1471           0 :                 RETURN_FALSE;
    1472             :         }
    1473             : 
    1474        4080 :         if (!time_len) {
    1475           1 :                 timelib_time_dtor(now); 
    1476           1 :                 RETURN_FALSE;
    1477             :         }
    1478             : 
    1479        4079 :         t = timelib_strtotime(times, time_len, &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    1480        4079 :         error1 = error->error_count;
    1481        4079 :         timelib_error_container_dtor(error);
    1482        4079 :         timelib_fill_holes(t, now, TIMELIB_NO_CLONE);
    1483        4079 :         timelib_update_ts(t, tzi);
    1484        4079 :         ts = timelib_date_to_int(t, &error2);
    1485             : 
    1486        4079 :         timelib_time_dtor(now);
    1487        4079 :         timelib_time_dtor(t);
    1488             : 
    1489        4079 :         if (error1 || error2) {
    1490          11 :                 RETURN_FALSE;
    1491             :         } else {
    1492        4068 :                 RETURN_LONG(ts);
    1493             :         }
    1494             : }
    1495             : /* }}} */
    1496             : 
    1497             : /* {{{ php_mktime - (gm)mktime helper */
    1498         994 : PHPAPI void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
    1499             : {
    1500         994 :         long hou = 0, min = 0, sec = 0, mon = 0, day = 0, yea = 0, dst = -1;
    1501             :         timelib_time *now;
    1502         994 :         timelib_tzinfo *tzi = NULL;
    1503         994 :         long ts, adjust_seconds = 0;
    1504             :         int error;
    1505             : 
    1506         994 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lllllll", &hou, &min, &sec, &mon, &day, &yea, &dst) == FAILURE) {
    1507         165 :                 RETURN_FALSE;
    1508             :         }
    1509             :         /* Initialize structure with current time */
    1510         829 :         now = timelib_time_ctor();
    1511         829 :         if (gmt) {
    1512         117 :                 timelib_unixtime2gmt(now, (timelib_sll) time(NULL));
    1513             :         } else {
    1514         712 :                 tzi = get_timezone_info(TSRMLS_C);
    1515         712 :                 now->tz_info = tzi;
    1516         712 :                 now->zone_type = TIMELIB_ZONETYPE_ID;
    1517         712 :                 timelib_unixtime2local(now, (timelib_sll) time(NULL));
    1518             :         }
    1519             :         /* Fill in the new data */
    1520         829 :         switch (ZEND_NUM_ARGS()) {
    1521             :                 case 7:
    1522             :                         /* break intentionally missing */
    1523             :                 case 6:
    1524         772 :                         if (yea >= 0 && yea < 70) {
    1525          25 :                                 yea += 2000;
    1526         722 :                         } else if (yea >= 70 && yea <= 100) {
    1527           8 :                                 yea += 1900;
    1528             :                         }
    1529         747 :                         now->y = yea;
    1530             :                         /* break intentionally missing again */
    1531             :                 case 5:
    1532         763 :                         now->d = day;
    1533             :                         /* break missing intentionally here too */
    1534             :                 case 4:
    1535         779 :                         now->m = mon;
    1536             :                         /* and here */
    1537             :                 case 3:
    1538         795 :                         now->s = sec;
    1539             :                         /* yup, this break isn't here on purpose too */
    1540             :                 case 2:
    1541         811 :                         now->i = min;
    1542             :                         /* last intentionally missing break */
    1543             :                 case 1:
    1544         827 :                         now->h = hou;
    1545         827 :                         break;
    1546             :                 default:
    1547           2 :                         php_error_docref(NULL TSRMLS_CC, E_STRICT, "You should be using the time() function instead");
    1548             :         }
    1549             :         /* Update the timestamp */
    1550         829 :         if (gmt) {
    1551         117 :                 timelib_update_ts(now, NULL);
    1552             :         } else {
    1553         712 :                 timelib_update_ts(now, tzi);
    1554             :         }
    1555             :         /* Support for the deprecated is_dst parameter */
    1556         829 :         if (dst != -1) {
    1557          39 :                 php_error_docref(NULL TSRMLS_CC, E_DEPRECATED, "The is_dst parameter is deprecated");
    1558          39 :                 if (gmt) {
    1559             :                         /* GMT never uses DST */
    1560           1 :                         if (dst == 1) {
    1561           0 :                                 adjust_seconds = -3600;
    1562             :                         }
    1563             :                 } else {
    1564             :                         /* Figure out is_dst for current TS */
    1565             :                         timelib_time_offset *tmp_offset;
    1566          38 :                         tmp_offset = timelib_get_time_zone_info(now->sse, tzi);
    1567          38 :                         if (dst == 1 && tmp_offset->is_dst == 0) {
    1568           7 :                                 adjust_seconds = -3600;
    1569             :                         }
    1570          38 :                         if (dst == 0 && tmp_offset->is_dst == 1) {
    1571          13 :                                 adjust_seconds = +3600;
    1572             :                         }
    1573          38 :                         timelib_time_offset_dtor(tmp_offset);
    1574             :                 }
    1575             :         }
    1576             :         /* Clean up and return */
    1577         829 :         ts = timelib_date_to_int(now, &error);
    1578         829 :         ts += adjust_seconds;
    1579         829 :         timelib_time_dtor(now);
    1580             : 
    1581         829 :         if (error) {
    1582           0 :                 RETURN_FALSE;
    1583             :         } else {
    1584         829 :                 RETURN_LONG(ts);
    1585             :         }
    1586             : }
    1587             : /* }}} */
    1588             : 
    1589             : /* {{{ proto int mktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]])
    1590             :    Get UNIX timestamp for a date */
    1591         804 : PHP_FUNCTION(mktime)
    1592             : {
    1593         804 :         php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    1594         804 : }
    1595             : /* }}} */
    1596             : 
    1597             : /* {{{ proto int gmmktime([int hour [, int min [, int sec [, int mon [, int day [, int year]]]]]])
    1598             :    Get UNIX timestamp for a GMT date */
    1599         190 : PHP_FUNCTION(gmmktime)
    1600             : {
    1601         190 :         php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    1602         190 : }
    1603             : /* }}} */
    1604             : 
    1605             : /* {{{ proto bool checkdate(int month, int day, int year)
    1606             :    Returns true(1) if it is a valid date in gregorian calendar */
    1607         100 : PHP_FUNCTION(checkdate)
    1608             : {
    1609             :         long m, d, y;
    1610             : 
    1611         100 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &m, &d, &y) == FAILURE) {
    1612          45 :                 RETURN_FALSE;
    1613             :         }
    1614             : 
    1615          55 :         if (y < 1 || y > 32767 || !timelib_valid_date(y, m, d)) {
    1616          36 :                 RETURN_FALSE;
    1617             :         }
    1618          19 :         RETURN_TRUE;    /* True : This month, day, year arguments are valid */
    1619             : }
    1620             : /* }}} */
    1621             : 
    1622             : #ifdef HAVE_STRFTIME
    1623             : /* {{{ php_strftime - (gm)strftime helper */
    1624         358 : PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
    1625             : {
    1626             :         char                *format, *buf;
    1627             :         int                  format_len;
    1628         358 :         long                 timestamp = 0;
    1629             :         struct tm            ta;
    1630         358 :         int                  max_reallocs = 5;
    1631         358 :         size_t               buf_len = 256, real_len;
    1632             :         timelib_time        *ts;
    1633             :         timelib_tzinfo      *tzi;
    1634         358 :         timelib_time_offset *offset = NULL;
    1635             : 
    1636         358 :         timestamp = (long) time(NULL);
    1637             : 
    1638         358 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &timestamp) == FAILURE) {
    1639          37 :                 RETURN_FALSE;
    1640             :         }
    1641             : 
    1642         321 :         if (format_len == 0) {
    1643          34 :                 RETURN_FALSE;
    1644             :         }
    1645             : 
    1646         287 :         ts = timelib_time_ctor();
    1647         287 :         if (gmt) {
    1648          97 :                 tzi = NULL;
    1649          97 :                 timelib_unixtime2gmt(ts, (timelib_sll) timestamp);
    1650             :         } else {
    1651         190 :                 tzi = get_timezone_info(TSRMLS_C);
    1652         190 :                 ts->tz_info = tzi;
    1653         190 :                 ts->zone_type = TIMELIB_ZONETYPE_ID;
    1654         190 :                 timelib_unixtime2local(ts, (timelib_sll) timestamp);
    1655             :         }
    1656         287 :         ta.tm_sec   = ts->s;
    1657         287 :         ta.tm_min   = ts->i;
    1658         287 :         ta.tm_hour  = ts->h;
    1659         287 :         ta.tm_mday  = ts->d;
    1660         287 :         ta.tm_mon   = ts->m - 1;
    1661         287 :         ta.tm_year  = ts->y - 1900;
    1662         287 :         ta.tm_wday  = timelib_day_of_week(ts->y, ts->m, ts->d);
    1663         287 :         ta.tm_yday  = timelib_day_of_year(ts->y, ts->m, ts->d);
    1664         287 :         if (gmt) {
    1665          97 :                 ta.tm_isdst = 0;
    1666             : #if HAVE_TM_GMTOFF
    1667          97 :                 ta.tm_gmtoff = 0;
    1668             : #endif
    1669             : #if HAVE_TM_ZONE
    1670          97 :                 ta.tm_zone = "GMT";
    1671             : #endif
    1672             :         } else {
    1673         190 :                 offset = timelib_get_time_zone_info(timestamp, tzi);
    1674             : 
    1675         190 :                 ta.tm_isdst = offset->is_dst;
    1676             : #if HAVE_TM_GMTOFF
    1677         190 :                 ta.tm_gmtoff = offset->offset;
    1678             : #endif
    1679             : #if HAVE_TM_ZONE
    1680         190 :                 ta.tm_zone = offset->abbr;
    1681             : #endif
    1682             :         }
    1683             : 
    1684             :         /* VS2012 crt has a bug where strftime crash with %z and %Z format when the
    1685             :            initial buffer is too small. See
    1686             :            http://connect.microsoft.com/VisualStudio/feedback/details/759720/vs2012-strftime-crash-with-z-formatting-code */
    1687         287 :         buf = (char *) emalloc(buf_len);
    1688         574 :         while ((real_len=strftime(buf, buf_len, format, &ta))==buf_len || real_len==0) {
    1689           0 :                 buf_len *= 2;
    1690           0 :                 buf = (char *) erealloc(buf, buf_len);
    1691           0 :                 if (!--max_reallocs) {
    1692           0 :                         break;
    1693             :                 }
    1694             :         }
    1695             : #if defined(PHP_WIN32) && _MSC_VER >= 1700
    1696             :         /* VS2012 strftime() returns number of characters, not bytes.
    1697             :                 See VC++11 bug id 766205. */
    1698             :         if (real_len > 0) {
    1699             :                 real_len = strlen(buf);
    1700             :         }
    1701             : #endif
    1702             : 
    1703         287 :         timelib_time_dtor(ts);
    1704         287 :         if (!gmt) {
    1705         190 :                 timelib_time_offset_dtor(offset);
    1706             :         }
    1707             : 
    1708         287 :         if (real_len && real_len != buf_len) {
    1709         287 :                 buf = (char *) erealloc(buf, real_len + 1);
    1710         287 :                 RETURN_STRINGL(buf, real_len, 0);
    1711             :         }
    1712           0 :         efree(buf);
    1713           0 :         RETURN_FALSE;
    1714             : }
    1715             : /* }}} */
    1716             : 
    1717             : /* {{{ proto string strftime(string format [, int timestamp])
    1718             :    Format a local time/date according to locale settings */
    1719         231 : PHP_FUNCTION(strftime)
    1720             : {
    1721         231 :         php_strftime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    1722         231 : }
    1723             : /* }}} */
    1724             : 
    1725             : /* {{{ proto string gmstrftime(string format [, int timestamp])
    1726             :    Format a GMT/UCT time/date according to locale settings */
    1727         127 : PHP_FUNCTION(gmstrftime)
    1728             : {
    1729         127 :         php_strftime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    1730         127 : }
    1731             : /* }}} */
    1732             : #endif
    1733             : 
    1734             : /* {{{ proto int time(void)
    1735             :    Return current UNIX timestamp */
    1736       97273 : PHP_FUNCTION(time)
    1737             : {
    1738       97273 :         RETURN_LONG((long)time(NULL));
    1739             : }
    1740             : /* }}} */
    1741             : 
    1742             : /* {{{ proto array localtime([int timestamp [, bool associative_array]])
    1743             :    Returns the results of the C system call localtime as an associative array if the associative_array argument is set to 1 other wise it is a regular array */
    1744         100 : PHP_FUNCTION(localtime)
    1745             : {
    1746         100 :         long timestamp = (long)time(NULL);
    1747         100 :         zend_bool associative = 0;
    1748             :         timelib_tzinfo *tzi;
    1749             :         timelib_time   *ts;
    1750             : 
    1751         100 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lb", &timestamp, &associative) == FAILURE) {
    1752          32 :                 RETURN_FALSE;
    1753             :         }
    1754             : 
    1755          68 :         tzi = get_timezone_info(TSRMLS_C);
    1756          68 :         ts = timelib_time_ctor();
    1757          68 :         ts->tz_info = tzi;
    1758          68 :         ts->zone_type = TIMELIB_ZONETYPE_ID;
    1759          68 :         timelib_unixtime2local(ts, (timelib_sll) timestamp);
    1760             : 
    1761          68 :         array_init(return_value);
    1762             : 
    1763          68 :         if (associative) {
    1764          35 :                 add_assoc_long(return_value, "tm_sec",   ts->s);
    1765          35 :                 add_assoc_long(return_value, "tm_min",   ts->i);
    1766          35 :                 add_assoc_long(return_value, "tm_hour",  ts->h);
    1767          35 :                 add_assoc_long(return_value, "tm_mday",  ts->d);
    1768          35 :                 add_assoc_long(return_value, "tm_mon",   ts->m - 1);
    1769          35 :                 add_assoc_long(return_value, "tm_year",  ts->y - 1900);
    1770          35 :                 add_assoc_long(return_value, "tm_wday",  timelib_day_of_week(ts->y, ts->m, ts->d));
    1771          35 :                 add_assoc_long(return_value, "tm_yday",  timelib_day_of_year(ts->y, ts->m, ts->d));
    1772          35 :                 add_assoc_long(return_value, "tm_isdst", ts->dst);
    1773             :         } else {
    1774          33 :                 add_next_index_long(return_value, ts->s);
    1775          33 :                 add_next_index_long(return_value, ts->i);
    1776          33 :                 add_next_index_long(return_value, ts->h);
    1777          33 :                 add_next_index_long(return_value, ts->d);
    1778          33 :                 add_next_index_long(return_value, ts->m - 1);
    1779          33 :                 add_next_index_long(return_value, ts->y- 1900);
    1780          33 :                 add_next_index_long(return_value, timelib_day_of_week(ts->y, ts->m, ts->d));
    1781          33 :                 add_next_index_long(return_value, timelib_day_of_year(ts->y, ts->m, ts->d));
    1782          33 :                 add_next_index_long(return_value, ts->dst);
    1783             :         }
    1784             : 
    1785          68 :         timelib_time_dtor(ts);
    1786             : }
    1787             : /* }}} */
    1788             : 
    1789             : /* {{{ proto array getdate([int timestamp])
    1790             :    Get date/time information */
    1791          51 : PHP_FUNCTION(getdate)
    1792             : {
    1793          51 :         long timestamp = (long)time(NULL);
    1794             :         timelib_tzinfo *tzi;
    1795             :         timelib_time   *ts;
    1796             : 
    1797          51 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &timestamp) == FAILURE) {
    1798          14 :                 RETURN_FALSE;
    1799             :         }
    1800             : 
    1801          37 :         tzi = get_timezone_info(TSRMLS_C);
    1802          37 :         ts = timelib_time_ctor();
    1803          37 :         ts->tz_info = tzi;
    1804          37 :         ts->zone_type = TIMELIB_ZONETYPE_ID;
    1805          37 :         timelib_unixtime2local(ts, (timelib_sll) timestamp);
    1806             : 
    1807          37 :         array_init(return_value);
    1808             : 
    1809          37 :         add_assoc_long(return_value, "seconds", ts->s);
    1810          37 :         add_assoc_long(return_value, "minutes", ts->i);
    1811          37 :         add_assoc_long(return_value, "hours", ts->h);
    1812          37 :         add_assoc_long(return_value, "mday", ts->d);
    1813          37 :         add_assoc_long(return_value, "wday", timelib_day_of_week(ts->y, ts->m, ts->d));
    1814          37 :         add_assoc_long(return_value, "mon", ts->m);
    1815          37 :         add_assoc_long(return_value, "year", ts->y);
    1816          37 :         add_assoc_long(return_value, "yday", timelib_day_of_year(ts->y, ts->m, ts->d));
    1817          37 :         add_assoc_string(return_value, "weekday", php_date_full_day_name(ts->y, ts->m, ts->d), 1);
    1818          37 :         add_assoc_string(return_value, "month", mon_full_names[ts->m - 1], 1);
    1819          37 :         add_index_long(return_value, 0, timestamp);
    1820             : 
    1821          37 :         timelib_time_dtor(ts);
    1822             : }
    1823             : /* }}} */
    1824             : 
    1825             : #define PHP_DATE_TIMEZONE_GROUP_AFRICA     0x0001
    1826             : #define PHP_DATE_TIMEZONE_GROUP_AMERICA    0x0002
    1827             : #define PHP_DATE_TIMEZONE_GROUP_ANTARCTICA 0x0004
    1828             : #define PHP_DATE_TIMEZONE_GROUP_ARCTIC     0x0008
    1829             : #define PHP_DATE_TIMEZONE_GROUP_ASIA       0x0010
    1830             : #define PHP_DATE_TIMEZONE_GROUP_ATLANTIC   0x0020
    1831             : #define PHP_DATE_TIMEZONE_GROUP_AUSTRALIA  0x0040
    1832             : #define PHP_DATE_TIMEZONE_GROUP_EUROPE     0x0080
    1833             : #define PHP_DATE_TIMEZONE_GROUP_INDIAN     0x0100
    1834             : #define PHP_DATE_TIMEZONE_GROUP_PACIFIC    0x0200
    1835             : #define PHP_DATE_TIMEZONE_GROUP_UTC        0x0400
    1836             : #define PHP_DATE_TIMEZONE_GROUP_ALL        0x07FF
    1837             : #define PHP_DATE_TIMEZONE_GROUP_ALL_W_BC   0x0FFF
    1838             : #define PHP_DATE_TIMEZONE_PER_COUNTRY      0x1000
    1839             : 
    1840             : #define PHP_DATE_PERIOD_EXCLUDE_START_DATE 0x0001
    1841             : 
    1842             : 
    1843             : /* define an overloaded iterator structure */
    1844             : typedef struct {
    1845             :         zend_object_iterator  intern;
    1846             :         zval                 *date_period_zval;
    1847             :         zval                 *current;
    1848             :         php_period_obj       *object;
    1849             :         int                   current_index;
    1850             : } date_period_it;
    1851             : 
    1852             : /* {{{ date_period_it_invalidate_current */
    1853          97 : static void date_period_it_invalidate_current(zend_object_iterator *iter TSRMLS_DC)
    1854             : {
    1855          97 :         date_period_it *iterator = (date_period_it *)iter;
    1856             : 
    1857          97 :         if (iterator->current) {
    1858          75 :                 zval_ptr_dtor(&iterator->current);
    1859          75 :                 iterator->current = NULL;
    1860             :         }
    1861          97 : }
    1862             : /* }}} */
    1863             : 
    1864             : 
    1865             : /* {{{ date_period_it_dtor */
    1866          11 : static void date_period_it_dtor(zend_object_iterator *iter TSRMLS_DC)
    1867             : {
    1868          11 :         date_period_it *iterator = (date_period_it *)iter;
    1869             : 
    1870          11 :         date_period_it_invalidate_current(iter TSRMLS_CC);
    1871             : 
    1872          11 :         zval_ptr_dtor(&iterator->date_period_zval);
    1873             : 
    1874          11 :         efree(iterator);
    1875          11 : }
    1876             : /* }}} */
    1877             : 
    1878             : 
    1879             : /* {{{ date_period_it_has_more */
    1880          86 : static int date_period_it_has_more(zend_object_iterator *iter TSRMLS_DC)
    1881             : {
    1882          86 :         date_period_it *iterator = (date_period_it *)iter;
    1883          86 :         php_period_obj *object   = iterator->object;
    1884          86 :         timelib_time   *it_time = object->current;
    1885             : 
    1886             :         /* apply modification if it's not the first iteration */
    1887          86 :         if (!object->include_start_date || iterator->current_index > 0) {
    1888          76 :                 it_time->have_relative = 1;
    1889          76 :                 it_time->relative = *object->interval;
    1890          76 :                 it_time->sse_uptodate = 0;
    1891          76 :                 timelib_update_ts(it_time, NULL);
    1892          76 :                 timelib_update_from_sse(it_time);
    1893             :         }
    1894             : 
    1895          86 :         if (object->end) {
    1896          46 :                 return object->current->sse < object->end->sse ? SUCCESS : FAILURE;
    1897             :         } else {
    1898          40 :                 return (iterator->current_index < object->recurrences) ? SUCCESS : FAILURE;
    1899             :         }
    1900             : }
    1901             : /* }}} */
    1902             : 
    1903             : 
    1904             : /* {{{ date_period_it_current_data */
    1905          75 : static void date_period_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
    1906             : {
    1907          75 :         date_period_it *iterator = (date_period_it *)iter;
    1908          75 :         php_period_obj *object   = iterator->object;
    1909          75 :         timelib_time   *it_time = object->current;
    1910             :         php_date_obj   *newdateobj;
    1911             : 
    1912             :         /* Create new object */
    1913          75 :         MAKE_STD_ZVAL(iterator->current);
    1914          75 :         php_date_instantiate(object->start_ce, iterator->current TSRMLS_CC);
    1915          75 :         newdateobj = (php_date_obj *) zend_object_store_get_object(iterator->current TSRMLS_CC);
    1916          75 :         newdateobj->time = timelib_time_ctor();
    1917          75 :         *newdateobj->time = *it_time;
    1918          75 :         if (it_time->tz_abbr) {
    1919          63 :                 newdateobj->time->tz_abbr = strdup(it_time->tz_abbr);
    1920             :         }
    1921          75 :         if (it_time->tz_info) {
    1922          63 :                 newdateobj->time->tz_info = it_time->tz_info;
    1923             :         }
    1924             :         
    1925          75 :         *data = &iterator->current;
    1926          75 : }
    1927             : /* }}} */
    1928             : 
    1929             : 
    1930             : /* {{{ date_period_it_current_key */
    1931           0 : static void date_period_it_current_key(zend_object_iterator *iter, zval *key TSRMLS_DC)
    1932             : {
    1933           0 :         date_period_it *iterator = (date_period_it *)iter;
    1934           0 :         ZVAL_LONG(key, iterator->current_index);
    1935           0 : }
    1936             : /* }}} */
    1937             : 
    1938             : 
    1939             : /* {{{ date_period_it_move_forward */
    1940          75 : static void date_period_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
    1941             : {
    1942          75 :         date_period_it   *iterator = (date_period_it *)iter;
    1943             : 
    1944          75 :         iterator->current_index++;
    1945          75 :         date_period_it_invalidate_current(iter TSRMLS_CC);
    1946          75 : }
    1947             : /* }}} */
    1948             : 
    1949             : 
    1950             : /* {{{ date_period_it_rewind */
    1951          11 : static void date_period_it_rewind(zend_object_iterator *iter TSRMLS_DC)
    1952             : {
    1953          11 :         date_period_it   *iterator = (date_period_it *)iter;
    1954             : 
    1955          11 :         iterator->current_index = 0;
    1956          11 :         if (iterator->object->current) {
    1957           3 :                 timelib_time_dtor(iterator->object->current);
    1958             :         }
    1959          11 :         iterator->object->current = timelib_time_clone(iterator->object->start);
    1960          11 :         date_period_it_invalidate_current(iter TSRMLS_CC);
    1961          11 : }
    1962             : /* }}} */
    1963             : 
    1964             : 
    1965             : /* iterator handler table */
    1966             : zend_object_iterator_funcs date_period_it_funcs = {
    1967             :         date_period_it_dtor,
    1968             :         date_period_it_has_more,
    1969             :         date_period_it_current_data,
    1970             :         date_period_it_current_key,
    1971             :         date_period_it_move_forward,
    1972             :         date_period_it_rewind,
    1973             :         date_period_it_invalidate_current
    1974             : };
    1975             : 
    1976             : 
    1977             : 
    1978          11 : zend_object_iterator *date_object_period_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
    1979             : {
    1980          11 :         date_period_it  *iterator = emalloc(sizeof(date_period_it));
    1981          11 :         php_period_obj  *dpobj    = (php_period_obj *)zend_object_store_get_object(object TSRMLS_CC);
    1982             : 
    1983          11 :         if (by_ref) {
    1984           0 :                 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
    1985             :         }
    1986             : 
    1987             :         Z_ADDREF_P(object);
    1988          11 :         iterator->intern.data = (void*) dpobj;
    1989          11 :         iterator->intern.funcs = &date_period_it_funcs;
    1990          11 :         iterator->date_period_zval = object;
    1991          11 :         iterator->object = dpobj;
    1992          11 :         iterator->current = NULL;
    1993             : 
    1994          11 :         return (zend_object_iterator*)iterator;
    1995             : }
    1996             : 
    1997       42337 : static int implement_date_interface_handler(zend_class_entry *interface, zend_class_entry *implementor TSRMLS_DC)
    1998             : {
    1999       42358 :         if (implementor->type == ZEND_USER_CLASS &&
    2000          19 :                 !instanceof_function(implementor, date_ce_date TSRMLS_CC) &&
    2001           2 :                 !instanceof_function(implementor, date_ce_immutable TSRMLS_CC)
    2002             :         ) {
    2003           1 :                 zend_error(E_ERROR, "DateTimeInterface can't be implemented by user classes");
    2004             :         }
    2005             : 
    2006       42336 :         return SUCCESS;
    2007             : }
    2008             : 
    2009       21159 : static void date_register_classes(TSRMLS_D)
    2010             : {
    2011             :         zend_class_entry ce_date, ce_immutable, ce_timezone, ce_interval, ce_period, ce_interface;
    2012             : 
    2013       21159 :         INIT_CLASS_ENTRY(ce_interface, "DateTimeInterface", date_funcs_interface);
    2014       21159 :         date_ce_interface = zend_register_internal_interface(&ce_interface TSRMLS_CC);
    2015       21159 :         date_ce_interface->interface_gets_implemented = implement_date_interface_handler;
    2016             : 
    2017       21159 :         INIT_CLASS_ENTRY(ce_date, "DateTime", date_funcs_date);
    2018       21159 :         ce_date.create_object = date_object_new_date;
    2019       21159 :         date_ce_date = zend_register_internal_class_ex(&ce_date, NULL, NULL TSRMLS_CC);
    2020       21159 :         memcpy(&date_object_handlers_date, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    2021       21159 :         date_object_handlers_date.clone_obj = date_object_clone_date;
    2022       21159 :         date_object_handlers_date.compare_objects = date_object_compare_date;
    2023       21159 :         date_object_handlers_date.get_properties = date_object_get_properties;
    2024       21159 :         date_object_handlers_date.get_gc = date_object_get_gc;
    2025       21159 :         zend_class_implements(date_ce_date TSRMLS_CC, 1, date_ce_interface);
    2026             : 
    2027             : #define REGISTER_DATE_CLASS_CONST_STRING(const_name, value) \
    2028             :         zend_declare_class_constant_stringl(date_ce_date, const_name, sizeof(const_name)-1, value, sizeof(value)-1 TSRMLS_CC);
    2029             : 
    2030       21159 :         REGISTER_DATE_CLASS_CONST_STRING("ATOM",    DATE_FORMAT_RFC3339);
    2031       21159 :         REGISTER_DATE_CLASS_CONST_STRING("COOKIE",  DATE_FORMAT_COOKIE);
    2032       21159 :         REGISTER_DATE_CLASS_CONST_STRING("ISO8601", DATE_FORMAT_ISO8601);
    2033       21159 :         REGISTER_DATE_CLASS_CONST_STRING("RFC822",  DATE_FORMAT_RFC822);
    2034       21159 :         REGISTER_DATE_CLASS_CONST_STRING("RFC850",  DATE_FORMAT_RFC850);
    2035       21159 :         REGISTER_DATE_CLASS_CONST_STRING("RFC1036", DATE_FORMAT_RFC1036);
    2036       21159 :         REGISTER_DATE_CLASS_CONST_STRING("RFC1123", DATE_FORMAT_RFC1123);
    2037       21159 :         REGISTER_DATE_CLASS_CONST_STRING("RFC2822", DATE_FORMAT_RFC2822);
    2038       21159 :         REGISTER_DATE_CLASS_CONST_STRING("RFC3339", DATE_FORMAT_RFC3339);
    2039       21159 :         REGISTER_DATE_CLASS_CONST_STRING("RSS",     DATE_FORMAT_RFC1123);
    2040       21159 :         REGISTER_DATE_CLASS_CONST_STRING("W3C",     DATE_FORMAT_RFC3339);
    2041             : 
    2042       21159 :         INIT_CLASS_ENTRY(ce_immutable, "DateTimeImmutable", date_funcs_immutable);
    2043       21159 :         ce_immutable.create_object = date_object_new_date;
    2044       21159 :         date_ce_immutable = zend_register_internal_class_ex(&ce_immutable, NULL, NULL TSRMLS_CC);
    2045       21159 :         memcpy(&date_object_handlers_immutable, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    2046       21159 :         date_object_handlers_immutable.clone_obj = date_object_clone_date;
    2047       21159 :         date_object_handlers_immutable.compare_objects = date_object_compare_date;
    2048       21159 :         date_object_handlers_immutable.get_properties = date_object_get_properties;
    2049       21159 :         zend_class_implements(date_ce_immutable TSRMLS_CC, 1, date_ce_interface);
    2050             : 
    2051       21159 :         INIT_CLASS_ENTRY(ce_timezone, "DateTimeZone", date_funcs_timezone);
    2052       21159 :         ce_timezone.create_object = date_object_new_timezone;
    2053       21159 :         date_ce_timezone = zend_register_internal_class_ex(&ce_timezone, NULL, NULL TSRMLS_CC);
    2054       21159 :         memcpy(&date_object_handlers_timezone, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    2055       21159 :         date_object_handlers_timezone.clone_obj = date_object_clone_timezone;
    2056       21159 :         date_object_handlers_timezone.get_properties = date_object_get_properties_timezone;
    2057       21159 :         date_object_handlers_timezone.get_gc = date_object_get_gc_timezone;
    2058             : 
    2059             : #define REGISTER_TIMEZONE_CLASS_CONST_STRING(const_name, value) \
    2060             :         zend_declare_class_constant_long(date_ce_timezone, const_name, sizeof(const_name)-1, value TSRMLS_CC);
    2061             : 
    2062       21159 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("AFRICA",      PHP_DATE_TIMEZONE_GROUP_AFRICA);
    2063       21159 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("AMERICA",     PHP_DATE_TIMEZONE_GROUP_AMERICA);
    2064       21159 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("ANTARCTICA",  PHP_DATE_TIMEZONE_GROUP_ANTARCTICA);
    2065       21159 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("ARCTIC",      PHP_DATE_TIMEZONE_GROUP_ARCTIC);
    2066       21159 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("ASIA",        PHP_DATE_TIMEZONE_GROUP_ASIA);
    2067       21159 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("ATLANTIC",    PHP_DATE_TIMEZONE_GROUP_ATLANTIC);
    2068       21159 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("AUSTRALIA",   PHP_DATE_TIMEZONE_GROUP_AUSTRALIA);
    2069       21159 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("EUROPE",      PHP_DATE_TIMEZONE_GROUP_EUROPE);
    2070       21159 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("INDIAN",      PHP_DATE_TIMEZONE_GROUP_INDIAN);
    2071       21159 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("PACIFIC",     PHP_DATE_TIMEZONE_GROUP_PACIFIC);
    2072       21159 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("UTC",         PHP_DATE_TIMEZONE_GROUP_UTC);
    2073       21159 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("ALL",         PHP_DATE_TIMEZONE_GROUP_ALL);
    2074       21159 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("ALL_WITH_BC", PHP_DATE_TIMEZONE_GROUP_ALL_W_BC);
    2075       21159 :         REGISTER_TIMEZONE_CLASS_CONST_STRING("PER_COUNTRY", PHP_DATE_TIMEZONE_PER_COUNTRY);
    2076             : 
    2077       21159 :         INIT_CLASS_ENTRY(ce_interval, "DateInterval", date_funcs_interval);
    2078       21159 :         ce_interval.create_object = date_object_new_interval;
    2079       21159 :         date_ce_interval = zend_register_internal_class_ex(&ce_interval, NULL, NULL TSRMLS_CC);
    2080       21159 :         memcpy(&date_object_handlers_interval, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    2081       21159 :         date_object_handlers_interval.clone_obj = date_object_clone_interval;
    2082       21159 :         date_object_handlers_interval.read_property = date_interval_read_property;
    2083       21159 :         date_object_handlers_interval.write_property = date_interval_write_property;
    2084       21159 :         date_object_handlers_interval.get_properties = date_object_get_properties_interval;
    2085       21159 :         date_object_handlers_interval.get_property_ptr_ptr = NULL;
    2086       21159 :         date_object_handlers_interval.get_gc = date_object_get_gc_interval;
    2087             : 
    2088       21159 :         INIT_CLASS_ENTRY(ce_period, "DatePeriod", date_funcs_period);
    2089       21159 :         ce_period.create_object = date_object_new_period;
    2090       21159 :         date_ce_period = zend_register_internal_class_ex(&ce_period, NULL, NULL TSRMLS_CC);
    2091       21159 :         date_ce_period->get_iterator = date_object_period_get_iterator;
    2092       21159 :         date_ce_period->iterator_funcs.funcs = &date_period_it_funcs;
    2093       21159 :         zend_class_implements(date_ce_period TSRMLS_CC, 1, zend_ce_traversable);
    2094       21159 :         memcpy(&date_object_handlers_period, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    2095       21159 :         date_object_handlers_period.clone_obj = date_object_clone_period;
    2096       21159 :         date_object_handlers_period.get_properties = date_object_get_properties_period;
    2097       21159 :         date_object_handlers_period.get_property_ptr_ptr = NULL;
    2098       21159 :         date_object_handlers_period.get_gc = date_object_get_gc_period;
    2099       21159 :         date_object_handlers_period.read_property = date_period_read_property;
    2100       21159 :         date_object_handlers_period.write_property = date_period_write_property;
    2101             : 
    2102             : #define REGISTER_PERIOD_CLASS_CONST_STRING(const_name, value) \
    2103             :         zend_declare_class_constant_long(date_ce_period, const_name, sizeof(const_name)-1, value TSRMLS_CC);
    2104             : 
    2105       21159 :         REGISTER_PERIOD_CLASS_CONST_STRING("EXCLUDE_START_DATE", PHP_DATE_PERIOD_EXCLUDE_START_DATE);
    2106       21159 : }
    2107             : 
    2108      179251 : static inline zend_object_value date_object_new_date_ex(zend_class_entry *class_type, php_date_obj **ptr TSRMLS_DC)
    2109             : {
    2110             :         php_date_obj *intern;
    2111             :         zend_object_value retval;
    2112             : 
    2113      179251 :         intern = emalloc(sizeof(php_date_obj));
    2114      179251 :         memset(intern, 0, sizeof(php_date_obj));
    2115      179251 :         if (ptr) {
    2116      174261 :                 *ptr = intern;
    2117             :         }
    2118             :         
    2119      179251 :         zend_object_std_init(&intern->std, class_type TSRMLS_CC);
    2120      179251 :         object_properties_init(&intern->std, class_type);
    2121             :         
    2122      179251 :         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_date, NULL TSRMLS_CC);
    2123      179251 :         retval.handlers = &date_object_handlers_date;
    2124             :         
    2125      179251 :         return retval;
    2126             : }
    2127             : 
    2128        4990 : static zend_object_value date_object_new_date(zend_class_entry *class_type TSRMLS_DC)
    2129             : {
    2130        4990 :         return date_object_new_date_ex(class_type, NULL TSRMLS_CC);
    2131             : }
    2132             : 
    2133      174261 : static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC)
    2134             : {
    2135      174261 :         php_date_obj *new_obj = NULL;
    2136      174261 :         php_date_obj *old_obj = (php_date_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
    2137      174261 :         zend_object_value new_ov = date_object_new_date_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
    2138             :         
    2139      174261 :         zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
    2140      174261 :         if (!old_obj->time) {
    2141           2 :                 return new_ov;
    2142             :         }
    2143             :         
    2144             :         /* this should probably moved to a new `timelib_time *timelime_time_clone(timelib_time *)` */
    2145      174259 :         new_obj->time = timelib_time_ctor();
    2146      174259 :         *new_obj->time = *old_obj->time;
    2147      174259 :         if (old_obj->time->tz_abbr) {
    2148      174259 :                 new_obj->time->tz_abbr = strdup(old_obj->time->tz_abbr);
    2149             :         }
    2150      174259 :         if (old_obj->time->tz_info) {
    2151      174259 :                 new_obj->time->tz_info = old_obj->time->tz_info;
    2152             :         }
    2153             :         
    2154      174259 :         return new_ov;
    2155             : }
    2156             : 
    2157          12 : static zval* date_clone_immutable(zval *object TSRMLS_DC)
    2158             : {
    2159             :         zval *new_object;
    2160             : 
    2161          12 :         ALLOC_ZVAL(new_object);
    2162          12 :         Z_OBJVAL_P(new_object) = date_object_clone_date(object TSRMLS_CC);
    2163             :         Z_SET_REFCOUNT_P(new_object, 1);
    2164             :         Z_SET_ISREF_P(new_object);
    2165          12 :         Z_TYPE_P(new_object) = IS_OBJECT;
    2166             : 
    2167          12 :         return new_object;
    2168             : }
    2169             : 
    2170      345619 : static int date_object_compare_date(zval *d1, zval *d2 TSRMLS_DC)
    2171             : {
    2172      345619 :         php_date_obj *o1 = zend_object_store_get_object(d1 TSRMLS_CC);
    2173      345619 :         php_date_obj *o2 = zend_object_store_get_object(d2 TSRMLS_CC);
    2174             : 
    2175      345619 :         if (!o1->time || !o2->time) {
    2176           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Trying to compare an incomplete DateTime or DateTimeImmutable object");
    2177           0 :                 return 1;
    2178             :         }
    2179      345619 :         if (!o1->time->sse_uptodate) {
    2180           0 :                 timelib_update_ts(o1->time, o1->time->tz_info);
    2181             :         }
    2182      345619 :         if (!o2->time->sse_uptodate) {
    2183           0 :                 timelib_update_ts(o2->time, o2->time->tz_info);
    2184             :         }
    2185             :         
    2186      345619 :         return (o1->time->sse == o2->time->sse) ? 0 : ((o1->time->sse < o2->time->sse) ? -1 : 1);
    2187             : }
    2188             : 
    2189           2 : static HashTable *date_object_get_gc(zval *object, zval ***table, int *n TSRMLS_DC)
    2190             : {
    2191           2 :         *table = NULL;
    2192           2 :         *n = 0;
    2193           2 :         return zend_std_get_properties(object TSRMLS_CC);
    2194             : }
    2195             : 
    2196           0 : static HashTable *date_object_get_gc_timezone(zval *object, zval ***table, int *n TSRMLS_DC)
    2197             : {
    2198             : 
    2199           0 :        *table = NULL;
    2200           0 :        *n = 0;
    2201           0 :        return zend_std_get_properties(object TSRMLS_CC);
    2202             : }
    2203             : 
    2204         430 : static HashTable *date_object_get_properties(zval *object TSRMLS_DC)
    2205             : {
    2206             :         HashTable *props;
    2207             :         zval *zv;
    2208             :         php_date_obj     *dateobj;
    2209             : 
    2210             : 
    2211         430 :         dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
    2212             : 
    2213         430 :         props = zend_std_get_properties(object TSRMLS_CC);
    2214             : 
    2215         430 :         if (!dateobj->time || GC_G(gc_active)) {
    2216          18 :                 return props;
    2217             :         }
    2218             : 
    2219             :         /* first we add the date and time in ISO format */
    2220         412 :         MAKE_STD_ZVAL(zv);
    2221         412 :         ZVAL_STRING(zv, date_format("Y-m-d H:i:s", 12, dateobj->time, 1), 0);
    2222         412 :         zend_hash_update(props, "date", 5, &zv, sizeof(zv), NULL);
    2223             : 
    2224             :         /* then we add the timezone name (or similar) */
    2225         412 :         if (dateobj->time->is_localtime) {
    2226         412 :                 MAKE_STD_ZVAL(zv);
    2227         412 :                 ZVAL_LONG(zv, dateobj->time->zone_type);
    2228         412 :                 zend_hash_update(props, "timezone_type", 14, &zv, sizeof(zv), NULL);
    2229             : 
    2230         412 :                 MAKE_STD_ZVAL(zv);
    2231         412 :                 switch (dateobj->time->zone_type) {
    2232             :                         case TIMELIB_ZONETYPE_ID:
    2233         373 :                                 ZVAL_STRING(zv, dateobj->time->tz_info->name, 1);
    2234         373 :                                 break;
    2235             :                         case TIMELIB_ZONETYPE_OFFSET: {
    2236          12 :                                 char *tmpstr = emalloc(sizeof("UTC+05:00"));
    2237          12 :                                 timelib_sll utc_offset = dateobj->time->z;
    2238             : 
    2239          24 :                                 snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d",
    2240             :                                         utc_offset > 0 ? '-' : '+',
    2241          12 :                                         abs(utc_offset / 60),
    2242          12 :                                         abs((utc_offset % 60)));
    2243             : 
    2244          12 :                                 ZVAL_STRING(zv, tmpstr, 0);
    2245             :                                 }
    2246          12 :                                 break;
    2247             :                         case TIMELIB_ZONETYPE_ABBR:
    2248          27 :                                 ZVAL_STRING(zv, dateobj->time->tz_abbr, 1);
    2249             :                                 break;
    2250             :                 }
    2251         412 :                 zend_hash_update(props, "timezone", 9, &zv, sizeof(zv), NULL);
    2252             :         }
    2253             : 
    2254         412 :         return props;
    2255             : }
    2256             : 
    2257         441 : static inline zend_object_value date_object_new_timezone_ex(zend_class_entry *class_type, php_timezone_obj **ptr TSRMLS_DC)
    2258             : {
    2259             :         php_timezone_obj *intern;
    2260             :         zend_object_value retval;
    2261             : 
    2262         441 :         intern = emalloc(sizeof(php_timezone_obj));
    2263         441 :         memset(intern, 0, sizeof(php_timezone_obj));
    2264         441 :         if (ptr) {
    2265           8 :                 *ptr = intern;
    2266             :         }
    2267             : 
    2268         441 :         zend_object_std_init(&intern->std, class_type TSRMLS_CC);
    2269         441 :         object_properties_init(&intern->std, class_type);
    2270             :         
    2271         441 :         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_timezone, NULL TSRMLS_CC);
    2272         441 :         retval.handlers = &date_object_handlers_timezone;
    2273             :         
    2274         441 :         return retval;
    2275             : }
    2276             : 
    2277         433 : static zend_object_value date_object_new_timezone(zend_class_entry *class_type TSRMLS_DC)
    2278             : {
    2279         433 :         return date_object_new_timezone_ex(class_type, NULL TSRMLS_CC);
    2280             : }
    2281             : 
    2282           8 : static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC)
    2283             : {
    2284           8 :         php_timezone_obj *new_obj = NULL;
    2285           8 :         php_timezone_obj *old_obj = (php_timezone_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
    2286           8 :         zend_object_value new_ov = date_object_new_timezone_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
    2287             :         
    2288           8 :         zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
    2289           8 :         if (!old_obj->initialized) {
    2290           1 :                 return new_ov;
    2291             :         }
    2292             :         
    2293           7 :         new_obj->type = old_obj->type;
    2294           7 :         new_obj->initialized = 1;
    2295           7 :         switch (new_obj->type) {
    2296             :                 case TIMELIB_ZONETYPE_ID:
    2297           6 :                         new_obj->tzi.tz = old_obj->tzi.tz;
    2298           6 :                         break;
    2299             :                 case TIMELIB_ZONETYPE_OFFSET:
    2300           0 :                         new_obj->tzi.utc_offset = old_obj->tzi.utc_offset;
    2301           0 :                         break;
    2302             :                 case TIMELIB_ZONETYPE_ABBR:
    2303           1 :                         new_obj->tzi.z.utc_offset = old_obj->tzi.z.utc_offset;
    2304           1 :                         new_obj->tzi.z.dst        = old_obj->tzi.z.dst;
    2305           1 :                         new_obj->tzi.z.abbr       = strdup(old_obj->tzi.z.abbr);
    2306             :                         break;
    2307             :         }
    2308             :         
    2309           7 :         return new_ov;
    2310             : }
    2311             : 
    2312          33 : static HashTable *date_object_get_properties_timezone(zval *object TSRMLS_DC)
    2313             : {
    2314             :         HashTable *props;
    2315             :         zval *zv;
    2316             :         php_timezone_obj     *tzobj;
    2317             : 
    2318             : 
    2319          33 :         tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
    2320             : 
    2321          33 :         props = zend_std_get_properties(object TSRMLS_CC);
    2322             : 
    2323          33 :         if (!tzobj->initialized) {
    2324           6 :                 return props;
    2325             :         }
    2326             : 
    2327          27 :         MAKE_STD_ZVAL(zv);
    2328          27 :         ZVAL_LONG(zv, tzobj->type);
    2329          27 :         zend_hash_update(props, "timezone_type", 14, &zv, sizeof(zv), NULL);
    2330             : 
    2331          27 :         MAKE_STD_ZVAL(zv);
    2332          27 :         switch (tzobj->type) {
    2333             :                 case TIMELIB_ZONETYPE_ID:
    2334          17 :                         ZVAL_STRING(zv, tzobj->tzi.tz->name, 1);
    2335          17 :                         break;
    2336             :                 case TIMELIB_ZONETYPE_OFFSET: {
    2337           3 :                         char *tmpstr = emalloc(sizeof("UTC+05:00"));
    2338             : 
    2339           9 :                         snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d",
    2340           3 :                         tzobj->tzi.utc_offset > 0 ? '-' : '+',
    2341           3 :                         abs(tzobj->tzi.utc_offset / 60),
    2342           3 :                         abs((tzobj->tzi.utc_offset % 60)));
    2343             : 
    2344           3 :                         ZVAL_STRING(zv, tmpstr, 0);
    2345             :                         }
    2346           3 :                         break;
    2347             :                 case TIMELIB_ZONETYPE_ABBR:
    2348           7 :                         ZVAL_STRING(zv, tzobj->tzi.z.abbr, 1);
    2349             :                         break;
    2350             :         }
    2351          27 :         zend_hash_update(props, "timezone", 9, &zv, sizeof(zv), NULL);
    2352             : 
    2353          27 :         return props;
    2354             : }
    2355             : 
    2356      349096 : static inline zend_object_value date_object_new_interval_ex(zend_class_entry *class_type, php_interval_obj **ptr TSRMLS_DC)
    2357             : {
    2358             :         php_interval_obj *intern;
    2359             :         zend_object_value retval;
    2360             : 
    2361      349096 :         intern = emalloc(sizeof(php_interval_obj));
    2362      349096 :         memset(intern, 0, sizeof(php_interval_obj));
    2363      349096 :         if (ptr) {
    2364           0 :                 *ptr = intern;
    2365             :         }
    2366             : 
    2367      349096 :         zend_object_std_init(&intern->std, class_type TSRMLS_CC);
    2368      349096 :         object_properties_init(&intern->std, class_type);
    2369             :         
    2370      349096 :         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);
    2371      349096 :         retval.handlers = &date_object_handlers_interval;
    2372             :         
    2373      349096 :         return retval;
    2374             : }
    2375             : 
    2376      349096 : static zend_object_value date_object_new_interval(zend_class_entry *class_type TSRMLS_DC)
    2377             : {
    2378      349096 :         return date_object_new_interval_ex(class_type, NULL TSRMLS_CC);
    2379             : }
    2380             : 
    2381           0 : static zend_object_value date_object_clone_interval(zval *this_ptr TSRMLS_DC)
    2382             : {
    2383           0 :         php_interval_obj *new_obj = NULL;
    2384           0 :         php_interval_obj *old_obj = (php_interval_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
    2385           0 :         zend_object_value new_ov = date_object_new_interval_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
    2386             :         
    2387           0 :         zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
    2388             : 
    2389             :         /** FIX ME ADD CLONE STUFF **/
    2390           0 :         return new_ov;
    2391             : }
    2392             : 
    2393           0 : static HashTable *date_object_get_gc_interval(zval *object, zval ***table, int *n TSRMLS_DC)
    2394             : {
    2395             : 
    2396           0 :         *table = NULL;
    2397           0 :         *n = 0;
    2398           0 :         return zend_std_get_properties(object TSRMLS_CC);
    2399             : }
    2400             : 
    2401          37 : static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC)
    2402             : {
    2403             :         HashTable *props;
    2404             :         zval *zv;
    2405             :         php_interval_obj     *intervalobj;
    2406             : 
    2407          37 :         intervalobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC);
    2408             : 
    2409          37 :         props = zend_std_get_properties(object TSRMLS_CC);
    2410             : 
    2411          37 :         if (!intervalobj->initialized) {
    2412          10 :                 return props;
    2413             :         }
    2414             : 
    2415             : #define PHP_DATE_INTERVAL_ADD_PROPERTY(n,f) \
    2416             :         MAKE_STD_ZVAL(zv); \
    2417             :         ZVAL_LONG(zv, (long)intervalobj->diff->f); \
    2418             :         zend_hash_update(props, n, strlen(n) + 1, &zv, sizeof(zv), NULL);
    2419             : 
    2420          27 :         PHP_DATE_INTERVAL_ADD_PROPERTY("y", y);
    2421          27 :         PHP_DATE_INTERVAL_ADD_PROPERTY("m", m);
    2422          27 :         PHP_DATE_INTERVAL_ADD_PROPERTY("d", d);
    2423          27 :         PHP_DATE_INTERVAL_ADD_PROPERTY("h", h);
    2424          27 :         PHP_DATE_INTERVAL_ADD_PROPERTY("i", i);
    2425          27 :         PHP_DATE_INTERVAL_ADD_PROPERTY("s", s);
    2426          27 :         PHP_DATE_INTERVAL_ADD_PROPERTY("weekday", weekday);
    2427          27 :         PHP_DATE_INTERVAL_ADD_PROPERTY("weekday_behavior", weekday_behavior);
    2428          27 :         PHP_DATE_INTERVAL_ADD_PROPERTY("first_last_day_of", first_last_day_of);
    2429          27 :         PHP_DATE_INTERVAL_ADD_PROPERTY("invert", invert);
    2430          27 :         if (intervalobj->diff->days != -99999) {
    2431          18 :                 PHP_DATE_INTERVAL_ADD_PROPERTY("days", days);
    2432             :         } else {
    2433           9 :                 MAKE_STD_ZVAL(zv);
    2434           9 :                 ZVAL_FALSE(zv);
    2435           9 :                 zend_hash_update(props, "days", 5, &zv, sizeof(zv), NULL);
    2436             :         }
    2437          27 :         PHP_DATE_INTERVAL_ADD_PROPERTY("special_type", special.type);
    2438          27 :         PHP_DATE_INTERVAL_ADD_PROPERTY("special_amount", special.amount);
    2439          27 :         PHP_DATE_INTERVAL_ADD_PROPERTY("have_weekday_relative", have_weekday_relative);
    2440          27 :         PHP_DATE_INTERVAL_ADD_PROPERTY("have_special_relative", have_special_relative);
    2441             : 
    2442          27 :         return props;
    2443             : }
    2444             : 
    2445          16 : static inline zend_object_value date_object_new_period_ex(zend_class_entry *class_type, php_period_obj **ptr TSRMLS_DC)
    2446             : {
    2447             :         php_period_obj *intern;
    2448             :         zend_object_value retval;
    2449             : 
    2450          16 :         intern = emalloc(sizeof(php_period_obj));
    2451          16 :         memset(intern, 0, sizeof(php_period_obj));
    2452          16 :         if (ptr) {
    2453           0 :                 *ptr = intern;
    2454             :         }
    2455             : 
    2456          16 :         zend_object_std_init(&intern->std, class_type TSRMLS_CC);
    2457          16 :         object_properties_init(&intern->std, class_type);
    2458             :         
    2459          16 :         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_period, NULL TSRMLS_CC);
    2460          16 :         retval.handlers = &date_object_handlers_period;
    2461             :         
    2462          16 :         return retval;
    2463             : }
    2464             : 
    2465          16 : static zend_object_value date_object_new_period(zend_class_entry *class_type TSRMLS_DC)
    2466             : {
    2467          16 :         return date_object_new_period_ex(class_type, NULL TSRMLS_CC);
    2468             : }
    2469             : 
    2470           0 : static zend_object_value date_object_clone_period(zval *this_ptr TSRMLS_DC)
    2471             : {
    2472           0 :         php_period_obj *new_obj = NULL;
    2473           0 :         php_period_obj *old_obj = (php_period_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
    2474           0 :         zend_object_value new_ov = date_object_new_period_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
    2475             :         
    2476           0 :         zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
    2477             : 
    2478             :         /** FIX ME ADD CLONE STUFF **/
    2479           0 :         return new_ov;
    2480             : }
    2481             : 
    2482      179251 : static void date_object_free_storage_date(void *object TSRMLS_DC)
    2483             : {
    2484      179251 :         php_date_obj *intern = (php_date_obj *)object;
    2485             : 
    2486      179251 :         if (intern->time) {
    2487      179203 :                 timelib_time_dtor(intern->time);
    2488             :         }
    2489             : 
    2490      179251 :         zend_object_std_dtor(&intern->std TSRMLS_CC);
    2491      179251 :         efree(object);
    2492      179251 : }
    2493             : 
    2494         441 : static void date_object_free_storage_timezone(void *object TSRMLS_DC)
    2495             : {
    2496         441 :         php_timezone_obj *intern = (php_timezone_obj *)object;
    2497             : 
    2498         441 :         if (intern->type == TIMELIB_ZONETYPE_ABBR) {
    2499          21 :                 free(intern->tzi.z.abbr);
    2500             :         }
    2501         441 :         zend_object_std_dtor(&intern->std TSRMLS_CC);
    2502         441 :         efree(object);
    2503         441 : }
    2504             : 
    2505      349096 : static void date_object_free_storage_interval(void *object TSRMLS_DC)
    2506             : {
    2507      349096 :         php_interval_obj *intern = (php_interval_obj *)object;
    2508             : 
    2509      349096 :         timelib_rel_time_dtor(intern->diff);
    2510      349096 :         zend_object_std_dtor(&intern->std TSRMLS_CC);
    2511      349096 :         efree(object);
    2512      349096 : }
    2513             : 
    2514          16 : static void date_object_free_storage_period(void *object TSRMLS_DC)
    2515             : {
    2516          16 :         php_period_obj *intern = (php_period_obj *)object;
    2517             : 
    2518          16 :         if (intern->start) {
    2519          12 :                 timelib_time_dtor(intern->start);
    2520             :         }
    2521             : 
    2522          16 :         if (intern->current) {
    2523           9 :                 timelib_time_dtor(intern->current);
    2524             :         }
    2525             : 
    2526          16 :         if (intern->end) {
    2527           4 :                 timelib_time_dtor(intern->end);
    2528             :         }
    2529             : 
    2530          16 :         timelib_rel_time_dtor(intern->interval);
    2531          16 :         zend_object_std_dtor(&intern->std TSRMLS_CC);
    2532          16 :         efree(object);
    2533          16 : }
    2534             : 
    2535             : /* Advanced Interface */
    2536      174922 : PHPAPI zval *php_date_instantiate(zend_class_entry *pce, zval *object TSRMLS_DC)
    2537             : {
    2538      174922 :         Z_TYPE_P(object) = IS_OBJECT;
    2539      174922 :         object_init_ex(object, pce);
    2540             :         Z_SET_REFCOUNT_P(object, 1);
    2541             :         Z_UNSET_ISREF_P(object);
    2542             : 
    2543      174922 :         return object;
    2544             : }
    2545             : 
    2546             : /* Helper function used to store the latest found warnings and errors while
    2547             :  * parsing, from either strtotime or parse_from_format. */
    2548        5156 : static void update_errors_warnings(timelib_error_container *last_errors TSRMLS_DC)
    2549             : {
    2550        5156 :         if (DATEG(last_errors)) {
    2551        4917 :                 timelib_error_container_dtor(DATEG(last_errors));
    2552        4917 :                 DATEG(last_errors) = NULL;
    2553             :         }
    2554        5156 :         DATEG(last_errors) = last_errors;
    2555        5156 : }
    2556             : 
    2557        4860 : PHPAPI int php_date_initialize(php_date_obj *dateobj, /*const*/ char *time_str, int time_str_len, char *format, zval *timezone_object, int ctor TSRMLS_DC)
    2558             : {
    2559             :         timelib_time   *now;
    2560        4860 :         timelib_tzinfo *tzi = NULL;
    2561        4860 :         timelib_error_container *err = NULL;
    2562        4860 :         int type = TIMELIB_ZONETYPE_ID, new_dst = 0;
    2563        4860 :         char *new_abbr = NULL;
    2564             :         timelib_sll     new_offset;
    2565             :         
    2566        4860 :         if (dateobj->time) {
    2567           0 :                 timelib_time_dtor(dateobj->time);
    2568             :         }
    2569        4860 :         if (format) {
    2570        1054 :                 dateobj->time = timelib_parse_from_format(format, time_str_len ? time_str : "", time_str_len ? time_str_len : 0, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    2571             :         } else {
    2572        3806 :                 dateobj->time = timelib_strtotime(time_str_len ? time_str : "now", time_str_len ? time_str_len : sizeof("now") -1, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    2573             :         }
    2574             : 
    2575             :         /* update last errors and warnings */
    2576        4860 :         update_errors_warnings(err TSRMLS_CC);
    2577             : 
    2578             : 
    2579        4860 :         if (ctor && err && err->error_count) {
    2580             :                 /* spit out the first library error message, at least */
    2581          78 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", time_str,
    2582          78 :                         err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message);
    2583             :         }
    2584        4860 :         if (err && err->error_count) {
    2585          59 :                 return 0;
    2586             :         }
    2587             : 
    2588        4801 :         if (timezone_object) {
    2589             :                 php_timezone_obj *tzobj;
    2590             : 
    2591          54 :                 tzobj = (php_timezone_obj *) zend_object_store_get_object(timezone_object TSRMLS_CC);
    2592          54 :                 switch (tzobj->type) {
    2593             :                         case TIMELIB_ZONETYPE_ID:
    2594          51 :                                 tzi = tzobj->tzi.tz;
    2595          51 :                                 break;
    2596             :                         case TIMELIB_ZONETYPE_OFFSET:
    2597           0 :                                 new_offset = tzobj->tzi.utc_offset;
    2598           0 :                                 break;
    2599             :                         case TIMELIB_ZONETYPE_ABBR:
    2600           3 :                                 new_offset = tzobj->tzi.z.utc_offset;
    2601           3 :                                 new_dst    = tzobj->tzi.z.dst;
    2602           3 :                                 new_abbr   = strdup(tzobj->tzi.z.abbr);
    2603             :                                 break;
    2604             :                 }
    2605          54 :                 type = tzobj->type;
    2606        4747 :         } else if (dateobj->time->tz_info) {
    2607         515 :                 tzi = dateobj->time->tz_info;
    2608             :         } else {
    2609        4232 :                 tzi = get_timezone_info(TSRMLS_C);
    2610             :         }
    2611             : 
    2612        4801 :         now = timelib_time_ctor();
    2613        4801 :         now->zone_type = type;
    2614        4801 :         switch (type) {
    2615             :                 case TIMELIB_ZONETYPE_ID:
    2616        4798 :                         now->tz_info = tzi;
    2617        4798 :                         break;
    2618             :                 case TIMELIB_ZONETYPE_OFFSET:
    2619           0 :                         now->z = new_offset;
    2620           0 :                         break;
    2621             :                 case TIMELIB_ZONETYPE_ABBR:
    2622           3 :                         now->z = new_offset;
    2623           3 :                         now->dst = new_dst;
    2624           3 :                         now->tz_abbr = new_abbr;
    2625             :                         break;
    2626             :         }
    2627        4801 :         timelib_unixtime2local(now, (timelib_sll) time(NULL));
    2628             : 
    2629        4801 :         timelib_fill_holes(dateobj->time, now, TIMELIB_NO_CLONE);
    2630        4801 :         timelib_update_ts(dateobj->time, tzi);
    2631        4801 :         timelib_update_from_sse(dateobj->time);
    2632             : 
    2633        4801 :         dateobj->time->have_relative = 0;
    2634             : 
    2635        4801 :         timelib_time_dtor(now);
    2636             : 
    2637        4801 :         return 1;
    2638             : }
    2639             : 
    2640             : /* {{{ proto DateTime date_create([string time[, DateTimeZone object]])
    2641             :    Returns new DateTime object
    2642             : */
    2643         241 : PHP_FUNCTION(date_create)
    2644             : {
    2645         241 :         zval           *timezone_object = NULL;
    2646         241 :         char           *time_str = NULL;
    2647         241 :         int             time_str_len = 0;
    2648             : 
    2649         241 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO!", &time_str, &time_str_len, &timezone_object, date_ce_timezone) == FAILURE) {
    2650          38 :                 RETURN_FALSE;
    2651             :         }
    2652             : 
    2653         203 :         php_date_instantiate(date_ce_date, return_value TSRMLS_CC);
    2654         203 :         if (!php_date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), time_str, time_str_len, NULL, timezone_object, 0 TSRMLS_CC)) {
    2655          25 :                 RETURN_FALSE;
    2656             :         }
    2657             : }
    2658             : /* }}} */
    2659             : 
    2660             : /* {{{ proto DateTime date_create_immutable([string time[, DateTimeZone object]])
    2661             :    Returns new DateTime object
    2662             : */
    2663          11 : PHP_FUNCTION(date_create_immutable)
    2664             : {
    2665          11 :         zval           *timezone_object = NULL;
    2666          11 :         char           *time_str = NULL;
    2667          11 :         int             time_str_len = 0;
    2668             : 
    2669          11 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO!", &time_str, &time_str_len, &timezone_object, date_ce_timezone) == FAILURE) {
    2670           0 :                 RETURN_FALSE;
    2671             :         }
    2672             : 
    2673          11 :         php_date_instantiate(date_ce_immutable, return_value TSRMLS_CC);
    2674          11 :         if (!php_date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), time_str, time_str_len, NULL, timezone_object, 0 TSRMLS_CC)) {
    2675           0 :                 RETURN_FALSE;
    2676             :         }
    2677             : }
    2678             : /* }}} */
    2679             : 
    2680             : /* {{{ proto DateTime date_create_from_format(string format, string time[, DateTimeZone object])
    2681             :    Returns new DateTime object formatted according to the specified format
    2682             : */
    2683        1054 : PHP_FUNCTION(date_create_from_format)
    2684             : {
    2685        1054 :         zval           *timezone_object = NULL;
    2686        1054 :         char           *time_str = NULL, *format_str = NULL;
    2687        1054 :         int             time_str_len = 0, format_str_len = 0;
    2688             : 
    2689        1054 :         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) {
    2690           1 :                 RETURN_FALSE;
    2691             :         }
    2692             : 
    2693        1053 :         php_date_instantiate(date_ce_date, return_value TSRMLS_CC);
    2694        1053 :         if (!php_date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), time_str, time_str_len, format_str, timezone_object, 0 TSRMLS_CC)) {
    2695           6 :                 RETURN_FALSE;
    2696             :         }
    2697             : }
    2698             : /* }}} */
    2699             : 
    2700             : /* {{{ proto DateTime date_create_immutable_from_format(string format, string time[, DateTimeZone object])
    2701             :    Returns new DateTime object formatted according to the specified format
    2702             : */
    2703           1 : PHP_FUNCTION(date_create_immutable_from_format)
    2704             : {
    2705           1 :         zval           *timezone_object = NULL;
    2706           1 :         char           *time_str = NULL, *format_str = NULL;
    2707           1 :         int             time_str_len = 0, format_str_len = 0;
    2708             : 
    2709           1 :         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) {
    2710           0 :                 RETURN_FALSE;
    2711             :         }
    2712             : 
    2713           1 :         php_date_instantiate(date_ce_immutable, return_value TSRMLS_CC);
    2714           1 :         if (!php_date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), time_str, time_str_len, format_str, timezone_object, 0 TSRMLS_CC)) {
    2715           0 :                 RETURN_FALSE;
    2716             :         }
    2717             : }
    2718             : /* }}} */
    2719             : 
    2720             : /* {{{ proto DateTime::__construct([string time[, DateTimeZone object]])
    2721             :    Creates new DateTime object
    2722             : */
    2723        3618 : PHP_METHOD(DateTime, __construct)
    2724             : {
    2725        3618 :         zval *timezone_object = NULL;
    2726        3618 :         char *time_str = NULL;
    2727        3618 :         int time_str_len = 0;
    2728             :         zend_error_handling error_handling;
    2729             : 
    2730        3618 :         zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
    2731        3618 :         if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO!", &time_str, &time_str_len, &timezone_object, date_ce_timezone)) {
    2732        3580 :                 php_date_initialize(zend_object_store_get_object(getThis() TSRMLS_CC), time_str, time_str_len, NULL, timezone_object, 1 TSRMLS_CC);
    2733             :         }
    2734        3618 :         zend_restore_error_handling(&error_handling TSRMLS_CC);
    2735        3618 : }
    2736             : /* }}} */
    2737             : 
    2738             : /* {{{ proto DateTimeImmutable::__construct([string time[, DateTimeZone object]])
    2739             :    Creates new DateTimeImmutable object
    2740             : */
    2741           6 : PHP_METHOD(DateTimeImmutable, __construct)
    2742             : {
    2743           6 :         zval *timezone_object = NULL;
    2744           6 :         char *time_str = NULL;
    2745           6 :         int time_str_len = 0;
    2746             :         zend_error_handling error_handling;
    2747             : 
    2748           6 :         zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
    2749           6 :         if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO!", &time_str, &time_str_len, &timezone_object, date_ce_timezone)) {
    2750           6 :                 php_date_initialize(zend_object_store_get_object(getThis() TSRMLS_CC), time_str, time_str_len, NULL, timezone_object, 1 TSRMLS_CC);
    2751             :         }
    2752           6 :         zend_restore_error_handling(&error_handling TSRMLS_CC);
    2753           6 : }
    2754             : /* }}} */
    2755             : 
    2756             : /* {{{ proto DateTimeImmutable::createFromMutable(DateTimeZone object)
    2757             :    Creates new DateTimeImmutable object from an existing mutable DateTime object.
    2758             : */
    2759           2 : PHP_METHOD(DateTimeImmutable, createFromMutable)
    2760             : {
    2761           2 :         zval *datetime_object = NULL;
    2762           2 :         php_date_obj *new_obj = NULL;
    2763           2 :         php_date_obj *old_obj = NULL;
    2764             : 
    2765           2 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O!", &datetime_object, date_ce_date) == FAILURE) {
    2766           1 :                 return;
    2767             :         }
    2768             : 
    2769           1 :         php_date_instantiate(date_ce_immutable, return_value TSRMLS_CC);
    2770           1 :         old_obj = (php_date_obj *) zend_object_store_get_object(datetime_object TSRMLS_CC);
    2771           1 :         new_obj = (php_date_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
    2772             : 
    2773           1 :         new_obj->time = timelib_time_ctor();
    2774           1 :         *new_obj->time = *old_obj->time;
    2775           1 :         if (old_obj->time->tz_abbr) {
    2776           1 :                 new_obj->time->tz_abbr = strdup(old_obj->time->tz_abbr);
    2777             :         }
    2778           1 :         if (old_obj->time->tz_info) {
    2779           1 :                 new_obj->time->tz_info = old_obj->time->tz_info;
    2780             :         }
    2781             : }
    2782             : /* }}} */
    2783             : 
    2784           9 : static int php_date_initialize_from_hash(zval **return_value, php_date_obj **dateobj, HashTable *myht TSRMLS_DC)
    2785             : {
    2786           9 :         zval            **z_date = NULL;
    2787           9 :         zval            **z_timezone = NULL;
    2788           9 :         zval            **z_timezone_type = NULL;
    2789           9 :         zval             *tmp_obj = NULL;
    2790             :         timelib_tzinfo   *tzi;
    2791             :         php_timezone_obj *tzobj;
    2792             : 
    2793           9 :         if (zend_hash_find(myht, "date", 5, (void**) &z_date) == SUCCESS) {
    2794           8 :                 convert_to_string(*z_date);
    2795           8 :                 if (zend_hash_find(myht, "timezone_type", 14, (void**) &z_timezone_type) == SUCCESS) {
    2796           8 :                         convert_to_long(*z_timezone_type);
    2797           8 :                         if (zend_hash_find(myht, "timezone", 9, (void**) &z_timezone) == SUCCESS) {
    2798           8 :                                 convert_to_string(*z_timezone);
    2799             : 
    2800           8 :                                 switch (Z_LVAL_PP(z_timezone_type)) {
    2801             :                                         case TIMELIB_ZONETYPE_OFFSET:
    2802             :                                         case TIMELIB_ZONETYPE_ABBR: {
    2803           0 :                                                 char *tmp = emalloc(Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2);
    2804             :                                                 int ret;
    2805           0 :                                                 snprintf(tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 2, "%s %s", Z_STRVAL_PP(z_date), Z_STRVAL_PP(z_timezone));
    2806           0 :                                                 ret = php_date_initialize(*dateobj, tmp, Z_STRLEN_PP(z_date) + Z_STRLEN_PP(z_timezone) + 1, NULL, NULL, 0 TSRMLS_CC);
    2807           0 :                                                 efree(tmp);
    2808           0 :                                                 return 1 == ret;
    2809             :                                         }
    2810             : 
    2811             :                                         case TIMELIB_ZONETYPE_ID: {
    2812             :                                                 int ret;
    2813           7 :                                                 convert_to_string(*z_timezone);
    2814             : 
    2815           7 :                                                 tzi = php_date_parse_tzfile(Z_STRVAL_PP(z_timezone), DATE_TIMEZONEDB TSRMLS_CC);
    2816             : 
    2817           7 :                                                 if (tzi == NULL) {
    2818           1 :                                                         return 0;
    2819             :                                                 }
    2820             : 
    2821           6 :                                                 ALLOC_INIT_ZVAL(tmp_obj);
    2822           6 :                                                 tzobj = zend_object_store_get_object(php_date_instantiate(date_ce_timezone, tmp_obj TSRMLS_CC) TSRMLS_CC);
    2823           6 :                                                 tzobj->type = TIMELIB_ZONETYPE_ID;
    2824           6 :                                                 tzobj->tzi.tz = tzi;
    2825           6 :                                                 tzobj->initialized = 1;
    2826             : 
    2827           6 :                                                 ret = php_date_initialize(*dateobj, Z_STRVAL_PP(z_date), Z_STRLEN_PP(z_date), NULL, tmp_obj, 0 TSRMLS_CC);
    2828           6 :                                                 zval_ptr_dtor(&tmp_obj);
    2829           6 :                                                 return 1 == ret;
    2830             :                                         }
    2831             :                                 }
    2832             :                         }
    2833             :                 }
    2834             :         }
    2835           2 :         return 0;
    2836             : }
    2837             : 
    2838             : /* {{{ proto DateTime::__set_state()
    2839             : */
    2840           0 : PHP_METHOD(DateTime, __set_state)
    2841             : {
    2842             :         php_date_obj     *dateobj;
    2843             :         zval             *array;
    2844             :         HashTable        *myht;
    2845             : 
    2846           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
    2847           0 :                 RETURN_FALSE;
    2848             :         }
    2849             : 
    2850           0 :         myht = HASH_OF(array);
    2851             : 
    2852           0 :         php_date_instantiate(date_ce_date, return_value TSRMLS_CC);
    2853           0 :         dateobj = (php_date_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
    2854           0 :         if (!php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC)) {
    2855           0 :                 php_error(E_ERROR, "Invalid serialization data for DateTime object");
    2856             :         }
    2857             : }
    2858             : /* }}} */
    2859             : 
    2860             : /* {{{ proto DateTimeImmutable::__set_state()
    2861             : */
    2862           0 : PHP_METHOD(DateTimeImmutable, __set_state)
    2863             : {
    2864             :         php_date_obj     *dateobj;
    2865             :         zval             *array;
    2866             :         HashTable        *myht;
    2867             : 
    2868           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
    2869           0 :                 RETURN_FALSE;
    2870             :         }
    2871             : 
    2872           0 :         myht = HASH_OF(array);
    2873             : 
    2874           0 :         php_date_instantiate(date_ce_immutable, return_value TSRMLS_CC);
    2875           0 :         dateobj = (php_date_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
    2876           0 :         if (!php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC)) {
    2877           0 :                 php_error(E_ERROR, "Invalid serialization data for DateTimeImmutable object");
    2878             :         }
    2879             : }
    2880             : /* }}} */
    2881             : 
    2882             : /* {{{ proto DateTime::__wakeup()
    2883             : */
    2884           9 : PHP_METHOD(DateTime, __wakeup)
    2885             : {
    2886           9 :         zval             *object = getThis();
    2887             :         php_date_obj     *dateobj;
    2888             :         HashTable        *myht;
    2889             : 
    2890           9 :         dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
    2891             : 
    2892           9 :         myht = Z_OBJPROP_P(object);
    2893             : 
    2894           9 :         if (!php_date_initialize_from_hash(&return_value, &dateobj, myht TSRMLS_CC)) {
    2895           5 :                 php_error(E_ERROR, "Invalid serialization data for DateTime object");
    2896             :         }
    2897           4 : }
    2898             : /* }}} */
    2899             : 
    2900             : /* Helper function used to add an associative array of warnings and errors to a zval */
    2901          86 : static void zval_from_error_container(zval *z, timelib_error_container *error)
    2902             : {
    2903             :         int   i;
    2904             :         zval *element;
    2905             : 
    2906          86 :         add_assoc_long(z, "warning_count", error->warning_count);
    2907          86 :         MAKE_STD_ZVAL(element);
    2908          86 :         array_init(element);
    2909         106 :         for (i = 0; i < error->warning_count; i++) {
    2910          20 :                 add_index_string(element, error->warning_messages[i].position, error->warning_messages[i].message, 1);
    2911             :         }
    2912          86 :         add_assoc_zval(z, "warnings", element);
    2913             : 
    2914          86 :         add_assoc_long(z, "error_count", error->error_count);
    2915          86 :         MAKE_STD_ZVAL(element);
    2916          86 :         array_init(element);
    2917         137 :         for (i = 0; i < error->error_count; i++) {
    2918          51 :                 add_index_string(element, error->error_messages[i].position, error->error_messages[i].message, 1);
    2919             :         }
    2920          86 :         add_assoc_zval(z, "errors", element);
    2921          86 : }
    2922             : 
    2923             : /* {{{ proto array date_get_last_errors()
    2924             :    Returns the warnings and errors found while parsing a date/time string.
    2925             : */
    2926          16 : PHP_FUNCTION(date_get_last_errors)
    2927             : {
    2928          16 :         if (DATEG(last_errors)) {
    2929          15 :                 array_init(return_value);
    2930          15 :                 zval_from_error_container(return_value, DATEG(last_errors));
    2931             :         } else {
    2932           1 :                 RETURN_FALSE;
    2933             :         }
    2934             : }
    2935             : /* }}} */
    2936             : 
    2937          71 : void php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAMETERS, timelib_time *parsed_time, struct timelib_error_container *error)
    2938             : {
    2939             :         zval *element;
    2940             : 
    2941          71 :         array_init(return_value);
    2942             : #define PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(name, elem) \
    2943             :         if (parsed_time->elem == -99999) {               \
    2944             :                 add_assoc_bool(return_value, #name, 0); \
    2945             :         } else {                                       \
    2946             :                 add_assoc_long(return_value, #name, parsed_time->elem); \
    2947             :         }
    2948          71 :         PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(year,      y);
    2949          71 :         PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(month,     m);
    2950          71 :         PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(day,       d);
    2951          71 :         PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(hour,      h);
    2952          71 :         PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(minute,    i);
    2953          71 :         PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(second,    s);
    2954             :         
    2955          71 :         if (parsed_time->f == -99999) {
    2956          53 :                 add_assoc_bool(return_value, "fraction", 0);
    2957             :         } else {
    2958          18 :                 add_assoc_double(return_value, "fraction", parsed_time->f);
    2959             :         }
    2960             : 
    2961          71 :         zval_from_error_container(return_value, error);
    2962             : 
    2963          71 :         timelib_error_container_dtor(error);
    2964             : 
    2965          71 :         add_assoc_bool(return_value, "is_localtime", parsed_time->is_localtime);
    2966             : 
    2967          71 :         if (parsed_time->is_localtime) {
    2968          19 :                 PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone_type, zone_type);
    2969          19 :                 switch (parsed_time->zone_type) {
    2970             :                         case TIMELIB_ZONETYPE_OFFSET:
    2971           5 :                                 PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone, z);
    2972           5 :                                 add_assoc_bool(return_value, "is_dst", parsed_time->dst);
    2973           5 :                                 break;
    2974             :                         case TIMELIB_ZONETYPE_ID:
    2975           0 :                                 if (parsed_time->tz_abbr) {
    2976           0 :                                         add_assoc_string(return_value, "tz_abbr", parsed_time->tz_abbr, 1);
    2977             :                                 }
    2978           0 :                                 if (parsed_time->tz_info) {
    2979           0 :                                         add_assoc_string(return_value, "tz_id", parsed_time->tz_info->name, 1);
    2980             :                                 }
    2981           0 :                                 break;
    2982             :                         case TIMELIB_ZONETYPE_ABBR:
    2983           7 :                                 PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(zone, z);
    2984           7 :                                 add_assoc_bool(return_value, "is_dst", parsed_time->dst);
    2985           7 :                                 add_assoc_string(return_value, "tz_abbr", parsed_time->tz_abbr, 1);
    2986             :                                 break;
    2987             :                 }
    2988             :         }
    2989          71 :         if (parsed_time->have_relative) {
    2990           7 :                 MAKE_STD_ZVAL(element);
    2991           7 :                 array_init(element);
    2992           7 :                 add_assoc_long(element, "year",   parsed_time->relative.y);
    2993           7 :                 add_assoc_long(element, "month",  parsed_time->relative.m);
    2994           7 :                 add_assoc_long(element, "day",    parsed_time->relative.d);
    2995           7 :                 add_assoc_long(element, "hour",   parsed_time->relative.h);
    2996           7 :                 add_assoc_long(element, "minute", parsed_time->relative.i);
    2997           7 :                 add_assoc_long(element, "second", parsed_time->relative.s);
    2998           7 :                 if (parsed_time->relative.have_weekday_relative) {
    2999           0 :                         add_assoc_long(element, "weekday", parsed_time->relative.weekday);
    3000             :                 }
    3001           7 :                 if (parsed_time->relative.have_special_relative && (parsed_time->relative.special.type == TIMELIB_SPECIAL_WEEKDAY)) {
    3002           0 :                         add_assoc_long(element, "weekdays", parsed_time->relative.special.amount);
    3003             :                 }
    3004           7 :                 if (parsed_time->relative.first_last_day_of) {
    3005           2 :                         add_assoc_bool(element, parsed_time->relative.first_last_day_of == 1 ? "first_day_of_month" : "last_day_of_month", 1);
    3006             :                 }
    3007           7 :                 add_assoc_zval(return_value, "relative", element);
    3008             :         }
    3009          71 :         timelib_time_dtor(parsed_time);
    3010          71 : }
    3011             : 
    3012             : /* {{{ proto array date_parse(string date)
    3013             :    Returns associative array with detailed info about given date
    3014             : */
    3015          63 : PHP_FUNCTION(date_parse)
    3016             : {
    3017             :         char                           *date;
    3018             :         int                             date_len;
    3019             :         struct timelib_error_container *error;
    3020             :         timelib_time                   *parsed_time;
    3021             :         
    3022          63 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &date, &date_len) == FAILURE) {
    3023           9 :                 RETURN_FALSE;
    3024             :         }
    3025             : 
    3026          54 :         parsed_time = timelib_strtotime(date, date_len, &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    3027          54 :         php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAM_PASSTHRU, parsed_time, error);
    3028             : }
    3029             : /* }}} */
    3030             : 
    3031             : /* {{{ proto array date_parse_from_format(string format, string date)
    3032             :    Returns associative array with detailed info about given date
    3033             : */
    3034          18 : PHP_FUNCTION(date_parse_from_format)
    3035             : {
    3036             :         char                           *date, *format;
    3037             :         int                             date_len, format_len;
    3038             :         struct timelib_error_container *error;
    3039             :         timelib_time                   *parsed_time;
    3040             :         
    3041          18 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &format, &format_len, &date, &date_len) == FAILURE) {
    3042           1 :                 RETURN_FALSE;
    3043             :         }
    3044             : 
    3045          17 :         parsed_time = timelib_parse_from_format(format, date, date_len, &error, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    3046          17 :         php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAM_PASSTHRU, parsed_time, error);
    3047             : }
    3048             : /* }}} */
    3049             : 
    3050             : /* {{{ proto string date_format(DateTimeInterface object, string format)
    3051             :    Returns date formatted according to given format
    3052             : */
    3053        5123 : PHP_FUNCTION(date_format)
    3054             : {
    3055             :         zval         *object;
    3056             :         php_date_obj *dateobj;
    3057             :         char         *format;
    3058             :         int           format_len;
    3059             : 
    3060        5123 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_interface, &format, &format_len) == FAILURE) {
    3061          48 :                 RETURN_FALSE;
    3062             :         }
    3063        5075 :         dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3064        5075 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3065        5072 :         RETURN_STRING(date_format(format, format_len, dateobj->time, dateobj->time->is_localtime), 0);
    3066             : }
    3067             : /* }}} */
    3068             : 
    3069         296 : static int php_date_modify(zval *object, char *modify, int modify_len TSRMLS_DC)
    3070             : {
    3071             :         php_date_obj *dateobj;
    3072             :         timelib_time *tmp_time;
    3073         296 :         timelib_error_container *err = NULL;
    3074             : 
    3075         296 :         dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3076             : 
    3077         296 :         if (!(dateobj->time)) {
    3078           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The DateTime object has not been correctly initialized by its constructor");
    3079           0 :                 return 0;
    3080             :         }
    3081             : 
    3082         296 :         tmp_time = timelib_strtotime(modify, modify_len, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    3083             : 
    3084             :         /* update last errors and warnings */
    3085         296 :         update_errors_warnings(err TSRMLS_CC);
    3086         296 :         if (err && err->error_count) {
    3087             :                 /* spit out the first library error message, at least */
    3088         123 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", modify,
    3089         123 :                         err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message);
    3090          41 :                 timelib_time_dtor(tmp_time);
    3091          41 :                 return 0;
    3092             :         }
    3093             : 
    3094         255 :         memcpy(&dateobj->time->relative, &tmp_time->relative, sizeof(struct timelib_rel_time));
    3095         255 :         dateobj->time->have_relative = tmp_time->have_relative;
    3096         255 :         dateobj->time->sse_uptodate = 0;
    3097             : 
    3098         255 :         if (tmp_time->y != -99999) {
    3099           2 :                 dateobj->time->y = tmp_time->y;
    3100             :         }
    3101         255 :         if (tmp_time->m != -99999) {
    3102           7 :                 dateobj->time->m = tmp_time->m;
    3103             :         }
    3104         255 :         if (tmp_time->d != -99999) {
    3105           7 :                 dateobj->time->d = tmp_time->d;
    3106             :         }
    3107             : 
    3108         255 :         if (tmp_time->h != -99999) {
    3109         222 :                 dateobj->time->h = tmp_time->h;
    3110         222 :                 if (tmp_time->i != -99999) {
    3111         220 :                         dateobj->time->i = tmp_time->i;
    3112         220 :                         if (tmp_time->s != -99999) {
    3113         220 :                                 dateobj->time->s = tmp_time->s;
    3114             :                         } else {
    3115           0 :                                 dateobj->time->s = 0;
    3116             :                         }
    3117             :                 } else {
    3118           2 :                         dateobj->time->i = 0;
    3119           2 :                         dateobj->time->s = 0;
    3120             :                 }
    3121             :         }
    3122         255 :         timelib_time_dtor(tmp_time);
    3123             : 
    3124         255 :         timelib_update_ts(dateobj->time, NULL);
    3125         255 :         timelib_update_from_sse(dateobj->time);
    3126         255 :         dateobj->time->have_relative = 0;
    3127             :         
    3128         255 :         return 1;
    3129             : }
    3130             : 
    3131             : /* {{{ proto DateTime date_modify(DateTime object, string modify)
    3132             :    Alters the timestamp.
    3133             : */
    3134         340 : PHP_FUNCTION(date_modify)
    3135             : {
    3136             :         zval         *object;
    3137             :         char         *modify;
    3138             :         int           modify_len;
    3139             : 
    3140         340 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_date, &modify, &modify_len) == FAILURE) {
    3141          48 :                 RETURN_FALSE;
    3142             :         }
    3143             : 
    3144         292 :         if (php_date_modify(object, modify, modify_len TSRMLS_CC)) {
    3145         502 :                 RETURN_ZVAL(object, 1, 0);
    3146             :         }
    3147             : 
    3148          41 :         RETURN_FALSE;
    3149             : }
    3150             : /* }}} */
    3151             : 
    3152             : /* {{{ proto DateTimeImmutable::modify()
    3153             : */
    3154           4 : PHP_METHOD(DateTimeImmutable, modify)
    3155             : {
    3156             :         zval *object, *new_object;
    3157             :         char *modify;
    3158             :         int   modify_len;
    3159             : 
    3160           4 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_immutable, &modify, &modify_len) == FAILURE) {
    3161           0 :                 RETURN_FALSE;
    3162             :         }
    3163             :         
    3164           4 :         new_object = date_clone_immutable(object TSRMLS_CC);
    3165           4 :         if (php_date_modify(new_object, modify, modify_len TSRMLS_CC)) {
    3166           4 :                 RETURN_ZVAL(new_object, 0, 1);
    3167             :         }
    3168             : 
    3169           0 :         RETURN_FALSE;
    3170             : }
    3171             : /* }}} */
    3172             : 
    3173      167470 : static void php_date_add(zval *object, zval *interval, zval *return_value TSRMLS_DC)
    3174             : {
    3175             :         php_date_obj     *dateobj;
    3176             :         php_interval_obj *intobj;
    3177             :         timelib_time     *new_time;
    3178             : 
    3179      167470 :         dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3180      167470 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3181      167470 :         intobj = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC);
    3182      167470 :         DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval);
    3183             : 
    3184      167470 :         new_time = timelib_add(dateobj->time, intobj->diff);
    3185      167470 :         timelib_time_dtor(dateobj->time);
    3186      167470 :         dateobj->time = new_time;
    3187             : }
    3188             : 
    3189             : /* {{{ proto DateTime date_add(DateTime object, DateInterval interval)
    3190             :    Adds an interval to the current date in object.
    3191             : */
    3192      167470 : PHP_FUNCTION(date_add)
    3193             : {
    3194             :         zval *object, *interval;
    3195             : 
    3196      167470 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) {
    3197           1 :                 RETURN_FALSE;
    3198             :         }
    3199             : 
    3200      167469 :         php_date_add(object, interval, return_value TSRMLS_CC);
    3201             : 
    3202      334938 :         RETURN_ZVAL(object, 1, 0);
    3203             : }
    3204             : /* }}} */
    3205             : 
    3206             : /* {{{ proto DateTimeImmutable::add()
    3207             : */
    3208           1 : PHP_METHOD(DateTimeImmutable, add)
    3209             : {
    3210             :         zval *object, *interval, *new_object;
    3211             : 
    3212           1 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_immutable, &interval, date_ce_interval) == FAILURE) {
    3213           0 :                 RETURN_FALSE;
    3214             :         }
    3215             : 
    3216           1 :         new_object = date_clone_immutable(object TSRMLS_CC);
    3217           1 :         php_date_add(new_object, interval, return_value TSRMLS_CC);
    3218             : 
    3219           1 :         RETURN_ZVAL(new_object, 0, 1);
    3220             : }
    3221             : /* }}} */
    3222             : 
    3223        7509 : static void php_date_sub(zval *object, zval *interval, zval *return_value TSRMLS_DC)
    3224             : {
    3225             :         php_date_obj     *dateobj;
    3226             :         php_interval_obj *intobj;
    3227             :         timelib_time     *new_time;
    3228             : 
    3229        7509 :         dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3230        7509 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3231        7509 :         intobj = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC);
    3232        7509 :         DATE_CHECK_INITIALIZED(intobj->initialized, DateInterval);
    3233             : 
    3234        7509 :         if (intobj->diff->have_special_relative) {
    3235           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only non-special relative time specifications are supported for subtraction");
    3236           2 :                 return;
    3237             :         }
    3238             : 
    3239        7507 :         new_time = timelib_sub(dateobj->time, intobj->diff);
    3240        7507 :         timelib_time_dtor(dateobj->time);
    3241        7507 :         dateobj->time = new_time;
    3242             : }
    3243             : 
    3244             : /* {{{ proto DateTime date_sub(DateTime object, DateInterval interval)
    3245             :    Subtracts an interval to the current date in object.
    3246             : */
    3247        7508 : PHP_FUNCTION(date_sub)
    3248             : {
    3249             :         zval *object, *interval;
    3250             : 
    3251        7508 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &interval, date_ce_interval) == FAILURE) {
    3252           0 :                 RETURN_FALSE;
    3253             :         }
    3254             : 
    3255        7508 :         php_date_sub(object, interval, return_value TSRMLS_CC);
    3256             : 
    3257       15016 :         RETURN_ZVAL(object, 1, 0);
    3258             : }
    3259             : /* }}} */
    3260             : 
    3261             : /* {{{ proto DateTimeImmutable::sub()
    3262             : */
    3263           1 : PHP_METHOD(DateTimeImmutable, sub)
    3264             : {
    3265             :         zval *object, *interval, *new_object;
    3266             : 
    3267           1 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_immutable, &interval, date_ce_interval) == FAILURE) {
    3268           0 :                 RETURN_FALSE;
    3269             :         }
    3270             : 
    3271           1 :         new_object = date_clone_immutable(object TSRMLS_CC);
    3272           1 :         php_date_sub(new_object, interval, return_value TSRMLS_CC);
    3273             : 
    3274           1 :         RETURN_ZVAL(new_object, 0, 1);
    3275             : }
    3276             : /* }}} */
    3277             : 
    3278         374 : static void set_timezone_from_timelib_time(php_timezone_obj *tzobj, timelib_time *t)
    3279             : {
    3280         374 :        tzobj->initialized = 1;
    3281         374 :        tzobj->type = t->zone_type;
    3282         374 :        switch (t->zone_type) {
    3283             :                case TIMELIB_ZONETYPE_ID:
    3284         338 :                        tzobj->tzi.tz = t->tz_info;
    3285         338 :                        break;
    3286             :                case TIMELIB_ZONETYPE_OFFSET:
    3287          16 :                        tzobj->tzi.utc_offset = t->z;
    3288          16 :                        break;
    3289             :                case TIMELIB_ZONETYPE_ABBR:
    3290          20 :                        tzobj->tzi.z.utc_offset = t->z;
    3291          20 :                        tzobj->tzi.z.dst = t->dst;
    3292          20 :                        tzobj->tzi.z.abbr = strdup(t->tz_abbr);
    3293             :                        break;
    3294             :        }
    3295         374 : }
    3296             : 
    3297             : 
    3298             : /* {{{ proto DateTimeZone date_timezone_get(DateTimeInterface object)
    3299             :    Return new DateTimeZone object relative to give DateTime
    3300             : */
    3301          80 : PHP_FUNCTION(date_timezone_get)
    3302             : {
    3303             :         zval             *object;
    3304             :         php_date_obj     *dateobj;
    3305             :         php_timezone_obj *tzobj;
    3306             : 
    3307          80 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_interface) == FAILURE) {
    3308          33 :                 RETURN_FALSE;
    3309             :         }
    3310          47 :         dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3311          47 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3312          47 :         if (dateobj->time->is_localtime/* && dateobj->time->tz_info*/) {
    3313          47 :                 php_date_instantiate(date_ce_timezone, return_value TSRMLS_CC);
    3314          47 :                 tzobj = (php_timezone_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
    3315          47 :                 set_timezone_from_timelib_time(tzobj, dateobj->time);
    3316             :         } else {
    3317           0 :                 RETURN_FALSE;
    3318             :         }
    3319             : }
    3320             : /* }}} */
    3321             : 
    3322         262 : static void php_date_timezone_set(zval *object, zval *timezone_object, zval *return_value TSRMLS_DC)
    3323             : {
    3324             :         php_date_obj     *dateobj;
    3325             :         php_timezone_obj *tzobj;
    3326             : 
    3327         262 :         dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3328         262 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3329         262 :         tzobj = (php_timezone_obj *) zend_object_store_get_object(timezone_object TSRMLS_CC);
    3330             : 
    3331         262 :         switch (tzobj->type) {
    3332             :                 case TIMELIB_ZONETYPE_OFFSET:
    3333           1 :                         timelib_set_timezone_from_offset(dateobj->time, tzobj->tzi.utc_offset);
    3334           1 :                         break;
    3335             :                 case TIMELIB_ZONETYPE_ABBR:
    3336           3 :                         timelib_set_timezone_from_abbr(dateobj->time, tzobj->tzi.z);
    3337           3 :                         break;
    3338             :                 case TIMELIB_ZONETYPE_ID:
    3339         258 :                         timelib_set_timezone(dateobj->time, tzobj->tzi.tz);
    3340             :                         break;
    3341             :         }
    3342         262 :         timelib_unixtime2local(dateobj->time, dateobj->time->sse);
    3343             : }
    3344             : 
    3345             : /* {{{ proto DateTime date_timezone_set(DateTime object, DateTimeZone object)
    3346             :    Sets the timezone for the DateTime object.
    3347             : */
    3348         352 : PHP_FUNCTION(date_timezone_set)
    3349             : {
    3350             :         zval *object;
    3351             :         zval *timezone_object;
    3352             : 
    3353         352 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_date, &timezone_object, date_ce_timezone) == FAILURE) {
    3354          92 :                 RETURN_FALSE;
    3355             :         }
    3356             : 
    3357         260 :         php_date_timezone_set(object, timezone_object, return_value TSRMLS_CC);
    3358             : 
    3359         520 :         RETURN_ZVAL(object, 1, 0);
    3360             : }
    3361             : /* }}} */
    3362             : 
    3363             : /* {{{ proto DateTimeImmutable::setTimezone()
    3364             : */
    3365           2 : PHP_METHOD(DateTimeImmutable, setTimezone)
    3366             : {
    3367             :         zval *object, *new_object;
    3368             :         zval *timezone_object;
    3369             : 
    3370           2 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_immutable, &timezone_object, date_ce_timezone) == FAILURE) {
    3371           0 :                 RETURN_FALSE;
    3372             :         }
    3373             : 
    3374           2 :         new_object = date_clone_immutable(object TSRMLS_CC);
    3375           2 :         php_date_timezone_set(new_object, timezone_object, return_value TSRMLS_CC);
    3376             : 
    3377           2 :         RETURN_ZVAL(new_object, 0, 1);
    3378             : }
    3379             : /* }}} */
    3380             : 
    3381             : /* {{{ proto long date_offset_get(DateTimeInterface object)
    3382             :    Returns the DST offset.
    3383             : */
    3384          60 : PHP_FUNCTION(date_offset_get)
    3385             : {
    3386             :         zval                *object;
    3387             :         php_date_obj        *dateobj;
    3388             :         timelib_time_offset *offset;
    3389             : 
    3390          60 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_interface) == FAILURE) {
    3391          34 :                 RETURN_FALSE;
    3392             :         }
    3393          26 :         dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3394          26 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3395          26 :         if (dateobj->time->is_localtime/* && dateobj->time->tz_info*/) {
    3396          26 :                 switch (dateobj->time->zone_type) {
    3397             :                         case TIMELIB_ZONETYPE_ID:
    3398           6 :                                 offset = timelib_get_time_zone_info(dateobj->time->sse, dateobj->time->tz_info);
    3399           6 :                                 RETVAL_LONG(offset->offset);
    3400           6 :                                 timelib_time_offset_dtor(offset);
    3401           6 :                                 break;
    3402             :                         case TIMELIB_ZONETYPE_OFFSET:
    3403          18 :                                 RETVAL_LONG(dateobj->time->z * -60);
    3404          18 :                                 break;
    3405             :                         case TIMELIB_ZONETYPE_ABBR:
    3406           2 :                                 RETVAL_LONG((dateobj->time->z - (60 * dateobj->time->dst)) * -60);
    3407             :                                 break;
    3408             :                 }
    3409          26 :                 return;
    3410             :         } else {
    3411           0 :                 RETURN_LONG(0);
    3412             :         }
    3413             : }
    3414             : /* }}} */
    3415             : 
    3416         133 : static void php_date_time_set(zval *object, long h, long i, long s, zval *return_value TSRMLS_DC)
    3417             : {
    3418             :         php_date_obj *dateobj;
    3419             : 
    3420         133 :         dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3421         133 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3422         133 :         dateobj->time->h = h;
    3423         133 :         dateobj->time->i = i;
    3424         133 :         dateobj->time->s = s;
    3425         133 :         timelib_update_ts(dateobj->time, NULL);
    3426             : }
    3427             : 
    3428             : /* {{{ proto DateTime date_time_set(DateTime object, long hour, long minute[, long second])
    3429             :    Sets the time.
    3430             : */
    3431         248 : PHP_FUNCTION(date_time_set)
    3432             : {
    3433             :         zval *object;
    3434         248 :         long  h, i, s = 0;
    3435             : 
    3436         248 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &h, &i, &s) == FAILURE) {
    3437         116 :                 RETURN_FALSE;
    3438             :         }
    3439             : 
    3440         132 :         php_date_time_set(object, h, i, s, return_value TSRMLS_CC);
    3441             : 
    3442         264 :         RETURN_ZVAL(object, 1, 0);
    3443             : }
    3444             : /* }}} */
    3445             : 
    3446             : /* {{{ proto DateTimeImmutable::setTime()
    3447             : */
    3448           1 : PHP_METHOD(DateTimeImmutable, setTime)
    3449             : {
    3450             :         zval *object, *new_object;
    3451           1 :         long  h, i, s = 0;
    3452             : 
    3453           1 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_immutable, &h, &i, &s) == FAILURE) {
    3454           0 :                 RETURN_FALSE;
    3455             :         }
    3456             : 
    3457           1 :         new_object = date_clone_immutable(object TSRMLS_CC);
    3458           1 :         php_date_time_set(new_object, h, i, s, return_value TSRMLS_CC);
    3459             : 
    3460           1 :         RETURN_ZVAL(new_object, 0, 1);
    3461             : }
    3462             : /* }}} */
    3463             : 
    3464         117 : static void php_date_date_set(zval *object, long y, long m, long d, zval *return_value TSRMLS_DC)
    3465             : {
    3466             :         php_date_obj *dateobj;
    3467             : 
    3468         117 :         dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3469         117 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3470         117 :         dateobj->time->y = y;
    3471         117 :         dateobj->time->m = m;
    3472         117 :         dateobj->time->d = d;
    3473         117 :         timelib_update_ts(dateobj->time, NULL);
    3474             : }
    3475             : 
    3476             : /* {{{ proto DateTime date_date_set(DateTime object, long year, long month, long day)
    3477             :    Sets the date.
    3478             : */
    3479         233 : PHP_FUNCTION(date_date_set)
    3480             : {
    3481             :         zval *object;
    3482             :         long  y, m, d;
    3483             : 
    3484         233 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olll", &object, date_ce_date, &y, &m, &d) == FAILURE) {
    3485         117 :                 RETURN_FALSE;
    3486             :         }
    3487             : 
    3488         116 :         php_date_date_set(object, y, m, d, return_value TSRMLS_CC);
    3489             : 
    3490         232 :         RETURN_ZVAL(object, 1, 0);
    3491             : }
    3492             : /* }}} */
    3493             : 
    3494             : /* {{{ proto DateTimeImmutable::setDate()
    3495             : */
    3496           1 : PHP_METHOD(DateTimeImmutable, setDate)
    3497             : {
    3498             :         zval *object, *new_object;
    3499             :         long  y, m, d;
    3500             : 
    3501           1 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olll", &object, date_ce_immutable, &y, &m, &d) == FAILURE) {
    3502           0 :                 RETURN_FALSE;
    3503             :         }
    3504             : 
    3505           1 :         new_object = date_clone_immutable(object TSRMLS_CC);
    3506           1 :         php_date_date_set(new_object, y, m, d, return_value TSRMLS_CC);
    3507             : 
    3508           1 :         RETURN_ZVAL(new_object, 0, 1);
    3509             : }
    3510             : /* }}} */
    3511             : 
    3512         104 : static void php_date_isodate_set(zval *object, long y, long w, long d, zval *return_value TSRMLS_DC)
    3513             : {
    3514             :         php_date_obj *dateobj;
    3515             : 
    3516         104 :         dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3517         104 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3518         104 :         dateobj->time->y = y;
    3519         104 :         dateobj->time->m = 1;
    3520         104 :         dateobj->time->d = 1;
    3521         104 :         memset(&dateobj->time->relative, 0, sizeof(dateobj->time->relative));
    3522         104 :         dateobj->time->relative.d = timelib_daynr_from_weeknr(y, w, d);
    3523         104 :         dateobj->time->have_relative = 1;
    3524             :         
    3525         104 :         timelib_update_ts(dateobj->time, NULL);
    3526             : }
    3527             : 
    3528             : /* {{{ proto DateTime date_isodate_set(DateTime object, long year, long week[, long day])
    3529             :    Sets the ISO date.
    3530             : */
    3531         220 : PHP_FUNCTION(date_isodate_set)
    3532             : {
    3533             :         zval *object;
    3534         220 :         long  y, w, d = 1;
    3535             : 
    3536         220 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_date, &y, &w, &d) == FAILURE) {
    3537         117 :                 RETURN_FALSE;
    3538             :         }
    3539             : 
    3540         103 :         php_date_isodate_set(object, y, w, d, return_value TSRMLS_CC);
    3541             : 
    3542         206 :         RETURN_ZVAL(object, 1, 0);
    3543             : }
    3544             : /* }}} */
    3545             : 
    3546             : /* {{{ proto DateTimeImmutable::setISODate()
    3547             : */
    3548           1 : PHP_METHOD(DateTimeImmutable, setISODate)
    3549             : {
    3550             :         zval *object, *new_object;
    3551           1 :         long  y, w, d = 1;
    3552             : 
    3553           1 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll|l", &object, date_ce_immutable, &y, &w, &d) == FAILURE) {
    3554           0 :                 RETURN_FALSE;
    3555             :         }
    3556             : 
    3557           1 :         new_object = date_clone_immutable(object TSRMLS_CC);
    3558           1 :         php_date_isodate_set(new_object, y, w, d, return_value TSRMLS_CC);
    3559             : 
    3560           1 :         RETURN_ZVAL(new_object, 0, 1);
    3561             : }
    3562             : /* }}} */
    3563             : 
    3564           5 : static void php_date_timestamp_set(zval *object, long timestamp, zval *return_value TSRMLS_DC)
    3565             : {
    3566             :         php_date_obj *dateobj;
    3567             : 
    3568           5 :         dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3569           5 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3570           5 :         timelib_unixtime2local(dateobj->time, (timelib_sll)timestamp);
    3571           5 :         timelib_update_ts(dateobj->time, NULL);
    3572             : }
    3573             : 
    3574             : /* {{{ proto DateTime date_timestamp_set(DateTime object, long unixTimestamp)
    3575             :    Sets the date and time based on an Unix timestamp.
    3576             : */
    3577           4 : PHP_FUNCTION(date_timestamp_set)
    3578             : {
    3579             :         zval *object;
    3580             :         long  timestamp;
    3581             : 
    3582           4 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &object, date_ce_date, &timestamp) == FAILURE) {
    3583           0 :                 RETURN_FALSE;
    3584             :         }
    3585             : 
    3586           4 :         php_date_timestamp_set(object, timestamp, return_value TSRMLS_CC);
    3587             : 
    3588           8 :         RETURN_ZVAL(object, 1, 0);
    3589             : }
    3590             : /* }}} */
    3591             : 
    3592             : /* {{{ proto DateTimeImmutable::setTimestamp()
    3593             : */
    3594           1 : PHP_METHOD(DateTimeImmutable, setTimestamp)
    3595             : {
    3596             :         zval *object, *new_object;
    3597             :         long  timestamp;
    3598             : 
    3599           1 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &object, date_ce_immutable, &timestamp) == FAILURE) {
    3600           0 :                 RETURN_FALSE;
    3601             :         }
    3602             : 
    3603           1 :         new_object = date_clone_immutable(object TSRMLS_CC);
    3604           1 :         php_date_timestamp_set(new_object, timestamp, return_value TSRMLS_CC);
    3605             : 
    3606           1 :         RETURN_ZVAL(new_object, 0, 1);
    3607             : }
    3608             : /* }}} */
    3609             : 
    3610             : /* {{{ proto long date_timestamp_get(DateTimeInterface object)
    3611             :    Gets the Unix timestamp.
    3612             : */
    3613          45 : PHP_FUNCTION(date_timestamp_get)
    3614             : {
    3615             :         zval         *object;
    3616             :         php_date_obj *dateobj;
    3617             :         long          timestamp;
    3618             :         int           error;
    3619             : 
    3620          45 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_interface) == FAILURE) {
    3621           1 :                 RETURN_FALSE;
    3622             :         }
    3623          44 :         dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3624          44 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3625          43 :         timelib_update_ts(dateobj->time, NULL);
    3626             : 
    3627          43 :         timestamp = timelib_date_to_int(dateobj->time, &error);
    3628          43 :         if (error) {
    3629           0 :                 RETURN_FALSE;
    3630             :         } else {
    3631          43 :                 RETVAL_LONG(timestamp);
    3632             :         }
    3633             : }
    3634             : /* }}} */
    3635             : 
    3636             : /* {{{ proto DateInterval date_diff(DateTime object [, bool absolute])
    3637             :    Returns the difference between two DateTime objects.
    3638             : */
    3639      173476 : PHP_FUNCTION(date_diff)
    3640             : {
    3641             :         zval         *object1, *object2;
    3642             :         php_date_obj *dateobj1, *dateobj2;
    3643             :         php_interval_obj *interval;
    3644      173476 :         long          absolute = 0;
    3645             : 
    3646      173476 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO|l", &object1, date_ce_interface, &object2, date_ce_interface, &absolute) == FAILURE) {
    3647           0 :                 RETURN_FALSE;
    3648             :         }
    3649      173476 :         dateobj1 = (php_date_obj *) zend_object_store_get_object(object1 TSRMLS_CC);
    3650      173476 :         dateobj2 = (php_date_obj *) zend_object_store_get_object(object2 TSRMLS_CC);
    3651      173476 :         DATE_CHECK_INITIALIZED(dateobj1->time, DateTimeInterface);
    3652      173476 :         DATE_CHECK_INITIALIZED(dateobj2->time, DateTimeInterface);
    3653      173476 :         timelib_update_ts(dateobj1->time, NULL);
    3654      173476 :         timelib_update_ts(dateobj2->time, NULL);
    3655             : 
    3656      173476 :         php_date_instantiate(date_ce_interval, return_value TSRMLS_CC);
    3657      173476 :         interval = zend_object_store_get_object(return_value TSRMLS_CC);
    3658      173476 :         interval->diff = timelib_diff(dateobj1->time, dateobj2->time);
    3659      173476 :         if (absolute) {
    3660           4 :                 interval->diff->invert = 0;
    3661             :         }
    3662      173476 :         interval->initialized = 1;
    3663             : }
    3664             : /* }}} */
    3665             : 
    3666         370 : static int timezone_initialize(php_timezone_obj *tzobj, /*const*/ char *tz TSRMLS_DC)
    3667             : {
    3668         370 :         timelib_time *dummy_t = ecalloc(1, sizeof(timelib_time));
    3669             :         int           dst, not_found;
    3670         370 :         char         *orig_tz = tz;
    3671             : 
    3672         370 :         dummy_t->z = timelib_parse_zone(&tz, &dst, dummy_t, &not_found, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    3673         370 :         if (not_found) {
    3674          43 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad timezone (%s)", orig_tz);
    3675          43 :                 efree(dummy_t);
    3676          43 :                 return FAILURE;
    3677             :         } else {
    3678         327 :                 set_timezone_from_timelib_time(tzobj, dummy_t);
    3679         327 :                 efree(dummy_t);
    3680         327 :                 return SUCCESS;
    3681             :         }
    3682             : }
    3683             : 
    3684             : /* {{{ proto DateTimeZone timezone_open(string timezone)
    3685             :    Returns new DateTimeZone object
    3686             : */
    3687          48 : PHP_FUNCTION(timezone_open)
    3688             : {
    3689             :         char *tz;
    3690             :         int   tz_len;
    3691             :         php_timezone_obj *tzobj;
    3692             : 
    3693          48 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tz, &tz_len) == FAILURE) {
    3694           8 :                 RETURN_FALSE;
    3695             :         }
    3696          40 :         tzobj = zend_object_store_get_object(php_date_instantiate(date_ce_timezone, return_value TSRMLS_CC) TSRMLS_CC);
    3697          40 :         if (SUCCESS != timezone_initialize(tzobj, tz TSRMLS_CC)) {
    3698          20 :                 RETURN_FALSE;
    3699             :         }
    3700             : }
    3701             : /* }}} */
    3702             : 
    3703             : /* {{{ proto DateTimeZone::__construct(string timezone)
    3704             :    Creates new DateTimeZone object.
    3705             : */
    3706         334 : PHP_METHOD(DateTimeZone, __construct)
    3707             : {
    3708             :         char *tz;
    3709             :         int tz_len;
    3710             :         php_timezone_obj *tzobj;
    3711             :         zend_error_handling error_handling;
    3712             :         
    3713         334 :         zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
    3714         334 :         if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tz, &tz_len)) {
    3715         327 :                 tzobj = zend_object_store_get_object(getThis() TSRMLS_CC);
    3716         327 :                 if (FAILURE == timezone_initialize(tzobj, tz TSRMLS_CC)) {
    3717          23 :                         ZVAL_NULL(getThis());
    3718             :                 }
    3719             :         }
    3720         334 :         zend_restore_error_handling(&error_handling TSRMLS_CC);
    3721         334 : }
    3722             : /* }}} */
    3723             : 
    3724           3 : static int php_date_timezone_initialize_from_hash(zval **return_value, php_timezone_obj **tzobj, HashTable *myht TSRMLS_DC)
    3725             : {
    3726           3 :         zval            **z_timezone = NULL;
    3727           3 :         zval            **z_timezone_type = NULL;
    3728             : 
    3729           3 :         if (zend_hash_find(myht, "timezone_type", 14, (void**) &z_timezone_type) == SUCCESS) {
    3730           3 :                 if (zend_hash_find(myht, "timezone", 9, (void**) &z_timezone) == SUCCESS) {
    3731           3 :                         convert_to_long(*z_timezone_type);
    3732           3 :                         if (SUCCESS == timezone_initialize(*tzobj, Z_STRVAL_PP(z_timezone) TSRMLS_CC)) {
    3733           3 :                                 return SUCCESS;
    3734             :                         }
    3735             :                 }
    3736             :         }
    3737           0 :         return FAILURE;
    3738             : }
    3739             : 
    3740             : /* {{{ proto DateTimeZone::__set_state()
    3741             :  *  */
    3742           0 : PHP_METHOD(DateTimeZone, __set_state)
    3743             : {
    3744             :         php_timezone_obj *tzobj;
    3745             :         zval             *array;
    3746             :         HashTable        *myht;
    3747             : 
    3748           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
    3749           0 :                 RETURN_FALSE;
    3750             :         }
    3751             : 
    3752           0 :         myht = HASH_OF(array);
    3753             : 
    3754           0 :         php_date_instantiate(date_ce_timezone, return_value TSRMLS_CC);
    3755           0 :         tzobj = (php_timezone_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
    3756           0 :         php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht TSRMLS_CC);
    3757             : }
    3758             : /* }}} */
    3759             : 
    3760             : /* {{{ proto DateTimeZone::__wakeup()
    3761             :  *  */
    3762           3 : PHP_METHOD(DateTimeZone, __wakeup)
    3763             : {
    3764           3 :         zval             *object = getThis();
    3765             :         php_timezone_obj *tzobj;
    3766             :         HashTable        *myht;
    3767             : 
    3768           3 :         tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3769             : 
    3770           3 :         myht = Z_OBJPROP_P(object);
    3771             :         
    3772           3 :         php_date_timezone_initialize_from_hash(&return_value, &tzobj, myht TSRMLS_CC);
    3773           3 : }
    3774             : /* }}} */
    3775             : 
    3776             : /* {{{ proto string timezone_name_get(DateTimeZone object)
    3777             :    Returns the name of the timezone.
    3778             : */
    3779          51 : PHP_FUNCTION(timezone_name_get)
    3780             : {
    3781             :         zval             *object;
    3782             :         php_timezone_obj *tzobj;
    3783             : 
    3784          51 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_timezone) == FAILURE) {
    3785           6 :                 RETURN_FALSE;
    3786             :         }
    3787          45 :         tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3788          45 :         DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
    3789             : 
    3790          44 :         switch (tzobj->type) {
    3791             :                 case TIMELIB_ZONETYPE_ID:
    3792          33 :                         RETURN_STRING(tzobj->tzi.tz->name, 1);
    3793             :                         break;
    3794             :                 case TIMELIB_ZONETYPE_OFFSET: {
    3795           8 :                         char *tmpstr = emalloc(sizeof("UTC+05:00"));
    3796           8 :                         timelib_sll utc_offset = tzobj->tzi.utc_offset;
    3797             : 
    3798          16 :                         snprintf(tmpstr, sizeof("+05:00"), "%c%02d:%02d",
    3799             :                                 utc_offset > 0 ? '-' : '+',
    3800           8 :                                 abs(utc_offset / 60),
    3801           8 :                                 abs((utc_offset % 60)));
    3802             : 
    3803           8 :                         RETURN_STRING(tmpstr, 0);
    3804             :                         }
    3805             :                         break;
    3806             :                 case TIMELIB_ZONETYPE_ABBR:
    3807           3 :                         RETURN_STRING(tzobj->tzi.z.abbr, 1);
    3808             :                         break;
    3809             :         }
    3810             : }
    3811             : /* }}} */
    3812             : 
    3813             : /* {{{ proto string timezone_name_from_abbr(string abbr[, long gmtOffset[, long isdst]])
    3814             :    Returns the timezone name from abbrevation
    3815             : */
    3816         107 : PHP_FUNCTION(timezone_name_from_abbr)
    3817             : {
    3818             :         char    *abbr;
    3819             :         char    *tzid;
    3820             :         int      abbr_len;
    3821         107 :         long     gmtoffset = -1;
    3822         107 :         long     isdst = -1;
    3823             : 
    3824         107 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &abbr, &abbr_len, &gmtoffset, &isdst) == FAILURE) {
    3825          35 :                 RETURN_FALSE;
    3826             :         }
    3827          72 :         tzid = timelib_timezone_id_from_abbr(abbr, gmtoffset, isdst);
    3828             : 
    3829          72 :         if (tzid) {
    3830          68 :                 RETURN_STRING(tzid, 1);
    3831             :         } else {
    3832           4 :                 RETURN_FALSE;
    3833             :         }
    3834             : }
    3835             : /* }}} */
    3836             : 
    3837             : /* {{{ proto long timezone_offset_get(DateTimeZone object, DateTime object)
    3838             :    Returns the timezone offset.
    3839             : */
    3840         118 : PHP_FUNCTION(timezone_offset_get)
    3841             : {
    3842             :         zval                *object, *dateobject;
    3843             :         php_timezone_obj    *tzobj;
    3844             :         php_date_obj        *dateobj;
    3845             :         timelib_time_offset *offset;
    3846             : 
    3847         118 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &object, date_ce_timezone, &dateobject, date_ce_date) == FAILURE) {
    3848          97 :                 RETURN_FALSE;
    3849             :         }
    3850          21 :         tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3851          21 :         DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
    3852          21 :         dateobj = (php_date_obj *) zend_object_store_get_object(dateobject TSRMLS_CC);
    3853          21 :         DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
    3854             : 
    3855          21 :         switch (tzobj->type) {
    3856             :                 case TIMELIB_ZONETYPE_ID:
    3857          12 :                         offset = timelib_get_time_zone_info(dateobj->time->sse, tzobj->tzi.tz);
    3858          12 :                         RETVAL_LONG(offset->offset);
    3859          12 :                         timelib_time_offset_dtor(offset);
    3860          12 :                         break;
    3861             :                 case TIMELIB_ZONETYPE_OFFSET:
    3862           6 :                         RETURN_LONG(tzobj->tzi.utc_offset * -60);
    3863             :                         break;
    3864             :                 case TIMELIB_ZONETYPE_ABBR:
    3865           3 :                         RETURN_LONG((tzobj->tzi.z.utc_offset - (tzobj->tzi.z.dst*60)) * -60);
    3866             :                         break;
    3867             :         }
    3868             : }
    3869             : /* }}} */
    3870             : 
    3871             : /* {{{ proto array timezone_transitions_get(DateTimeZone object [, long timestamp_begin [, long timestamp_end ]])
    3872             :    Returns numerically indexed array containing associative array for all transitions in the specified range for the timezone.
    3873             : */
    3874          94 : PHP_FUNCTION(timezone_transitions_get)
    3875             : {
    3876             :         zval                *object, *element;
    3877             :         php_timezone_obj    *tzobj;
    3878          94 :         unsigned int         i, begin = 0, found;
    3879          94 :         long                 timestamp_begin = LONG_MIN, timestamp_end = LONG_MAX;
    3880             : 
    3881          94 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|ll", &object, date_ce_timezone, &timestamp_begin, &timestamp_end) == FAILURE) {
    3882          60 :                 RETURN_FALSE;
    3883             :         }
    3884          34 :         tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3885          34 :         DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
    3886          34 :         if (tzobj->type != TIMELIB_ZONETYPE_ID) {
    3887           0 :                 RETURN_FALSE;
    3888             :         }
    3889             : 
    3890             : #define add_nominal() \
    3891             :                 MAKE_STD_ZVAL(element); \
    3892             :                 array_init(element); \
    3893             :                 add_assoc_long(element, "ts",     timestamp_begin); \
    3894             :                 add_assoc_string(element, "time", php_format_date(DATE_FORMAT_ISO8601, 13, timestamp_begin, 0 TSRMLS_CC), 0); \
    3895             :                 add_assoc_long(element, "offset", tzobj->tzi.tz->type[0].offset); \
    3896             :                 add_assoc_bool(element, "isdst",  tzobj->tzi.tz->type[0].isdst); \
    3897             :                 add_assoc_string(element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[0].abbr_idx], 1); \
    3898             :                 add_next_index_zval(return_value, element);
    3899             : 
    3900             : #define add(i,ts) \
    3901             :                 MAKE_STD_ZVAL(element); \
    3902             :                 array_init(element); \
    3903             :                 add_assoc_long(element, "ts",     ts); \
    3904             :                 add_assoc_string(element, "time", php_format_date(DATE_FORMAT_ISO8601, 13, ts, 0 TSRMLS_CC), 0); \
    3905             :                 add_assoc_long(element, "offset", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].offset); \
    3906             :                 add_assoc_bool(element, "isdst",  tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].isdst); \
    3907             :                 add_assoc_string(element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].abbr_idx], 1); \
    3908             :                 add_next_index_zval(return_value, element);
    3909             : 
    3910             : #define add_last() add(tzobj->tzi.tz->timecnt - 1, timestamp_begin)
    3911             : 
    3912          34 :         array_init(return_value);
    3913             : 
    3914          34 :         if (timestamp_begin == LONG_MIN) {
    3915           4 :                 add_nominal();
    3916           4 :                 begin = 0;
    3917           4 :                 found = 1;
    3918             :         } else {
    3919          30 :                 begin = 0;
    3920          30 :                 found = 0;
    3921          30 :                 if (tzobj->tzi.tz->timecnt > 0) {
    3922             :                         do {
    3923        3375 :                                 if (tzobj->tzi.tz->trans[begin] > timestamp_begin) {
    3924          30 :                                         if (begin > 0) {
    3925          30 :                                                 add(begin - 1, timestamp_begin);
    3926             :                                         } else {
    3927           0 :                                                 add_nominal();
    3928             :                                         }
    3929          30 :                                         found = 1;
    3930          30 :                                         break;
    3931             :                                 }
    3932        3345 :                                 begin++;
    3933        3345 :                         } while (begin < tzobj->tzi.tz->timecnt);
    3934             :                 }
    3935             :         }
    3936             : 
    3937          34 :         if (!found) {
    3938           0 :                 if (tzobj->tzi.tz->timecnt > 0) {
    3939           0 :                         add_last();
    3940             :                 } else {
    3941           0 :                         add_nominal();
    3942             :                 }
    3943             :         } else {
    3944        4917 :                 for (i = begin; i < tzobj->tzi.tz->timecnt; ++i) {
    3945        4883 :                         if (tzobj->tzi.tz->trans[i] < timestamp_end) {
    3946        1073 :                                 add(i, tzobj->tzi.tz->trans[i]);
    3947             :                         }
    3948             :                 }
    3949             :         }
    3950             : }
    3951             : /* }}} */
    3952             : 
    3953             : /* {{{ proto array timezone_location_get()
    3954             :    Returns location information for a timezone, including country code, latitude/longitude and comments
    3955             : */
    3956           2 : PHP_FUNCTION(timezone_location_get)
    3957             : {
    3958             :         zval                *object;
    3959             :         php_timezone_obj    *tzobj;
    3960             : 
    3961           2 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_timezone) == FAILURE) {
    3962           0 :                 RETURN_FALSE;
    3963             :         }
    3964           2 :         tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
    3965           2 :         DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
    3966           1 :         if (tzobj->type != TIMELIB_ZONETYPE_ID) {
    3967           0 :                 RETURN_FALSE;
    3968             :         }
    3969             : 
    3970           1 :         array_init(return_value);
    3971           1 :         add_assoc_string(return_value, "country_code", tzobj->tzi.tz->location.country_code, 1);
    3972           1 :         add_assoc_double(return_value, "latitude", tzobj->tzi.tz->location.latitude);
    3973           1 :         add_assoc_double(return_value, "longitude", tzobj->tzi.tz->location.longitude);
    3974           1 :         add_assoc_string(return_value, "comments", tzobj->tzi.tz->location.comments, 1);
    3975             : }
    3976             : /* }}} */
    3977             : 
    3978      175601 : static int date_interval_initialize(timelib_rel_time **rt, /*const*/ char *format, int format_length TSRMLS_DC)
    3979             : {
    3980      175601 :         timelib_time     *b = NULL, *e = NULL;
    3981      175601 :         timelib_rel_time *p = NULL;
    3982      175601 :         int               r = 0;
    3983      175601 :         int               retval = 0;
    3984             :         struct timelib_error_container *errors;
    3985             : 
    3986      175601 :         timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors);
    3987             :         
    3988      175601 :         if (errors->error_count > 0) {
    3989           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad format (%s)", format);
    3990           2 :                 retval = FAILURE;
    3991             :         } else {
    3992      175599 :                 if(p) {
    3993      175594 :                         *rt = p;
    3994      175594 :                         retval = SUCCESS;
    3995             :                 } else {
    3996           8 :                         if(b && e) {
    3997           3 :                                 timelib_update_ts(b, NULL);
    3998           3 :                                 timelib_update_ts(e, NULL);
    3999           3 :                                 *rt = timelib_diff(b, e);
    4000           3 :                                 retval = SUCCESS;
    4001             :                         } else {
    4002           2 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse interval (%s)", format);
    4003           2 :                                 retval = FAILURE;
    4004             :                         }
    4005             :                 }
    4006             :         }
    4007      175601 :         timelib_error_container_dtor(errors);
    4008      175601 :         return retval;
    4009             : }
    4010             : 
    4011             : /* {{{ date_interval_read_property */
    4012          38 : zval *date_interval_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
    4013             : {
    4014             :         php_interval_obj *obj;
    4015             :         zval *retval;
    4016             :         zval tmp_member;
    4017          38 :         timelib_sll value = -1;
    4018             : 
    4019          38 :         if (member->type != IS_STRING) {
    4020           1 :                 tmp_member = *member;
    4021             :                 zval_copy_ctor(&tmp_member);
    4022           1 :                 convert_to_string(&tmp_member);
    4023           1 :                 member = &tmp_member;
    4024           1 :                 key = NULL;
    4025             :         }
    4026             : 
    4027          38 :         obj = (php_interval_obj *)zend_objects_get_address(object TSRMLS_CC);
    4028             : 
    4029          38 :         if (!obj->initialized) {
    4030           3 :                 retval = (zend_get_std_object_handlers())->read_property(object, member, type, key TSRMLS_CC);
    4031           3 :                 if (member == &tmp_member) {
    4032             :                         zval_dtor(member);
    4033             :                 }
    4034           3 :                 return retval;
    4035             :         }
    4036             : 
    4037             : #define GET_VALUE_FROM_STRUCT(n,m)            \
    4038             :         if (strcmp(Z_STRVAL_P(member), m) == 0) { \
    4039             :                 value = obj->diff->n;                 \
    4040             :                 break;                                                            \
    4041             :         }
    4042             :         do {
    4043          35 :                 GET_VALUE_FROM_STRUCT(y, "y");
    4044          31 :                 GET_VALUE_FROM_STRUCT(m, "m");
    4045          27 :                 GET_VALUE_FROM_STRUCT(d, "d");
    4046          22 :                 GET_VALUE_FROM_STRUCT(h, "h");
    4047          18 :                 GET_VALUE_FROM_STRUCT(i, "i");
    4048          14 :                 GET_VALUE_FROM_STRUCT(s, "s");
    4049          10 :                 GET_VALUE_FROM_STRUCT(invert, "invert");
    4050           9 :                 GET_VALUE_FROM_STRUCT(days, "days");
    4051             :                 /* didn't find any */
    4052           4 :                 retval = (zend_get_std_object_handlers())->read_property(object, member, type, key TSRMLS_CC);
    4053             : 
    4054           4 :                 if (member == &tmp_member) {
    4055             :                         zval_dtor(member);
    4056             :                 }
    4057             : 
    4058           4 :                 return retval;
    4059             :         } while(0);
    4060             : 
    4061          31 :         ALLOC_INIT_ZVAL(retval);
    4062             :         Z_SET_REFCOUNT_P(retval, 0);
    4063             : 
    4064          31 :         if (value != -99999) {
    4065          30 :                 ZVAL_LONG(retval, value);
    4066             :         } else {
    4067           1 :                 ZVAL_FALSE(retval);
    4068             :         }
    4069             : 
    4070          31 :         if (member == &tmp_member) {
    4071             :                 zval_dtor(member);
    4072             :         }
    4073             : 
    4074          31 :         return retval;
    4075             : }
    4076             : /* }}} */
    4077             : 
    4078             : /* {{{ date_interval_write_property */
    4079         536 : void date_interval_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
    4080             : {
    4081             :         php_interval_obj *obj;
    4082             :         zval tmp_member, tmp_value;
    4083             : 
    4084         536 :         if (member->type != IS_STRING) {
    4085           0 :                 tmp_member = *member;
    4086             :                 zval_copy_ctor(&tmp_member);
    4087           0 :                 convert_to_string(&tmp_member);
    4088           0 :                 member = &tmp_member;
    4089           0 :                 key = NULL;
    4090             :         }
    4091             : 
    4092         536 :         obj = (php_interval_obj *)zend_objects_get_address(object TSRMLS_CC);
    4093             : 
    4094         536 :         if (!obj->initialized) {
    4095           1 :                 (zend_get_std_object_handlers())->write_property(object, member, value, key TSRMLS_CC);
    4096           1 :                 if (member == &tmp_member) {
    4097             :                         zval_dtor(member);
    4098             :                 }
    4099           1 :                 return;
    4100             :         }
    4101             : 
    4102             : #define SET_VALUE_FROM_STRUCT(n,m)            \
    4103             :         if (strcmp(Z_STRVAL_P(member), m) == 0) { \
    4104             :                 if (value->type != IS_LONG) {         \
    4105             :                         tmp_value = *value;               \
    4106             :                         zval_copy_ctor(&tmp_value);       \
    4107             :                         convert_to_long(&tmp_value);      \
    4108             :                         value = &tmp_value;               \
    4109             :                 }                                     \
    4110             :                 obj->diff->n = Z_LVAL_P(value);       \
    4111             :                 if (value == &tmp_value) {            \
    4112             :                         zval_dtor(value);                 \
    4113             :                 }                                     \
    4114             :                 break;                                                            \
    4115             :         }
    4116             : 
    4117             :         do {
    4118         535 :                 SET_VALUE_FROM_STRUCT(y, "y");
    4119         535 :                 SET_VALUE_FROM_STRUCT(m, "m");
    4120         536 :                 SET_VALUE_FROM_STRUCT(d, "d");
    4121         534 :                 SET_VALUE_FROM_STRUCT(h, "h");
    4122         534 :                 SET_VALUE_FROM_STRUCT(i, "i");
    4123         534 :                 SET_VALUE_FROM_STRUCT(s, "s");
    4124        1598 :                 SET_VALUE_FROM_STRUCT(invert, "invert");
    4125             :                 /* didn't find any */
    4126           2 :                 (zend_get_std_object_handlers())->write_property(object, member, value, key TSRMLS_CC);
    4127             :         } while(0);
    4128             : 
    4129         535 :         if (member == &tmp_member) {
    4130             :                 zval_dtor(member);
    4131             :         }
    4132             : }
    4133             : /* }}} */
    4134             : 
    4135             : 
    4136             : /* {{{ proto DateInterval::__construct([string interval_spec])
    4137             :    Creates new DateInterval object.
    4138             : */
    4139      175601 : PHP_METHOD(DateInterval, __construct)
    4140             : {
    4141      175601 :         char *interval_string = NULL;
    4142             :         int   interval_string_length;
    4143             :         php_interval_obj *diobj;
    4144             :         timelib_rel_time *reltime;
    4145             :         zend_error_handling error_handling;
    4146             :         
    4147      175601 :         zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
    4148      175601 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &interval_string, &interval_string_length) == SUCCESS) {
    4149      175601 :                 if (date_interval_initialize(&reltime, interval_string, interval_string_length TSRMLS_CC) == SUCCESS) {
    4150      175597 :                         diobj = zend_object_store_get_object(getThis() TSRMLS_CC);
    4151      175597 :                         diobj->diff = reltime;
    4152      175597 :                         diobj->initialized = 1;
    4153             :                 } else {
    4154           4 :                         ZVAL_NULL(getThis());
    4155             :                 }
    4156             :         }
    4157      175601 :         zend_restore_error_handling(&error_handling TSRMLS_CC);
    4158      175601 : }
    4159             : /* }}} */
    4160             : 
    4161             : 
    4162           6 : static int php_date_interval_initialize_from_hash(zval **return_value, php_interval_obj **intobj, HashTable *myht TSRMLS_DC)
    4163             : {
    4164           6 :         (*intobj)->diff = timelib_rel_time_ctor();
    4165             : 
    4166             : #define PHP_DATE_INTERVAL_READ_PROPERTY(element, member, itype, def) \
    4167             :         do { \
    4168             :                 zval **z_arg = NULL; \
    4169             :                 if (zend_hash_find(myht, element, strlen(element) + 1, (void**) &z_arg) == SUCCESS) { \
    4170             :                         convert_to_long(*z_arg); \
    4171             :                         (*intobj)->diff->member = (itype)Z_LVAL_PP(z_arg); \
    4172             :                 } else { \
    4173             :                         (*intobj)->diff->member = (itype)def; \
    4174             :                 } \
    4175             :         } while (0);
    4176             : 
    4177             : #define PHP_DATE_INTERVAL_READ_PROPERTY_I64(element, member) \
    4178             :         do { \
    4179             :                 zval **z_arg = NULL; \
    4180             :                 if (zend_hash_find(myht, element, strlen(element) + 1, (void**) &z_arg) == SUCCESS) { \
    4181             :                         convert_to_string(*z_arg); \
    4182             :                         DATE_A64I((*intobj)->diff->member, Z_STRVAL_PP(z_arg)); \
    4183             :                 } else { \
    4184             :                         (*intobj)->diff->member = -1LL; \
    4185             :                 } \
    4186             :         } while (0);
    4187             : 
    4188           6 :         PHP_DATE_INTERVAL_READ_PROPERTY("y", y, timelib_sll, -1)
    4189           6 :         PHP_DATE_INTERVAL_READ_PROPERTY("m", m, timelib_sll, -1)
    4190           6 :         PHP_DATE_INTERVAL_READ_PROPERTY("d", d, timelib_sll, -1)
    4191           6 :         PHP_DATE_INTERVAL_READ_PROPERTY("h", h, timelib_sll, -1)
    4192           6 :         PHP_DATE_INTERVAL_READ_PROPERTY("i", i, timelib_sll, -1)
    4193           6 :         PHP_DATE_INTERVAL_READ_PROPERTY("s", s, timelib_sll, -1)
    4194           6 :         PHP_DATE_INTERVAL_READ_PROPERTY("weekday", weekday, int, -1)
    4195           6 :         PHP_DATE_INTERVAL_READ_PROPERTY("weekday_behavior", weekday_behavior, int, -1)
    4196           6 :         PHP_DATE_INTERVAL_READ_PROPERTY("first_last_day_of", first_last_day_of, int, -1)
    4197           6 :         PHP_DATE_INTERVAL_READ_PROPERTY("invert", invert, int, 0);
    4198           6 :         PHP_DATE_INTERVAL_READ_PROPERTY_I64("days", days);
    4199           6 :         PHP_DATE_INTERVAL_READ_PROPERTY("special_type", special.type, unsigned int, 0);
    4200           6 :         PHP_DATE_INTERVAL_READ_PROPERTY_I64("special_amount", special.amount);
    4201           6 :         PHP_DATE_INTERVAL_READ_PROPERTY("have_weekday_relative", have_weekday_relative, unsigned int, 0);
    4202           6 :         PHP_DATE_INTERVAL_READ_PROPERTY("have_special_relative", have_special_relative, unsigned int, 0);
    4203           6 :         (*intobj)->initialized = 1;
    4204             : 
    4205           6 :         return 0;
    4206             : }
    4207             : 
    4208             : /* {{{ proto DateInterval::__set_state()
    4209             : */
    4210           1 : PHP_METHOD(DateInterval, __set_state)
    4211             : {
    4212             :         php_interval_obj *intobj;
    4213             :         zval             *array;
    4214             :         HashTable        *myht;
    4215             : 
    4216           1 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
    4217           0 :                 RETURN_FALSE;
    4218             :         }
    4219             : 
    4220           1 :         myht = HASH_OF(array);
    4221             : 
    4222           1 :         php_date_instantiate(date_ce_interval, return_value TSRMLS_CC);
    4223           1 :         intobj = (php_interval_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
    4224           1 :         php_date_interval_initialize_from_hash(&return_value, &intobj, myht TSRMLS_CC);
    4225             : }
    4226             : /* }}} */
    4227             : 
    4228             : /* {{{ proto DateInterval::__wakeup()
    4229             : */
    4230           5 : PHP_METHOD(DateInterval, __wakeup)
    4231             : {
    4232           5 :         zval             *object = getThis();
    4233             :         php_interval_obj *intobj;
    4234             :         HashTable        *myht;
    4235             : 
    4236           5 :         intobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC);
    4237             : 
    4238           5 :         myht = Z_OBJPROP_P(object);
    4239             : 
    4240           5 :         php_date_interval_initialize_from_hash(&return_value, &intobj, myht TSRMLS_CC);
    4241           5 : }
    4242             : /* }}} */
    4243             : /* {{{ proto DateInterval date_interval_create_from_date_string(string time)
    4244             :    Uses the normal date parsers and sets up a DateInterval from the relative parts of the parsed string
    4245             : */
    4246           8 : PHP_FUNCTION(date_interval_create_from_date_string)
    4247             : {
    4248           8 :         char           *time_str = NULL;
    4249           8 :         int             time_str_len = 0;
    4250             :         timelib_time   *time;
    4251           8 :         timelib_error_container *err = NULL;
    4252             :         php_interval_obj *diobj;
    4253             : 
    4254           8 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &time_str, &time_str_len) == FAILURE) {
    4255           0 :                 RETURN_FALSE;
    4256             :         }
    4257             : 
    4258           8 :         php_date_instantiate(date_ce_interval, return_value TSRMLS_CC);
    4259             : 
    4260           8 :         time = timelib_strtotime(time_str, time_str_len, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
    4261           8 :         diobj = (php_interval_obj *) zend_object_store_get_object(return_value TSRMLS_CC);
    4262           8 :         diobj->diff = timelib_rel_time_clone(&time->relative);
    4263           8 :         diobj->initialized = 1;
    4264           8 :         timelib_time_dtor(time);
    4265           8 :         timelib_error_container_dtor(err);
    4266             : }
    4267             : /* }}} */
    4268             : 
    4269             : /* {{{ date_interval_format -  */
    4270      173488 : static char *date_interval_format(char *format, int format_len, timelib_rel_time *t)
    4271             : {
    4272      173488 :         smart_str            string = {0};
    4273      173488 :         int                  i, length, have_format_spec = 0;
    4274             :         char                 buffer[33];
    4275             : 
    4276      173488 :         if (!format_len) {
    4277           0 :                 return estrdup("");
    4278             :         }
    4279             : 
    4280     1909438 :         for (i = 0; i < format_len; i++) {
    4281     1735950 :                 if (have_format_spec) {
    4282      520992 :                         switch (format[i]) {
    4283           1 :                                 case 'Y': length = slprintf(buffer, 32, "%02d", (int) t->y); break;
    4284      173109 :                                 case 'y': length = slprintf(buffer, 32, "%d", (int) t->y); break;
    4285             : 
    4286           1 :                                 case 'M': length = slprintf(buffer, 32, "%02d", (int) t->m); break;
    4287      173109 :                                 case 'm': length = slprintf(buffer, 32, "%d", (int) t->m); break;
    4288             : 
    4289           1 :                                 case 'D': length = slprintf(buffer, 32, "%02d", (int) t->d); break;
    4290      173152 :                                 case 'd': length = slprintf(buffer, 32, "%d", (int) t->d); break;
    4291             : 
    4292           1 :                                 case 'H': length = slprintf(buffer, 32, "%02d", (int) t->h); break;
    4293         357 :                                 case 'h': length = slprintf(buffer, 32, "%d", (int) t->h); break;
    4294             : 
    4295           1 :                                 case 'I': length = slprintf(buffer, 32, "%02d", (int) t->i); break;
    4296         317 :                                 case 'i': length = slprintf(buffer, 32, "%d", (int) t->i); break;
    4297             : 
    4298           1 :                                 case 'S': length = slprintf(buffer, 32, "%02ld", (long) t->s); break;
    4299         316 :                                 case 's': length = slprintf(buffer, 32, "%ld", (long) t->s); break;
    4300             : 
    4301             :                                 case 'a': {
    4302         311 :                                         if ((int) t->days != -99999) {
    4303         309 :                                                 length = slprintf(buffer, 32, "%d", (int) t->days);
    4304             :                                         } else {
    4305           2 :                                                 length = slprintf(buffer, 32, "(unknown)");
    4306             :                                         }
    4307         311 :                                 } break;
    4308           2 :                                 case 'r': length = slprintf(buffer, 32, "%s", t->invert ? "-" : ""); break;
    4309         310 :                                 case 'R': length = slprintf(buffer, 32, "%c", t->invert ? '-' : '+'); break;
    4310             : 
    4311           1 :                                 case '%': length = slprintf(buffer, 32, "%%"); break;
    4312           2 :                                 default: buffer[0] = '%'; buffer[1] = format[i]; buffer[2] = '\0'; length = 2; break;
    4313             :                         }
    4314      520992 :                         smart_str_appendl(&string, buffer, length);
    4315      520992 :                         have_format_spec = 0;
    4316             :                 } else {
    4317     1214958 :                         if (format[i] == '%') {
    4318      520992 :                                 have_format_spec = 1;
    4319             :                         } else {
    4320      693966 :                                 smart_str_appendc(&string, format[i]);
    4321             :                         }
    4322             :                 }
    4323             :         }
    4324             : 
    4325      173488 :         smart_str_0(&string);
    4326             : 
    4327      173488 :         return string.c;
    4328             : }
    4329             : /* }}} */
    4330             : 
    4331             : /* {{{ proto string date_interval_format(DateInterval object, string format)
    4332             :    Formats the interval.
    4333             : */
    4334      173488 : PHP_FUNCTION(date_interval_format)
    4335             : {
    4336             :         zval             *object;
    4337             :         php_interval_obj *diobj;
    4338             :         char             *format;
    4339             :         int               format_len;
    4340             : 
    4341      173488 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, date_ce_interval, &format, &format_len) == FAILURE) {
    4342           0 :                 RETURN_FALSE;
    4343             :         }
    4344      173488 :         diobj = (php_interval_obj *) zend_object_store_get_object(object TSRMLS_CC);
    4345      173488 :         DATE_CHECK_INITIALIZED(diobj->initialized, DateInterval);
    4346             : 
    4347      173488 :         RETURN_STRING(date_interval_format(format, format_len, diobj->diff), 0);
    4348             : }
    4349             : /* }}} */
    4350             : 
    4351           3 : static int date_period_initialize(timelib_time **st, timelib_time **et, timelib_rel_time **d, long *recurrences, /*const*/ char *format, int format_length TSRMLS_DC)
    4352             : {
    4353           3 :         timelib_time     *b = NULL, *e = NULL;
    4354           3 :         timelib_rel_time *p = NULL;
    4355           3 :         int               r = 0;
    4356           3 :         int               retval = 0;
    4357             :         struct timelib_error_container *errors;
    4358             : 
    4359           3 :         timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors);
    4360             :         
    4361           3 :         if (errors->error_count > 0) {
    4362           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad format (%s)", format);
    4363           2 :                 retval = FAILURE;
    4364             :         } else {
    4365           1 :                 *st = b;
    4366           1 :                 *et = e;
    4367           1 :                 *d  = p;
    4368           1 :                 *recurrences = r;
    4369           1 :                 retval = SUCCESS;
    4370             :         }
    4371           3 :         timelib_error_container_dtor(errors);
    4372           3 :         return retval;
    4373             : }
    4374             : 
    4375             : /* {{{ proto DatePeriod::__construct(DateTime $start, DateInterval $interval, int recurrences|DateTime $end)
    4376             :    Creates new DatePeriod object.
    4377             : */
    4378          14 : PHP_METHOD(DatePeriod, __construct)
    4379             : {
    4380             :         php_period_obj   *dpobj;
    4381             :         php_date_obj     *dateobj;
    4382             :         php_interval_obj *intobj;
    4383          14 :         zval *start, *end = NULL, *interval;
    4384          14 :         long  recurrences = 0, options = 0;
    4385          14 :         char *isostr = NULL;
    4386          14 :         int   isostr_len = 0;
    4387             :         timelib_time *clone;
    4388             :         zend_error_handling error_handling;
    4389             :         
    4390          14 :         zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
    4391          14 :         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "OOl|l", &start, date_ce_interface, &interval, date_ce_interval, &recurrences, &options) == FAILURE) {
    4392           8 :                 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "OOO|l", &start, date_ce_interface, &interval, date_ce_interval, &end, date_ce_interface, &options) == FAILURE) {
    4393           4 :                         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &isostr, &isostr_len, &options) == FAILURE) {
    4394           1 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "This constructor accepts either (DateTimeInterface, DateInterval, int) OR (DateTimeInterface, DateInterval, DateTime) OR (string) as arguments.");
    4395           1 :                                 zend_restore_error_handling(&error_handling TSRMLS_CC);
    4396           1 :                                 return;
    4397             :                         }
    4398             :                 }
    4399             :         }
    4400             : 
    4401          13 :         dpobj = zend_object_store_get_object(getThis() TSRMLS_CC);
    4402          13 :         dpobj->current = NULL;
    4403             : 
    4404          13 :         if (isostr) {
    4405           3 :                 date_period_initialize(&(dpobj->start), &(dpobj->end), &(dpobj->interval), &recurrences, isostr, isostr_len TSRMLS_CC);
    4406           3 :                 if (dpobj->start == NULL) {
    4407           2 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ISO interval '%s' did not contain a start date.", isostr);
    4408             :                 }
    4409           3 :                 if (dpobj->interval == NULL) {
    4410           2 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ISO interval '%s' did not contain an interval.", isostr);
    4411             :                 }
    4412           3 :                 if (dpobj->end == NULL && recurrences == 0) {
    4413           2 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ISO interval '%s' did not contain an end date or a recurrence count.", isostr);
    4414             :                 }
    4415             : 
    4416           3 :                 if (dpobj->start) {
    4417           1 :                         timelib_update_ts(dpobj->start, NULL);
    4418             :                 }
    4419           3 :                 if (dpobj->end) {
    4420           0 :                         timelib_update_ts(dpobj->end, NULL);
    4421             :                 }
    4422           3 :                 dpobj->start_ce = date_ce_date;
    4423             :         } else {
    4424             :                 /* init */
    4425          10 :                 intobj  = (php_interval_obj *) zend_object_store_get_object(interval TSRMLS_CC);
    4426             : 
    4427             :                 /* start date */
    4428          10 :                 dateobj = (php_date_obj *) zend_object_store_get_object(start TSRMLS_CC);
    4429          10 :                 clone = timelib_time_ctor();
    4430          10 :                 memcpy(clone, dateobj->time, sizeof(timelib_time));
    4431          10 :                 if (dateobj->time->tz_abbr) {
    4432          10 :                         clone->tz_abbr = strdup(dateobj->time->tz_abbr);
    4433             :                 }
    4434          10 :                 if (dateobj->time->tz_info) {
    4435          10 :                         clone->tz_info = dateobj->time->tz_info;
    4436             :                 }
    4437          10 :                 dpobj->start = clone;
    4438          10 :                 dpobj->start_ce = Z_OBJCE_P(start);
    4439             : 
    4440             :                 /* interval */
    4441          10 :                 dpobj->interval = timelib_rel_time_clone(intobj->diff);
    4442             : 
    4443             :                 /* end date */
    4444          10 :                 if (end) {
    4445           4 :                         dateobj = (php_date_obj *) zend_object_store_get_object(end TSRMLS_CC);
    4446           4 :                         clone = timelib_time_clone(dateobj->time);
    4447           4 :                         dpobj->end = clone;
    4448             :                 }
    4449             :         }
    4450             : 
    4451             :         /* options */
    4452          13 :         dpobj->include_start_date = !(options & PHP_DATE_PERIOD_EXCLUDE_START_DATE);
    4453             : 
    4454             :         /* recurrrences */
    4455          13 :         dpobj->recurrences = recurrences + dpobj->include_start_date;
    4456             : 
    4457          13 :         dpobj->initialized = 1;
    4458             : 
    4459          13 :         zend_restore_error_handling(&error_handling TSRMLS_CC);
    4460             : }
    4461             : /* }}} */
    4462             : 
    4463        3480 : static int check_id_allowed(char *id, long what)
    4464             : {
    4465        3480 :         if (what & PHP_DATE_TIMEZONE_GROUP_AFRICA     && strncasecmp(id, "Africa/",      7) == 0) return 1;
    4466        3264 :         if (what & PHP_DATE_TIMEZONE_GROUP_AMERICA    && strncasecmp(id, "America/",     8) == 0) return 1;
    4467        2444 :         if (what & PHP_DATE_TIMEZONE_GROUP_ANTARCTICA && strncasecmp(id, "Antarctica/", 11) == 0) return 1;
    4468        2396 :         if (what & PHP_DATE_TIMEZONE_GROUP_ARCTIC     && strncasecmp(id, "Arctic/",      7) == 0) return 1;
    4469        2392 :         if (what & PHP_DATE_TIMEZONE_GROUP_ASIA       && strncasecmp(id, "Asia/",        5) == 0) return 1;
    4470        2028 :         if (what & PHP_DATE_TIMEZONE_GROUP_ATLANTIC   && strncasecmp(id, "Atlantic/",    9) == 0) return 1;
    4471        1980 :         if (what & PHP_DATE_TIMEZONE_GROUP_AUSTRALIA  && strncasecmp(id, "Australia/",  10) == 0) return 1;
    4472        1888 :         if (what & PHP_DATE_TIMEZONE_GROUP_EUROPE     && strncasecmp(id, "Europe/",      7) == 0) return 1;
    4473        1593 :         if (what & PHP_DATE_TIMEZONE_GROUP_INDIAN     && strncasecmp(id, "Indian/",      7) == 0) return 1;
    4474        1549 :         if (what & PHP_DATE_TIMEZONE_GROUP_PACIFIC    && strncasecmp(id, "Pacific/",     8) == 0) return 1;
    4475        1381 :         if (what & PHP_DATE_TIMEZONE_GROUP_UTC        && strncasecmp(id, "UTC",          3) == 0) return 1;
    4476        1376 :         return 0;
    4477             : }
    4478             : 
    4479             : /* {{{ proto array timezone_identifiers_list([long what[, string country]])
    4480             :    Returns numerically index array with all timezone identifiers.
    4481             : */
    4482           8 : PHP_FUNCTION(timezone_identifiers_list)
    4483             : {
    4484             :         const timelib_tzdb             *tzdb;
    4485             :         const timelib_tzdb_index_entry *table;
    4486             :         int                             i, item_count;
    4487           8 :         long                            what = PHP_DATE_TIMEZONE_GROUP_ALL;
    4488           8 :         char                           *option = NULL;
    4489           8 :         int                             option_len = 0;
    4490             : 
    4491           8 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ls", &what, &option, &option_len) == FAILURE) {
    4492           0 :                 RETURN_FALSE;
    4493             :         }
    4494             : 
    4495             :         /* Extra validation */
    4496           8 :         if (what == PHP_DATE_TIMEZONE_PER_COUNTRY && option_len != 2) {
    4497           1 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "A two-letter ISO 3166-1 compatible country code is expected");
    4498           1 :                 RETURN_FALSE;
    4499             :         }
    4500             : 
    4501           7 :         tzdb = DATE_TIMEZONEDB;
    4502           7 :         item_count = tzdb->index_size;
    4503           7 :         table = tzdb->index;
    4504             :         
    4505           7 :         array_init(return_value);
    4506             : 
    4507        4067 :         for (i = 0; i < item_count; ++i) {
    4508        4060 :                 if (what == PHP_DATE_TIMEZONE_PER_COUNTRY) {
    4509           0 :                         if (tzdb->data[table[i].pos + 5] == option[0] && tzdb->data[table[i].pos + 6] == option[1]) {
    4510           0 :                                 add_next_index_string(return_value, table[i].id, 1);
    4511             :                         }
    4512        4060 :                 } else if (what == PHP_DATE_TIMEZONE_GROUP_ALL_W_BC || (check_id_allowed(table[i].id, what) && (tzdb->data[table[i].pos + 4] == '\1'))) {
    4513        2451 :                         add_next_index_string(return_value, table[i].id, 1);
    4514             :                 }
    4515             :         };
    4516             : }
    4517             : /* }}} */
    4518             : 
    4519             : /* {{{ proto array timezone_version_get()
    4520             :    Returns the Olson database version number.
    4521             : */
    4522           0 : PHP_FUNCTION(timezone_version_get)
    4523             : {
    4524             :         const timelib_tzdb *tzdb;
    4525             : 
    4526           0 :         tzdb = DATE_TIMEZONEDB;
    4527           0 :         RETURN_STRING(tzdb->version, 1);
    4528             : }
    4529             : /* }}} */
    4530             : 
    4531             : /* {{{ proto array timezone_abbreviations_list()
    4532             :    Returns associative array containing dst, offset and the timezone name
    4533             : */
    4534           4 : PHP_FUNCTION(timezone_abbreviations_list)
    4535             : {
    4536             :         const timelib_tz_lookup_table *table, *entry;
    4537             :         zval                          *element, **abbr_array_pp, *abbr_array;
    4538             :         
    4539           4 :         table = timelib_timezone_abbreviations_list();
    4540           4 :         array_init(return_value);
    4541           4 :         entry = table;
    4542             : 
    4543             :         do {
    4544        7920 :                 MAKE_STD_ZVAL(element);
    4545        7920 :                 array_init(element);
    4546        7920 :                 add_assoc_bool(element, "dst", entry->type);
    4547        7920 :                 add_assoc_long(element, "offset", entry->gmtoffset);
    4548        7920 :                 if (entry->full_tz_name) {
    4549        7820 :                         add_assoc_string(element, "timezone_id", entry->full_tz_name, 1);
    4550             :                 } else {
    4551         100 :                         add_assoc_null(element, "timezone_id");
    4552             :                 }
    4553             : 
    4554        7920 :                 if (zend_hash_find(HASH_OF(return_value), entry->name, strlen(entry->name) + 1, (void **) &abbr_array_pp) == FAILURE) {
    4555        1492 :                         MAKE_STD_ZVAL(abbr_array);
    4556        1492 :                         array_init(abbr_array);
    4557        1492 :                         add_assoc_zval(return_value, entry->name, abbr_array);
    4558             :                 } else {
    4559        6428 :                         abbr_array = *abbr_array_pp;
    4560             :                 }
    4561        7920 :                 add_next_index_zval(abbr_array, element);
    4562        7920 :                 entry++;
    4563        7920 :         } while (entry->name);
    4564           4 : }
    4565             : /* }}} */
    4566             : 
    4567             : /* {{{ proto bool date_default_timezone_set(string timezone_identifier)
    4568             :    Sets the default timezone used by all date/time functions in a script */
    4569         686 : PHP_FUNCTION(date_default_timezone_set)
    4570             : {
    4571             :         char *zone;
    4572             :         int   zone_len;
    4573             : 
    4574         686 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &zone, &zone_len) == FAILURE) {
    4575           4 :                 RETURN_FALSE;
    4576             :         }
    4577         682 :         if (!timelib_timezone_id_is_valid(zone, DATE_TIMEZONEDB)) {
    4578          25 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Timezone ID '%s' is invalid", zone);
    4579          25 :                 RETURN_FALSE;
    4580             :         }
    4581         657 :         if (DATEG(timezone)) {
    4582         123 :                 efree(DATEG(timezone));
    4583         123 :                 DATEG(timezone) = NULL;
    4584             :         }
    4585         657 :         DATEG(timezone) = estrndup(zone, zone_len);
    4586         657 :         RETURN_TRUE;
    4587             : }
    4588             : /* }}} */
    4589             : 
    4590             : /* {{{ proto string date_default_timezone_get()
    4591             :    Gets the default timezone used by all date/time functions in a script */
    4592          12 : PHP_FUNCTION(date_default_timezone_get)
    4593             : {
    4594             :         timelib_tzinfo *default_tz;
    4595             : 
    4596          12 :         default_tz = get_timezone_info(TSRMLS_C);
    4597          12 :         RETVAL_STRING(default_tz->name, 1);
    4598          12 : }
    4599             : /* }}} */
    4600             : 
    4601             : /* {{{ php_do_date_sunrise_sunset
    4602             :  *  Common for date_sunrise() and date_sunset() functions
    4603             :  */
    4604         964 : static void php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAMETERS, int calc_sunset)
    4605             : {
    4606         964 :         double latitude = 0.0, longitude = 0.0, zenith = 0.0, gmt_offset = 0, altitude;
    4607             :         double h_rise, h_set, N;
    4608             :         timelib_sll rise, set, transit;
    4609         964 :         long time, retformat = 0;
    4610             :         int             rs;
    4611             :         timelib_time   *t;
    4612             :         timelib_tzinfo *tzi;
    4613             :         char           *retstr;
    4614             :         
    4615         964 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|ldddd", &time, &retformat, &latitude, &longitude, &zenith, &gmt_offset) == FAILURE) {
    4616         390 :                 RETURN_FALSE;
    4617             :         }
    4618             :         
    4619         574 :         switch (ZEND_NUM_ARGS()) {
    4620             :                 case 1:
    4621           0 :                         retformat = SUNFUNCS_RET_STRING;
    4622             :                 case 2:
    4623           0 :                         latitude = INI_FLT("date.default_latitude");
    4624             :                 case 3:
    4625           0 :                         longitude = INI_FLT("date.default_longitude");
    4626             :                 case 4:
    4627          48 :                         if (calc_sunset) {
    4628          24 :                                 zenith = INI_FLT("date.sunset_zenith");
    4629             :                         } else {
    4630          24 :                                 zenith = INI_FLT("date.sunrise_zenith");
    4631             :                         }
    4632             :                 case 5:
    4633             :                 case 6:
    4634         574 :                         break;
    4635             :                 default:
    4636           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid format");
    4637           0 :                         RETURN_FALSE;
    4638             :                         break;
    4639             :         }
    4640        1142 :         if (retformat != SUNFUNCS_RET_TIMESTAMP &&
    4641         390 :                 retformat != SUNFUNCS_RET_STRING &&
    4642         178 :                 retformat != SUNFUNCS_RET_DOUBLE)
    4643             :         {
    4644           8 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong return format given, pick one of SUNFUNCS_RET_TIMESTAMP, SUNFUNCS_RET_STRING or SUNFUNCS_RET_DOUBLE");
    4645           8 :                 RETURN_FALSE;
    4646             :         }
    4647         566 :         altitude = 90 - zenith;
    4648             : 
    4649             :         /* Initialize time struct */
    4650         566 :         t = timelib_time_ctor();
    4651         566 :         tzi = get_timezone_info(TSRMLS_C);
    4652         566 :         t->tz_info = tzi;
    4653         566 :         t->zone_type = TIMELIB_ZONETYPE_ID;
    4654             : 
    4655         566 :         if (ZEND_NUM_ARGS() <= 5) {
    4656          48 :                 gmt_offset = timelib_get_current_offset(t) / 3600;
    4657             :         }
    4658             : 
    4659         566 :         timelib_unixtime2local(t, time);
    4660         566 :         rs = timelib_astro_rise_set_altitude(t, longitude, latitude, altitude, 1, &h_rise, &h_set, &rise, &set, &transit);
    4661         566 :         timelib_time_dtor(t);
    4662             :         
    4663         566 :         if (rs != 0) {
    4664         120 :                 RETURN_FALSE;
    4665             :         }
    4666             : 
    4667         446 :         if (retformat == SUNFUNCS_RET_TIMESTAMP) {
    4668         144 :                 RETURN_LONG(calc_sunset ? set : rise);
    4669             :         }
    4670         302 :         N = (calc_sunset ? h_set : h_rise) + gmt_offset;
    4671             : 
    4672         302 :         if (N > 24 || N < 0) {
    4673          28 :                 N -= floor(N / 24) * 24;
    4674             :         }
    4675             : 
    4676         302 :         switch (retformat) {
    4677             :                 case SUNFUNCS_RET_STRING:
    4678         172 :                         spprintf(&retstr, 0, "%02d:%02d", (int) N, (int) (60 * (N - (int) N)));
    4679         172 :                         RETURN_STRINGL(retstr, 5, 0);
    4680             :                         break;
    4681             :                 case SUNFUNCS_RET_DOUBLE:
    4682         130 :                         RETURN_DOUBLE(N);
    4683             :                         break;
    4684             :         }
    4685             : }
    4686             : /* }}} */
    4687             : 
    4688             : /* {{{ proto mixed date_sunrise(mixed time [, int format [, float latitude [, float longitude [, float zenith [, float gmt_offset]]]]])
    4689             :    Returns time of sunrise for a given day and location */
    4690         481 : PHP_FUNCTION(date_sunrise)
    4691             : {
    4692         481 :         php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    4693         481 : }
    4694             : /* }}} */
    4695             : 
    4696             : /* {{{ proto mixed date_sunset(mixed time [, int format [, float latitude [, float longitude [, float zenith [, float gmt_offset]]]]])
    4697             :    Returns time of sunset for a given day and location */
    4698         483 : PHP_FUNCTION(date_sunset)
    4699             : {
    4700         483 :         php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    4701         483 : }
    4702             : /* }}} */
    4703             : 
    4704             : /* {{{ proto array date_sun_info(long time, float latitude, float longitude)
    4705             :    Returns an array with information about sun set/rise and twilight begin/end */
    4706          77 : PHP_FUNCTION(date_sun_info)
    4707             : {
    4708             :         long            time;
    4709             :         double          latitude, longitude;
    4710             :         timelib_time   *t, *t2;
    4711             :         timelib_tzinfo *tzi;
    4712             :         int             rs;
    4713             :         timelib_sll     rise, set, transit;
    4714             :         int             dummy;
    4715             :         double          ddummy;
    4716             :         
    4717          77 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ldd", &time, &latitude, &longitude) == FAILURE) {
    4718          24 :                 RETURN_FALSE;
    4719             :         }
    4720             :         /* Initialize time struct */
    4721          53 :         t = timelib_time_ctor();
    4722          53 :         tzi = get_timezone_info(TSRMLS_C);
    4723          53 :         t->tz_info = tzi;
    4724          53 :         t->zone_type = TIMELIB_ZONETYPE_ID;
    4725          53 :         timelib_unixtime2local(t, time);
    4726             : 
    4727             :         /* Setup */
    4728          53 :         t2 = timelib_time_ctor();
    4729          53 :         array_init(return_value);
    4730             :         
    4731             :         /* Get sun up/down and transit */
    4732          53 :         rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -35.0/60, 1, &ddummy, &ddummy, &rise, &set, &transit);
    4733          53 :         switch (rs) {
    4734             :                 case -1: /* always below */
    4735           0 :                         add_assoc_bool(return_value, "sunrise", 0);
    4736           0 :                         add_assoc_bool(return_value, "sunset", 0);
    4737           0 :                         break;
    4738             :                 case 1: /* always above */
    4739           1 :                         add_assoc_bool(return_value, "sunrise", 1);
    4740           1 :                         add_assoc_bool(return_value, "sunset", 1);
    4741           1 :                         break;
    4742             :                 default:
    4743          52 :                         t2->sse = rise;
    4744          52 :                         add_assoc_long(return_value, "sunrise", timelib_date_to_int(t2, &dummy));
    4745          52 :                         t2->sse = set;
    4746          52 :                         add_assoc_long(return_value, "sunset", timelib_date_to_int(t2, &dummy));
    4747             :         }
    4748          53 :         t2->sse = transit;
    4749          53 :         add_assoc_long(return_value, "transit", timelib_date_to_int(t2, &dummy));
    4750             : 
    4751             :         /* Get civil twilight */
    4752          53 :         rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -6.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
    4753          53 :         switch (rs) {
    4754             :                 case -1: /* always below */
    4755           0 :                         add_assoc_bool(return_value, "civil_twilight_begin", 0);
    4756           0 :                         add_assoc_bool(return_value, "civil_twilight_end", 0);
    4757           0 :                         break;
    4758             :                 case 1: /* always above */
    4759           1 :                         add_assoc_bool(return_value, "civil_twilight_begin", 1);
    4760           1 :                         add_assoc_bool(return_value, "civil_twilight_end", 1);
    4761           1 :                         break;
    4762             :                 default:
    4763          52 :                         t2->sse = rise;
    4764          52 :                         add_assoc_long(return_value, "civil_twilight_begin", timelib_date_to_int(t2, &dummy));
    4765          52 :                         t2->sse = set;
    4766          52 :                         add_assoc_long(return_value, "civil_twilight_end", timelib_date_to_int(t2, &dummy));
    4767             :         }
    4768             : 
    4769             :         /* Get nautical twilight */
    4770          53 :         rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -12.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
    4771          53 :         switch (rs) {
    4772             :                 case -1: /* always below */
    4773           0 :                         add_assoc_bool(return_value, "nautical_twilight_begin", 0);
    4774           0 :                         add_assoc_bool(return_value, "nautical_twilight_end", 0);
    4775           0 :                         break;
    4776             :                 case 1: /* always above */
    4777           0 :                         add_assoc_bool(return_value, "nautical_twilight_begin", 1);
    4778           0 :                         add_assoc_bool(return_value, "nautical_twilight_end", 1);
    4779           0 :                         break;
    4780             :                 default:
    4781          53 :                         t2->sse = rise;
    4782          53 :                         add_assoc_long(return_value, "nautical_twilight_begin", timelib_date_to_int(t2, &dummy));
    4783          53 :                         t2->sse = set;
    4784          53 :                         add_assoc_long(return_value, "nautical_twilight_end", timelib_date_to_int(t2, &dummy));
    4785             :         }
    4786             : 
    4787             :         /* Get astronomical twilight */
    4788          53 :         rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -18.0, 0, &ddummy, &ddummy, &rise, &set, &transit);
    4789          53 :         switch (rs) {
    4790             :                 case -1: /* always below */
    4791           0 :                         add_assoc_bool(return_value, "astronomical_twilight_begin", 0);
    4792           0 :                         add_assoc_bool(return_value, "astronomical_twilight_end", 0);
    4793           0 :                         break;
    4794             :                 case 1: /* always above */
    4795           0 :                         add_assoc_bool(return_value, "astronomical_twilight_begin", 1);
    4796           0 :                         add_assoc_bool(return_value, "astronomical_twilight_end", 1);
    4797           0 :                         break;
    4798             :                 default:
    4799          53 :                         t2->sse = rise;
    4800          53 :                         add_assoc_long(return_value, "astronomical_twilight_begin", timelib_date_to_int(t2, &dummy));
    4801          53 :                         t2->sse = set;
    4802          53 :                         add_assoc_long(return_value, "astronomical_twilight_end", timelib_date_to_int(t2, &dummy));
    4803             :         }
    4804          53 :         timelib_time_dtor(t);
    4805          53 :         timelib_time_dtor(t2);
    4806             : }
    4807             : /* }}} */
    4808             : 
    4809           0 : static HashTable *date_object_get_gc_period(zval *object, zval ***table, int *n TSRMLS_DC)
    4810             : {
    4811           0 :         *table = NULL;
    4812           0 :         *n = 0;
    4813           0 :         return zend_std_get_properties(object TSRMLS_CC);
    4814             : }
    4815             : 
    4816           9 : static HashTable *date_object_get_properties_period(zval *object TSRMLS_DC)
    4817             : {
    4818             :         HashTable               *props;
    4819             :         zval                    *zv;
    4820             :         php_period_obj  *period_obj;
    4821             : 
    4822           9 :         period_obj = zend_object_store_get_object(object TSRMLS_CC);
    4823             : 
    4824           9 :         props = zend_std_get_properties(object TSRMLS_CC);
    4825             : 
    4826           9 :         if (!period_obj->start || GC_G(gc_active)) {
    4827           4 :                 return props;
    4828             :         }
    4829             : 
    4830           5 :         MAKE_STD_ZVAL(zv);
    4831           5 :         if (period_obj->start) {
    4832             :                 php_date_obj *date_obj;
    4833           5 :                 object_init_ex(zv, date_ce_date);
    4834           5 :                 date_obj = zend_object_store_get_object(zv TSRMLS_CC);
    4835           5 :                 date_obj->time = timelib_time_clone(period_obj->start);
    4836             :         } else {
    4837           0 :                 ZVAL_NULL(zv);
    4838             :         }
    4839           5 :         zend_hash_update(props, "start", sizeof("start"), &zv, sizeof(zv), NULL);
    4840             : 
    4841           5 :         MAKE_STD_ZVAL(zv);
    4842           5 :         if (period_obj->current) {
    4843             :                 php_date_obj *date_obj;
    4844           3 :                 object_init_ex(zv, date_ce_date);
    4845           3 :                 date_obj = zend_object_store_get_object(zv TSRMLS_CC);
    4846           3 :                 date_obj->time = timelib_time_clone(period_obj->current);
    4847             :         } else {
    4848           2 :                 ZVAL_NULL(zv);
    4849             :         }
    4850           5 :         zend_hash_update(props, "current", sizeof("current"), &zv, sizeof(zv), NULL);
    4851             : 
    4852           5 :         MAKE_STD_ZVAL(zv);
    4853           5 :         if (period_obj->end) {
    4854             :                 php_date_obj *date_obj;
    4855           0 :                 object_init_ex(zv, date_ce_date);
    4856           0 :                 date_obj = zend_object_store_get_object(zv TSRMLS_CC);
    4857           0 :                 date_obj->time = timelib_time_clone(period_obj->end);
    4858             :         } else {
    4859           5 :                 ZVAL_NULL(zv);
    4860             :         }
    4861           5 :         zend_hash_update(props, "end", sizeof("end"), &zv, sizeof(zv), NULL);
    4862             : 
    4863           5 :         MAKE_STD_ZVAL(zv);
    4864           5 :         if (period_obj->interval) {
    4865             :                 php_interval_obj *interval_obj;
    4866           5 :                 object_init_ex(zv, date_ce_interval);
    4867           5 :                 interval_obj = zend_object_store_get_object(zv TSRMLS_CC);
    4868           5 :                 interval_obj->diff = timelib_rel_time_clone(period_obj->interval);
    4869           5 :                 interval_obj->initialized = 1;
    4870             :         } else {
    4871           0 :                 ZVAL_NULL(zv);
    4872             :         }
    4873           5 :         zend_hash_update(props, "interval", sizeof("interval"), &zv, sizeof(zv), NULL);
    4874             :         
    4875             :         /* converted to larger type (int->long); must check when unserializing */
    4876           5 :         MAKE_STD_ZVAL(zv);
    4877           5 :         ZVAL_LONG(zv, (long) period_obj->recurrences);
    4878           5 :         zend_hash_update(props, "recurrences", sizeof("recurrences"), &zv, sizeof(zv), NULL);
    4879             : 
    4880           5 :         MAKE_STD_ZVAL(zv);
    4881           5 :         ZVAL_BOOL(zv, period_obj->include_start_date);
    4882           5 :         zend_hash_update(props, "include_start_date", sizeof("include_start_date"), &zv, sizeof(zv), NULL);
    4883             : 
    4884           5 :         return props;
    4885             : }
    4886             : 
    4887           2 : static int php_date_period_initialize_from_hash(php_period_obj *period_obj, HashTable *myht TSRMLS_DC)
    4888             : {
    4889             :         zval **ht_entry;
    4890             : 
    4891             :         /* this function does no rollback on error */
    4892             : 
    4893           2 :         if (zend_hash_find(myht, "start", sizeof("start"), (void**) &ht_entry) == SUCCESS) {
    4894           2 :                 if (Z_TYPE_PP(ht_entry) == IS_OBJECT && Z_OBJCE_PP(ht_entry) == date_ce_date) {
    4895             :                         php_date_obj *date_obj;
    4896           1 :                         date_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC);
    4897           1 :                         period_obj->start = timelib_time_clone(date_obj->time);
    4898           1 :                         period_obj->start_ce = Z_OBJCE_PP(ht_entry);
    4899           0 :                 } else if (Z_TYPE_PP(ht_entry) != IS_NULL) {
    4900           0 :                         return 0;
    4901             :                 }
    4902             :         } else {
    4903           1 :                 return 0;
    4904             :         }
    4905             : 
    4906           1 :         if (zend_hash_find(myht, "end", sizeof("end"), (void**) &ht_entry) == SUCCESS) {
    4907           1 :                 if (Z_TYPE_PP(ht_entry) == IS_OBJECT && Z_OBJCE_PP(ht_entry) == date_ce_date) {
    4908             :                         php_date_obj *date_obj;
    4909           0 :                         date_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC);
    4910           0 :                         period_obj->end = timelib_time_clone(date_obj->time);
    4911           1 :                 } else if (Z_TYPE_PP(ht_entry) != IS_NULL) {
    4912           0 :                         return 0;
    4913             :                 }
    4914             :         } else {
    4915           0 :                 return 0;
    4916             :         }
    4917             : 
    4918           1 :         if (zend_hash_find(myht, "current", sizeof("current"), (void**) &ht_entry) == SUCCESS) {
    4919           2 :                 if (Z_TYPE_PP(ht_entry) == IS_OBJECT && Z_OBJCE_PP(ht_entry) == date_ce_date) {
    4920             :                         php_date_obj *date_obj;
    4921           1 :                         date_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC);
    4922           1 :                         period_obj->current = timelib_time_clone(date_obj->time);
    4923           0 :                 } else if (Z_TYPE_PP(ht_entry) != IS_NULL)  {
    4924           0 :                         return 0;
    4925             :                 }
    4926             :         } else {
    4927           0 :                 return 0;
    4928             :         }
    4929             : 
    4930           1 :         if (zend_hash_find(myht, "interval", sizeof("interval"), (void**) &ht_entry) == SUCCESS) {
    4931           2 :                 if (Z_TYPE_PP(ht_entry) == IS_OBJECT && Z_OBJCE_PP(ht_entry) == date_ce_interval) {
    4932             :                         php_interval_obj *interval_obj;
    4933           1 :                         interval_obj = zend_object_store_get_object(*ht_entry TSRMLS_CC);
    4934           1 :                         period_obj->interval = timelib_rel_time_clone(interval_obj->diff);
    4935             :                 } else { /* interval is required */
    4936           0 :                         return 0;
    4937             :                 }
    4938             :         } else {
    4939           0 :                 return 0;
    4940             :         }
    4941             : 
    4942           5 :         if (zend_hash_find(myht, "recurrences", sizeof("recurrences"), (void**) &ht_entry) == SUCCESS &&
    4943           3 :                         Z_TYPE_PP(ht_entry) == IS_LONG && Z_LVAL_PP(ht_entry) >= 0 && Z_LVAL_PP(ht_entry) <= INT_MAX) {
    4944           1 :                 period_obj->recurrences = Z_LVAL_PP(ht_entry);
    4945             :         } else {
    4946           0 :                 return 0;
    4947             :         }
    4948             : 
    4949           3 :         if (zend_hash_find(myht, "include_start_date", sizeof("include_start_date"), (void**) &ht_entry) == SUCCESS &&
    4950           1 :                         Z_TYPE_PP(ht_entry) == IS_BOOL) {
    4951           1 :                 period_obj->include_start_date = Z_BVAL_PP(ht_entry);
    4952             :         } else {
    4953           0 :                 return 0;
    4954             :         }
    4955             : 
    4956           1 :         period_obj->initialized = 1;
    4957             :         
    4958           1 :         return 1;
    4959             : }
    4960             : 
    4961             : /* {{{ proto DatePeriod::__set_state()
    4962             : */
    4963           0 : PHP_METHOD(DatePeriod, __set_state)
    4964             : {
    4965             :         php_period_obj   *period_obj;
    4966             :         zval             *array;
    4967             :         HashTable        *myht;
    4968             : 
    4969           0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
    4970           0 :                 RETURN_FALSE;
    4971             :         }
    4972             : 
    4973           0 :         myht = Z_ARRVAL_P(array);
    4974             :         
    4975           0 :         object_init_ex(return_value, date_ce_period);
    4976           0 :         period_obj = zend_object_store_get_object(return_value TSRMLS_CC);
    4977           0 :         if (!php_date_period_initialize_from_hash(period_obj, myht TSRMLS_CC)) {
    4978           0 :                 php_error(E_ERROR, "Invalid serialization data for DatePeriod object");
    4979             :         }
    4980             : }
    4981             : /* }}} */
    4982             : 
    4983             : /* {{{ proto DatePeriod::__wakeup()
    4984             : */
    4985           2 : PHP_METHOD(DatePeriod, __wakeup)
    4986             : {
    4987           2 :         zval             *object = getThis();
    4988             :         php_period_obj   *period_obj;
    4989             :         HashTable        *myht;
    4990             : 
    4991           2 :         period_obj = zend_object_store_get_object(object TSRMLS_CC);
    4992             : 
    4993           2 :         myht = Z_OBJPROP_P(object);
    4994             : 
    4995           2 :         if (!php_date_period_initialize_from_hash(period_obj, myht TSRMLS_CC)) {
    4996           1 :                 php_error(E_ERROR, "Invalid serialization data for DatePeriod object");
    4997             :         }
    4998           1 : }
    4999             : /* }}} */
    5000             : 
    5001             : /* {{{ date_period_read_property */
    5002           0 : static zval *date_period_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
    5003             : {
    5004             :         zval *zv;
    5005           0 :         if (type != BP_VAR_IS && type != BP_VAR_R) {
    5006           0 :                 php_error_docref(NULL TSRMLS_CC, E_ERROR, "Retrieval of DatePeriod properties for modification is unsupported");
    5007             :         }
    5008             : 
    5009           0 :         Z_OBJPROP_P(object); /* build properties hash table */
    5010             : 
    5011           0 :         zv = std_object_handlers.read_property(object, member, type, key TSRMLS_CC);
    5012           0 :         if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJ_HANDLER_P(zv, clone_obj)) {
    5013             :                 /* defensive copy */
    5014           0 :                 zend_object_value zov = Z_OBJ_HANDLER_P(zv, clone_obj)(zv TSRMLS_CC);
    5015           0 :                 MAKE_STD_ZVAL(zv);
    5016           0 :                 Z_TYPE_P(zv) = IS_OBJECT;
    5017           0 :                 Z_OBJVAL_P(zv) = zov;
    5018             :         }
    5019             : 
    5020           0 :         return zv;
    5021             : }
    5022             : /* }}} */
    5023             : 
    5024             : /* {{{ date_period_write_property */
    5025           0 : static void date_period_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
    5026             : {
    5027           0 :         php_error_docref(NULL TSRMLS_CC, E_ERROR, "Writing to DatePeriod properties is unsupported");
    5028           0 : }
    5029             : /* }}} */
    5030             : 
    5031             : 
    5032             : /*
    5033             :  * Local variables:
    5034             :  * tab-width: 4
    5035             :  * c-basic-offset: 4
    5036             :  * End:
    5037             :  * vim600: fdm=marker
    5038             :  * vim: noet sw=4 ts=4
    5039             :  */

Generated by: LCOV version 1.10

Generated at Wed, 16 Apr 2014 12:47:46 +0000 (2 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.