mirror of
https://github.com/php/php-src.git
synced 2024-12-13 20:05:26 +08:00
1104 lines
31 KiB
C
1104 lines
31 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| PHP Version 5 |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 1997-2004 The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.0 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_0.txt. |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Authors: Andi Gutmans <andi@zend.com> |
|
|
| Zeev Suraski <zeev@zend.com> |
|
|
| Rasmus Lerdorf <rasmus@php.net> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
/* $Id$ */
|
|
|
|
#include "php.h"
|
|
#include "zend_operators.h"
|
|
#include "datetime.h"
|
|
#include "php_globals.h"
|
|
|
|
#include <time.h>
|
|
#ifdef HAVE_SYS_TIME_H
|
|
# include <sys/time.h>
|
|
#endif
|
|
#include <stdio.h>
|
|
|
|
#include "php_parsedate.h"
|
|
|
|
char *mon_full_names[] = {
|
|
"January", "February", "March", "April",
|
|
"May", "June", "July", "August",
|
|
"September", "October", "November", "December"
|
|
};
|
|
|
|
char *mon_short_names[] = {
|
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
|
};
|
|
|
|
char *day_full_names[] = {
|
|
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
|
|
};
|
|
|
|
char *day_short_names[] = {
|
|
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
|
};
|
|
|
|
#if !defined(HAVE_TM_ZONE) && !defined(_TIMEZONE) && !defined(HAVE_DECLARED_TIMEZONE)
|
|
#if defined(NETWARE) && defined(NEW_LIBC)
|
|
#define timezone _timezone /* timezone is called '_timezone' in new version of LibC */
|
|
#endif
|
|
extern time_t timezone;
|
|
extern int daylight;
|
|
#endif
|
|
|
|
static int phpday_tab[2][12] = {
|
|
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
|
|
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
|
};
|
|
|
|
#define isleap(year) ((((year) % 4) == 0 && ((year) % 100) != 0) || ((year) % 400)==0)
|
|
#define YEAR_BASE 1900
|
|
|
|
/* {{{ proto int time(void)
|
|
Return current UNIX timestamp */
|
|
PHP_FUNCTION(time)
|
|
{
|
|
RETURN_LONG((long)time(NULL));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ php_mktime
|
|
*/
|
|
void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gm)
|
|
{
|
|
pval **arguments[7];
|
|
struct tm *ta, tmbuf;
|
|
time_t t, seconds;
|
|
int i, gmadjust, arg_count = ZEND_NUM_ARGS();
|
|
int is_dst = -1, chgsecs = 0;
|
|
long val;
|
|
|
|
if (arg_count > 7 || zend_get_parameters_array_ex(arg_count, arguments) == FAILURE) {
|
|
WRONG_PARAM_COUNT;
|
|
}
|
|
/* convert supplied arguments to longs */
|
|
for (i = 0; i < arg_count; i++) {
|
|
convert_to_long_ex(arguments[i]);
|
|
}
|
|
t = time(NULL);
|
|
#ifdef HAVE_TZSET
|
|
tzset();
|
|
#endif
|
|
/*
|
|
** Set default time parameters with local time values,
|
|
** EVEN when some GMT time parameters are specified!
|
|
** This may give strange result, with PHP gmmktime(0, 0, 0),
|
|
** which is assumed to return GMT midnight time
|
|
** for today (in localtime), so that the result time may be
|
|
** AFTER or BEFORE the current time.
|
|
** May be we should initialize tn using gmtime(), so that
|
|
** default parameters for PHP gmmktime would be the current
|
|
** GMT time values...
|
|
*/
|
|
ta = php_localtime_r(&t, &tmbuf);
|
|
|
|
/* Let DST be unknown. mktime() should compute the right value
|
|
** and behave correctly. Unless the user overrides this.
|
|
*/
|
|
ta->tm_isdst = -1;
|
|
|
|
/*
|
|
** Now change date values with supplied parameters.
|
|
*/
|
|
switch(arg_count) {
|
|
case 7: /* daylight saving time flag */
|
|
#ifdef PHP_WIN32
|
|
if (daylight > 0) {
|
|
ta->tm_isdst = is_dst = Z_LVAL_PP(arguments[6]);
|
|
} else {
|
|
ta->tm_isdst = is_dst = 0;
|
|
}
|
|
#else
|
|
ta->tm_isdst = is_dst = Z_LVAL_PP(arguments[6]);
|
|
#endif
|
|
/* fall-through */
|
|
case 6: /* year */
|
|
/* special case:
|
|
a zero in year, month and day is considered illegal
|
|
as it would be interpreted as 30.11.1999 otherwise
|
|
*/
|
|
if ( ( Z_LVAL_PP(arguments[5])==0)
|
|
&&(Z_LVAL_PP(arguments[4])==0)
|
|
&&(Z_LVAL_PP(arguments[3])==0)
|
|
) {
|
|
RETURN_LONG(-1);
|
|
}
|
|
|
|
/*
|
|
** Accept parameter in range 0..1000 interpreted as 1900..2900
|
|
** (if 100 is given, it means year 2000)
|
|
** or in range 1001..9999 interpreted as is (this will store
|
|
** negative tm_year for years in range 1001..1899)
|
|
** This function is then Y2K ready, and accepts a wide range of
|
|
** dates including the whole gregorian calendar.
|
|
** But it cannot represent ancestral dates prior to year 1001.
|
|
** Additionally, input parameters of 0..70 are mapped to 100..170
|
|
*/
|
|
if (Z_LVAL_PP(arguments[5]) < 70)
|
|
ta->tm_year = Z_LVAL_PP(arguments[5]) + 100;
|
|
else
|
|
ta->tm_year = Z_LVAL_PP(arguments[5])
|
|
- ((Z_LVAL_PP(arguments[5]) > 1000) ? 1900 : 0);
|
|
/* fall-through */
|
|
case 5: /* day in month (1-based) */
|
|
val = (*arguments[4])->value.lval;
|
|
if (val < 1) {
|
|
chgsecs += (1-val) * 60*60*24;
|
|
val = 1;
|
|
}
|
|
ta->tm_mday = val;
|
|
/* fall-through */
|
|
case 4: /* month (zero-based) */
|
|
val = (*arguments[3])->value.lval - 1;
|
|
while (val < 0) {
|
|
val += 12; ta->tm_year--;
|
|
}
|
|
ta->tm_mon = val;
|
|
/* fall-through */
|
|
case 3: /* second */
|
|
val = (*arguments[2])->value.lval;
|
|
if (val < 1) {
|
|
chgsecs += (1-val); val = 1;
|
|
}
|
|
ta->tm_sec = val;
|
|
/* fall-through */
|
|
case 2: /* minute */
|
|
val = (*arguments[1])->value.lval;
|
|
if (val < 1) {
|
|
chgsecs += (1-val) * 60; val = 1;
|
|
}
|
|
ta->tm_min = val;
|
|
/* fall-through */
|
|
case 1: /* hour */
|
|
val = (*arguments[0])->value.lval;
|
|
/*
|
|
We avoid midnight and a couple of hours after midnight here to work around
|
|
various OS-level bugs in mktime and specifically daylight savings time issues
|
|
in many mktime implementation.
|
|
See bugs #27533 and #27719 for more info.
|
|
*/
|
|
if (val < 4) {
|
|
chgsecs += (4-val) * 60*60; val = 4;
|
|
}
|
|
ta->tm_hour = val;
|
|
/* fall-through */
|
|
case 0:
|
|
break;
|
|
}
|
|
|
|
t = mktime(ta);
|
|
|
|
#ifdef PHP_WIN32
|
|
if (t - chgsecs < 0) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Windows does not support negative values for this function");
|
|
RETURN_LONG(-1);
|
|
}
|
|
#endif
|
|
|
|
seconds = t - chgsecs;
|
|
|
|
/*
|
|
Here we check to see if the chgsecs fuzz factor we applied caused us to
|
|
move from dst to non-dst or vice-versa. If so we adjust accordingly to
|
|
avoid being off by an hour on the dst changeover date.
|
|
*/
|
|
if (is_dst == -1) {
|
|
struct tm t1, t2;
|
|
t1 = *localtime(&t);
|
|
t2 = *localtime(&seconds);
|
|
|
|
if (t1.tm_isdst != t2.tm_isdst) {
|
|
seconds += (t1.tm_isdst == 1) ? 3600 : -3600;
|
|
ta = localtime(&seconds);
|
|
}
|
|
|
|
/*
|
|
If the user didn't specify whether the timestamp passed in was dst or not
|
|
then we fill it in based on the dst setting at the evaluated timestamp
|
|
at the current TZ
|
|
*/
|
|
is_dst = ta->tm_isdst;
|
|
}
|
|
|
|
if (gm) {
|
|
#if HAVE_TM_GMTOFF
|
|
/*
|
|
** mktime(ta) very nicely just filled ta->tm_gmtoff with
|
|
** the exactly right value for adjustment if we want GMT.
|
|
*/
|
|
gmadjust = ta->tm_gmtoff;
|
|
#else
|
|
/*
|
|
** If correcting for daylight savings time, we set the adjustment to
|
|
** the value of timezone - 3600 seconds.
|
|
*/
|
|
#ifdef __CYGWIN__
|
|
gmadjust = -(is_dst ? _timezone - 3600 : _timezone);
|
|
#else
|
|
gmadjust = -(is_dst ? timezone - 3600 : timezone);
|
|
#endif
|
|
#endif
|
|
seconds += gmadjust;
|
|
}
|
|
|
|
RETURN_LONG(seconds);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int mktime(int hour, int min, int sec, int mon, int day, int year)
|
|
Get UNIX timestamp for a date */
|
|
PHP_FUNCTION(mktime)
|
|
{
|
|
php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int gmmktime(int hour, int min, int sec, int mon, int day, int year)
|
|
Get UNIX timestamp for a GMT date */
|
|
PHP_FUNCTION(gmmktime)
|
|
{
|
|
php_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ php_date
|
|
*/
|
|
static void php_date(INTERNAL_FUNCTION_PARAMETERS, int gm)
|
|
{
|
|
pval **format, **timestamp;
|
|
time_t the_time;
|
|
struct tm *ta, tmbuf;
|
|
int i, size = 0, length, h, beat, fd, wd, yd, wk;
|
|
char tmp_buff[32];
|
|
#if !HAVE_TM_GMTOFF
|
|
long tzone;
|
|
char *tname[2]= {"GMT Standard Time", "BST"};
|
|
#endif
|
|
|
|
switch(ZEND_NUM_ARGS()) {
|
|
case 1:
|
|
if (zend_get_parameters_ex(1, &format) == FAILURE) {
|
|
WRONG_PARAM_COUNT;
|
|
}
|
|
the_time = time(NULL);
|
|
break;
|
|
case 2:
|
|
if (zend_get_parameters_ex(2, &format, ×tamp) == FAILURE) {
|
|
WRONG_PARAM_COUNT;
|
|
}
|
|
convert_to_long_ex(timestamp);
|
|
the_time = Z_LVAL_PP(timestamp);
|
|
#ifdef PHP_WIN32
|
|
if (the_time < 0) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Windows does not support dates prior to midnight (00:00:00), January 1, 1970");
|
|
RETURN_FALSE;
|
|
}
|
|
#endif
|
|
break;
|
|
default:
|
|
WRONG_PARAM_COUNT;
|
|
}
|
|
convert_to_string_ex(format);
|
|
|
|
if (gm) {
|
|
ta = php_gmtime_r(&the_time, &tmbuf);
|
|
#if !HAVE_TM_GMTOFF
|
|
tzone = 0;
|
|
#endif
|
|
} else {
|
|
ta = php_localtime_r(&the_time, &tmbuf);
|
|
#if !HAVE_TM_GMTOFF
|
|
#ifdef __CYGWIN__
|
|
tzone = _timezone;
|
|
#else
|
|
tzone = timezone;
|
|
#endif
|
|
if (tzname[0] != NULL) {
|
|
tname[0] = tzname[0];
|
|
} else {
|
|
tname[0] = "???";
|
|
}
|
|
|
|
if (tzname[1] != NULL) {
|
|
tname[1] = tzname[1];
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (!ta) { /* that really shouldn't happen... */
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unexpected error");
|
|
RETURN_FALSE;
|
|
}
|
|
for (i = 0; i < Z_STRLEN_PP(format); i++) {
|
|
switch (Z_STRVAL_PP(format)[i]) {
|
|
case 'r': /* rfc822 format */
|
|
size += 31;
|
|
break;
|
|
case 'c': /* iso8601 date (Dublin Core Date) */
|
|
size += 25;
|
|
break;
|
|
case 'U': /* seconds since the epoch */
|
|
size += 10;
|
|
break;
|
|
case 'F': /* month, textual, full */
|
|
case 'l': /* day (of the week), textual */
|
|
size += 28;
|
|
break;
|
|
case 'T': /* timezone name */
|
|
#if HAVE_TM_ZONE
|
|
size += strlen(ta->tm_zone);
|
|
#elif HAVE_TZNAME
|
|
if (ta->tm_isdst > 0 ) {
|
|
size += strlen(tname[1]);
|
|
} else {
|
|
size += strlen(tname[0]);
|
|
}
|
|
#endif
|
|
break;
|
|
case 'Z': /* timezone offset in seconds */
|
|
size += 6;
|
|
break;
|
|
case 'O': /* GMT offset in [+-]HHMM format */
|
|
size += 5;
|
|
break;
|
|
case 'Y': /* year, numeric, 4 digits */
|
|
size += 4;
|
|
break;
|
|
case 'M': /* month, textual, 3 letters */
|
|
case 'D': /* day, textual, 3 letters */
|
|
case 'z': /* day of the year, 1 to 366 */
|
|
case 'B': /* Swatch Beat, 3 digits */
|
|
size += 3;
|
|
break;
|
|
case 'y': /* year, numeric, 2 digits */
|
|
case 'm': /* month, numeric */
|
|
case 'n': /* month, numeric, no leading zeroes */
|
|
case 'd': /* day of the month, numeric */
|
|
case 'j': /* day of the month, numeric, no leading zeros */
|
|
case 'H': /* hour, numeric, 24 hour format */
|
|
case 'h': /* hour, numeric, 12 hour format */
|
|
case 'G': /* hour, numeric, 24 hour format, no leading zeroes */
|
|
case 'g': /* hour, numeric, 12 hour format, no leading zeroes */
|
|
case 'i': /* minutes, numeric */
|
|
case 's': /* seconds, numeric */
|
|
case 'A': /* AM/PM */
|
|
case 'a': /* am/pm */
|
|
case 'S': /* standard english suffix for the day of the month (e.g. 3rd, 2nd, etc) */
|
|
case 't': /* days in current month */
|
|
case 'W': /* ISO-8601 week number of year, weeks starting on Monday */
|
|
size += 2;
|
|
break;
|
|
case '\\':
|
|
if (i < Z_STRLEN_PP(format) - 1) {
|
|
i++;
|
|
}
|
|
size ++;
|
|
break;
|
|
case 'L': /* boolean for leap year */
|
|
case 'w': /* day of the week, numeric */
|
|
case 'I': /* DST? */
|
|
default:
|
|
size++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Z_STRVAL_P(return_value) = (char *) emalloc(size + 1);
|
|
Z_STRVAL_P(return_value)[0] = '\0';
|
|
|
|
for (i = 0; i < Z_STRLEN_PP(format); i++) {
|
|
switch (Z_STRVAL_PP(format)[i]) {
|
|
case '\\':
|
|
if (i < Z_STRLEN_PP(format) - 1) {
|
|
char ch[2];
|
|
ch[0]=Z_STRVAL_PP(format)[i + 1];
|
|
ch[1]='\0';
|
|
strcat(Z_STRVAL_P(return_value), ch);
|
|
i++;
|
|
}
|
|
break;
|
|
case 'U': /* seconds since the epoch */
|
|
sprintf(tmp_buff, "%ld", (long)the_time); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'F': /* month, textual, full */
|
|
strcat(Z_STRVAL_P(return_value), mon_full_names[ta->tm_mon]);
|
|
break;
|
|
case 'l': /* day (of the week), textual, full */
|
|
strcat(Z_STRVAL_P(return_value), day_full_names[ta->tm_wday]);
|
|
break;
|
|
case 'Y': /* year, numeric, 4 digits */
|
|
sprintf(tmp_buff, "%d", ta->tm_year + YEAR_BASE); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'M': /* month, textual, 3 letters */
|
|
strcat(Z_STRVAL_P(return_value), mon_short_names[ta->tm_mon]);
|
|
break;
|
|
case 'D': /* day (of the week), textual, 3 letters */
|
|
strcat(Z_STRVAL_P(return_value), day_short_names[ta->tm_wday]);
|
|
break;
|
|
case 'z': /* day (of the year) */
|
|
sprintf(tmp_buff, "%d", ta->tm_yday); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'y': /* year, numeric, 2 digits */
|
|
sprintf(tmp_buff, "%02d", ((ta->tm_year)%100)); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'm': /* month, numeric */
|
|
sprintf(tmp_buff, "%02d", ta->tm_mon + 1); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'n': /* month, numeric, no leading zeros */
|
|
sprintf(tmp_buff, "%d", ta->tm_mon + 1); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'd': /* day of the month, numeric */
|
|
sprintf(tmp_buff, "%02d", ta->tm_mday); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'j':
|
|
sprintf(tmp_buff, "%d", ta->tm_mday); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'H': /* hour, numeric, 24 hour format */
|
|
sprintf(tmp_buff, "%02d", ta->tm_hour); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'h': /* hour, numeric, 12 hour format */
|
|
h = ta->tm_hour % 12; if (h==0) h = 12;
|
|
sprintf(tmp_buff, "%02d", h); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'G': /* hour, numeric, 24 hour format, no leading zeros */
|
|
sprintf(tmp_buff, "%d", ta->tm_hour); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'g': /* hour, numeric, 12 hour format, no leading zeros */
|
|
h = ta->tm_hour % 12; if (h==0) h = 12;
|
|
sprintf(tmp_buff, "%d", h); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'i': /* minutes, numeric */
|
|
sprintf(tmp_buff, "%02d", ta->tm_min); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 's': /* seconds, numeric */
|
|
sprintf(tmp_buff, "%02d", ta->tm_sec); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'A': /* AM/PM */
|
|
strcat(Z_STRVAL_P(return_value), (ta->tm_hour >= 12 ? "PM" : "AM"));
|
|
break;
|
|
case 'a': /* am/pm */
|
|
strcat(Z_STRVAL_P(return_value), (ta->tm_hour >= 12 ? "pm" : "am"));
|
|
break;
|
|
case 'S': /* standard english suffix, e.g. 2nd/3rd for the day of the month */
|
|
if (ta->tm_mday >= 10 && ta->tm_mday <= 19) {
|
|
strcat(Z_STRVAL_P(return_value), "th");
|
|
} else {
|
|
switch (ta->tm_mday % 10) {
|
|
case 1:
|
|
strcat(Z_STRVAL_P(return_value), "st");
|
|
break;
|
|
case 2:
|
|
strcat(Z_STRVAL_P(return_value), "nd");
|
|
break;
|
|
case 3:
|
|
strcat(Z_STRVAL_P(return_value), "rd");
|
|
break;
|
|
default:
|
|
strcat(Z_STRVAL_P(return_value), "th");
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case 't': /* days in current month */
|
|
sprintf(tmp_buff, "%2d", phpday_tab[isleap((ta->tm_year+YEAR_BASE))][ta->tm_mon] );
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'w': /* day of the week, numeric EXTENSION */
|
|
sprintf(tmp_buff, "%01d", ta->tm_wday); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'O': /* GMT offset in [+-]HHMM format */
|
|
#if HAVE_TM_GMTOFF
|
|
sprintf(tmp_buff, "%c%02d%02d", (ta->tm_gmtoff < 0) ? '-' : '+', abs(ta->tm_gmtoff / 3600), abs( (ta->tm_gmtoff % 3600) / 60 ));
|
|
#else
|
|
sprintf(tmp_buff, "%c%02d%02d", ((ta->tm_isdst ? tzone - 3600:tzone)>0)?'-':'+', abs((ta->tm_isdst ? tzone - 3600 : tzone) / 3600), abs(((ta->tm_isdst ? tzone - 3600 : tzone) % 3600) / 60));
|
|
#endif
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'Z': /* timezone offset in seconds */
|
|
#if HAVE_TM_GMTOFF
|
|
sprintf(tmp_buff, "%ld", ta->tm_gmtoff);
|
|
#else
|
|
sprintf(tmp_buff, "%ld", ta->tm_isdst ? -(tzone- 3600) : -tzone);
|
|
#endif
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'L': /* boolean for leapyear */
|
|
sprintf(tmp_buff, "%d", (isleap((ta->tm_year+YEAR_BASE)) ? 1 : 0 ) );
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'T': /* timezone name */
|
|
#if HAVE_TM_ZONE
|
|
strcat(Z_STRVAL_P(return_value), ta->tm_zone);
|
|
#elif HAVE_TZNAME
|
|
strcat(Z_STRVAL_P(return_value), ta->tm_isdst ? tname[1] : tname[0]);
|
|
#endif
|
|
break;
|
|
case 'B': /* Swatch Beat a.k.a. Internet Time */
|
|
beat = (((((long)the_time)-(((long)the_time) -
|
|
((((long)the_time) % 86400) + 3600))) * 10) / 864);
|
|
while (beat < 0) {
|
|
beat += 1000;
|
|
}
|
|
beat = beat % 1000;
|
|
sprintf(tmp_buff, "%03d", beat); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'I':
|
|
sprintf(tmp_buff, "%d", ta->tm_isdst);
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'r':
|
|
#if HAVE_TM_GMTOFF
|
|
sprintf(tmp_buff, "%3s, %2d %3s %04d %02d:%02d:%02d %c%02d%02d",
|
|
day_short_names[ta->tm_wday],
|
|
ta->tm_mday,
|
|
mon_short_names[ta->tm_mon],
|
|
ta->tm_year + YEAR_BASE,
|
|
ta->tm_hour,
|
|
ta->tm_min,
|
|
ta->tm_sec,
|
|
(ta->tm_gmtoff < 0) ? '-' : '+',
|
|
abs(ta->tm_gmtoff / 3600),
|
|
abs( (ta->tm_gmtoff % 3600) / 60 )
|
|
);
|
|
#else
|
|
sprintf(tmp_buff, "%3s, %2d %3s %04d %02d:%02d:%02d %c%02d%02d",
|
|
day_short_names[ta->tm_wday],
|
|
ta->tm_mday,
|
|
mon_short_names[ta->tm_mon],
|
|
ta->tm_year + YEAR_BASE,
|
|
ta->tm_hour,
|
|
ta->tm_min,
|
|
ta->tm_sec,
|
|
((ta->tm_isdst ? tzone - 3600 : tzone) > 0) ? '-' : '+',
|
|
abs((ta->tm_isdst ? tzone - 3600 : tzone) / 3600),
|
|
abs( ((ta->tm_isdst ? tzone - 3600 : tzone) % 3600) / 60 )
|
|
);
|
|
#endif
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'c':
|
|
#if HAVE_TM_GMTOFF
|
|
sprintf(tmp_buff, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
|
|
ta->tm_year + YEAR_BASE,
|
|
ta->tm_mon + 1,
|
|
ta->tm_mday,
|
|
ta->tm_hour,
|
|
ta->tm_min,
|
|
ta->tm_sec,
|
|
(ta->tm_gmtoff < 0) ? '-' : '+',
|
|
abs(ta->tm_gmtoff / 3600),
|
|
abs( (ta->tm_gmtoff % 3600) / 60 )
|
|
);
|
|
#else
|
|
sprintf(tmp_buff, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
|
|
ta->tm_year + YEAR_BASE,
|
|
ta->tm_mon + 1,
|
|
ta->tm_mday,
|
|
ta->tm_hour,
|
|
ta->tm_min,
|
|
ta->tm_sec,
|
|
((ta->tm_isdst ? tzone - 3600 : tzone) > 0) ? '-' : '+',
|
|
abs((ta->tm_isdst ? tzone - 3600 : tzone) / 3600),
|
|
abs( ((ta->tm_isdst ? tzone - 3600 : tzone) % 3600) / 60 )
|
|
);
|
|
#endif
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
case 'W': /* ISO-8601 week number of year, weeks starting on Monday */
|
|
wd = ta->tm_wday == 0 ? 6 : ta->tm_wday - 1; /* weekday */
|
|
yd = ta->tm_yday + 1; /* days since January 1st */
|
|
|
|
fd = (7 + wd - yd % 7+ 1) % 7; /* weekday (1st January) */
|
|
|
|
/* week is a last year week (52 or 53) */
|
|
if ((yd <= 7 - fd) && fd > 3){
|
|
wk = (fd == 4 || (fd == 5 && isleap((ta->tm_year + YEAR_BASE - 1)))) ? 53 : 52;
|
|
}
|
|
/* week is a next year week (1) */
|
|
else if (isleap((ta->tm_year+YEAR_BASE)) + 365 - yd < 3 - wd){
|
|
wk = 1;
|
|
}
|
|
/* normal week */
|
|
else {
|
|
wk = (yd + 6 - wd + fd) / 7 - (fd > 3);
|
|
}
|
|
|
|
sprintf(tmp_buff, "%d", wk); /* SAFE */
|
|
strcat(Z_STRVAL_P(return_value), tmp_buff);
|
|
break;
|
|
|
|
default:
|
|
length = strlen(Z_STRVAL_P(return_value));
|
|
Z_STRVAL_P(return_value)[length] = Z_STRVAL_PP(format)[i];
|
|
Z_STRVAL_P(return_value)[length + 1] = '\0';
|
|
break;
|
|
}
|
|
}
|
|
Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
|
|
Z_TYPE_P(return_value) = IS_STRING;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string date(string format [, int timestamp])
|
|
Format a local time/date */
|
|
PHP_FUNCTION(date)
|
|
{
|
|
php_date(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string gmdate(string format [, int timestamp])
|
|
Format a GMT/UTC date/time */
|
|
PHP_FUNCTION(gmdate)
|
|
{
|
|
php_date(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ php_idate
|
|
*/
|
|
int php_idate(char format, int timestamp, int gm)
|
|
{
|
|
time_t the_time;
|
|
struct tm *ta, tmbuf;
|
|
int h, beat, fd, wd, yd, wk;
|
|
#if !HAVE_TM_GMTOFF
|
|
long tzone;
|
|
char *tname[2]= {"GMT Standard Time", "BST"};
|
|
#endif
|
|
|
|
the_time = timestamp;
|
|
|
|
if (gm) {
|
|
ta = php_gmtime_r(&the_time, &tmbuf);
|
|
#if !HAVE_TM_GMTOFF
|
|
tzone = 0;
|
|
#endif
|
|
} else {
|
|
ta = php_localtime_r(&the_time, &tmbuf);
|
|
#if !HAVE_TM_GMTOFF
|
|
#ifdef __CYGWIN__
|
|
tzone = _timezone;
|
|
#else
|
|
tzone = timezone;
|
|
#endif
|
|
tname[0] = tzname[0];
|
|
#endif
|
|
}
|
|
|
|
switch (format) {
|
|
case 'U': /* seconds since the epoch */
|
|
return (long)the_time;
|
|
case 'Y': /* year, numeric, 4 digits */
|
|
return ta->tm_year + YEAR_BASE;
|
|
case 'z': /* day (of the year) */
|
|
return ta->tm_yday;
|
|
case 'y': /* year, numeric, 2 digits */
|
|
return (ta->tm_year) % 100;
|
|
case 'm': /* month, numeric */
|
|
case 'n':
|
|
return ta->tm_mon + 1;
|
|
case 'd': /* day of the month, numeric */
|
|
case 'j':
|
|
return ta->tm_mday;
|
|
case 'H': /* hour, numeric, 24 hour format */
|
|
case 'G':
|
|
return ta->tm_hour;
|
|
case 'h': /* hour, numeric, 12 hour format */
|
|
case 'g':
|
|
h = ta->tm_hour % 12;
|
|
if (h == 0) {
|
|
h = 12;
|
|
}
|
|
return h;
|
|
case 'i': /* minutes, numeric */
|
|
return ta->tm_min;
|
|
case 's': /* seconds, numeric */
|
|
return ta->tm_sec;
|
|
case 't': /* days in current month */
|
|
return phpday_tab[isleap((ta->tm_year + YEAR_BASE))][ta->tm_mon];
|
|
case 'w': /* day of the week, numeric EXTENSION */
|
|
return ta->tm_wday;
|
|
case 'Z': /* timezone offset in seconds */
|
|
#if HAVE_TM_GMTOFF
|
|
return ta->tm_gmtoff;
|
|
#else
|
|
return ta->tm_isdst ? -(tzone - 3600) : -tzone;
|
|
#endif
|
|
case 'L': /* boolean for leapyear */
|
|
return isleap(ta->tm_year + YEAR_BASE) ? 1 : 0;
|
|
case 'B': /* Swatch Beat a.k.a. Internet Time */
|
|
beat = (((((long)the_time) - (((long)the_time) - ((((long)the_time) % 86400) + 3600))) * 10) / 864);
|
|
while (beat < 0) {
|
|
beat += 1000;
|
|
}
|
|
beat = beat % 1000;
|
|
return beat;
|
|
case 'I':
|
|
return ta->tm_isdst;
|
|
case 'W': /* ISO-8601 week number of year, weeks starting on Monday */
|
|
wd = (ta->tm_wday == 0) ? 6 : ta->tm_wday - 1; /* weekday */
|
|
yd = ta->tm_yday + 1; /* days since January 1st */
|
|
fd = (7 + wd - yd % 7+ 1) % 7; /* weekday (1st January) */
|
|
if ((yd <= 7 - fd) && fd > 3) { /* week is a last year week (52 or 53) */
|
|
wk = (fd == 4 || (fd == 5 && isleap((ta->tm_year + YEAR_BASE - 1)))) ? 53 : 52;
|
|
}
|
|
/* week is a next year week (1) */
|
|
else if (isleap((ta->tm_year + YEAR_BASE)) + 365 - yd < 3 - wd) {
|
|
wk = 1;
|
|
}
|
|
/* normal week */
|
|
else {
|
|
wk = (yd + 6 - wd + fd) / 7 - (fd > 3);
|
|
}
|
|
return wk;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int idate(string format [, int timestamp])
|
|
Format a local time/date as integer */
|
|
PHP_FUNCTION(idate)
|
|
{
|
|
zval **format, **timestamp;
|
|
int t, ret;
|
|
|
|
switch (ZEND_NUM_ARGS()) {
|
|
case 1:
|
|
if (zend_get_parameters_ex(1, &format) == FAILURE) {
|
|
WRONG_PARAM_COUNT;
|
|
}
|
|
t = time(NULL);
|
|
break;
|
|
case 2:
|
|
if (zend_get_parameters_ex(2, &format, ×tamp) == FAILURE) {
|
|
WRONG_PARAM_COUNT;
|
|
}
|
|
convert_to_long_ex(timestamp);
|
|
t = Z_LVAL_PP(timestamp);
|
|
break;
|
|
default:
|
|
WRONG_PARAM_COUNT;
|
|
}
|
|
|
|
convert_to_string_ex(format);
|
|
|
|
if (Z_STRLEN_PP(format) != 1) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "idate format is one char");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
ret = php_idate(Z_STRVAL_PP(format)[0], t, 0);
|
|
RETURN_LONG(ret);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto array localtime([int timestamp [, bool associative_array]])
|
|
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 */
|
|
PHP_FUNCTION(localtime)
|
|
{
|
|
zval **timestamp_arg, **assoc_array_arg;
|
|
struct tm *ta, tmbuf;
|
|
time_t timestamp;
|
|
int assoc_array = 0;
|
|
int arg_count = ZEND_NUM_ARGS();
|
|
|
|
if (arg_count < 0 || arg_count > 2 ||
|
|
zend_get_parameters_ex(arg_count, ×tamp_arg, &assoc_array_arg) == FAILURE) {
|
|
WRONG_PARAM_COUNT;
|
|
}
|
|
|
|
switch (arg_count) {
|
|
case 0:
|
|
timestamp = (long)time(NULL);
|
|
break;
|
|
case 1:
|
|
convert_to_long_ex(timestamp_arg);
|
|
timestamp = Z_LVAL_PP(timestamp_arg);
|
|
break;
|
|
case 2:
|
|
convert_to_long_ex(timestamp_arg);
|
|
convert_to_long_ex(assoc_array_arg);
|
|
timestamp = Z_LVAL_PP(timestamp_arg);
|
|
assoc_array = Z_LVAL_PP(assoc_array_arg);
|
|
break;
|
|
}
|
|
|
|
#ifdef PHP_WIN32
|
|
if (timestamp < 0) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Windows does not support negative values for this function");
|
|
RETURN_FALSE
|
|
}
|
|
#endif
|
|
|
|
if (NULL == (ta = php_localtime_r(×tamp, &tmbuf))) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid local time");
|
|
RETURN_FALSE;
|
|
}
|
|
array_init(return_value);
|
|
|
|
if (assoc_array) {
|
|
add_assoc_long(return_value, "tm_sec", ta->tm_sec);
|
|
add_assoc_long(return_value, "tm_min", ta->tm_min);
|
|
add_assoc_long(return_value, "tm_hour", ta->tm_hour);
|
|
add_assoc_long(return_value, "tm_mday", ta->tm_mday);
|
|
add_assoc_long(return_value, "tm_mon", ta->tm_mon);
|
|
add_assoc_long(return_value, "tm_year", ta->tm_year);
|
|
add_assoc_long(return_value, "tm_wday", ta->tm_wday);
|
|
add_assoc_long(return_value, "tm_yday", ta->tm_yday);
|
|
add_assoc_long(return_value, "tm_isdst", ta->tm_isdst);
|
|
} else {
|
|
add_next_index_long(return_value, ta->tm_sec);
|
|
add_next_index_long(return_value, ta->tm_min);
|
|
add_next_index_long(return_value, ta->tm_hour);
|
|
add_next_index_long(return_value, ta->tm_mday);
|
|
add_next_index_long(return_value, ta->tm_mon);
|
|
add_next_index_long(return_value, ta->tm_year);
|
|
add_next_index_long(return_value, ta->tm_wday);
|
|
add_next_index_long(return_value, ta->tm_yday);
|
|
add_next_index_long(return_value, ta->tm_isdst);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto array getdate([int timestamp])
|
|
Get date/time information */
|
|
PHP_FUNCTION(getdate)
|
|
{
|
|
pval **timestamp_arg;
|
|
struct tm *ta, tmbuf;
|
|
time_t timestamp;
|
|
|
|
if (ZEND_NUM_ARGS() == 0) {
|
|
timestamp = time(NULL);
|
|
} else if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, ×tamp_arg) == FAILURE) {
|
|
WRONG_PARAM_COUNT;
|
|
} else {
|
|
convert_to_long_ex(timestamp_arg);
|
|
timestamp = Z_LVAL_PP(timestamp_arg);
|
|
}
|
|
|
|
ta = php_localtime_r(×tamp, &tmbuf);
|
|
if (!ta) {
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot perform date calculation");
|
|
return;
|
|
}
|
|
array_init(return_value);
|
|
add_assoc_long(return_value, "seconds", ta->tm_sec);
|
|
add_assoc_long(return_value, "minutes", ta->tm_min);
|
|
add_assoc_long(return_value, "hours", ta->tm_hour);
|
|
add_assoc_long(return_value, "mday", ta->tm_mday);
|
|
add_assoc_long(return_value, "wday", ta->tm_wday);
|
|
add_assoc_long(return_value, "mon", ta->tm_mon + 1);
|
|
add_assoc_long(return_value, "year", ta->tm_year + 1900);
|
|
add_assoc_long(return_value, "yday", ta->tm_yday);
|
|
add_assoc_string(return_value, "weekday", day_full_names[ta->tm_wday], 1);
|
|
add_assoc_string(return_value, "month", mon_full_names[ta->tm_mon], 1);
|
|
add_index_long(return_value, 0, timestamp);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ php_std_date
|
|
Return date string in standard format for http headers */
|
|
char *php_std_date(time_t t TSRMLS_DC)
|
|
{
|
|
struct tm *tm1, tmbuf;
|
|
char *str;
|
|
|
|
tm1 = php_gmtime_r(&t, &tmbuf);
|
|
str = emalloc(81);
|
|
if (PG(y2k_compliance)) {
|
|
snprintf(str, 80, "%s, %02d-%s-%04d %02d:%02d:%02d GMT",
|
|
day_short_names[tm1->tm_wday],
|
|
tm1->tm_mday,
|
|
mon_short_names[tm1->tm_mon],
|
|
tm1->tm_year + 1900,
|
|
tm1->tm_hour, tm1->tm_min, tm1->tm_sec);
|
|
} else {
|
|
snprintf(str, 80, "%s, %02d-%s-%02d %02d:%02d:%02d GMT",
|
|
day_short_names[tm1->tm_wday],
|
|
tm1->tm_mday,
|
|
mon_short_names[tm1->tm_mon],
|
|
((tm1->tm_year) % 100),
|
|
tm1->tm_hour, tm1->tm_min, tm1->tm_sec);
|
|
}
|
|
|
|
str[79] = 0;
|
|
return (str);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool checkdate(int month, int day, int year)
|
|
Returns true(1) if it is a valid date in gregorian calendar */
|
|
PHP_FUNCTION(checkdate)
|
|
{
|
|
long m, d, y;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &m, &d, &y) == FAILURE) {
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (y < 1 || y > 32767 || m < 1 || m > 12 || d < 1 || d > phpday_tab[isleap(y)][m - 1]) {
|
|
RETURN_FALSE;
|
|
}
|
|
RETURN_TRUE; /* True : This month, day, year arguments are valid */
|
|
}
|
|
/* }}} */
|
|
|
|
#if HAVE_STRFTIME
|
|
/* {{{ _php_strftime
|
|
*/
|
|
void _php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gm)
|
|
{
|
|
pval **format_arg, **timestamp_arg;
|
|
char *format, *buf;
|
|
time_t timestamp;
|
|
struct tm *ta, tmbuf;
|
|
int max_reallocs = 5;
|
|
size_t buf_len=64, real_len;
|
|
|
|
switch (ZEND_NUM_ARGS()) {
|
|
case 1:
|
|
if (zend_get_parameters_ex(1, &format_arg)==FAILURE) {
|
|
RETURN_FALSE;
|
|
}
|
|
time(×tamp);
|
|
break;
|
|
case 2:
|
|
if (zend_get_parameters_ex(2, &format_arg, ×tamp_arg)==FAILURE) {
|
|
RETURN_FALSE;
|
|
}
|
|
convert_to_long_ex(timestamp_arg);
|
|
timestamp = Z_LVAL_PP(timestamp_arg);
|
|
break;
|
|
default:
|
|
WRONG_PARAM_COUNT;
|
|
break;
|
|
}
|
|
|
|
convert_to_string_ex(format_arg);
|
|
if (Z_STRLEN_PP(format_arg)==0) {
|
|
RETURN_FALSE;
|
|
}
|
|
#ifdef PHP_WIN32
|
|
if (timestamp < 0) {
|
|
RETURN_FALSE;
|
|
}
|
|
#endif
|
|
format = Z_STRVAL_PP(format_arg);
|
|
if (gm) {
|
|
ta = php_gmtime_r(×tamp, &tmbuf);
|
|
} else {
|
|
ta = php_localtime_r(×tamp, &tmbuf);
|
|
}
|
|
|
|
buf = (char *) emalloc(buf_len);
|
|
while ((real_len=strftime(buf, buf_len, format, ta))==buf_len || real_len==0) {
|
|
buf_len *= 2;
|
|
buf = (char *) erealloc(buf, buf_len);
|
|
if (!--max_reallocs) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (real_len && real_len != buf_len) {
|
|
buf = (char *) erealloc(buf, real_len + 1);
|
|
RETURN_STRINGL(buf, real_len, 0);
|
|
}
|
|
efree(buf);
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string strftime(string format [, int timestamp])
|
|
Format a local time/date according to locale settings */
|
|
PHP_FUNCTION(strftime)
|
|
{
|
|
_php_strftime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string gmstrftime(string format [, int timestamp])
|
|
Format a GMT/UCT time/date according to locale settings */
|
|
PHP_FUNCTION(gmstrftime)
|
|
{
|
|
_php_strftime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
|
|
}
|
|
/* }}} */
|
|
|
|
#endif
|
|
|
|
/* {{{ proto int strtotime(string time, int now)
|
|
Convert string representation of date and time to a timestamp */
|
|
PHP_FUNCTION(strtotime)
|
|
{
|
|
zval **z_time, **z_now;
|
|
int argc;
|
|
time_t now;
|
|
|
|
argc = ZEND_NUM_ARGS();
|
|
|
|
if (argc < 1 || argc > 2 || zend_get_parameters_ex(argc, &z_time, &z_now)==FAILURE) {
|
|
WRONG_PARAM_COUNT;
|
|
}
|
|
|
|
convert_to_string_ex(z_time);
|
|
if (Z_STRLEN_PP(z_time) == 0)
|
|
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Called with empty time parameter");
|
|
if (argc == 2) {
|
|
convert_to_long_ex(z_now);
|
|
now = Z_LVAL_PP(z_now);
|
|
RETURN_LONG(php_parse_date(Z_STRVAL_PP(z_time), &now));
|
|
} else {
|
|
RETURN_LONG(php_parse_date(Z_STRVAL_PP(z_time), NULL));
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
|
|
/*
|
|
* Local variables:
|
|
* tab-width: 4
|
|
* c-basic-offset: 4
|
|
* End:
|
|
* vim600: sw=4 ts=4 fdm=marker
|
|
* vim<600: sw=4 ts=4
|
|
*/
|