[prev in list] [next in list] [prev in thread] [next in thread] 

List:       pecl-cvs
Subject:    [PECL-CVS] =?utf-8?q?svn:_/pecl/dbase/trunk/_config.m4_config.w32_dbase.c_dbf=5Fhead.c_dbf=5Fmisc.c_
From:       Christoph_Michael_Becker <cmb () php ! net>
Date:       2016-10-30 12:14:01
Message-ID: svn-cmb-1477829641-340796-478505852 () svn ! php ! net
[Download RAW message or body]

cmb                                      Sun, 30 Oct 2016 12:14:01 +0000

Revision: http://svn.php.net/viewvc?view=revision&revision=340796

Log:
Add support for datetime fields

We add support for FoxPro datetime fields, which store an exact
timestamp in two binary dwords, representing the Julian day number and
the number of milliseconds since midnight, respectively. These are
represented in userland as strings with the format "YYYYMMDDhhmmss.uuu",
which conforms to ISO-8601.

According to the current handling of date fields, the validity of input
and output is not checked, i.e. it is possible to store invalid datetime
values in the database. If necessary, respective checks have to be made
by the programmer.

To avoid reinventing the wheel, but also not to rely on ext/calendar, we
add the respective functionality and adapt the names to avoid build
conflicts.

Changed paths:
    U   pecl/dbase/trunk/config.m4
    U   pecl/dbase/trunk/config.w32
    U   pecl/dbase/trunk/dbase.c
    U   pecl/dbase/trunk/dbf_head.c
    U   pecl/dbase/trunk/dbf_misc.c
    U   pecl/dbase/trunk/dbf_misc.h
    U   pecl/dbase/trunk/dbf_rec.c
    U   pecl/dbase/trunk/dbf_rec.h
    A   pecl/dbase/trunk/dbf_sdncal.h
    A   pecl/dbase/trunk/gregor.c
    U   pecl/dbase/trunk/tests/bug52112.phpt
    U   pecl/dbase/trunk/tests/dbase_add_record_basic.phpt
    U   pecl/dbase/trunk/tests/dbase_add_record_error.phpt
    U   pecl/dbase/trunk/tests/dbase_add_record_variation1.phpt
    U   pecl/dbase/trunk/tests/dbase_add_record_variation2.phpt
    U   pecl/dbase/trunk/tests/dbase_add_record_variation3.phpt
    U   pecl/dbase/trunk/tests/dbase_delete_record_basic.phpt
    U   pecl/dbase/trunk/tests/dbase_get_header_info_basic.phpt
    U   pecl/dbase/trunk/tests/dbase_get_record_basic.phpt
    U   pecl/dbase/trunk/tests/dbase_get_record_with_names_basic.phpt
    U   pecl/dbase/trunk/tests/dbase_numfields_basic.phpt
    U   pecl/dbase/trunk/tests/dbase_pack_basic.phpt
    U   pecl/dbase/trunk/tests/dbase_replace_record_basic.phpt
    U   pecl/dbase/trunk/tests/dbase_replace_record_error.phpt
    U   pecl/dbase/trunk/tests/dbase_replace_record_variation1.phpt
    U   pecl/dbase/trunk/tests/dbase_replace_record_variation2.phpt
    U   pecl/dbase/trunk/tests/dbase_replace_record_variation3.phpt
    U   pecl/dbase/trunk/tests/example.dbf
    U   pecl/dbase/trunk/tests/example.php
    A   pecl/dbase/trunk/tests/type_datetime.phpt


["svn-diffs-340796.txt" (text/x-diff)]

Modified: pecl/dbase/trunk/config.m4
===================================================================
--- pecl/dbase/trunk/config.m4	2016-10-30 08:33:55 UTC (rev 340795)
+++ pecl/dbase/trunk/config.m4	2016-10-30 12:14:01 UTC (rev 340796)
@@ -7,5 +7,5 @@

 if test "$PHP_DBASE" = "yes"; then
   AC_DEFINE(DBASE,1,[ ])
-  PHP_NEW_EXTENSION(dbase, dbf_head.c dbf_rec.c dbf_misc.c dbf_ndx.c dbase.c, \
$ext_shared) +  PHP_NEW_EXTENSION(dbase, dbf_head.c dbf_rec.c dbf_misc.c dbf_ndx.c \
dbase.c gregor.c, $ext_shared)  fi

Modified: pecl/dbase/trunk/config.w32
===================================================================
--- pecl/dbase/trunk/config.w32	2016-10-30 08:33:55 UTC (rev 340795)
+++ pecl/dbase/trunk/config.w32	2016-10-30 12:14:01 UTC (rev 340796)
@@ -4,7 +4,7 @@
 ARG_ENABLE("dbase", "Enable the bundled dbase library", "no");

 if (PHP_DBASE != "no") {
-	EXTENSION("dbase", "dbase.c dbf_head.c dbf_misc.c dbf_ndx.c dbf_rec.c");
+	EXTENSION("dbase", "dbase.c dbf_head.c dbf_misc.c dbf_ndx.c dbf_rec.c gregor.c");
 	AC_DEFINE('HAVE_DBASE', 1, 'dbase support');
 	ADD_FLAG("CFLAGS_DBASE", "/D DBASE=1");
 }

Modified: pecl/dbase/trunk/dbase.c
===================================================================
--- pecl/dbase/trunk/dbase.c	2016-10-30 08:33:55 UTC (rev 340795)
+++ pecl/dbase/trunk/dbase.c	2016-10-30 12:14:01 UTC (rev 340796)
@@ -244,8 +244,21 @@
 		}

 		convert_to_string(field);
-		snprintf(t_cp, cur_f->db_flen+1, cur_f->db_format, Z_STRVAL_P(field));

+		switch (cur_f->db_type) {
+			case 'T':
+				{
+					int jdn, msecs;
+
+					db_get_timestamp(Z_STRVAL_P(field), &jdn, &msecs);
+					put_long(t_cp, jdn);
+					put_long(t_cp + 4, msecs);
+				}
+				break;
+			default:
+				snprintf(t_cp, cur_f->db_flen+1, cur_f->db_format, Z_STRVAL_P(field));
+		}
+
 		t_cp += cur_f->db_flen;
 	}

@@ -355,7 +368,11 @@
 			cursize = cur_f->db_flen + 1;
 			fnp = erealloc(fnp, cursize);
 		}
-		snprintf(str_value, cursize, cur_f->db_format, get_field_val(data, cur_f, fnp));
+		if (*cur_f->db_format) {
+			snprintf(str_value, cursize, cur_f->db_format, get_field_val(data, cur_f, fnp));
+		} else {
+			memcpy(str_value, get_binary_field_val(data, cur_f, fnp), cur_f->db_flen);
+		}

 		/* now convert it to the right php internal type */
 		switch (cur_f->db_type) {
@@ -423,6 +440,18 @@
 			case 'M':
 				/* this is a memo field. don't know how to deal with this yet */
 				break;
+			case 'T':
+				{
+					char buf[19];
+
+					db_set_timestamp(buf, get_long(str_value), get_long(str_value + 4));
+					if (!assoc) {
+						add_next_index_string(return_value, buf);
+					} else {
+						add_assoc_string(return_value, cur_f->db_fname, buf);
+					}
+				}
+				break;
 			default:
 				/* should deal with this in some way */
 				break;
@@ -571,6 +600,7 @@
 			/* should create the memo file here, probably */
 			break;
 		case 'D':
+		case 'T':
 			cur_f->db_flen = 8;
 			break;
 		case 'F':
@@ -734,14 +764,15 @@

 		/* field type */
 		switch (cur_f->db_type) {
-			case 'C': add_assoc_string(&row, "type", "character");	break;
-			case 'D': add_assoc_string(&row, "type", "date"); 		break;
-			case 'I': add_assoc_string(&row, "type", "integer"); 		break;
-			case 'N': add_assoc_string(&row, "type", "number"); 		break;
-			case 'L': add_assoc_string(&row, "type", "boolean");		break;
-			case 'M': add_assoc_string(&row, "type", "memo");			break;
+			case 'C': add_assoc_string(&row, "type", "character"); break;
+			case 'D': add_assoc_string(&row, "type", "date");      break;
+			case 'T': add_assoc_string(&row, "type", "datetime");  break;
+			case 'I': add_assoc_string(&row, "type", "integer");   break;
+			case 'N': add_assoc_string(&row, "type", "number");    break;
+			case 'L': add_assoc_string(&row, "type", "boolean");   break;
+			case 'M': add_assoc_string(&row, "type", "memo");      break;
 			case 'F': add_assoc_string(&row, "type", "float");     break;
-			default:  add_assoc_string(&row, "type", "unknown");		break;
+			default:  add_assoc_string(&row, "type", "unknown");   break;
 		}

 		/* length of field */

Modified: pecl/dbase/trunk/dbf_head.c
===================================================================
--- pecl/dbase/trunk/dbf_head.c	2016-10-30 08:33:55 UTC (rev 340795)
+++ pecl/dbase/trunk/dbf_head.c	2016-10-30 12:14:01 UTC (rev 340796)
@@ -165,6 +165,7 @@
 			dbf->db_flen = 1;
 			break;
 	    case 'D':
+	    case 'T':
 			dbf->db_flen = 8;
 			break;
 	    default:
@@ -257,6 +258,9 @@
 	   case 'M':
 		strlcpy(format, "%s", sizeof(format));
 		break;
+	   case 'T':
+		format[0] = '\0';
+		break;
 	   default:
 		return NULL;
 	}

Modified: pecl/dbase/trunk/dbf_misc.c
===================================================================
--- pecl/dbase/trunk/dbf_misc.c	2016-10-30 08:33:55 UTC (rev 340795)
+++ pecl/dbase/trunk/dbf_misc.c	2016-10-30 12:14:01 UTC (rev 340796)
@@ -8,6 +8,7 @@
 #include <sys/types.h>

 #include "dbf_misc.h"
+#include "dbf_sdncal.h"

 #include "php_reentrancy.h"

@@ -144,6 +145,33 @@
 	return day;
 }

+void db_set_timestamp(char *cp, int jdn, int msecs)
+{
+	int year, month, day, hour, minute, second, millis;
+
+	db_sdn_to_gregorian(jdn, &year, &month, &day);
+
+	millis = msecs % 1000;
+	msecs /= 1000;
+	second = msecs % 60;
+	msecs /= 60;
+	minute = msecs % 60;
+	msecs /= 60;
+	hour = msecs;
+
+	snprintf(cp, 19, "%04d%02d%02d%02d%02d%02d.%03d", year, month, day, hour, minute, \
second, millis); +}
+
+void db_get_timestamp(char *cp, int *jdn, int *msecs)
+{
+	int year, month, day, hour, minute, second, millis;
+
+	sscanf(cp, "%04d%02d%02d%02d%02d%02d.%03d", &year, &month, &day, &hour, &minute, \
&second, &millis); +
+	*jdn = db_gregorian_to_sdn(year, month, day);
+	*msecs = (hour * 60 * 60 * 1000) + (minute * 60 * 1000) + (second * 1000) + millis;
+}
+
 #include <time.h>

 char *db_cur_date(char *cp)

Modified: pecl/dbase/trunk/dbf_misc.h
===================================================================
--- pecl/dbase/trunk/dbf_misc.h	2016-10-30 08:33:55 UTC (rev 340795)
+++ pecl/dbase/trunk/dbf_misc.h	2016-10-30 12:14:01 UTC (rev 340796)
@@ -11,3 +11,5 @@
 extern int db_date_month(char *cp);
 extern int db_date_day(char *cp);
 extern char *db_cur_date(char *cp);
+void db_set_timestamp(char *cp, int jdn, int msecs);
+void db_get_timestamp(char *cp, int *jdn, int *msecs);

Modified: pecl/dbase/trunk/dbf_rec.c
===================================================================
--- pecl/dbase/trunk/dbf_rec.c	2016-10-30 08:33:55 UTC (rev 340795)
+++ pecl/dbase/trunk/dbf_rec.c	2016-10-30 12:14:01 UTC (rev 340796)
@@ -170,6 +170,16 @@
 	return cp;
 }

+char *get_binary_field_val(char *rp, dbfield_t *fldp, char *cp)
+{
+	int flen = fldp->db_flen;
+
+	if ( !cp )
+		cp = (char *)emalloc(flen);
+	memcpy(cp, &rp[fldp->db_foffset], flen);
+	return cp;
+}
+
 void put_field_val(char *rp, dbfield_t *fldp, char *cp)
 {
 	strncpy(&rp[fldp->db_foffset], cp, fldp->db_flen);

Modified: pecl/dbase/trunk/dbf_rec.h
===================================================================
--- pecl/dbase/trunk/dbf_rec.h	2016-10-30 08:33:55 UTC (rev 340795)
+++ pecl/dbase/trunk/dbf_rec.h	2016-10-30 12:14:01 UTC (rev 340796)
@@ -5,6 +5,7 @@
 extern int del_dbf_record(dbhead_t *dbh, long rec_num);
 int pack_dbf(dbhead_t *dbh);
 extern char *get_field_val(char *rp, dbfield_t *fldp, char *cp);
+char *get_binary_field_val(char *rp, dbfield_t *fldp, char *cp);
 void put_field_val(char *rp, dbfield_t *fldp, char *cp);
 void out_rec(dbhead_t *dbh, dbfield_t *dbf, char *cp);
 extern int is_valid_rec(char *cp);

Added: pecl/dbase/trunk/dbf_sdncal.h
===================================================================
--- pecl/dbase/trunk/dbf_sdncal.h	                        (rev 0)
+++ pecl/dbase/trunk/dbf_sdncal.h	2016-10-30 12:14:01 UTC (rev 340796)
@@ -0,0 +1,76 @@
+#ifndef DBF_SDNCAL_H
+#define DBF_SDNCAL_H
+/*
+ * This code has been modified for use with PHP
+ * by Shane Caraveo shane@caraveo.com
+ * see below for more details
+ *
+ * This code has been adapted for the dbase extension
+ * by Christoph M. Becker <cmbecker69@gmx.de> *
+ */
+
+/* $selId: sdncal.h,v 2.0 1995/10/24 01:13:06 lees Exp $
+ * Copyright 1993-1995, Scott E. Lee, all rights reserved.
+ * Permission granted to use, copy, modify, distribute and sell so long as
+ * the above copyright and this permission statement are retained in all
+ * copies.  THERE IS NO WARRANTY - USE AT YOUR OWN RISK.
+ */
+
+/**************************************************************************
+ *
+ * This package defines a set of routines that convert calendar dates to
+ * and from a serial day number (SDN).  The SDN is a serial numbering of
+ * days where SDN 1 is November 25, 4714 BC in the Gregorian calendar and
+ * SDN 2447893 is January 1, 1990.  This system of day numbering is
+ * sometimes referred to as Julian days, but to avoid confusion with the
+ * Julian calendar, it is referred to as serial day numbers here.  The term
+ * Julian days is also used to mean the number of days since the beginning
+ * of the current year.
+ *
+ * The SDN can be used as an intermediate step in converting from one
+ * calendar system to another (such as Gregorian to Jewish).  It can also
+ * be used for date computations such as easily comparing two dates,
+ * determining the day of the week, finding the date of yesterday or
+ * calculating the number of days between two dates.
+ *
+ * When using this software on 16 bit systems, be careful to store SDNs in
+ * a long int, because it will not fit in the 16 bits that some systems
+ * allocate to an int.
+ *
+ * For each calendar, there are two routines provided.  One converts dates
+ * in that calendar to SDN and the other converts SDN to calendar dates.
+ * The routines are named SdnTo<CALENDAR>() and <CALENDAR>ToSdn(), where
+ * <CALENDAR> is the name of the calendar system.
+ *
+ * SDN values less than one are not supported.  If a conversion routine
+ * returns an SDN of zero, this means that the date given is either invalid
+ * or is outside the supported range for that calendar.
+ *
+ * At least some validity checks are performed on input dates.  For
+ * example, a negative month number will result in the return of zero for
+ * the SDN.  A returned SDN greater than one does not necessarily mean that
+ * the input date was valid.  To determine if the date is valid, convert it
+ * to SDN, and if the SDN is greater than zero, convert it back to a date
+ * and compare to the original.  For example:
+ *
+ *    int y1, m1, d1;
+ *    int y2, m2, d2;
+ *    zend_long sdn;
+ *    ...
+ *    sdn = GregorianToSdn(y1, m1, d1);
+ *    if (sdn > 0) {
+ *        SdnToGregorian(sdn, &y2, &m2, &d2);
+ *        if (y1 == y2 && m1 == m2 && d1 == d2) {
+ *            ... date is valid ...
+ *        }
+ *    }
+ *
+ **************************************************************************/
+
+#include "php.h"
+
+/* Gregorian calendar conversions. */
+void db_sdn_to_gregorian(zend_long sdn, int *pYear, int *pMonth, int *pDay);
+zend_long db_gregorian_to_sdn(int year, int month, int day);
+
+#endif /* DBF_SDNCAL_H */


Property changes on: pecl/dbase/trunk/dbf_sdncal.h
___________________________________________________________________
Added: svn:keywords
   + Id
Added: svn:eol-style
   + LF

Added: pecl/dbase/trunk/gregor.c
===================================================================
--- pecl/dbase/trunk/gregor.c	                        (rev 0)
+++ pecl/dbase/trunk/gregor.c	2016-10-30 12:14:01 UTC (rev 340796)
@@ -0,0 +1,225 @@
+/* $selId: gregor.c,v 2.0 1995/10/24 01:13:06 lees Exp $
+ * Copyright 1993-1995, Scott E. Lee, all rights reserved.
+ * Permission granted to use, copy, modify, distribute and sell so long as
+ * the above copyright and this permission statement are retained in all
+ * copies.  THERE IS NO WARRANTY - USE AT YOUR OWN RISK.
+ */
+
+/**************************************************************************
+ *
+ * These are the externally visible components of this file:
+ *
+ *     void
+ *     SdnToGregorian(
+ *         long int  sdn,
+ *         int      *pYear,
+ *         int      *pMonth,
+ *         int      *pDay);
+ *
+ * Convert a SDN to a Gregorian calendar date.  If the input SDN is less
+ * than 1, the three output values will all be set to zero, otherwise
+ * *pYear will be >= -4714 and != 0; *pMonth will be in the range 1 to 12
+ * inclusive; *pDay will be in the range 1 to 31 inclusive.
+ *
+ *     long int
+ *     GregorianToSdn(
+ *         int inputYear,
+ *         int inputMonth,
+ *         int inputDay);
+ *
+ * Convert a Gregorian calendar date to a SDN.  Zero is returned when the
+ * input date is detected as invalid or out of the supported range.  The
+ * return value will be > 0 for all valid, supported dates, but there are
+ * some invalid dates that will return a positive value.  To verify that a
+ * date is valid, convert it to SDN and then back and compare with the
+ * original.
+ *
+ *
+ * VALID RANGE
+ *
+ *     4714 B.C. to at least 10000 A.D.
+ *
+ *     Although this software can handle dates all the way back to 4714
+ *     B.C., such use may not be meaningful.  The Gregorian calendar was
+ *     not instituted until October 15, 1582 (or October 5, 1582 in the
+ *     Julian calendar).  Some countries did not accept it until much
+ *     later.  For example, Britain converted in 1752, The USSR in 1918 and
+ *     Greece in 1923.  Most European countries used the Julian calendar
+ *     prior to the Gregorian.
+ *
+ * CALENDAR OVERVIEW
+ *
+ *     The Gregorian calendar is a modified version of the Julian calendar.
+ *     The only difference being the specification of leap years.  The
+ *     Julian calendar specifies that every year that is a multiple of 4
+ *     will be a leap year.  This leads to a year that is 365.25 days long,
+ *     but the current accepted value for the tropical year is 365.242199
+ *     days.
+ *
+ *     To correct this error in the length of the year and to bring the
+ *     vernal equinox back to March 21, Pope Gregory XIII issued a papal
+ *     bull declaring that Thursday October 4, 1582 would be followed by
+ *     Friday October 15, 1582 and that centennial years would only be a
+ *     leap year if they were a multiple of 400.  This shortened the year
+ *     by 3 days per 400 years, giving a year of 365.2425 days.
+ *
+ *     Another recently proposed change in the leap year rule is to make
+ *     years that are multiples of 4000 not a leap year, but this has never
+ *     been officially accepted and this rule is not implemented in these
+ *     algorithms.
+ *
+ * ALGORITHMS
+ *
+ *     The calculations are based on three different cycles: a 400 year
+ *     cycle of leap years, a 4 year cycle of leap years and a 5 month
+ *     cycle of month lengths.
+ *
+ *     The 5 month cycle is used to account for the varying lengths of
+ *     months.  You will notice that the lengths alternate between 30
+ *     and 31 days, except for three anomalies: both July and August
+ *     have 31 days, both December and January have 31, and February
+ *     is less than 30.  Starting with March, the lengths are in a
+ *     cycle of 5 months (31, 30, 31, 30, 31):
+ *
+ *         Mar   31 days  \
+ *         Apr   30 days   |
+ *         May   31 days    > First cycle
+ *         Jun   30 days   |
+ *         Jul   31 days  /
+ *
+ *         Aug   31 days  \
+ *         Sep   30 days   |
+ *         Oct   31 days    > Second cycle
+ *         Nov   30 days   |
+ *         Dec   31 days  /
+ *
+ *         Jan   31 days  \
+ *         Feb 28/9 days   |
+ *                          > Third cycle (incomplete)
+ *
+ *     For this reason the calculations (internally) assume that the
+ *     year starts with March 1.
+ *
+ * TESTING
+ *
+ *     This algorithm has been tested from the year 4714 B.C. to 10000
+ *     A.D.  The source code of the verification program is included in
+ *     this package.
+ *
+ * REFERENCES
+ *
+ *     Conversions Between Calendar Date and Julian Day Number by Robert J.
+ *     Tantzen, Communications of the Association for Computing Machinery
+ *     August 1963.  (Also published in Collected Algorithms from CACM,
+ *     algorithm number 199).
+ *
+ **************************************************************************/
+
+#include "dbf_sdncal.h"
+#include <limits.h>
+
+#define GREGOR_SDN_OFFSET         32045
+#define DAYS_PER_5_MONTHS  153
+#define DAYS_PER_4_YEARS   1461
+#define DAYS_PER_400_YEARS 146097
+
+void db_sdn_to_gregorian(
+					   zend_long sdn,
+					   int *pYear,
+					   int *pMonth,
+					   int *pDay)
+{
+	int century;
+	int year;
+	int month;
+	int day;
+	zend_long temp;
+	int dayOfYear;
+
+	if (sdn <= 0 ||
+			sdn > (LONG_MAX - 4 * GREGOR_SDN_OFFSET) / 4) {
+		goto fail;
+	}
+	temp = (sdn + GREGOR_SDN_OFFSET) * 4 - 1;
+
+	/* Calculate the century (year/100). */
+	century = temp / DAYS_PER_400_YEARS;
+
+	/* Calculate the year and day of year (1 <= dayOfYear <= 366). */
+	temp = ((temp % DAYS_PER_400_YEARS) / 4) * 4 + 3;
+	year = (century * 100) + (temp / DAYS_PER_4_YEARS);
+	dayOfYear = (temp % DAYS_PER_4_YEARS) / 4 + 1;
+
+	/* Calculate the month and day of month. */
+	temp = dayOfYear * 5 - 3;
+	month = temp / DAYS_PER_5_MONTHS;
+	day = (temp % DAYS_PER_5_MONTHS) / 5 + 1;
+
+	/* Convert to the normal beginning of the year. */
+	if (month < 10) {
+		month += 3;
+	} else {
+		year += 1;
+		month -= 9;
+	}
+
+	/* Adjust to the B.C./A.D. type numbering. */
+	year -= 4800;
+	if (year <= 0)
+		year--;
+
+	*pYear = year;
+	*pMonth = month;
+	*pDay = day;
+	return;
+
+fail:
+	*pYear = 0;
+	*pMonth = 0;
+	*pDay = 0;
+}
+
+zend_long db_gregorian_to_sdn(
+						   int inputYear,
+						   int inputMonth,
+						   int inputDay)
+{
+	int year;
+	int month;
+
+	/* check for invalid dates */
+	if (inputYear == 0 || inputYear < -4714 ||
+		inputMonth <= 0 || inputMonth > 12 ||
+		inputDay <= 0 || inputDay > 31) {
+		return (0);
+	}
+	/* check for dates before SDN 1 (Nov 25, 4714 B.C.) */
+	if (inputYear == -4714) {
+		if (inputMonth < 11) {
+			return (0);
+		}
+		if (inputMonth == 11 && inputDay < 25) {
+			return (0);
+		}
+	}
+	/* Make year always a positive number. */
+	if (inputYear < 0) {
+		year = inputYear + 4801;
+	} else {
+		year = inputYear + 4800;
+	}
+
+	/* Adjust the start of the year. */
+	if (inputMonth > 2) {
+		month = inputMonth - 3;
+	} else {
+		month = inputMonth + 9;
+		year--;
+	}
+
+	return (((year / 100) * DAYS_PER_400_YEARS) / 4
+			+ ((year % 100) * DAYS_PER_4_YEARS) / 4
+			+ (month * DAYS_PER_5_MONTHS + 2) / 5
+			+ inputDay
+			- GREGOR_SDN_OFFSET);
+}


Property changes on: pecl/dbase/trunk/gregor.c
___________________________________________________________________
Added: svn:keywords
   + Id
Added: svn:eol-style
   + LF

Modified: pecl/dbase/trunk/tests/bug52112.phpt
===================================================================
--- pecl/dbase/trunk/tests/bug52112.phpt	2016-10-30 08:33:55 UTC (rev 340795)
+++ pecl/dbase/trunk/tests/bug52112.phpt	2016-10-30 12:14:01 UTC (rev 340796)
@@ -25,7 +25,7 @@
 ===DONE===
 --EXPECTF--
 resource(%d) of type (dbase)
-array(6) {
+array(7) {
   [0]=>
   int(1)
   [1]=>
@@ -33,19 +33,23 @@
   [2]=>
   string(8) "19840501"
   [3]=>
+  string(18) "19840501000000.000"
+  [4]=>
   int(1)
-  [4]=>
+  [5]=>
   float(123,45)
   ["deleted"]=>
   int(0)
 }
-array(6) {
+array(7) {
   ["ID"]=>
   int(1)
   ["NAME"]=>
   string(25) "dBase III                "
   ["RELEASED"]=>
   string(8) "19840501"
+  ["RELEASED_X"]=>
+  string(18) "19840501000000.000"
   ["SUPORTED"]=>
   int(1)
   ["PRICE"]=>

Modified: pecl/dbase/trunk/tests/dbase_add_record_basic.phpt
===================================================================
--- pecl/dbase/trunk/tests/dbase_add_record_basic.phpt	2016-10-30 08:33:55 UTC (rev \
                340795)
+++ pecl/dbase/trunk/tests/dbase_add_record_basic.phpt	2016-10-30 12:14:01 UTC (rev \
340796) @@ -12,7 +12,7 @@
 $db = dbase_open($filename, DBASE_RDWR);
 var_dump($db);

-var_dump(dbase_add_record($db, array(4, 'JPLDIS', '19730101', 'F', 1234567.89)));
+var_dump(dbase_add_record($db, array(4, 'JPLDIS', '19730101', '19730101104923.123', \
'F', 1234567.89)));

 var_dump(dbase_numrecords($db));
 var_dump(dbase_get_record($db, 4));
@@ -24,7 +24,7 @@
 resource(%d) of type (dbase)
 bool(true)
 int(4)
-array(6) {
+array(7) {
   [0]=>
   int(4)
   [1]=>
@@ -32,8 +32,10 @@
   [2]=>
   string(8) "19730101"
   [3]=>
+  string(18) "19730101104923.123"
+  [4]=>
   int(0)
-  [4]=>
+  [5]=>
   float(1234567.89)
   ["deleted"]=>
   int(0)

Modified: pecl/dbase/trunk/tests/dbase_add_record_error.phpt
===================================================================
--- pecl/dbase/trunk/tests/dbase_add_record_error.phpt	2016-10-30 08:33:55 UTC (rev \
                340795)
+++ pecl/dbase/trunk/tests/dbase_add_record_error.phpt	2016-10-30 12:14:01 UTC (rev \
340796) @@ -23,7 +23,7 @@
 --EXPECTF--
 Argument 2 passed to dbase_add_record() must be of the type array, string given

-Warning: dbase_add_record(): expected 5 fields, but got 0 in %s on line %d
+Warning: dbase_add_record(): expected 6 fields, but got 0 in %s on line %d
 bool(false)
 ===DONE===
 --CLEAN--

Modified: pecl/dbase/trunk/tests/dbase_add_record_variation1.phpt
===================================================================
--- pecl/dbase/trunk/tests/dbase_add_record_variation1.phpt	2016-10-30 08:33:55 UTC \
                (rev 340795)
+++ pecl/dbase/trunk/tests/dbase_add_record_variation1.phpt	2016-10-30 12:14:01 UTC \
(rev 340796) @@ -16,7 +16,7 @@
 var_dump($record);

 unset($record['deleted']);
-$record[3] = $record[3] ? 'T' : 'F'; // we have to cater to bool fields ourselves
+$record[4] = $record[4] ? 'T' : 'F'; // we have to cater to bool fields ourselves
 var_dump(dbase_add_record($db, $record));

 var_dump(dbase_get_record($db, 4));
@@ -26,7 +26,7 @@
 ===DONE===
 --EXPECTF--
 resource(%d) of type (dbase)
-array(6) {
+array(7) {
   [0]=>
   int(1)
   [1]=>
@@ -34,14 +34,16 @@
   [2]=>
   string(8) "19840501"
   [3]=>
+  string(18) "19840501000000.000"
+  [4]=>
   int(1)
-  [4]=>
+  [5]=>
   float(123.45)
   ["deleted"]=>
   int(0)
 }
 bool(true)
-array(6) {
+array(7) {
   [0]=>
   int(1)
   [1]=>
@@ -49,8 +51,10 @@
   [2]=>
   string(8) "19840501"
   [3]=>
+  string(18) "19840501000000.000"
+  [4]=>
   int(1)
-  [4]=>
+  [5]=>
   float(123.45)
   ["deleted"]=>
   int(0)

Modified: pecl/dbase/trunk/tests/dbase_add_record_variation2.phpt
===================================================================
--- pecl/dbase/trunk/tests/dbase_add_record_variation2.phpt	2016-10-30 08:33:55 UTC \
                (rev 340795)
+++ pecl/dbase/trunk/tests/dbase_add_record_variation2.phpt	2016-10-30 12:14:01 UTC \
(rev 340796) @@ -27,13 +27,15 @@
 ===DONE===
 --EXPECTF--
 resource(%d) of type (dbase)
-array(6) {
+array(7) {
   ["ID"]=>
   int(1)
   ["NAME"]=>
   string(25) "dBase III                "
   ["RELEASED"]=>
   string(8) "19840501"
+  ["RELEASED_X"]=>
+  string(18) "19840501000000.000"
   ["SUPORTED"]=>
   int(1)
   ["PRICE"]=>
@@ -42,13 +44,15 @@
   int(0)
 }
 bool(true)
-array(6) {
+array(7) {
   ["ID"]=>
   int(1)
   ["NAME"]=>
   string(25) "dBase III                "
   ["RELEASED"]=>
   string(8) "19840501"
+  ["RELEASED_X"]=>
+  string(18) "19840501000000.000"
   ["SUPORTED"]=>
   int(1)
   ["PRICE"]=>

Modified: pecl/dbase/trunk/tests/dbase_add_record_variation3.phpt
===================================================================
--- pecl/dbase/trunk/tests/dbase_add_record_variation3.phpt	2016-10-30 08:33:55 UTC \
                (rev 340795)
+++ pecl/dbase/trunk/tests/dbase_add_record_variation3.phpt	2016-10-30 12:14:01 UTC \
(rev 340796) @@ -11,7 +11,7 @@
 $filename = __DIR__ . DIRECTORY_SEPARATOR . 'dbase_add_record_variation3.dbf';
 copy(__DIR__ . DIRECTORY_SEPARATOR . 'example.dbf', $filename);
 $db = dbase_open($filename, 2);
-dbase_add_record($db, array(4711, 'foo', '20161028', 'F', 1.23));
+dbase_add_record($db, array(4711, 'foo', '20161028', '20161028123456.789', 'F', \
1.23));  dbase_close($db);
 $date = getdate();
 $result = unpack('C4byte', file_get_contents($filename));

Modified: pecl/dbase/trunk/tests/dbase_delete_record_basic.phpt
===================================================================
--- pecl/dbase/trunk/tests/dbase_delete_record_basic.phpt	2016-10-30 08:33:55 UTC \
                (rev 340795)
+++ pecl/dbase/trunk/tests/dbase_delete_record_basic.phpt	2016-10-30 12:14:01 UTC \
(rev 340796) @@ -24,7 +24,7 @@
 resource(%d) of type (dbase)
 bool(true)
 int(3)
-array(6) {
+array(7) {
   [0]=>
   int(2)
   [1]=>
@@ -32,8 +32,10 @@
   [2]=>
   string(8) "19850525"
   [3]=>
+  string(18) "19850525120000.000"
+  [4]=>
   int(0)
-  [4]=>
+  [5]=>
   float(56.78)
   ["deleted"]=>
   int(1)

Modified: pecl/dbase/trunk/tests/dbase_get_header_info_basic.phpt
===================================================================
--- pecl/dbase/trunk/tests/dbase_get_header_info_basic.phpt	2016-10-30 08:33:55 UTC \
                (rev 340795)
+++ pecl/dbase/trunk/tests/dbase_get_header_info_basic.phpt	2016-10-30 12:14:01 UTC \
(rev 340796) @@ -19,7 +19,7 @@
 ===DONE===
 --EXPECTF--
 resource(%d) of type (dbase)
-array(5) {
+array(6) {
   [0]=>
   array(6) {
     ["name"]=>
@@ -68,6 +68,21 @@
   [3]=>
   array(6) {
     ["name"]=>
+    string(10) "RELEASED_X"
+    ["type"]=>
+    string(8) "datetime"
+    ["length"]=>
+    int(8)
+    ["precision"]=>
+    int(0)
+    ["format"]=>
+    string(0) ""
+    ["offset"]=>
+    int(39)
+  }
+  [4]=>
+  array(6) {
+    ["name"]=>
     string(8) "SUPORTED"
     ["type"]=>
     string(7) "boolean"
@@ -78,9 +93,9 @@
     ["format"]=>
     string(3) "%1s"
     ["offset"]=>
-    int(39)
+    int(47)
   }
-  [4]=>
+  [5]=>
   array(6) {
     ["name"]=>
     string(5) "PRICE"
@@ -93,7 +108,7 @@
     ["format"]=>
     string(4) "%10s"
     ["offset"]=>
-    int(40)
+    int(48)
   }
 }
 bool(true)

Modified: pecl/dbase/trunk/tests/dbase_get_record_basic.phpt
===================================================================
--- pecl/dbase/trunk/tests/dbase_get_record_basic.phpt	2016-10-30 08:33:55 UTC (rev \
                340795)
+++ pecl/dbase/trunk/tests/dbase_get_record_basic.phpt	2016-10-30 12:14:01 UTC (rev \
340796) @@ -19,7 +19,7 @@
 ===DONE===
 --EXPECTF--
 resource(%d) of type (dbase)
-array(6) {
+array(7) {
   [0]=>
   int(3)
   [1]=>
@@ -27,8 +27,10 @@
   [2]=>
   string(8) "20010627"
   [3]=>
+  string(18) "20010627235959.999"
+  [4]=>
   int(0)
-  [4]=>
+  [5]=>
   float(0.9)
   ["deleted"]=>
   int(0)

Modified: pecl/dbase/trunk/tests/dbase_get_record_with_names_basic.phpt
===================================================================
--- pecl/dbase/trunk/tests/dbase_get_record_with_names_basic.phpt	2016-10-30 08:33:55 \
                UTC (rev 340795)
+++ pecl/dbase/trunk/tests/dbase_get_record_with_names_basic.phpt	2016-10-30 12:14:01 \
UTC (rev 340796) @@ -19,13 +19,15 @@
 ===DONE===
 --EXPECTF--
 resource(%d) of type (dbase)
-array(6) {
+array(7) {
   ["ID"]=>
   int(1)
   ["NAME"]=>
   string(25) "dBase III                "
   ["RELEASED"]=>
   string(8) "19840501"
+  ["RELEASED_X"]=>
+  string(18) "19840501000000.000"
   ["SUPORTED"]=>
   int(1)
   ["PRICE"]=>

Modified: pecl/dbase/trunk/tests/dbase_numfields_basic.phpt
===================================================================
--- pecl/dbase/trunk/tests/dbase_numfields_basic.phpt	2016-10-30 08:33:55 UTC (rev \
                340795)
+++ pecl/dbase/trunk/tests/dbase_numfields_basic.phpt	2016-10-30 12:14:01 UTC (rev \
340796) @@ -19,7 +19,7 @@
 ===DONE===
 --EXPECTF--
 resource(%d) of type (dbase)
-int(5)
+int(6)
 bool(true)
 ===DONE===
 --CLEAN--

Modified: pecl/dbase/trunk/tests/dbase_pack_basic.phpt
===================================================================
--- pecl/dbase/trunk/tests/dbase_pack_basic.phpt	2016-10-30 08:33:55 UTC (rev 340795)
+++ pecl/dbase/trunk/tests/dbase_pack_basic.phpt	2016-10-30 12:14:01 UTC (rev 340796)
@@ -26,7 +26,7 @@
 bool(true)
 bool(true)
 int(2)
-array(6) {
+array(7) {
   [0]=>
   int(3)
   [1]=>
@@ -34,8 +34,10 @@
   [2]=>
   string(8) "20010627"
   [3]=>
+  string(18) "20010627235959.999"
+  [4]=>
   int(0)
-  [4]=>
+  [5]=>
   float(0.9)
   ["deleted"]=>
   int(0)

Modified: pecl/dbase/trunk/tests/dbase_replace_record_basic.phpt
===================================================================
--- pecl/dbase/trunk/tests/dbase_replace_record_basic.phpt	2016-10-30 08:33:55 UTC \
                (rev 340795)
+++ pecl/dbase/trunk/tests/dbase_replace_record_basic.phpt	2016-10-30 12:14:01 UTC \
(rev 340796) @@ -12,7 +12,7 @@
 $db = dbase_open($filename, DBASE_RDWR);
 var_dump($db);

-var_dump(dbase_replace_record($db, array(4, 'JPLDIS', '19730101', 'F', 1234567.89), \
2)); +var_dump(dbase_replace_record($db, array(4, 'JPLDIS', '19730101', \
'19730101123456.789', 'F', 1234567.89), 2));

 var_dump(dbase_numrecords($db));
 var_dump(dbase_get_record($db, 2));
@@ -24,7 +24,7 @@
 resource(%d) of type (dbase)
 bool(true)
 int(3)
-array(6) {
+array(7) {
   [0]=>
   int(4)
   [1]=>
@@ -32,8 +32,10 @@
   [2]=>
   string(8) "19730101"
   [3]=>
+  string(18) "19730101123456.789"
+  [4]=>
   int(0)
-  [4]=>
+  [5]=>
   float(1234567.89)
   ["deleted"]=>
   int(0)

Modified: pecl/dbase/trunk/tests/dbase_replace_record_error.phpt
===================================================================
--- pecl/dbase/trunk/tests/dbase_replace_record_error.phpt	2016-10-30 08:33:55 UTC \
                (rev 340795)
+++ pecl/dbase/trunk/tests/dbase_replace_record_error.phpt	2016-10-30 12:14:01 UTC \
(rev 340796) @@ -23,7 +23,7 @@
 --EXPECTF--
 Argument 2 passed to dbase_replace_record() must be of the type array, string given

-Warning: dbase_replace_record(): expected 5 fields, but got 0 in %s on line %d
+Warning: dbase_replace_record(): expected 6 fields, but got 0 in %s on line %d
 bool(false)
 ===DONE===
 --CLEAN--

Modified: pecl/dbase/trunk/tests/dbase_replace_record_variation1.phpt
===================================================================
--- pecl/dbase/trunk/tests/dbase_replace_record_variation1.phpt	2016-10-30 08:33:55 \
                UTC (rev 340795)
+++ pecl/dbase/trunk/tests/dbase_replace_record_variation1.phpt	2016-10-30 12:14:01 \
UTC (rev 340796) @@ -16,8 +16,8 @@
 var_dump($record);

 unset($record['deleted']);
-$record[3] = $record[3] ? 'T' : 'F'; // we have to cater to bool fields ourselves
-$record[4] = 12.34;
+$record[4] = $record[4] ? 'T' : 'F'; // we have to cater to bool fields ourselves
+$record[5] = 12.34;
 var_dump(dbase_replace_record($db, $record, 1));

 var_dump(dbase_get_record($db, 1));
@@ -27,7 +27,7 @@
 ===DONE===
 --EXPECTF--
 resource(%d) of type (dbase)
-array(6) {
+array(7) {
   [0]=>
   int(1)
   [1]=>
@@ -35,14 +35,16 @@
   [2]=>
   string(8) "19840501"
   [3]=>
+  string(18) "19840501000000.000"
+  [4]=>
   int(1)
-  [4]=>
+  [5]=>
   float(123.45)
   ["deleted"]=>
   int(0)
 }
 bool(true)
-array(6) {
+array(7) {
   [0]=>
   int(1)
   [1]=>
@@ -50,8 +52,10 @@
   [2]=>
   string(8) "19840501"
   [3]=>
+  string(18) "19840501000000.000"
+  [4]=>
   int(1)
-  [4]=>
+  [5]=>
   float(12.34)
   ["deleted"]=>
   int(0)

Modified: pecl/dbase/trunk/tests/dbase_replace_record_variation2.phpt
===================================================================
--- pecl/dbase/trunk/tests/dbase_replace_record_variation2.phpt	2016-10-30 08:33:55 \
                UTC (rev 340795)
+++ pecl/dbase/trunk/tests/dbase_replace_record_variation2.phpt	2016-10-30 12:14:01 \
UTC (rev 340796) @@ -28,13 +28,15 @@
 ===DONE===
 --EXPECTF--
 resource(%d) of type (dbase)
-array(6) {
+array(7) {
   ["ID"]=>
   int(1)
   ["NAME"]=>
   string(25) "dBase III                "
   ["RELEASED"]=>
   string(8) "19840501"
+  ["RELEASED_X"]=>
+  string(18) "19840501000000.000"
   ["SUPORTED"]=>
   int(1)
   ["PRICE"]=>
@@ -43,13 +45,15 @@
   int(0)
 }
 bool(true)
-array(6) {
+array(7) {
   ["ID"]=>
   int(1)
   ["NAME"]=>
   string(25) "dBase III                "
   ["RELEASED"]=>
   string(8) "19840501"
+  ["RELEASED_X"]=>
+  string(18) "19840501000000.000"
   ["SUPORTED"]=>
   int(1)
   ["PRICE"]=>

Modified: pecl/dbase/trunk/tests/dbase_replace_record_variation3.phpt
===================================================================
--- pecl/dbase/trunk/tests/dbase_replace_record_variation3.phpt	2016-10-30 08:33:55 \
                UTC (rev 340795)
+++ pecl/dbase/trunk/tests/dbase_replace_record_variation3.phpt	2016-10-30 12:14:01 \
UTC (rev 340796) @@ -11,7 +11,7 @@
 $filename = __DIR__ . DIRECTORY_SEPARATOR . 'dbase_replace_record_variation3.dbf';
 copy(__DIR__ . DIRECTORY_SEPARATOR . 'example.dbf', $filename);
 $db = dbase_open($filename, 2);
-dbase_replace_record($db, array(4711, 'foo', '20161028', 'F', 1.23), 1);
+dbase_replace_record($db, array(4711, 'foo', '20161028', '20161028123456.789', 'F', \
1.23), 1);  dbase_close($db);
 $date = getdate();
 $result = unpack('C4byte', file_get_contents($filename));

Modified: pecl/dbase/trunk/tests/example.dbf
===================================================================
(Binary files differ)

Modified: pecl/dbase/trunk/tests/example.php
===================================================================
--- pecl/dbase/trunk/tests/example.php	2016-10-30 08:33:55 UTC (rev 340795)
+++ pecl/dbase/trunk/tests/example.php	2016-10-30 12:14:01 UTC (rev 340796)
@@ -8,15 +8,16 @@
     array('ID', 'N', 5, 0),
     array('NAME', 'C', 25),
     array('RELEASED', 'D'),
+    array('RELEASED_X', 'T'),
     array('SUPORTED', 'L'),
     array('PRICE', 'N', 10, 2)
 );
 $db = dbase_create($filename, $definition);

 $records = array(
-    array(1, 'dBase III', '19840501', 'T', 123.45),
-    array(2, 'Clipper', '19850525', 'F', 56.78),
-    array(3, 'Visual FoxPro 7.0', '20010627', 'F', 0.90)
+    array(1, 'dBase III', '19840501', '19840501000000.000', 'T', 123.45),
+    array(2, 'Clipper', '19850525', '1985052512000000.000', 'F', 56.78),
+    array(3, 'Visual FoxPro 7.0', '20010627', '20010627235959.999', 'F', 0.90)
 );
 foreach ($records as $record) {
     dbase_add_record($db, $record);

Added: pecl/dbase/trunk/tests/type_datetime.phpt
===================================================================
--- pecl/dbase/trunk/tests/type_datetime.phpt	                        (rev 0)
+++ pecl/dbase/trunk/tests/type_datetime.phpt	2016-10-30 12:14:01 UTC (rev 340796)
@@ -0,0 +1,72 @@
+--TEST--
+Reading and writing of datetime values
+--SKIPIF--
+<?php
+if (!extension_loaded('dbase')) die('skip dbase extension not available');
+?>
+--FILE--
+<?php
+$db = dbase_create(
+    __DIR__ . DIRECTORY_SEPARATOR . 'type_datetime.dbf',
+    array(
+        array('datetime', 'T')
+    )
+);
+
+$values = array(
+    // good values
+    '00010101000000.000', // minimum
+    '15821015120000.000', // gregorian calendar
+    '19690324101000.000', // author's birthday
+    '19950608090000.000', // PHP's birthday
+    '19991231235959.999', // millenium - 1msec
+    '20000101000000.000', // millenium
+    '20630405111500.000', // Bozeman, Montana
+    '45670123123456.789', // all digits
+    '99991231235959.999',  // maximum
+
+    // bad values - will be silently accepted, but produce garbage
+    '00000000000000.000',
+    '99999999999999.999',
+);
+
+foreach ($values as $value) {
+    dbase_add_record($db, array($value));
+}
+
+for ($i = 1; $i <= dbase_numrecords($db); $i++) {
+    var_dump(
+        dbase_get_record($db, $i)[0],
+        dbase_get_record_with_names($db, $i)['datetime']
+    );
+}
+?>
+===DONE===
+--EXPECT--
+string(18) "00010101000000.000"
+string(18) "00010101000000.000"
+string(18) "15821015120000.000"
+string(18) "15821015120000.000"
+string(18) "19690324101000.000"
+string(18) "19690324101000.000"
+string(18) "19950608090000.000"
+string(18) "19950608090000.000"
+string(18) "19991231235959.999"
+string(18) "19991231235959.999"
+string(18) "20000101000000.000"
+string(18) "20000101000000.000"
+string(18) "20630405111500.000"
+string(18) "20630405111500.000"
+string(18) "45670123123456.789"
+string(18) "45670123123456.789"
+string(18) "99991231235959.999"
+string(18) "99991231235959.999"
+string(18) "00000000000000.000"
+string(18) "00000000000000.000"
+string(18) "000000001004039.99"
+string(18) "000000001004039.99"
+===DONE===
+--CLEAN--
+<?php
+unlink(__DIR__ . DIRECTORY_SEPARATOR . 'type_datetime.dbf');
+?>



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

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic