From dbf06dbf189fa86ef33d88c9c5415ba6e9ca0460 Mon Sep 17 00:00:00 2001 From: David Puglielli Date: Mon, 26 Feb 2018 14:24:25 -0800 Subject: [PATCH 01/10] New test for returning dates as strings --- .../sqlsrv_ae_datetimes_as_strings.phpt | 595 ++++++++++++++++++ 1 file changed, 595 insertions(+) create mode 100644 test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt diff --git a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt new file mode 100644 index 00000000..8168d385 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt @@ -0,0 +1,595 @@ +--TEST-- +Test various date and time types with AE and ReturnDatesAsStrings set to true +--SKIPIF-- + +--FILE-- +1) { + $datetimeonly = $ret_date_time[0]." ".$ret_date_time[1]; + } + if (sizeof($ret_date_time)>2) { + $timezone = $ret_date_time[2]; + $dtoffset = $ret_date_time[0]." ".substr($ret_date_time[1], 0, -1)." ".$ret_date_time[2]; + } + + if ($returnStrings == true) { + switch ($datetimetype) { + case 'date': + if ($retrievedDate != $test_date_time[0][0]) { + fatalError("Dates do not match!"); + } + break; + case 'time': + if ($retrievedDate != $test_date_time[0][1]."0" and + $retrievedDate != $test_date_time[1][1]."0" and + $retrievedDate != $test_date_time[2][1]."0" and + $retrievedDate != $test_date_time[3][1]."0" ) { + fatalError("Times do not match!"); + } + break; + case 'datetime': + if ($retrievedDate."000" != $testingDate[0] and + $retrievedDate."000" != $testingDate[1] and + $retrievedDate."000" != $testingDate[2] and + $retrievedDate."000" != $testingDate[3] ) { + fatalError("Datetimes do not match!"); + } + break; + case 'datetime2': + if ($retrievedDate != $testingDate[0]."0" and + $retrievedDate != $testingDate[1]."0" and + $retrievedDate != $testingDate[2]."0" and + $retrievedDate != $testingDate[3]."0" ) { + fatalError("Datetime2s do not match!"); + } + break; + case 'datetimeoffset': + if ($dtoffset != $testingDate[4] and + $dtoffset != $testingDate[5] and + $dtoffset != $testingDate[6] and + $dtoffset != $testingDate[7] ) { + fatalError("Datetimeoffsets do not match!"); + } + break; + case 'smalldatetime': + if ($retrievedDate.".000000" != $testingDate[0] and + $retrievedDate.".000000" != $testingDate[1] and + $retrievedDate.".000000" != $testingDate[2] and + $retrievedDate.".000000" != $testingDate[3] ) { + fatalError("Smalldatetimes do not match!"); + } + break; + } + } + else { + switch ($datetimetype) { + case 'date': + if ($ret_date_time[0] != $test_date_time[0][0]) { + fatalError("Dates do not match!"); + } + break; + case 'time': + if ($ret_date_time[1] != $test_date_time[0][1] and + $ret_date_time[1] != $test_date_time[1][1] and + $ret_date_time[1] != $test_date_time[2][1] and + $ret_date_time[1] != $test_date_time[3][1] ) { + fatalError("Times do not match!"); + } + break; + case 'datetime': + if ($datetimeonly != $testingDate[0] and + $datetimeonly != $testingDate[1] and + $datetimeonly != $testingDate[2] and + $datetimeonly != $testingDate[3] ) { + fatalError("Datetimes do not match!"); + } + break; + case 'datetime2': + if ($datetimeonly != $testingDate[0] and + $datetimeonly != $testingDate[1] and + $datetimeonly != $testingDate[2] and + $datetimeonly != $testingDate[3] ) { + fatalError("Datetime2s do not match!"); + } + break; + case 'datetimeoffset': + if ($retrievedDate != $testingDate[4] and + $retrievedDate != $testingDate[5] and + $retrievedDate != $testingDate[6] and + $retrievedDate != $testingDate[7] ) { + fatalError("Datetimeoffsets do not match!"); + } + break; + case 'smalldatetime': + if ($datetimeonly != $testingDate[0] and + $datetimeonly != $testingDate[1] and + $datetimeonly != $testingDate[2] and + $datetimeonly != $testingDate[3] ) { + fatalError("Smalldatetimes do not match!"); + } + break; + } + } +} + +function InsertDatesAndOrTimes($conn, $datetimetype, &$formats_array, $array_size, $SQLSRV_SQLTYPE_CONST) +{ + $tableName = "table_of_$datetimetype"; + $columns = array(new AE\ColumnMeta('int', 'id'), + new AE\ColumnMeta("$datetimetype", "c1_$datetimetype")); + $stmt = AE\createTable($conn, $tableName, $columns); + if (!$stmt) { + fatalError("Failed to create table $tableName\n"); + } + + $insertSql = "INSERT INTO [$tableName] (id, [c1_$datetimetype]) VALUES (?, ?)"; + for ($i=0; $i<$array_size; $i++) + { + $stmt = sqlsrv_prepare($conn, $insertSql, array($i, array($formats_array[$i], SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), $SQLSRV_SQLTYPE_CONST))); + ExecutePreparedStmt($stmt); + $stmt = sqlsrv_prepare($conn, $insertSql, array($i, $formats_array[$i])); + ExecutePreparedStmt($stmt); + + // date_create can fail if the argument is not a format PHP recognises; + // this is not a problem for this test. + if (date_create($formats_array[$i]) != false) { + $stmt = sqlsrv_prepare($conn, $insertSql, array($i, array(date_create($formats_array[$i]), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), $SQLSRV_SQLTYPE_CONST))); + ExecutePreparedStmt($stmt); + $stmt = sqlsrv_prepare($conn, $insertSql, array($i, date_create($formats_array[$i]))); + ExecutePreparedStmt($stmt); + } + } +} + +function FetchDatesAndOrTimes($conn, $datetimetype, &$testingDate, $returnDatesAsStrings) +{ + $tableName = "table_of_$datetimetype"; + + echo "Select fields as strings:\n"; + + $stmt = sqlsrv_query($conn, "SELECT * FROM [$tableName]"); + if ($stmt === false) { + fatalError("Select from $tableName failed"); + } + + while (sqlsrv_fetch($stmt)) { + $idnum = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR)); + $datetime = sqlsrv_get_field($stmt, 1, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR)); + + if (!is_string($datetime)) { + fatalError("sqlsrv_get_field did not return string but string was specified"); + } + + CompareDateTime($datetimetype, true, $testingDate, $datetime); + } + + // retrieve date time fields as DateTime objects + echo "Select fields as DateTime objects:\n"; + + $stmt = sqlsrv_query($conn, "SELECT * FROM [$tableName]"); + if ($stmt === false) { + fatalError("Select from $tableName failed"); + } + + while (sqlsrv_fetch($stmt)) { + $idnum = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR)); + $datetime = sqlsrv_get_field($stmt, 1, SQLSRV_PHPTYPE_DATETIME); + + if (!($datetime instanceof DateTime)) { + fatalError("sqlsrv_get_field did not return DateTime but DateTime was specified"); + } + + $datetime = ($datetimetype == 'datetimeoffset') ? date_format($datetime, 'Y-m-d H:i:s.u P') : date_format($datetime, 'Y-m-d H:i:s.u'); + + CompareDateTime($datetimetype, false, $testingDate, $datetime); + } + + // retrieve date time fields without explicitly requesting the type + echo "Select fields with no type information provided:\n"; + + $stmt = sqlsrv_query($conn, "SELECT * FROM [$tableName]"); + if ($stmt === false) { + fatalError("Select from $tableName failed"); + } + + while (sqlsrv_fetch($stmt)) { + $idnum = sqlsrv_get_field($stmt, 0); + $datetime = sqlsrv_get_field($stmt, 1); + + if ($returnDatesAsStrings == true) { + if (!is_string($datetime)) { + fatalError("String for date expected, not a string"); + } + + CompareDateTime($datetimetype, $returnDatesAsStrings, $testingDate, $datetime); + } + else { // ReturnsDatesAsStrings is false + if (!($datetime instanceof DateTime)) { + fatalError("DateTime object expected, not a DateTime"); + } + + $datetime = ($datetimetype == 'datetimeoffset') ? date_format($datetime, 'Y-m-d H:i:s.u P') : date_format($datetime, 'Y-m-d H:i:s.u'); + + CompareDateTime($datetimetype, $returnDatesAsStrings, $testingDate, $datetime); + } + } + + // retrieve date time fields as default + echo "Select using fetch_array:\n"; + + $stmt = sqlsrv_query($conn, "SELECT * FROM [$tableName]"); + if ($stmt === false) { + fatalError("Select from $tableName failed"); + } + + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_NUMERIC)) { + $idnum = $row[0]; + + if ($returnDatesAsStrings == true) { + if (!is_string($row[1])) { + fatalError("String for date expected, not a string"); + } + + CompareDateTime($datetimetype, $returnDatesAsStrings, $testingDate, $row[1]); + } + else { + if (!($row[1] instanceof DateTime)) { + fatalError("DateTime object expected, not a DateTime"); + } + + $datetime = ($datetimetype == 'datetimeoffset') ? date_format($row[1], 'Y-m-d H:i:s.u P') : date_format($row[1], 'Y-m-d H:i:s.u'); + + CompareDateTime($datetimetype, $returnDatesAsStrings, $testingDate, $datetime); + } + } + + print_r(sqlsrv_field_metadata($stmt)[1]); + +} + +// The date used for the test will be Januray 31, 2002, or 2002/01/31. +// This will sidestep issues involving the use of two digit years since +// SQL Server defaults to 19 as the first two digits. +// Time is 23:59:29.049876 +// Note that smalldatetime rounds to the nearest minute, and that may cause +// this test to fail if it rolls over to the next day. +// Incidentally, this datetime corresponds to a timestamp of 1012521599. +$year = '2002'; +$month = '01'; +$month_name = 'January'; +$month_abbr = 'Jan'; +$day = '31'; +$hour = '23'; +$hour12 = '11'; +$meridian = 'PM'; +$minute = '59'; +$second = '29'; +$frac = '04'; +$frac2 = '9876'; +$tz_correction = '+08:00'; + +$testingDate = array($year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."0000", + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000", + $year."-".$month."-".$day." ".$hour.":".$minute.":00.000000", + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2." ".$tz_correction, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."0000 ".$tz_correction, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000 ".$tz_correction, + $year."-".$month."-".$day." ".$hour.":".$minute.":00.000000 ".$tz_correction, + ); + +// These formats are for the ODBC driver with types specified in sqlsrv_prepare() +$date_formats = array($year."-".$month."-".$day + ); +$time_formats = array($hour.":".$minute.":".$second, + $hour.":".$minute.":".$second.".".$frac, + $hour.":".$minute.":".$second.".".$frac.$frac2 + ); + +// These formats are not accepted by either the ODBC driver or by PHP, but +// can possibly be wrangled in sqlsrv_prepare() using strings instead of +// the dedicated date and time types. +$date_formats_nonODBC = array($year."/".$month."/".$day, + $month."/".$day."/".$year, + $month."-".$day."-".$year, + $day."/".$month."/".$year, + $day."-".$month."-".$year, + $month_name." ".$day.", ".$year, + $day."-".$month_name."-".$year, + $day."-".$month_abbr."-".$year + ); +$time_formats_nonODBC = array($hour12.":".$minute." ".$meridian, + $hour12.":".$minute.":".$second." ".$meridian, + $hour12.":".$minute.":".$second.".".$frac." ".$meridian, + $hour12.":".$minute.":".$second.".".$frac.$frac2." ".$meridian, + $hour.":".$minute + ); + +// Create arrays containing the ODBC-standard formats, and larger arrays +// containing the non-standard formats, for the supported SQL Server +// date and time types. +$date_formats_all = array_merge($date_formats, $date_formats_nonODBC); +$time_formats_all = array_merge($time_formats, $time_formats_nonODBC); + +$datetime_formats_all = array(); +$datetime2_formats_all = array(); +$datetimeoffset_formats_all = array(); +$datetimesmall_formats_all = array(); + +$SZ_TIME_all = sizeof($time_formats_all); +$SZ_DATE_all = sizeof($date_formats_all); +$SZ_DATETIME_all = $SZ_TIME_all*$SZ_DATE_all; + +// Create compound date/time types. For datetime, remove the extra precision +// of $frac2. For smalldatetime, remove the extra precision of $frac and $frac2. +// If the data in $frac and/or $frac2 is found elsewhere in the date/time, the +// data will be garbled. For example, if the year is 2002 and $frac2 is 2002, +// the code below will remove any instances of '2002' in the datetime and +// smalldatetime strings, producing garbage for those types. User must be +// cognizant of this when testing different dates and times. +for ($i=0; $i<$SZ_DATE_all; $i++) +{ + for ($j=0; $j<$SZ_TIME_all; $j++) + { + $datetime_formats_all[] = str_replace($frac2, "", $date_formats_all[$i]." ".$time_formats_all[$j]); + $datetime2_formats_all[] = $date_formats_all[$i]." ".$time_formats_all[$j]; + $datetimeoffset_formats_all[] = $date_formats_all[$i]." ".$time_formats_all[$j].$tz_correction; + if (str_replace(".".$frac.$frac2, "", $date_formats_all[$i]." ".$time_formats_all[$j]) == ($date_formats_all[$i]." ".$time_formats_all[$j])) { + $datetimesmall_formats_all[] = str_replace(".".$frac, "", $date_formats_all[$i]." ".$time_formats_all[$j]); + } + else { + $datetimesmall_formats_all[] = str_replace(".".$frac.$frac2, "", $date_formats_all[$i]." ".$time_formats_all[$j]); + } + } +} + +date_default_timezone_set('Canada/Pacific'); +sqlsrv_configure('WarningsReturnAsErrors', 0); +sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL); +sqlsrv_configure('LogSubsystems', SQLSRV_LOG_SYSTEM_OFF); + +require_once('MsCommon.inc'); + +$returnDatesAsStrings = true; + +$conn = AE\connect(array('ReturnDatesAsStrings' => $returnDatesAsStrings)); + +InsertDatesAndOrTimes($conn, 'date', $date_formats_all, $SZ_DATE_all, SQLSRV_SQLTYPE_DATE); +InsertDatesAndOrTimes($conn, 'time', $time_formats_all, $SZ_TIME_all, SQLSRV_SQLTYPE_TIME); +InsertDatesAndOrTimes($conn, 'datetime', $datetime_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIME); +InsertDatesAndOrTimes($conn, 'datetime2', $datetime2_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIME2); +InsertDatesAndOrTimes($conn, 'datetimeoffset', $datetimeoffset_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIMEOFFSET); +InsertDatesAndOrTimes($conn, 'smalldatetime', $datetimesmall_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_SMALLDATETIME); + +FetchDatesAndOrTimes($conn, 'date', $testingDate, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'time', $testingDate, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetime', $testingDate, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetime2', $testingDate, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetimeoffset', $testingDate, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'smalldatetime', $testingDate, $returnDatesAsStrings); + +sqlsrv_close($conn); + +$returnDatesAsStrings = false; + +$conn = AE\connect(array('ReturnDatesAsStrings' => $returnDatesAsStrings)); + +InsertDatesAndOrTimes($conn, 'date', $date_formats_all, $SZ_DATE_all, SQLSRV_SQLTYPE_DATE); +InsertDatesAndOrTimes($conn, 'time', $time_formats_all, $SZ_TIME_all, SQLSRV_SQLTYPE_TIME); +InsertDatesAndOrTimes($conn, 'datetime', $datetime_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIME); +InsertDatesAndOrTimes($conn, 'datetime2', $datetime2_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIME2); +InsertDatesAndOrTimes($conn, 'datetimeoffset', $datetimeoffset_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIMEOFFSET); +InsertDatesAndOrTimes($conn, 'smalldatetime', $datetimesmall_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_SMALLDATETIME); + +FetchDatesAndOrTimes($conn, 'date', $testingDate, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'time', $testingDate, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetime', $testingDate, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetime2', $testingDate, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetimeoffset', $testingDate, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'smalldatetime', $testingDate, $returnDatesAsStrings); + +sqlsrv_close($conn); + +?> +--EXPECT-- +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Array +( + [Name] => c1_date + [Type] => 91 + [Size] => + [Precision] => 10 + [Scale] => 0 + [Nullable] => 1 +) +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Array +( + [Name] => c1_time + [Type] => -154 + [Size] => + [Precision] => 16 + [Scale] => 7 + [Nullable] => 1 +) +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Array +( + [Name] => c1_datetime + [Type] => 93 + [Size] => + [Precision] => 23 + [Scale] => 3 + [Nullable] => 1 +) +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Array +( + [Name] => c1_datetime2 + [Type] => 93 + [Size] => + [Precision] => 27 + [Scale] => 7 + [Nullable] => 1 +) +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Array +( + [Name] => c1_datetimeoffset + [Type] => -155 + [Size] => + [Precision] => 34 + [Scale] => 7 + [Nullable] => 1 +) +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Array +( + [Name] => c1_smalldatetime + [Type] => 93 + [Size] => + [Precision] => 16 + [Scale] => 0 + [Nullable] => 1 +) +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Array +( + [Name] => c1_date + [Type] => 91 + [Size] => + [Precision] => 10 + [Scale] => 0 + [Nullable] => 1 +) +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Array +( + [Name] => c1_time + [Type] => -154 + [Size] => + [Precision] => 16 + [Scale] => 7 + [Nullable] => 1 +) +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Array +( + [Name] => c1_datetime + [Type] => 93 + [Size] => + [Precision] => 23 + [Scale] => 3 + [Nullable] => 1 +) +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Array +( + [Name] => c1_datetime2 + [Type] => 93 + [Size] => + [Precision] => 27 + [Scale] => 7 + [Nullable] => 1 +) +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Array +( + [Name] => c1_datetimeoffset + [Type] => -155 + [Size] => + [Precision] => 34 + [Scale] => 7 + [Nullable] => 1 +) +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Array +( + [Name] => c1_smalldatetime + [Type] => 93 + [Size] => + [Precision] => 16 + [Scale] => 0 + [Nullable] => 1 +) \ No newline at end of file From 4866b9c75ed36b2c4a54ca8649f7a20ffa39bebd Mon Sep 17 00:00:00 2001 From: David Puglielli Date: Wed, 14 Mar 2018 12:54:24 -0700 Subject: [PATCH 02/10] updated datetime test --- .../sqlsrv_ae_datetimes_as_strings.phpt | 286 ++++++++++-------- 1 file changed, 159 insertions(+), 127 deletions(-) diff --git a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt index 8168d385..b39d580f 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt @@ -4,8 +4,14 @@ Test various date and time types with AE and ReturnDatesAsStrings set to true --FILE-- 1) { - $datetimeonly = $ret_date_time[0]." ".$ret_date_time[1]; - } - if (sizeof($ret_date_time)>2) { - $timezone = $ret_date_time[2]; - $dtoffset = $ret_date_time[0]." ".substr($ret_date_time[1], 0, -1)." ".$ret_date_time[2]; - } + // If $retrievedDateTime is a string of format 'Y-m-d H:i:s.u' or 'Y-m-d H:i:s.u P', + // split it into [0]:date, [1]:time, and possibly [2]:timezone offset + $retrieved_date_time = explode(" ", $retrievedDateTime); if ($returnStrings == true) { switch ($datetimetype) { case 'date': - if ($retrievedDate != $test_date_time[0][0]) { + // Direct comparison of retrieved date and expected date + if ($retrievedDateTime != $expected_date_time[0][0]) { fatalError("Dates do not match!"); } break; - case 'time': - if ($retrievedDate != $test_date_time[0][1]."0" and - $retrievedDate != $test_date_time[1][1]."0" and - $retrievedDate != $test_date_time[2][1]."0" and - $retrievedDate != $test_date_time[3][1]."0" ) { + case 'time': + // Compare SQL time with expected time. The expected time was input + // with an accuracy of microseconds and the SQL Servertime type has + // accuracy to 100 ns, so times are returned with an extra zero. For + // comparison the zero is appended to the times in expected_time_date. + if ($retrievedDateTime != $expected_date_time[0][1]."0" and + $retrievedDateTime != $expected_date_time[1][1]."0" and + $retrievedDateTime != $expected_date_time[2][1]."0" and + $retrievedDateTime != $expected_date_time[3][1]."0" ) { fatalError("Times do not match!"); } break; case 'datetime': - if ($retrievedDate."000" != $testingDate[0] and - $retrievedDate."000" != $testingDate[1] and - $retrievedDate."000" != $testingDate[2] and - $retrievedDate."000" != $testingDate[3] ) { + // Compare retrieved SQL datetime with expected date/time. + // SQL Server's datetime type is accurate to milliseconds and + // the expected time is accurate to microseconds, so append + // three zeroes to the retrieved time for comparison. + if ($retrievedDateTime."000" != $expectedDateTime[0] and + $retrievedDateTime."000" != $expectedDateTime[1] and + $retrievedDateTime."000" != $expectedDateTime[2] and + $retrievedDateTime."000" != $expectedDateTime[3] ) { fatalError("Datetimes do not match!"); } break; case 'datetime2': - if ($retrievedDate != $testingDate[0]."0" and - $retrievedDate != $testingDate[1]."0" and - $retrievedDate != $testingDate[2]."0" and - $retrievedDate != $testingDate[3]."0" ) { + // Compare retrieved SQL datetime2 with expected date/time. + // SQL Server's datetime2 type is accurate to 100 ns and + // the expected time is accurate to microseconds, so append + // a zero to the expected time for comparison. + if ($retrievedDateTime != $expectedDateTime[0]."0" and + $retrievedDateTime != $expectedDateTime[1]."0" and + $retrievedDateTime != $expectedDateTime[2]."0" and + $retrievedDateTime != $expectedDateTime[3]."0" ) { fatalError("Datetime2s do not match!"); } break; case 'datetimeoffset': - if ($dtoffset != $testingDate[4] and - $dtoffset != $testingDate[5] and - $dtoffset != $testingDate[6] and - $dtoffset != $testingDate[7] ) { + // Compare the SQL datetimeoffset retrieved with expected + // date/time. datetimeoffset is accurate to 100 ns, so the + // extra zero is removed in $dtoffset to create a format accurate + // to microseconds for comparison with the expected date/time/timezone. + $dtoffset = $retrieved_date_time[0]." ".substr($retrieved_date_time[1], 0, -1)." ".$retrieved_date_time[2]; + if ($dtoffset != $expectedDateTime[4] and + $dtoffset != $expectedDateTime[5] and + $dtoffset != $expectedDateTime[6] and + $dtoffset != $expectedDateTime[7] ) { fatalError("Datetimeoffsets do not match!"); } break; case 'smalldatetime': - if ($retrievedDate.".000000" != $testingDate[0] and - $retrievedDate.".000000" != $testingDate[1] and - $retrievedDate.".000000" != $testingDate[2] and - $retrievedDate.".000000" != $testingDate[3] ) { + // Compare retrieved SQL smalldatetime with expected date/time. + // SQL Server's smalldatetime type is accurate to seconds and + // the expected time is accurate to microseconds, so append + // '.000000' to the expected time for comparison. + if ($retrievedDateTime.".000000" != $expectedDateTime[0] and + $retrievedDateTime.".000000" != $expectedDateTime[1] and + $retrievedDateTime.".000000" != $expectedDateTime[2] and + $retrievedDateTime.".000000" != $expectedDateTime[3] ) { fatalError("Smalldatetimes do not match!"); } break; } - } - else { + } else { + // Combine the retrieved date and time. + if (sizeof($retrieved_date_time)>1) { + $date_time_only = $retrieved_date_time[0]." ".$retrieved_date_time[1]; + } + + // Times returned by SQL Server are accurate to 100 ns, but when + // formatted using PHP's date_format() function, the times are accurate + // to microseconds. So both retrieved and expected times are accurate + // to microseconds, and no need for adding zeroes in any of the + // comparisons below. switch ($datetimetype) { case 'date': - if ($ret_date_time[0] != $test_date_time[0][0]) { + // Comparison of dates only. + if ($retrieved_date_time[0] != $expected_date_time[0][0]) { fatalError("Dates do not match!"); } break; case 'time': - if ($ret_date_time[1] != $test_date_time[0][1] and - $ret_date_time[1] != $test_date_time[1][1] and - $ret_date_time[1] != $test_date_time[2][1] and - $ret_date_time[1] != $test_date_time[3][1] ) { + // Comparison of times only. + if ($retrieved_date_time[1] != $expected_date_time[0][1] and + $retrieved_date_time[1] != $expected_date_time[1][1] and + $retrieved_date_time[1] != $expected_date_time[2][1] and + $retrieved_date_time[1] != $expected_date_time[3][1] ) { fatalError("Times do not match!"); } break; case 'datetime': - if ($datetimeonly != $testingDate[0] and - $datetimeonly != $testingDate[1] and - $datetimeonly != $testingDate[2] and - $datetimeonly != $testingDate[3] ) { + case 'datetime2': + case 'smalldatetime': + // Test combined date and time. The $expectedDateTime values + // all have a different number of trailing zeroes to match + // the precision of different SQL types. + if ($date_time_only != $expectedDateTime[0] and + $date_time_only != $expectedDateTime[1] and + $date_time_only != $expectedDateTime[2] and + $date_time_only != $expectedDateTime[3] ) { fatalError("Datetimes do not match!"); } break; - case 'datetime2': - if ($datetimeonly != $testingDate[0] and - $datetimeonly != $testingDate[1] and - $datetimeonly != $testingDate[2] and - $datetimeonly != $testingDate[3] ) { - fatalError("Datetime2s do not match!"); - } - break; case 'datetimeoffset': - if ($retrievedDate != $testingDate[4] and - $retrievedDate != $testingDate[5] and - $retrievedDate != $testingDate[6] and - $retrievedDate != $testingDate[7] ) { + // The retrieved date/time string will have a timezone + // correction appended to it when the returned type is + // datetimeoffset. + if ($retrievedDateTime != $expectedDateTime[4] and + $retrievedDateTime != $expectedDateTime[5] and + $retrievedDateTime != $expectedDateTime[6] and + $retrievedDateTime != $expectedDateTime[7] ) { fatalError("Datetimeoffsets do not match!"); } break; - case 'smalldatetime': - if ($datetimeonly != $testingDate[0] and - $datetimeonly != $testingDate[1] and - $datetimeonly != $testingDate[2] and - $datetimeonly != $testingDate[3] ) { - fatalError("Smalldatetimes do not match!"); - } - break; } } } @@ -168,8 +196,8 @@ function InsertDatesAndOrTimes($conn, $datetimetype, &$formats_array, $array_siz } $insertSql = "INSERT INTO [$tableName] (id, [c1_$datetimetype]) VALUES (?, ?)"; - for ($i=0; $i<$array_size; $i++) - { + + for ($i = 0; $i < $array_size; $i++) { $stmt = sqlsrv_prepare($conn, $insertSql, array($i, array($formats_array[$i], SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), $SQLSRV_SQLTYPE_CONST))); ExecutePreparedStmt($stmt); $stmt = sqlsrv_prepare($conn, $insertSql, array($i, $formats_array[$i])); @@ -186,7 +214,7 @@ function InsertDatesAndOrTimes($conn, $datetimetype, &$formats_array, $array_siz } } -function FetchDatesAndOrTimes($conn, $datetimetype, &$testingDate, $returnDatesAsStrings) +function FetchDatesAndOrTimes($conn, $datetimetype, &$expectedDateTime, $returnDatesAsStrings) { $tableName = "table_of_$datetimetype"; @@ -205,10 +233,11 @@ function FetchDatesAndOrTimes($conn, $datetimetype, &$testingDate, $returnDatesA fatalError("sqlsrv_get_field did not return string but string was specified"); } - CompareDateTime($datetimetype, true, $testingDate, $datetime); + CompareDateTime($datetimetype, true, $expectedDateTime, $datetime); } // retrieve date time fields as DateTime objects + // format them as strings using date_format() for comparison echo "Select fields as DateTime objects:\n"; $stmt = sqlsrv_query($conn, "SELECT * FROM [$tableName]"); @@ -226,7 +255,7 @@ function FetchDatesAndOrTimes($conn, $datetimetype, &$testingDate, $returnDatesA $datetime = ($datetimetype == 'datetimeoffset') ? date_format($datetime, 'Y-m-d H:i:s.u P') : date_format($datetime, 'Y-m-d H:i:s.u'); - CompareDateTime($datetimetype, false, $testingDate, $datetime); + CompareDateTime($datetimetype, false, $expectedDateTime, $datetime); } // retrieve date time fields without explicitly requesting the type @@ -246,16 +275,15 @@ function FetchDatesAndOrTimes($conn, $datetimetype, &$testingDate, $returnDatesA fatalError("String for date expected, not a string"); } - CompareDateTime($datetimetype, $returnDatesAsStrings, $testingDate, $datetime); - } - else { // ReturnsDatesAsStrings is false + CompareDateTime($datetimetype, $returnDatesAsStrings, $expectedDateTime, $datetime); + } else { // ReturnsDatesAsStrings is false if (!($datetime instanceof DateTime)) { fatalError("DateTime object expected, not a DateTime"); } $datetime = ($datetimetype == 'datetimeoffset') ? date_format($datetime, 'Y-m-d H:i:s.u P') : date_format($datetime, 'Y-m-d H:i:s.u'); - CompareDateTime($datetimetype, $returnDatesAsStrings, $testingDate, $datetime); + CompareDateTime($datetimetype, $returnDatesAsStrings, $expectedDateTime, $datetime); } } @@ -275,16 +303,15 @@ function FetchDatesAndOrTimes($conn, $datetimetype, &$testingDate, $returnDatesA fatalError("String for date expected, not a string"); } - CompareDateTime($datetimetype, $returnDatesAsStrings, $testingDate, $row[1]); - } - else { + CompareDateTime($datetimetype, $returnDatesAsStrings, $expectedDateTime, $row[1]); + } else { if (!($row[1] instanceof DateTime)) { fatalError("DateTime object expected, not a DateTime"); } $datetime = ($datetimetype == 'datetimeoffset') ? date_format($row[1], 'Y-m-d H:i:s.u P') : date_format($row[1], 'Y-m-d H:i:s.u'); - CompareDateTime($datetimetype, $returnDatesAsStrings, $testingDate, $datetime); + CompareDateTime($datetimetype, $returnDatesAsStrings, $expectedDateTime, $datetime); } } @@ -313,15 +340,21 @@ $frac = '04'; $frac2 = '9876'; $tz_correction = '+08:00'; -$testingDate = array($year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2, - $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."0000", - $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000", - $year."-".$month."-".$day." ".$hour.":".$minute.":00.000000", - $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2." ".$tz_correction, - $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."0000 ".$tz_correction, - $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000 ".$tz_correction, - $year."-".$month."-".$day." ".$hour.":".$minute.":00.000000 ".$tz_correction, - ); +// This is the array of dates/times/timezones to test against. They have +// different numbers of trailing zeroes to match the precision of different +// SQL date and time types, but all go up to microseconds because that's +// how PHP formats times with date_format(), allowing direct string comparisons +// when the DateTime objects retrieved from a table are formatted as strings +// with date_format(). +$expectedDateTime = array($year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."0000", + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000", + $year."-".$month."-".$day." ".$hour.":".$minute.":00.000000", + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2." ".$tz_correction, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."0000 ".$tz_correction, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000 ".$tz_correction, + $year."-".$month."-".$day." ".$hour.":".$minute.":00.000000 ".$tz_correction, + ); // These formats are for the ODBC driver with types specified in sqlsrv_prepare() $date_formats = array($year."-".$month."-".$day @@ -365,12 +398,14 @@ $SZ_TIME_all = sizeof($time_formats_all); $SZ_DATE_all = sizeof($date_formats_all); $SZ_DATETIME_all = $SZ_TIME_all*$SZ_DATE_all; -// Create compound date/time types. For datetime, remove the extra precision -// of $frac2. For smalldatetime, remove the extra precision of $frac and $frac2. -// If the data in $frac and/or $frac2 is found elsewhere in the date/time, the -// data will be garbled. For example, if the year is 2002 and $frac2 is 2002, -// the code below will remove any instances of '2002' in the datetime and -// smalldatetime strings, producing garbage for those types. User must be +// Create compound date/time/timezone arrays corresponding to the SQL Server +// date/time types by concatenating the dates and times from above. For the +// datetime type, remove the extra precision of $frac2. For the smalldatetime +// type, remove the extra precision of $frac and $frac2. If the numerical +// string in $frac and/or $frac2 is found elsewhere in the date/time, the data +// will be garbled. For example, if the year is 2002 and $frac2 is 2002, the +// code below will remove any instances of '2002' in the datetime and +// smalldatetime strings, producing garbage for those types. User must be // cognizant of this when testing different dates and times. for ($i=0; $i<$SZ_DATE_all; $i++) { @@ -381,20 +416,17 @@ for ($i=0; $i<$SZ_DATE_all; $i++) $datetimeoffset_formats_all[] = $date_formats_all[$i]." ".$time_formats_all[$j].$tz_correction; if (str_replace(".".$frac.$frac2, "", $date_formats_all[$i]." ".$time_formats_all[$j]) == ($date_formats_all[$i]." ".$time_formats_all[$j])) { $datetimesmall_formats_all[] = str_replace(".".$frac, "", $date_formats_all[$i]." ".$time_formats_all[$j]); - } - else { + } else { $datetimesmall_formats_all[] = str_replace(".".$frac.$frac2, "", $date_formats_all[$i]." ".$time_formats_all[$j]); } } } date_default_timezone_set('Canada/Pacific'); -sqlsrv_configure('WarningsReturnAsErrors', 0); +sqlsrv_configure('WarningsReturnAsErrors', 1); sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL); sqlsrv_configure('LogSubsystems', SQLSRV_LOG_SYSTEM_OFF); -require_once('MsCommon.inc'); - $returnDatesAsStrings = true; $conn = AE\connect(array('ReturnDatesAsStrings' => $returnDatesAsStrings)); @@ -406,12 +438,12 @@ InsertDatesAndOrTimes($conn, 'datetime2', $datetime2_formats_all, $SZ_DATETIME_a InsertDatesAndOrTimes($conn, 'datetimeoffset', $datetimeoffset_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIMEOFFSET); InsertDatesAndOrTimes($conn, 'smalldatetime', $datetimesmall_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_SMALLDATETIME); -FetchDatesAndOrTimes($conn, 'date', $testingDate, $returnDatesAsStrings); -FetchDatesAndOrTimes($conn, 'time', $testingDate, $returnDatesAsStrings); -FetchDatesAndOrTimes($conn, 'datetime', $testingDate, $returnDatesAsStrings); -FetchDatesAndOrTimes($conn, 'datetime2', $testingDate, $returnDatesAsStrings); -FetchDatesAndOrTimes($conn, 'datetimeoffset', $testingDate, $returnDatesAsStrings); -FetchDatesAndOrTimes($conn, 'smalldatetime', $testingDate, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'date', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'time', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetime', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetime2', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetimeoffset', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'smalldatetime', $expectedDateTime, $returnDatesAsStrings); sqlsrv_close($conn); @@ -426,12 +458,12 @@ InsertDatesAndOrTimes($conn, 'datetime2', $datetime2_formats_all, $SZ_DATETIME_a InsertDatesAndOrTimes($conn, 'datetimeoffset', $datetimeoffset_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIMEOFFSET); InsertDatesAndOrTimes($conn, 'smalldatetime', $datetimesmall_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_SMALLDATETIME); -FetchDatesAndOrTimes($conn, 'date', $testingDate, $returnDatesAsStrings); -FetchDatesAndOrTimes($conn, 'time', $testingDate, $returnDatesAsStrings); -FetchDatesAndOrTimes($conn, 'datetime', $testingDate, $returnDatesAsStrings); -FetchDatesAndOrTimes($conn, 'datetime2', $testingDate, $returnDatesAsStrings); -FetchDatesAndOrTimes($conn, 'datetimeoffset', $testingDate, $returnDatesAsStrings); -FetchDatesAndOrTimes($conn, 'smalldatetime', $testingDate, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'date', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'time', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetime', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetime2', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetimeoffset', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'smalldatetime', $expectedDateTime, $returnDatesAsStrings); sqlsrv_close($conn); From d025172a8eb546e3106b70fd25c1708b481df39c Mon Sep 17 00:00:00 2001 From: David Puglielli Date: Wed, 14 Mar 2018 16:14:04 -0700 Subject: [PATCH 03/10] Fixes per review comments --- .../sqlsrv_ae_datetimes_as_strings.phpt | 309 ++++++++++-------- 1 file changed, 164 insertions(+), 145 deletions(-) diff --git a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt index b39d580f..9b560900 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt @@ -31,22 +31,17 @@ function ExecutePreparedStmt($stmt) } } -// Compare dates retrieved from the database with the date used for testing. +// Compare dates retrieved from the database with the date used for testing +// when ReturnDatesAsStrings is true. // $expectedDateTime is an array of strings like '2002-01-31 23:59:59.049876' // $retrievedDateTime is date/time string of format either 'Y-m-d H:i:s.u' or // 'Y-m-d H:i:s.u P', which is the format returned when $returnDatesAsStrings -// is true, or by the date_format() calls in FetchDatesAndOrTimes when a PHP -// DateTime object is retrieved (i.e. when $returnDatesAsStrings is false), -// unless $datetimetype is date or time. In those cases: -// If $datetimetype is date and $returnDatesAsStrings is false: -// The date is as expected, the time defaults to 00:00:00.0000 -// If $datetimetype is time and $returnStrings is false: -// The date defaults to the current date, the time is as expected. -// If $datetimetype is date and $returnStrings is true: +// is true, unless $datetimetype is date or time. In those cases: +// If $datetimetype is 'date': // $retrievedDateTime is only a date. -// If $datetimetype is 'time' and $returnStrings is true: +// If $datetimetype is 'time': // $retrievedDateTime is only a time. -function CompareDateTime($datetimetype, $returnStrings, &$expectedDateTime, $retrievedDateTime) +function CompareDateTimeString($datetimetype, &$expectedDateTime, $retrievedDateTime) { $expected_date_time = array(); @@ -60,130 +55,152 @@ function CompareDateTime($datetimetype, $returnStrings, &$expectedDateTime, $ret // split it into [0]:date, [1]:time, and possibly [2]:timezone offset $retrieved_date_time = explode(" ", $retrievedDateTime); - if ($returnStrings == true) { - switch ($datetimetype) { - case 'date': - // Direct comparison of retrieved date and expected date - if ($retrievedDateTime != $expected_date_time[0][0]) { - fatalError("Dates do not match!"); - } - break; - case 'time': - // Compare SQL time with expected time. The expected time was input - // with an accuracy of microseconds and the SQL Servertime type has - // accuracy to 100 ns, so times are returned with an extra zero. For - // comparison the zero is appended to the times in expected_time_date. - if ($retrievedDateTime != $expected_date_time[0][1]."0" and - $retrievedDateTime != $expected_date_time[1][1]."0" and - $retrievedDateTime != $expected_date_time[2][1]."0" and - $retrievedDateTime != $expected_date_time[3][1]."0" ) { - fatalError("Times do not match!"); - } - break; - case 'datetime': - // Compare retrieved SQL datetime with expected date/time. - // SQL Server's datetime type is accurate to milliseconds and - // the expected time is accurate to microseconds, so append - // three zeroes to the retrieved time for comparison. - if ($retrievedDateTime."000" != $expectedDateTime[0] and - $retrievedDateTime."000" != $expectedDateTime[1] and - $retrievedDateTime."000" != $expectedDateTime[2] and - $retrievedDateTime."000" != $expectedDateTime[3] ) { - fatalError("Datetimes do not match!"); - } - break; - case 'datetime2': - // Compare retrieved SQL datetime2 with expected date/time. - // SQL Server's datetime2 type is accurate to 100 ns and - // the expected time is accurate to microseconds, so append - // a zero to the expected time for comparison. - if ($retrievedDateTime != $expectedDateTime[0]."0" and - $retrievedDateTime != $expectedDateTime[1]."0" and - $retrievedDateTime != $expectedDateTime[2]."0" and - $retrievedDateTime != $expectedDateTime[3]."0" ) { - fatalError("Datetime2s do not match!"); - } - break; - case 'datetimeoffset': - // Compare the SQL datetimeoffset retrieved with expected - // date/time. datetimeoffset is accurate to 100 ns, so the - // extra zero is removed in $dtoffset to create a format accurate - // to microseconds for comparison with the expected date/time/timezone. - $dtoffset = $retrieved_date_time[0]." ".substr($retrieved_date_time[1], 0, -1)." ".$retrieved_date_time[2]; - if ($dtoffset != $expectedDateTime[4] and - $dtoffset != $expectedDateTime[5] and - $dtoffset != $expectedDateTime[6] and - $dtoffset != $expectedDateTime[7] ) { - fatalError("Datetimeoffsets do not match!"); - } - break; - case 'smalldatetime': - // Compare retrieved SQL smalldatetime with expected date/time. - // SQL Server's smalldatetime type is accurate to seconds and - // the expected time is accurate to microseconds, so append - // '.000000' to the expected time for comparison. - if ($retrievedDateTime.".000000" != $expectedDateTime[0] and - $retrievedDateTime.".000000" != $expectedDateTime[1] and - $retrievedDateTime.".000000" != $expectedDateTime[2] and - $retrievedDateTime.".000000" != $expectedDateTime[3] ) { - fatalError("Smalldatetimes do not match!"); - } - break; - } - } else { - // Combine the retrieved date and time. - if (sizeof($retrieved_date_time)>1) { - $date_time_only = $retrieved_date_time[0]." ".$retrieved_date_time[1]; - } - - // Times returned by SQL Server are accurate to 100 ns, but when - // formatted using PHP's date_format() function, the times are accurate - // to microseconds. So both retrieved and expected times are accurate - // to microseconds, and no need for adding zeroes in any of the - // comparisons below. - switch ($datetimetype) { - case 'date': - // Comparison of dates only. - if ($retrieved_date_time[0] != $expected_date_time[0][0]) { - fatalError("Dates do not match!"); - } - break; - case 'time': - // Comparison of times only. - if ($retrieved_date_time[1] != $expected_date_time[0][1] and - $retrieved_date_time[1] != $expected_date_time[1][1] and - $retrieved_date_time[1] != $expected_date_time[2][1] and - $retrieved_date_time[1] != $expected_date_time[3][1] ) { - fatalError("Times do not match!"); - } - break; - case 'datetime': - case 'datetime2': - case 'smalldatetime': - // Test combined date and time. The $expectedDateTime values - // all have a different number of trailing zeroes to match - // the precision of different SQL types. - if ($date_time_only != $expectedDateTime[0] and - $date_time_only != $expectedDateTime[1] and - $date_time_only != $expectedDateTime[2] and - $date_time_only != $expectedDateTime[3] ) { - fatalError("Datetimes do not match!"); - } - break; - case 'datetimeoffset': - // The retrieved date/time string will have a timezone - // correction appended to it when the returned type is - // datetimeoffset. - if ($retrievedDateTime != $expectedDateTime[4] and - $retrievedDateTime != $expectedDateTime[5] and - $retrievedDateTime != $expectedDateTime[6] and - $retrievedDateTime != $expectedDateTime[7] ) { - fatalError("Datetimeoffsets do not match!"); - } - break; - } + switch ($datetimetype) { + case 'date': + // Direct comparison of retrieved date and expected date + if ($retrievedDateTime != $expected_date_time[0][0]) { + fatalError("Dates do not match!"); + } + break; + case 'time': + // Compare SQL time with expected time. The expected time was input + // with an accuracy of 0.000001 s and the SQL Server time type has + // accuracy to 0.0000001 s, so times are returned with an extra zero. For + // comparison the zero is appended to the times in expected_time_date. + if ($retrievedDateTime != $expected_date_time[0][1]."0" and + $retrievedDateTime != $expected_date_time[1][1]."0" and + $retrievedDateTime != $expected_date_time[2][1]."0" and + $retrievedDateTime != $expected_date_time[3][1]."0") { + fatalError("Times do not match!"); + } + break; + case 'datetime': + // Compare retrieved SQL datetime with expected date/time. + // SQL Server's datetime type is accurate to 0.001 s and + // the expected time is accurate to 0.000001 s, so append + // three zeroes to the retrieved time for comparison. + if ($retrievedDateTime."000" != $expectedDateTime[0] and + $retrievedDateTime."000" != $expectedDateTime[1] and + $retrievedDateTime."000" != $expectedDateTime[2] and + $retrievedDateTime."000" != $expectedDateTime[3]) { + fatalError("Datetimes do not match!"); + } + break; + case 'datetime2': + // Compare retrieved SQL datetime2 with expected date/time. + // SQL Server's datetime2 type is accurate to 0.0000001 s and + // the expected time is accurate to 0.000001 s, so append + // a zero to the expected time for comparison. + if ($retrievedDateTime != $expectedDateTime[0]."0" and + $retrievedDateTime != $expectedDateTime[1]."0" and + $retrievedDateTime != $expectedDateTime[2]."0" and + $retrievedDateTime != $expectedDateTime[3]."0") { + fatalError("Datetime2s do not match!"); + } + break; + case 'datetimeoffset': + // Compare the SQL datetimeoffset retrieved with expected + // date/time. datetimeoffset is accurate to 0.0000001 s, so the + // extra zero is removed in $dtoffset to create a format accurate + // to 0.000001 s for comparison with the expected date/time/timezone. + $dtoffset = $retrieved_date_time[0]." ".substr($retrieved_date_time[1], 0, -1)." ".$retrieved_date_time[2]; + if ($dtoffset != $expectedDateTime[4] and + $dtoffset != $expectedDateTime[5] and + $dtoffset != $expectedDateTime[6]) { + fatalError("Datetimeoffsets do not match!"); + } + break; + case 'smalldatetime': + // Compare retrieved SQL smalldatetime with expected date/time. + // SQL Server's smalldatetime type is accurate to seconds and + // the expected time is accurate to 0.000001 s, so append + // '.000000' to the expected time for comparison. + if ($retrievedDateTime.".000000" != $expectedDateTime[0] and + $retrievedDateTime.".000000" != $expectedDateTime[1] and + $retrievedDateTime.".000000" != $expectedDateTime[2] and + $retrievedDateTime.".000000" != $expectedDateTime[3]) { + fatalError("Smalldatetimes do not match!"); + } + break; } -} +} + +// Compare dates retrieved from the database with the date used for testing +// when ReturnDatesAsStrings is false. +// $expectedDateTime is an array of strings like '2002-01-31 23:59:59.049876' +// $retrievedDateTime is date/time string of format either 'Y-m-d H:i:s.u' or +// 'Y-m-d H:i:s.u P', which is the format returned by the date_format() calls +// in FetchDatesAndOrTimes when a PHP DateTime object is retrieved, +// unless $datetimetype is date or time. In those cases: +// If $datetimetype is 'date': +// The date is as expected, the time defaults to 00:00:00.0000 +// If $datetimetype is 'time': +// The date defaults to the current date, the time is as expected. +function CompareDateTimeObject($datetimetype, &$expectedDateTime, $retrievedDateTime) +{ + $expected_date_time = array(); + + // Split each element of the testing date/time into + // [0]:date, [1]:time, and possibly [2]:timezone offset + for ($i = 0; $i < sizeof($expectedDateTime); ++$i) { + $expected_date_time[] = explode(" ", $expectedDateTime[$i]); + } + + // If $retrievedDateTime is a string of format 'Y-m-d H:i:s.u' or 'Y-m-d H:i:s.u P', + // split it into [0]:date, [1]:time, and possibly [2]:timezone offset + $retrieved_date_time = explode(" ", $retrievedDateTime); + + // Times returned by SQL Server are accurate to 0.0000001 s, but when + // formatted using PHP's date_format() function, the times are accurate + // to 0.000001 s. So both retrieved and expected times are accurate + // to the same precision, and no need for adding zeroes in any of the + // comparisons below. + switch ($datetimetype) { + case 'date': + // Comparison of dates only. + if ($retrieved_date_time[0] != $expected_date_time[0][0]) { + fatalError("Dates do not match!"); + } + break; + case 'time': + // Comparison of times only. + if ($retrieved_date_time[1] != $expected_date_time[0][1] and + $retrieved_date_time[1] != $expected_date_time[1][1] and + $retrieved_date_time[1] != $expected_date_time[2][1] and + $retrieved_date_time[1] != $expected_date_time[3][1]) { + fatalError("Times do not match!"); + } + break; + case 'datetime': + case 'datetime2': + case 'smalldatetime': + // Combine the retrieved date and time. + if (sizeof($retrieved_date_time)>1) { + $date_time_only = $retrieved_date_time[0]." ".$retrieved_date_time[1]; + } + + // Test combined date and time. The $expectedDateTime values + // all have a different number of trailing zeroes to match + // the precision of different SQL types. + if ($date_time_only != $expectedDateTime[0] and + $date_time_only != $expectedDateTime[1] and + $date_time_only != $expectedDateTime[2] and + $date_time_only != $expectedDateTime[3]) { + fatalError("Datetimes do not match!"); + } + break; + case 'datetimeoffset': + // The retrieved date/time string will have a timezone + // correction appended to it when the returned type is + // datetimeoffset. + if ($retrievedDateTime != $expectedDateTime[4] and + $retrievedDateTime != $expectedDateTime[5] and + $retrievedDateTime != $expectedDateTime[6]) { + fatalError("Datetimeoffsets do not match!"); + } + break; + } +} function InsertDatesAndOrTimes($conn, $datetimetype, &$formats_array, $array_size, $SQLSRV_SQLTYPE_CONST) { @@ -233,7 +250,7 @@ function FetchDatesAndOrTimes($conn, $datetimetype, &$expectedDateTime, $returnD fatalError("sqlsrv_get_field did not return string but string was specified"); } - CompareDateTime($datetimetype, true, $expectedDateTime, $datetime); + CompareDateTimeString($datetimetype, $expectedDateTime, $datetime); } // retrieve date time fields as DateTime objects @@ -253,9 +270,10 @@ function FetchDatesAndOrTimes($conn, $datetimetype, &$expectedDateTime, $returnD fatalError("sqlsrv_get_field did not return DateTime but DateTime was specified"); } + // append a timezone offset if it's the datetimeoffset type $datetime = ($datetimetype == 'datetimeoffset') ? date_format($datetime, 'Y-m-d H:i:s.u P') : date_format($datetime, 'Y-m-d H:i:s.u'); - CompareDateTime($datetimetype, false, $expectedDateTime, $datetime); + CompareDateTimeObject($datetimetype, $expectedDateTime, $datetime); } // retrieve date time fields without explicitly requesting the type @@ -275,15 +293,16 @@ function FetchDatesAndOrTimes($conn, $datetimetype, &$expectedDateTime, $returnD fatalError("String for date expected, not a string"); } - CompareDateTime($datetimetype, $returnDatesAsStrings, $expectedDateTime, $datetime); + CompareDateTimeString($datetimetype, $expectedDateTime, $datetime); } else { // ReturnsDatesAsStrings is false if (!($datetime instanceof DateTime)) { fatalError("DateTime object expected, not a DateTime"); } + // append a timezone offset if it's the datetimeoffset type $datetime = ($datetimetype == 'datetimeoffset') ? date_format($datetime, 'Y-m-d H:i:s.u P') : date_format($datetime, 'Y-m-d H:i:s.u'); - CompareDateTime($datetimetype, $returnDatesAsStrings, $expectedDateTime, $datetime); + CompareDateTimeObject($datetimetype, $expectedDateTime, $datetime); } } @@ -303,15 +322,16 @@ function FetchDatesAndOrTimes($conn, $datetimetype, &$expectedDateTime, $returnD fatalError("String for date expected, not a string"); } - CompareDateTime($datetimetype, $returnDatesAsStrings, $expectedDateTime, $row[1]); + CompareDateTimeString($datetimetype, $expectedDateTime, $row[1]); } else { if (!($row[1] instanceof DateTime)) { fatalError("DateTime object expected, not a DateTime"); } + // append a timezone offset if it's the datetimeoffset type $datetime = ($datetimetype == 'datetimeoffset') ? date_format($row[1], 'Y-m-d H:i:s.u P') : date_format($row[1], 'Y-m-d H:i:s.u'); - CompareDateTime($datetimetype, $returnDatesAsStrings, $expectedDateTime, $datetime); + CompareDateTimeObject($datetimetype, $expectedDateTime, $datetime); } } @@ -342,10 +362,10 @@ $tz_correction = '+08:00'; // This is the array of dates/times/timezones to test against. They have // different numbers of trailing zeroes to match the precision of different -// SQL date and time types, but all go up to microseconds because that's -// how PHP formats times with date_format(), allowing direct string comparisons -// when the DateTime objects retrieved from a table are formatted as strings -// with date_format(). +// SQL date and time types, but all go up to microseconds (0.000001 s) because +// that's how PHP formats times with date_format(), allowing direct string +// comparisons when the DateTime objects retrieved from a table are formatted +// as strings with date_format(). $expectedDateTime = array($year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2, $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."0000", $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000", @@ -353,7 +373,6 @@ $expectedDateTime = array($year."-".$month."-".$day." ".$hour.":".$minute.":".$s $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2." ".$tz_correction, $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."0000 ".$tz_correction, $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000 ".$tz_correction, - $year."-".$month."-".$day." ".$hour.":".$minute.":00.000000 ".$tz_correction, ); // These formats are for the ODBC driver with types specified in sqlsrv_prepare() From ebfc750023be151c9c848c6a9408e46cd4774271 Mon Sep 17 00:00:00 2001 From: David Puglielli Date: Wed, 14 Mar 2018 16:45:54 -0700 Subject: [PATCH 04/10] More fixes per review comments --- .../sqlsrv_ae_datetimes_as_strings.phpt | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt index 9b560900..2b5af739 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt @@ -71,7 +71,7 @@ function CompareDateTimeString($datetimetype, &$expectedDateTime, $retrievedDate $retrievedDateTime != $expected_date_time[1][1]."0" and $retrievedDateTime != $expected_date_time[2][1]."0" and $retrievedDateTime != $expected_date_time[3][1]."0") { - fatalError("Times do not match!"); + fatalError("Times do not match!"); } break; case 'datetime': @@ -83,7 +83,7 @@ function CompareDateTimeString($datetimetype, &$expectedDateTime, $retrievedDate $retrievedDateTime."000" != $expectedDateTime[1] and $retrievedDateTime."000" != $expectedDateTime[2] and $retrievedDateTime."000" != $expectedDateTime[3]) { - fatalError("Datetimes do not match!"); + fatalError("Datetimes do not match!"); } break; case 'datetime2': @@ -95,7 +95,7 @@ function CompareDateTimeString($datetimetype, &$expectedDateTime, $retrievedDate $retrievedDateTime != $expectedDateTime[1]."0" and $retrievedDateTime != $expectedDateTime[2]."0" and $retrievedDateTime != $expectedDateTime[3]."0") { - fatalError("Datetime2s do not match!"); + fatalError("Datetime2s do not match!"); } break; case 'datetimeoffset': @@ -106,8 +106,9 @@ function CompareDateTimeString($datetimetype, &$expectedDateTime, $retrievedDate $dtoffset = $retrieved_date_time[0]." ".substr($retrieved_date_time[1], 0, -1)." ".$retrieved_date_time[2]; if ($dtoffset != $expectedDateTime[4] and $dtoffset != $expectedDateTime[5] and - $dtoffset != $expectedDateTime[6]) { - fatalError("Datetimeoffsets do not match!"); + $dtoffset != $expectedDateTime[6] and + $dtoffset != $expectedDateTime[7]) {echo "1: $dtoffset 2: $expectedDateTime[4] 3: $expectedDateTime[5] 4: $expectedDateTime[5]\n"; + fatalError("Datetimeoffsets do not match!"); } break; case 'smalldatetime': @@ -119,7 +120,7 @@ function CompareDateTimeString($datetimetype, &$expectedDateTime, $retrievedDate $retrievedDateTime.".000000" != $expectedDateTime[1] and $retrievedDateTime.".000000" != $expectedDateTime[2] and $retrievedDateTime.".000000" != $expectedDateTime[3]) { - fatalError("Smalldatetimes do not match!"); + fatalError("Smalldatetimes do not match!"); } break; } @@ -168,7 +169,7 @@ function CompareDateTimeObject($datetimetype, &$expectedDateTime, $retrievedDate $retrieved_date_time[1] != $expected_date_time[1][1] and $retrieved_date_time[1] != $expected_date_time[2][1] and $retrieved_date_time[1] != $expected_date_time[3][1]) { - fatalError("Times do not match!"); + fatalError("Times do not match!"); } break; case 'datetime': @@ -186,7 +187,7 @@ function CompareDateTimeObject($datetimetype, &$expectedDateTime, $retrievedDate $date_time_only != $expectedDateTime[1] and $date_time_only != $expectedDateTime[2] and $date_time_only != $expectedDateTime[3]) { - fatalError("Datetimes do not match!"); + fatalError("Datetimes do not match!"); } break; case 'datetimeoffset': @@ -195,8 +196,9 @@ function CompareDateTimeObject($datetimetype, &$expectedDateTime, $retrievedDate // datetimeoffset. if ($retrievedDateTime != $expectedDateTime[4] and $retrievedDateTime != $expectedDateTime[5] and - $retrievedDateTime != $expectedDateTime[6]) { - fatalError("Datetimeoffsets do not match!"); + $retrievedDateTime != $expectedDateTime[6] and + $retrievedDateTime != $expectedDateTime[7]) { + fatalError("Datetimeoffsets do not match!"); } break; } @@ -373,6 +375,7 @@ $expectedDateTime = array($year."-".$month."-".$day." ".$hour.":".$minute.":".$s $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2." ".$tz_correction, $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."0000 ".$tz_correction, $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000 ".$tz_correction, + $year."-".$month."-".$day." ".$hour.":".$minute.":00.000000 ".$tz_correction, ); // These formats are for the ODBC driver with types specified in sqlsrv_prepare() From 1666e6247f2bd7146221a18867e30b4de0facee1 Mon Sep 17 00:00:00 2001 From: David Puglielli Date: Mon, 19 Mar 2018 14:08:29 -0700 Subject: [PATCH 05/10] Updated datetime test --- .../sqlsrv_ae_datetimes_as_strings.phpt | 520 ++++++++---------- 1 file changed, 244 insertions(+), 276 deletions(-) diff --git a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt index 2b5af739..443c02e6 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt @@ -33,188 +33,215 @@ function ExecutePreparedStmt($stmt) // Compare dates retrieved from the database with the date used for testing // when ReturnDatesAsStrings is true. -// $expectedDateTime is an array of strings like '2002-01-31 23:59:59.049876' -// $retrievedDateTime is date/time string of format either 'Y-m-d H:i:s.u' or -// 'Y-m-d H:i:s.u P', which is the format returned when $returnDatesAsStrings -// is true, unless $datetimetype is date or time. In those cases: -// If $datetimetype is 'date': -// $retrievedDateTime is only a date. -// If $datetimetype is 'time': -// $retrievedDateTime is only a time. -function CompareDateTimeString($datetimetype, &$expectedDateTime, $retrievedDateTime) +// $expectedDateTime is an array of date/time strings corresponding to the different SQL Server types. +// $retrievedDateTime is date/time string whose format depends on $dateTimeType. +function CompareDateTimeString($dateTimeType, &$expectedDateTime, $retrievedDateTime) { - $expected_date_time = array(); - - // Split each element of the testing date/time into - // [0]:date, [1]:time, and possibly [2]:timezone offset - for ($i = 0; $i < sizeof($expectedDateTime); ++$i) { - $expected_date_time[] = explode(" ", $expectedDateTime[$i]); - } - - // If $retrievedDateTime is a string of format 'Y-m-d H:i:s.u' or 'Y-m-d H:i:s.u P', - // split it into [0]:date, [1]:time, and possibly [2]:timezone offset - $retrieved_date_time = explode(" ", $retrievedDateTime); - - switch ($datetimetype) { + switch ($dateTimeType) { case 'date': // Direct comparison of retrieved date and expected date - if ($retrievedDateTime != $expected_date_time[0][0]) { - fatalError("Dates do not match!"); - } + if ($retrievedDateTime != $expectedDateTime['date'][0]) fatalError("Dates do not match!"); break; case 'time': // Compare SQL time with expected time. The expected time was input // with an accuracy of 0.000001 s and the SQL Server time type has - // accuracy to 0.0000001 s, so times are returned with an extra zero. For - // comparison the zero is appended to the times in expected_time_date. - if ($retrievedDateTime != $expected_date_time[0][1]."0" and - $retrievedDateTime != $expected_date_time[1][1]."0" and - $retrievedDateTime != $expected_date_time[2][1]."0" and - $retrievedDateTime != $expected_date_time[3][1]."0") { - fatalError("Times do not match!"); - } + // accuracy to 0.0000001 s, so retrieved times have an extra zero. + // For comparison a zero is appended to the $expectedDateTime. + if ($retrievedDateTime != $expectedDateTime['time'][1]."0" and + $retrievedDateTime != $expectedDateTime['time'][2]."0" and + $retrievedDateTime != $expectedDateTime['time'][3]."0" and + $retrievedDateTime != $expectedDateTime['time'][4]."0") fatalError("Times do not match!"); break; case 'datetime': // Compare retrieved SQL datetime with expected date/time. - // SQL Server's datetime type is accurate to 0.001 s and - // the expected time is accurate to 0.000001 s, so append - // three zeroes to the retrieved time for comparison. - if ($retrievedDateTime."000" != $expectedDateTime[0] and - $retrievedDateTime."000" != $expectedDateTime[1] and - $retrievedDateTime."000" != $expectedDateTime[2] and - $retrievedDateTime."000" != $expectedDateTime[3]) { - fatalError("Datetimes do not match!"); - } + // SQL Server's datetime type is accurate to 0.000, 0.003, or + // 0.007 s. We have already accounted for that in + // $expectedDateTime['datetime']. + if ($retrievedDateTime != $expectedDateTime['datetime'][0] and + $retrievedDateTime != $expectedDateTime['datetime'][1] and + $retrievedDateTime != $expectedDateTime['datetime'][2] and + $retrievedDateTime != $expectedDateTime['datetime'][3]) + { + print_r($retrievedDateTime); + print_r($expectedDateTime); + fatalError("Datetimes do not match!"); + } break; case 'datetime2': // Compare retrieved SQL datetime2 with expected date/time. // SQL Server's datetime2 type is accurate to 0.0000001 s and // the expected time is accurate to 0.000001 s, so append // a zero to the expected time for comparison. - if ($retrievedDateTime != $expectedDateTime[0]."0" and - $retrievedDateTime != $expectedDateTime[1]."0" and - $retrievedDateTime != $expectedDateTime[2]."0" and - $retrievedDateTime != $expectedDateTime[3]."0") { - fatalError("Datetime2s do not match!"); - } + if ($retrievedDateTime != $expectedDateTime['datetime2'][1]."0" and + $retrievedDateTime != $expectedDateTime['datetime2'][2]."0" and + $retrievedDateTime != $expectedDateTime['datetime2'][3]."0" and + $retrievedDateTime != $expectedDateTime['datetime2'][4]."0") fatalError("Datetime2s do not match!"); break; case 'datetimeoffset': // Compare the SQL datetimeoffset retrieved with expected // date/time. datetimeoffset is accurate to 0.0000001 s, so the // extra zero is removed in $dtoffset to create a format accurate // to 0.000001 s for comparison with the expected date/time/timezone. - $dtoffset = $retrieved_date_time[0]." ".substr($retrieved_date_time[1], 0, -1)." ".$retrieved_date_time[2]; - if ($dtoffset != $expectedDateTime[4] and - $dtoffset != $expectedDateTime[5] and - $dtoffset != $expectedDateTime[6] and - $dtoffset != $expectedDateTime[7]) {echo "1: $dtoffset 2: $expectedDateTime[4] 3: $expectedDateTime[5] 4: $expectedDateTime[5]\n"; - fatalError("Datetimeoffsets do not match!"); - } + $ret_date_time = explode(" ", $retrievedDateTime); + $dtoffset = $ret_date_time[0]." ".substr($ret_date_time[1], 0, -1)." ".$ret_date_time[2]; + if ($dtoffset != $expectedDateTime['datetimeoffset'][1] and + $dtoffset != $expectedDateTime['datetimeoffset'][2] and + $dtoffset != $expectedDateTime['datetimeoffset'][3] and + $dtoffset != $expectedDateTime['datetimeoffset'][4]) fatalError("Datetimeoffsets do not match!"); break; case 'smalldatetime': // Compare retrieved SQL smalldatetime with expected date/time. - // SQL Server's smalldatetime type is accurate to seconds and - // the expected time is accurate to 0.000001 s, so append - // '.000000' to the expected time for comparison. - if ($retrievedDateTime.".000000" != $expectedDateTime[0] and - $retrievedDateTime.".000000" != $expectedDateTime[1] and - $retrievedDateTime.".000000" != $expectedDateTime[2] and - $retrievedDateTime.".000000" != $expectedDateTime[3]) { - fatalError("Smalldatetimes do not match!"); - } + // SQL Server's smalldatetime type is accurate to seconds only. + if ($retrievedDateTime != $expectedDateTime['smalldatetime'][0]) fatalError("Smalldatetimes do not match!"); break; } } // Compare dates retrieved from the database with the date used for testing // when ReturnDatesAsStrings is false. -// $expectedDateTime is an array of strings like '2002-01-31 23:59:59.049876' -// $retrievedDateTime is date/time string of format either 'Y-m-d H:i:s.u' or -// 'Y-m-d H:i:s.u P', which is the format returned by the date_format() calls -// in FetchDatesAndOrTimes when a PHP DateTime object is retrieved, -// unless $datetimetype is date or time. In those cases: -// If $datetimetype is 'date': +// $expectedDateTime is an array of date/time strings corresponding to the different SQL Server types. +// $retrievedDateTime is an array of date/time strings returned by the date_format() calls +// in FetchDatesAndOrTimes when a PHP DateTime object is retrieved. Note how +// dates and times are handled when the type is time and date: +// If $dateTimeType is 'date': // The date is as expected, the time defaults to 00:00:00.0000 -// If $datetimetype is 'time': +// If $dateTimeType is 'time': // The date defaults to the current date, the time is as expected. -function CompareDateTimeObject($datetimetype, &$expectedDateTime, $retrievedDateTime) +function CompareDateTimeObject($dateTimeType, &$expectedDateTime, &$retrievedDateTime) { - $expected_date_time = array(); - - // Split each element of the testing date/time into - // [0]:date, [1]:time, and possibly [2]:timezone offset - for ($i = 0; $i < sizeof($expectedDateTime); ++$i) { - $expected_date_time[] = explode(" ", $expectedDateTime[$i]); - } + // To compare offsets when the retrieved DateTime object defaults + // to the default offset, take the date and time from the retrieved + // string and append the offset from the expected date/time + $ret_date_time = explode(" ",$retrievedDateTime['datetimeoffset']); + $ret_date_time = $ret_date_time[0]." ".$ret_date_time[1]." ".explode(" ",$expectedDateTime['datetimeoffset'][0])[2]; - // If $retrievedDateTime is a string of format 'Y-m-d H:i:s.u' or 'Y-m-d H:i:s.u P', - // split it into [0]:date, [1]:time, and possibly [2]:timezone offset - $retrieved_date_time = explode(" ", $retrievedDateTime); - // Times returned by SQL Server are accurate to 0.0000001 s, but when // formatted using PHP's date_format() function, the times are accurate // to 0.000001 s. So both retrieved and expected times are accurate // to the same precision, and no need for adding zeroes in any of the // comparisons below. - switch ($datetimetype) { + switch ($dateTimeType) { case 'date': // Comparison of dates only. - if ($retrieved_date_time[0] != $expected_date_time[0][0]) { - fatalError("Dates do not match!"); - } + if ($retrievedDateTime['date'] != $expectedDateTime['date'][0]) fatalError("Date tested, dates do not match!"); + if (explode(" ", $retrievedDateTime['datetime'])[0] != explode(" ", $expectedDateTime['datetime'][0])[0]) fatalError("Date tested, datetimes do not match!"); + if (explode(" ", $retrievedDateTime['datetime2'])[0] != explode(" ", $expectedDateTime['datetime2'][0])[0]) fatalError("Date tested, datetime2s do not match!"); + if (explode(" ", $retrievedDateTime['datetimeoffset'])[0] != explode(" ", $expectedDateTime['datetimeoffset'][0])[0]) fatalError("Date tested, datetimeoffsets do not match!"); + if (explode(" ", $retrievedDateTime['smalldatetime'])[0] != explode(" ", $expectedDateTime['smalldatetime'][0])[0]) fatalError("Date tested, smalldatetimes do not match!"); break; case 'time': - // Comparison of times only. - if ($retrieved_date_time[1] != $expected_date_time[0][1] and - $retrieved_date_time[1] != $expected_date_time[1][1] and - $retrieved_date_time[1] != $expected_date_time[2][1] and - $retrieved_date_time[1] != $expected_date_time[3][1]) { - fatalError("Times do not match!"); - } + if ($retrievedDateTime['time'] != $expectedDateTime['time'][1] and + $retrievedDateTime['time'] != $expectedDateTime['time'][2] and + $retrievedDateTime['time'] != $expectedDateTime['time'][3] and + $retrievedDateTime['time'] != $expectedDateTime['time'][4]) fatalError("Time tested, times do not match!"); + if (explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][1])[1] and + explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][2])[1] and + explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][3])[1] and + explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][4])[1]) fatalError("Time tested, datetimes do not match!"); + if (explode(" ", $retrievedDateTime['datetime2'])[1] != explode(" ", $expectedDateTime['datetime2'][1])[1] and + explode(" ", $retrievedDateTime['datetime2'])[1] != explode(" ", $expectedDateTime['datetime2'][2])[1] and + explode(" ", $retrievedDateTime['datetime2'])[1] != explode(" ", $expectedDateTime['datetime2'][3])[1] and + explode(" ", $retrievedDateTime['datetime2'])[1] != explode(" ", $expectedDateTime['datetime2'][4])[1]) fatalError("Time tested, datetime2s do not match!"); + if (explode(" ", $retrievedDateTime['datetimeoffset'])[1] != explode(" ", $expectedDateTime['datetimeoffset'][1])[1] and + explode(" ", $retrievedDateTime['datetimeoffset'])[1] != explode(" ", $expectedDateTime['datetimeoffset'][2])[1] and + explode(" ", $retrievedDateTime['datetimeoffset'])[1] != explode(" ", $expectedDateTime['datetimeoffset'][3])[1] and + explode(" ", $retrievedDateTime['datetimeoffset'])[1] != explode(" ", $expectedDateTime['datetimeoffset'][4])[1]) fatalError("Time tested, datetimeoffsets do not match!"); + if (explode(" ", $retrievedDateTime['smalldatetime'])[1] != explode(" ", $expectedDateTime['smalldatetime'][0])[1]) fatalError("Time tested, smalldatetimes do not match!"); break; case 'datetime': + if ($retrievedDateTime['date'] != $expectedDateTime['date'][0]) fatalError("Datetime tested, dates do not match!"); + if ($retrievedDateTime['time'] != $expectedDateTime['time'][0] and + $retrievedDateTime['time'] != $expectedDateTime['time'][1] and + $retrievedDateTime['time'] != $expectedDateTime['time'][2] and + $retrievedDateTime['time'] != $expectedDateTime['time'][3] and + $retrievedDateTime['time'] != $expectedDateTime['time'][4]) fatalError("Datetime tested, times do not match!"); + if ($retrievedDateTime['datetime'] != $expectedDateTime['datetime'][0] and + $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][1] and + $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][2] and + $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][3]) fatalError("Datetime tested, datetimes do not match!"); + if ($retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][0] and + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][1] and + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][2] and + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][3] and + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][4]) fatalError("Datetime tested, datetime2s do not match!"); + if ($ret_date_time != $expectedDateTime['datetimeoffset'][0] and + $ret_date_time != $expectedDateTime['datetimeoffset'][1] and + $ret_date_time != $expectedDateTime['datetimeoffset'][2] and + $ret_date_time != $expectedDateTime['datetimeoffset'][3] and + $ret_date_time != $expectedDateTime['datetimeoffset'][4]) fatalError("Datetime tested, datetimeoffsets do not match!"); + if ($retrievedDateTime['smalldatetime'] != $expectedDateTime['smalldatetime'][0]) fatalError("Datetime tested, smalldatetimes do not match!"); + break; case 'datetime2': - case 'smalldatetime': - // Combine the retrieved date and time. - if (sizeof($retrieved_date_time)>1) { - $date_time_only = $retrieved_date_time[0]." ".$retrieved_date_time[1]; - } - - // Test combined date and time. The $expectedDateTime values - // all have a different number of trailing zeroes to match - // the precision of different SQL types. - if ($date_time_only != $expectedDateTime[0] and - $date_time_only != $expectedDateTime[1] and - $date_time_only != $expectedDateTime[2] and - $date_time_only != $expectedDateTime[3]) { - fatalError("Datetimes do not match!"); - } + if ($retrievedDateTime['date'] != $expectedDateTime['date'][0]) fatalError("Datetime2 tested, dates do not match!"); + if ($retrievedDateTime['time'] != $expectedDateTime['time'][1] and + $retrievedDateTime['time'] != $expectedDateTime['time'][2] and + $retrievedDateTime['time'] != $expectedDateTime['time'][3] and + $retrievedDateTime['time'] != $expectedDateTime['time'][4]) fatalError("Datetime2 tested, times do not match!"); + if ($retrievedDateTime['datetime'] != $expectedDateTime['datetime'][1] and + $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][2] and + $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][3]) fatalError("Datetime2 tested, datetimes do not match!"); + if ($retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][1] and + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][2] and + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][3] and + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][4]) fatalError("Datetime2 tested, datetime2s do not match!"); + if ($ret_date_time != $expectedDateTime['datetimeoffset'][1] and + $ret_date_time != $expectedDateTime['datetimeoffset'][2] and + $ret_date_time != $expectedDateTime['datetimeoffset'][3] and + $ret_date_time != $expectedDateTime['datetimeoffset'][4]) fatalError("Datetime2 tested, datetimeoffsets do not match!"); + if ($retrievedDateTime['smalldatetime'] != $expectedDateTime['smalldatetime'][0]) fatalError("Datetime2 tested, smalldatetimes do not match!"); break; case 'datetimeoffset': - // The retrieved date/time string will have a timezone - // correction appended to it when the returned type is - // datetimeoffset. - if ($retrievedDateTime != $expectedDateTime[4] and - $retrievedDateTime != $expectedDateTime[5] and - $retrievedDateTime != $expectedDateTime[6] and - $retrievedDateTime != $expectedDateTime[7]) { - fatalError("Datetimeoffsets do not match!"); - } + if ($retrievedDateTime['date'] != $expectedDateTime['date'][0]) fatalError("Datetimeoffset tested, dates do not match!"); + if ($retrievedDateTime['time'] != $expectedDateTime['time'][1] and + $retrievedDateTime['time'] != $expectedDateTime['time'][2] and + $retrievedDateTime['time'] != $expectedDateTime['time'][3] and + $retrievedDateTime['time'] != $expectedDateTime['time'][4]) fatalError("Datetimeoffset tested, times do not match!"); + if ($retrievedDateTime['datetime'] != $expectedDateTime['datetime'][1] and + $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][2] and + $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][3]) fatalError("Datetimeoffset tested, datetimes do not match!"); + if ($retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][1] and + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][2] and + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][3] and + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][4]) fatalError("Datetimeoffset tested, datetime2s do not match!"); + if ($retrievedDateTime['datetimeoffset'] != $expectedDateTime['datetimeoffset'][1] and + $retrievedDateTime['datetimeoffset'] != $expectedDateTime['datetimeoffset'][2] and + $retrievedDateTime['datetimeoffset'] != $expectedDateTime['datetimeoffset'][3] and + $retrievedDateTime['datetimeoffset'] != $expectedDateTime['datetimeoffset'][4]) fatalError("Datetimeoffset tested, datetimeoffsets do not match!"); + if ($retrievedDateTime['smalldatetime'] != $expectedDateTime['smalldatetime'][0]) fatalError("Datetimeoffset tested, smalldatetimes do not match!"); + break; + case 'smalldatetime': + if ($retrievedDateTime['date'] != $expectedDateTime['date'][0]) fatalError("Smalldatetime tested, dates do not match!"); + if ($retrievedDateTime['time'] != $expectedDateTime['time'][1] and + $retrievedDateTime['time'] != $expectedDateTime['time'][2] and + $retrievedDateTime['time'] != $expectedDateTime['time'][3] and + $retrievedDateTime['time'] != $expectedDateTime['time'][4]) fatalError("Smalldatetime tested, times do not match!"); + if ($retrievedDateTime['datetime'] != $expectedDateTime['datetime'][1] and + $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][2] and + $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][3]) fatalError("Smalldatetime tested, datetimes do not match!"); + if ($retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][1] and + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][2] and + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][3] and + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][4]) fatalError("Smalldatetime tested, datetime2s do not match!"); + if ($ret_date_time != $expectedDateTime['datetimeoffset'][1] and + $ret_date_time != $expectedDateTime['datetimeoffset'][2] and + $ret_date_time != $expectedDateTime['datetimeoffset'][3] and + $ret_date_time != $expectedDateTime['datetimeoffset'][4]) fatalError("Smalldatetime tested, datetimeoffsets do not match!"); + if ($retrievedDateTime['smalldatetime'] != $expectedDateTime['smalldatetime'][0]) fatalError("Smalldatetime tested, smalldatetimes do not match!"); break; } } -function InsertDatesAndOrTimes($conn, $datetimetype, &$formats_array, $array_size, $SQLSRV_SQLTYPE_CONST) +function InsertDatesAndOrTimes($conn, $dateTimeType, &$formats_array, $array_size, $SQLSRV_SQLTYPE_CONST) { - $tableName = "table_of_$datetimetype"; + $tableName = "table_of_$dateTimeType"; $columns = array(new AE\ColumnMeta('int', 'id'), - new AE\ColumnMeta("$datetimetype", "c1_$datetimetype")); + new AE\ColumnMeta("$dateTimeType", "c1_$dateTimeType")); $stmt = AE\createTable($conn, $tableName, $columns); if (!$stmt) { fatalError("Failed to create table $tableName\n"); } - $insertSql = "INSERT INTO [$tableName] (id, [c1_$datetimetype]) VALUES (?, ?)"; + $insertSql = "INSERT INTO [$tableName] (id, [c1_$dateTimeType]) VALUES (?, ?)"; for ($i = 0; $i < $array_size; $i++) { $stmt = sqlsrv_prepare($conn, $insertSql, array($i, array($formats_array[$i], SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), $SQLSRV_SQLTYPE_CONST))); @@ -233,9 +260,9 @@ function InsertDatesAndOrTimes($conn, $datetimetype, &$formats_array, $array_siz } } -function FetchDatesAndOrTimes($conn, $datetimetype, &$expectedDateTime, $returnDatesAsStrings) +function FetchDatesAndOrTimes($conn, $dateTimeType, &$expectedDateTime, $returnDatesAsStrings) { - $tableName = "table_of_$datetimetype"; + $tableName = "table_of_$dateTimeType"; echo "Select fields as strings:\n"; @@ -251,8 +278,8 @@ function FetchDatesAndOrTimes($conn, $datetimetype, &$expectedDateTime, $returnD if (!is_string($datetime)) { fatalError("sqlsrv_get_field did not return string but string was specified"); } - - CompareDateTimeString($datetimetype, $expectedDateTime, $datetime); + + CompareDateTimeString($dateTimeType, $expectedDateTime, $datetime); } // retrieve date time fields as DateTime objects @@ -272,10 +299,18 @@ function FetchDatesAndOrTimes($conn, $datetimetype, &$expectedDateTime, $returnD fatalError("sqlsrv_get_field did not return DateTime but DateTime was specified"); } - // append a timezone offset if it's the datetimeoffset type - $datetime = ($datetimetype == 'datetimeoffset') ? date_format($datetime, 'Y-m-d H:i:s.u P') : date_format($datetime, 'Y-m-d H:i:s.u'); - - CompareDateTimeObject($datetimetype, $expectedDateTime, $datetime); + // The formats below correspond to the SQL date and time types, + // but PHP allows users to format the date arbitrarily. The + // formats below are probably the most likely to be used. + $datetimeArray = array('date'=>date_format($datetime, 'Y-m-d'), + 'time'=>date_format($datetime, 'H:i:s.u'), + 'datetime'=>date_format($datetime, 'Y-m-d H:i:s.v'), + 'datetime2'=>date_format($datetime, 'Y-m-d H:i:s.u'), + 'datetimeoffset'=>date_format($datetime, 'Y-m-d H:i:s.u P'), + 'smalldatetime'=>date_format($datetime, 'Y-m-d H:i').":00", + ); + + CompareDateTimeObject($dateTimeType, $expectedDateTime, $datetimeArray); } // retrieve date time fields without explicitly requesting the type @@ -295,16 +330,21 @@ function FetchDatesAndOrTimes($conn, $datetimetype, &$expectedDateTime, $returnD fatalError("String for date expected, not a string"); } - CompareDateTimeString($datetimetype, $expectedDateTime, $datetime); - } else { // ReturnsDatesAsStrings is false + CompareDateTimeString($dateTimeType, $expectedDateTime, $datetime); + } else { // ReturnDatesAsStrings is false if (!($datetime instanceof DateTime)) { fatalError("DateTime object expected, not a DateTime"); } - // append a timezone offset if it's the datetimeoffset type - $datetime = ($datetimetype == 'datetimeoffset') ? date_format($datetime, 'Y-m-d H:i:s.u P') : date_format($datetime, 'Y-m-d H:i:s.u'); - - CompareDateTimeObject($datetimetype, $expectedDateTime, $datetime); + $datetimeArray = array('date'=>date_format($datetime, 'Y-m-d'), + 'time'=>date_format($datetime, 'H:i:s.u'), + 'datetime'=>date_format($datetime, 'Y-m-d H:i:s.v'), + 'datetime2'=>date_format($datetime, 'Y-m-d H:i:s.u'), + 'datetimeoffset'=>date_format($datetime, 'Y-m-d H:i:s.u P'), + 'smalldatetime'=>date_format($datetime, 'Y-m-d H:i').":00", + ); + + CompareDateTimeObject($dateTimeType, $expectedDateTime, $datetimeArray); } } @@ -324,30 +364,35 @@ function FetchDatesAndOrTimes($conn, $datetimetype, &$expectedDateTime, $returnD fatalError("String for date expected, not a string"); } - CompareDateTimeString($datetimetype, $expectedDateTime, $row[1]); - } else { + CompareDateTimeString($dateTimeType, $expectedDateTime, $row[1]); + } else { // ReturnDatesAsStrings is false if (!($row[1] instanceof DateTime)) { fatalError("DateTime object expected, not a DateTime"); } - // append a timezone offset if it's the datetimeoffset type - $datetime = ($datetimetype == 'datetimeoffset') ? date_format($row[1], 'Y-m-d H:i:s.u P') : date_format($row[1], 'Y-m-d H:i:s.u'); + $datetimeArray = array('date'=>date_format($datetime, 'Y-m-d'), + 'time'=>date_format($datetime, 'H:i:s.u'), + 'datetime'=>date_format($datetime, 'Y-m-d H:i:s.v'), + 'datetime2'=>date_format($datetime, 'Y-m-d H:i:s.u'), + 'datetimeoffset'=>date_format($datetime, 'Y-m-d H:i:s.u P'), + 'smalldatetime'=>date_format($datetime, 'Y-m-d H:i').":00", + ); - CompareDateTimeObject($datetimetype, $expectedDateTime, $datetime); + CompareDateTimeObject($dateTimeType, $expectedDateTime, $datetimeArray); } } - - print_r(sqlsrv_field_metadata($stmt)[1]); - } // The date used for the test will be Januray 31, 2002, or 2002/01/31. -// This will sidestep issues involving the use of two digit years since -// SQL Server defaults to 19 as the first two digits. -// Time is 23:59:29.049876 -// Note that smalldatetime rounds to the nearest minute, and that may cause -// this test to fail if it rolls over to the next day. -// Incidentally, this datetime corresponds to a timestamp of 1012521599. +// This will sidestep issues involving the use of two digit years. +// Time is 23:59:29.049876. User can substitute any values they wish for date +// and time, except for values that would cause rollovers to the next +// second/minute/hour/day/month/year because there is no logic in this test +// to handle rollovers. This warning applies to +// 1. datetime when $frac is '999', because datetime is accurate to .000, .003, +// or .007 s, and 999 would roll over to the next second when inserted. +// 2. smalldatetime when $second is >= 30, because smalldatetime rounds to the +// nearest minute, and that may cause this test to fail if it rolls over to the next day. $year = '2002'; $month = '01'; $month_name = 'January'; @@ -358,24 +403,55 @@ $hour12 = '11'; $meridian = 'PM'; $minute = '59'; $second = '29'; -$frac = '04'; -$frac2 = '9876'; +$frac = '049'; +$frac2 = '876'; $tz_correction = '+08:00'; +// The datetime type is accurate to .000, .003, or .007 second, so adjust +// $frac appropriately for that type. Do not use '999' +$frac_rounded = $frac; +if ($frac[2] == '2' or $frac[2] == '4') $frac_rounded[2] = '3'; +elseif ($frac[2] == '5' or $frac[2] == '6' or $frac[2] == '8') $frac_rounded[2] = '7'; +elseif ($frac[2] == '1') $frac_rounded[2] = '0'; +elseif ($frac[2] == '9') +{ + // Get as integer and add one, then get as string back, prepend '0' if result is less than 100 + $frac_int = intval($frac); + $frac_int += 1; + $frac_rounded = $frac_int < 100 ? '0'.strval($frac_int) : strval($frac_int); +} + // This is the array of dates/times/timezones to test against. They have -// different numbers of trailing zeroes to match the precision of different -// SQL date and time types, but all go up to microseconds (0.000001 s) because -// that's how PHP formats times with date_format(), allowing direct string -// comparisons when the DateTime objects retrieved from a table are formatted -// as strings with date_format(). -$expectedDateTime = array($year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2, - $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."0000", - $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000", - $year."-".$month."-".$day." ".$hour.":".$minute.":00.000000", - $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2." ".$tz_correction, - $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."0000 ".$tz_correction, - $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000 ".$tz_correction, - $year."-".$month."-".$day." ".$hour.":".$minute.":00.000000 ".$tz_correction, +// different numbers of trailing zeroes to match the precision of the +// SQL Server date and time types, but only up to microseconds (0.000001 s) +// because that is PHP's maximum precision when formatting times with +// date_format() (time, datetime2, and datetimeoffset go up to 0.0000001 s precision.) +// This allows direct string comparisons when the DateTime objects retrieved from +// a table are formatted as strings with date_format(). However, when returning +// dates as strings using ReturnDatesAsStrings set to true, the returned +// data defaults to SQL Server type precision, so for comparisons some zeroes +// have to be added or removed from the values below. +$expectedDateTime = array('date'=>array($year."-".$month."-".$day), + 'time'=>array($hour.":".$minute.":".$second.".".$frac_rounded."000", + $hour.":".$minute.":".$second.".".$frac.$frac2, + $hour.":".$minute.":".$second.".".$frac."000", + $hour.":".$minute.":".$second.".000000", + $hour.":".$minute.":00.000000"), + 'datetime'=>array($year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac_rounded, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000", + $year."-".$month."-".$day." ".$hour.":".$minute.":00.000"), + 'datetime2'=>array($year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac_rounded."000", + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."000", + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000", + $year."-".$month."-".$day." ".$hour.":".$minute.":00.000000"), + 'datetimeoffset'=>array($year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac_rounded."000 ".$tz_correction, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2." ".$tz_correction, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."000 ".$tz_correction, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000 ".$tz_correction, + $year."-".$month."-".$day." ".$hour.":".$minute.":00.000000 ".$tz_correction), + 'smalldatetime'=>array($year."-".$month."-".$day." ".$hour.":".$minute.":00"), ); // These formats are for the ODBC driver with types specified in sqlsrv_prepare() @@ -425,8 +501,8 @@ $SZ_DATETIME_all = $SZ_TIME_all*$SZ_DATE_all; // datetime type, remove the extra precision of $frac2. For the smalldatetime // type, remove the extra precision of $frac and $frac2. If the numerical // string in $frac and/or $frac2 is found elsewhere in the date/time, the data -// will be garbled. For example, if the year is 2002 and $frac2 is 2002, the -// code below will remove any instances of '2002' in the datetime and +// will be garbled. For example, if the year is 2002 and $frac2 is 002, the +// code below will remove any instances of '002' in the datetime and // smalldatetime strings, producing garbage for those types. User must be // cognizant of this when testing different dates and times. for ($i=0; $i<$SZ_DATE_all; $i++) @@ -495,155 +571,47 @@ Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: -Array -( - [Name] => c1_date - [Type] => 91 - [Size] => - [Precision] => 10 - [Scale] => 0 - [Nullable] => 1 -) Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: -Array -( - [Name] => c1_time - [Type] => -154 - [Size] => - [Precision] => 16 - [Scale] => 7 - [Nullable] => 1 -) Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: -Array -( - [Name] => c1_datetime - [Type] => 93 - [Size] => - [Precision] => 23 - [Scale] => 3 - [Nullable] => 1 -) Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: -Array -( - [Name] => c1_datetime2 - [Type] => 93 - [Size] => - [Precision] => 27 - [Scale] => 7 - [Nullable] => 1 -) Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: -Array -( - [Name] => c1_datetimeoffset - [Type] => -155 - [Size] => - [Precision] => 34 - [Scale] => 7 - [Nullable] => 1 -) Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: -Array -( - [Name] => c1_smalldatetime - [Type] => 93 - [Size] => - [Precision] => 16 - [Scale] => 0 - [Nullable] => 1 -) Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: -Array -( - [Name] => c1_date - [Type] => 91 - [Size] => - [Precision] => 10 - [Scale] => 0 - [Nullable] => 1 -) Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: -Array -( - [Name] => c1_time - [Type] => -154 - [Size] => - [Precision] => 16 - [Scale] => 7 - [Nullable] => 1 -) Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: -Array -( - [Name] => c1_datetime - [Type] => 93 - [Size] => - [Precision] => 23 - [Scale] => 3 - [Nullable] => 1 -) Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: -Array -( - [Name] => c1_datetime2 - [Type] => 93 - [Size] => - [Precision] => 27 - [Scale] => 7 - [Nullable] => 1 -) Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: -Array -( - [Name] => c1_datetimeoffset - [Type] => -155 - [Size] => - [Precision] => 34 - [Scale] => 7 - [Nullable] => 1 -) Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: -Select using fetch_array: -Array -( - [Name] => c1_smalldatetime - [Type] => 93 - [Size] => - [Precision] => 16 - [Scale] => 0 - [Nullable] => 1 -) \ No newline at end of file +Select using fetch_array: \ No newline at end of file From a630c44a5cbfd2d25dd0f078861d0da4be213f95 Mon Sep 17 00:00:00 2001 From: David Puglielli Date: Tue, 20 Mar 2018 12:26:27 -0700 Subject: [PATCH 06/10] Updated datetime test --- test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt index 443c02e6..f1aceb7c 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt @@ -136,8 +136,7 @@ function CompareDateTimeObject($dateTimeType, &$expectedDateTime, &$retrievedDat $retrievedDateTime['time'] != $expectedDateTime['time'][4]) fatalError("Time tested, times do not match!"); if (explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][1])[1] and explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][2])[1] and - explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][3])[1] and - explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][4])[1]) fatalError("Time tested, datetimes do not match!"); + explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][3])[1]) fatalError("Time tested, datetimes do not match!"); if (explode(" ", $retrievedDateTime['datetime2'])[1] != explode(" ", $expectedDateTime['datetime2'][1])[1] and explode(" ", $retrievedDateTime['datetime2'])[1] != explode(" ", $expectedDateTime['datetime2'][2])[1] and explode(" ", $retrievedDateTime['datetime2'])[1] != explode(" ", $expectedDateTime['datetime2'][3])[1] and From edb7bd03d36c3c5449ebf929fdf02a17b1e833e4 Mon Sep 17 00:00:00 2001 From: David Puglielli Date: Tue, 20 Mar 2018 12:48:39 -0700 Subject: [PATCH 07/10] Debugging datetime test --- test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt index f1aceb7c..09d27c55 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt @@ -136,7 +136,10 @@ function CompareDateTimeObject($dateTimeType, &$expectedDateTime, &$retrievedDat $retrievedDateTime['time'] != $expectedDateTime['time'][4]) fatalError("Time tested, times do not match!"); if (explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][1])[1] and explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][2])[1] and - explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][3])[1]) fatalError("Time tested, datetimes do not match!"); + explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][3])[1]) { + print_r($retrievedDateTime); + print_r($expectedDateTime); + fatalError("Time tested, datetimes do not match!");} if (explode(" ", $retrievedDateTime['datetime2'])[1] != explode(" ", $expectedDateTime['datetime2'][1])[1] and explode(" ", $retrievedDateTime['datetime2'])[1] != explode(" ", $expectedDateTime['datetime2'][2])[1] and explode(" ", $retrievedDateTime['datetime2'])[1] != explode(" ", $expectedDateTime['datetime2'][3])[1] and From af8baf145160c5873e4f123a296c31bbec39bc88 Mon Sep 17 00:00:00 2001 From: David Puglielli Date: Tue, 20 Mar 2018 13:44:47 -0700 Subject: [PATCH 08/10] Debugging datetime test --- .../sqlsrv_ae_datetimes_as_strings.phpt | 103 ++++++++++-------- 1 file changed, 55 insertions(+), 48 deletions(-) diff --git a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt index 09d27c55..50b771b5 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt @@ -31,6 +31,19 @@ function ExecutePreparedStmt($stmt) } } +// If there is an error in comparison, output the types, the data, and die +function mismatchError($dateTimeType, $compareType, $retrieved, $expected) +{ + echo "Error comparing dateTimeType = $dateTimeType against $compareType\n"; + if (is_array($retrieved)) { + print_r($retrieved[$compareType]); + } else { + print_r($retrieved); + } + print_r($expected[$compareType]); + fatalError("Retrieved and expected output do not match!"); +} + // Compare dates retrieved from the database with the date used for testing // when ReturnDatesAsStrings is true. // $expectedDateTime is an array of date/time strings corresponding to the different SQL Server types. @@ -40,7 +53,7 @@ function CompareDateTimeString($dateTimeType, &$expectedDateTime, $retrievedDate switch ($dateTimeType) { case 'date': // Direct comparison of retrieved date and expected date - if ($retrievedDateTime != $expectedDateTime['date'][0]) fatalError("Dates do not match!"); + if ($retrievedDateTime != $expectedDateTime['date'][0]) mismatchError('date', 'date', $retrievedDateTime, $expectedDateTime); break; case 'time': // Compare SQL time with expected time. The expected time was input @@ -50,7 +63,7 @@ function CompareDateTimeString($dateTimeType, &$expectedDateTime, $retrievedDate if ($retrievedDateTime != $expectedDateTime['time'][1]."0" and $retrievedDateTime != $expectedDateTime['time'][2]."0" and $retrievedDateTime != $expectedDateTime['time'][3]."0" and - $retrievedDateTime != $expectedDateTime['time'][4]."0") fatalError("Times do not match!"); + $retrievedDateTime != $expectedDateTime['time'][4]."0") mismatchError('time', 'time', $retrievedDateTime, $expectedDateTime); break; case 'datetime': // Compare retrieved SQL datetime with expected date/time. @@ -60,12 +73,7 @@ function CompareDateTimeString($dateTimeType, &$expectedDateTime, $retrievedDate if ($retrievedDateTime != $expectedDateTime['datetime'][0] and $retrievedDateTime != $expectedDateTime['datetime'][1] and $retrievedDateTime != $expectedDateTime['datetime'][2] and - $retrievedDateTime != $expectedDateTime['datetime'][3]) - { - print_r($retrievedDateTime); - print_r($expectedDateTime); - fatalError("Datetimes do not match!"); - } + $retrievedDateTime != $expectedDateTime['datetime'][3]) mismatchError('datetime', 'datetime', $retrievedDateTime, $expectedDateTime); break; case 'datetime2': // Compare retrieved SQL datetime2 with expected date/time. @@ -75,7 +83,7 @@ function CompareDateTimeString($dateTimeType, &$expectedDateTime, $retrievedDate if ($retrievedDateTime != $expectedDateTime['datetime2'][1]."0" and $retrievedDateTime != $expectedDateTime['datetime2'][2]."0" and $retrievedDateTime != $expectedDateTime['datetime2'][3]."0" and - $retrievedDateTime != $expectedDateTime['datetime2'][4]."0") fatalError("Datetime2s do not match!"); + $retrievedDateTime != $expectedDateTime['datetime2'][4]."0") mismatchError('datetime2', 'datetime2', $retrievedDateTime, $expectedDateTime); break; case 'datetimeoffset': // Compare the SQL datetimeoffset retrieved with expected @@ -87,12 +95,12 @@ function CompareDateTimeString($dateTimeType, &$expectedDateTime, $retrievedDate if ($dtoffset != $expectedDateTime['datetimeoffset'][1] and $dtoffset != $expectedDateTime['datetimeoffset'][2] and $dtoffset != $expectedDateTime['datetimeoffset'][3] and - $dtoffset != $expectedDateTime['datetimeoffset'][4]) fatalError("Datetimeoffsets do not match!"); + $dtoffset != $expectedDateTime['datetimeoffset'][4]) mismatchError('datetimeoffset', 'datetimeoffset', $dtoffset, $expectedDateTime); break; case 'smalldatetime': // Compare retrieved SQL smalldatetime with expected date/time. // SQL Server's smalldatetime type is accurate to seconds only. - if ($retrievedDateTime != $expectedDateTime['smalldatetime'][0]) fatalError("Smalldatetimes do not match!"); + if ($retrievedDateTime != $expectedDateTime['smalldatetime'][0]) mismatchError('smalldatetime', 'smalldatetime', $retrievedDateTime, $expectedDateTime); break; } } @@ -123,112 +131,109 @@ function CompareDateTimeObject($dateTimeType, &$expectedDateTime, &$retrievedDat switch ($dateTimeType) { case 'date': // Comparison of dates only. - if ($retrievedDateTime['date'] != $expectedDateTime['date'][0]) fatalError("Date tested, dates do not match!"); - if (explode(" ", $retrievedDateTime['datetime'])[0] != explode(" ", $expectedDateTime['datetime'][0])[0]) fatalError("Date tested, datetimes do not match!"); - if (explode(" ", $retrievedDateTime['datetime2'])[0] != explode(" ", $expectedDateTime['datetime2'][0])[0]) fatalError("Date tested, datetime2s do not match!"); - if (explode(" ", $retrievedDateTime['datetimeoffset'])[0] != explode(" ", $expectedDateTime['datetimeoffset'][0])[0]) fatalError("Date tested, datetimeoffsets do not match!"); - if (explode(" ", $retrievedDateTime['smalldatetime'])[0] != explode(" ", $expectedDateTime['smalldatetime'][0])[0]) fatalError("Date tested, smalldatetimes do not match!"); + if ($retrievedDateTime['date'] != $expectedDateTime['date'][0]) mismatchError('date', 'date', $retrievedDateTime, $expectedDateTime); + if (explode(" ", $retrievedDateTime['datetime'])[0] != explode(" ", $expectedDateTime['datetime'][0])[0]) mismatchError('date', 'datetime', $retrievedDateTime, $expectedDateTime); + if (explode(" ", $retrievedDateTime['datetime2'])[0] != explode(" ", $expectedDateTime['datetime2'][0])[0]) mismatchError('date', 'datetime2', $retrievedDateTime, $expectedDateTime); + if (explode(" ", $retrievedDateTime['datetimeoffset'])[0] != explode(" ", $expectedDateTime['datetimeoffset'][0])[0]) mismatchError('date', 'datetimeoffset', $retrievedDateTime, $expectedDateTime); + if (explode(" ", $retrievedDateTime['smalldatetime'])[0] != explode(" ", $expectedDateTime['smalldatetime'][0])[0]) mismatchError('date', 'smalldatetime', $retrievedDateTime, $expectedDateTime); break; case 'time': if ($retrievedDateTime['time'] != $expectedDateTime['time'][1] and $retrievedDateTime['time'] != $expectedDateTime['time'][2] and $retrievedDateTime['time'] != $expectedDateTime['time'][3] and - $retrievedDateTime['time'] != $expectedDateTime['time'][4]) fatalError("Time tested, times do not match!"); + $retrievedDateTime['time'] != $expectedDateTime['time'][4]) mismatchError('time', 'time', $retrievedDateTime, $expectedDateTime); if (explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][1])[1] and explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][2])[1] and - explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][3])[1]) { - print_r($retrievedDateTime); - print_r($expectedDateTime); - fatalError("Time tested, datetimes do not match!");} + explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][3])[1]) mismatchError('time', 'datetime', $retrievedDateTime, $expectedDateTime); if (explode(" ", $retrievedDateTime['datetime2'])[1] != explode(" ", $expectedDateTime['datetime2'][1])[1] and explode(" ", $retrievedDateTime['datetime2'])[1] != explode(" ", $expectedDateTime['datetime2'][2])[1] and explode(" ", $retrievedDateTime['datetime2'])[1] != explode(" ", $expectedDateTime['datetime2'][3])[1] and - explode(" ", $retrievedDateTime['datetime2'])[1] != explode(" ", $expectedDateTime['datetime2'][4])[1]) fatalError("Time tested, datetime2s do not match!"); + explode(" ", $retrievedDateTime['datetime2'])[1] != explode(" ", $expectedDateTime['datetime2'][4])[1]) mismatchError('time', 'datetime2', $retrievedDateTime, $expectedDateTime); if (explode(" ", $retrievedDateTime['datetimeoffset'])[1] != explode(" ", $expectedDateTime['datetimeoffset'][1])[1] and explode(" ", $retrievedDateTime['datetimeoffset'])[1] != explode(" ", $expectedDateTime['datetimeoffset'][2])[1] and explode(" ", $retrievedDateTime['datetimeoffset'])[1] != explode(" ", $expectedDateTime['datetimeoffset'][3])[1] and - explode(" ", $retrievedDateTime['datetimeoffset'])[1] != explode(" ", $expectedDateTime['datetimeoffset'][4])[1]) fatalError("Time tested, datetimeoffsets do not match!"); - if (explode(" ", $retrievedDateTime['smalldatetime'])[1] != explode(" ", $expectedDateTime['smalldatetime'][0])[1]) fatalError("Time tested, smalldatetimes do not match!"); + explode(" ", $retrievedDateTime['datetimeoffset'])[1] != explode(" ", $expectedDateTime['datetimeoffset'][4])[1]) mismatchError('time', 'datetimeoffset', $retrievedDateTime, $expectedDateTime); + if (explode(" ", $retrievedDateTime['smalldatetime'])[1] != explode(" ", $expectedDateTime['smalldatetime'][0])[1]) mismatchError('time', 'smalldatetime', $retrievedDateTime, $expectedDateTime); break; case 'datetime': - if ($retrievedDateTime['date'] != $expectedDateTime['date'][0]) fatalError("Datetime tested, dates do not match!"); + if ($retrievedDateTime['date'] != $expectedDateTime['date'][0]) mismatchError('datetime', 'date', $retrievedDateTime, $expectedDateTime); if ($retrievedDateTime['time'] != $expectedDateTime['time'][0] and $retrievedDateTime['time'] != $expectedDateTime['time'][1] and $retrievedDateTime['time'] != $expectedDateTime['time'][2] and $retrievedDateTime['time'] != $expectedDateTime['time'][3] and - $retrievedDateTime['time'] != $expectedDateTime['time'][4]) fatalError("Datetime tested, times do not match!"); + $retrievedDateTime['time'] != $expectedDateTime['time'][4]) mismatchError('datetime', 'time', $retrievedDateTime, $expectedDateTime); if ($retrievedDateTime['datetime'] != $expectedDateTime['datetime'][0] and $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][1] and $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][2] and - $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][3]) fatalError("Datetime tested, datetimes do not match!"); + $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][3]) mismatchError('datetime', 'datetime', $retrievedDateTime, $expectedDateTime); if ($retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][0] and $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][1] and $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][2] and $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][3] and - $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][4]) fatalError("Datetime tested, datetime2s do not match!"); + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][4]) mismatchError('datetime', 'datetime2', $retrievedDateTime, $expectedDateTime); if ($ret_date_time != $expectedDateTime['datetimeoffset'][0] and $ret_date_time != $expectedDateTime['datetimeoffset'][1] and $ret_date_time != $expectedDateTime['datetimeoffset'][2] and $ret_date_time != $expectedDateTime['datetimeoffset'][3] and - $ret_date_time != $expectedDateTime['datetimeoffset'][4]) fatalError("Datetime tested, datetimeoffsets do not match!"); - if ($retrievedDateTime['smalldatetime'] != $expectedDateTime['smalldatetime'][0]) fatalError("Datetime tested, smalldatetimes do not match!"); + $ret_date_time != $expectedDateTime['datetimeoffset'][4]) mismatchError('datetime', 'datetimeoffset', $retrievedDateTime, $expectedDateTime); + if ($retrievedDateTime['smalldatetime'] != $expectedDateTime['smalldatetime'][0]) mismatchError('datetime', 'smalldatetime', $retrievedDateTime, $expectedDateTime); break; case 'datetime2': - if ($retrievedDateTime['date'] != $expectedDateTime['date'][0]) fatalError("Datetime2 tested, dates do not match!"); + if ($retrievedDateTime['date'] != $expectedDateTime['date'][0]) mismatchError('datetime2', 'date', $retrievedDateTime, $expectedDateTime); if ($retrievedDateTime['time'] != $expectedDateTime['time'][1] and $retrievedDateTime['time'] != $expectedDateTime['time'][2] and $retrievedDateTime['time'] != $expectedDateTime['time'][3] and - $retrievedDateTime['time'] != $expectedDateTime['time'][4]) fatalError("Datetime2 tested, times do not match!"); + $retrievedDateTime['time'] != $expectedDateTime['time'][4]) mismatchError('datetime2', 'time', $retrievedDateTime, $expectedDateTime); if ($retrievedDateTime['datetime'] != $expectedDateTime['datetime'][1] and $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][2] and - $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][3]) fatalError("Datetime2 tested, datetimes do not match!"); + $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][3]) mismatchError('datetime2', 'datetime', $retrievedDateTime, $expectedDateTime); if ($retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][1] and $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][2] and $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][3] and - $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][4]) fatalError("Datetime2 tested, datetime2s do not match!"); + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][4]) mismatchError('datetime2', 'datetime2', $retrievedDateTime, $expectedDateTime); if ($ret_date_time != $expectedDateTime['datetimeoffset'][1] and $ret_date_time != $expectedDateTime['datetimeoffset'][2] and $ret_date_time != $expectedDateTime['datetimeoffset'][3] and - $ret_date_time != $expectedDateTime['datetimeoffset'][4]) fatalError("Datetime2 tested, datetimeoffsets do not match!"); - if ($retrievedDateTime['smalldatetime'] != $expectedDateTime['smalldatetime'][0]) fatalError("Datetime2 tested, smalldatetimes do not match!"); + $ret_date_time != $expectedDateTime['datetimeoffset'][4]) mismatchError('datetime2', 'datetimeoffset', $retrievedDateTime, $expectedDateTime); + if ($retrievedDateTime['smalldatetime'] != $expectedDateTime['smalldatetime'][0]) mismatchError('datetime2', 'smalldatetime', $retrievedDateTime, $expectedDateTime); break; case 'datetimeoffset': - if ($retrievedDateTime['date'] != $expectedDateTime['date'][0]) fatalError("Datetimeoffset tested, dates do not match!"); + if ($retrievedDateTime['date'] != $expectedDateTime['date'][0]) mismatchError('datetimeoffset', 'date', $retrievedDateTime, $expectedDateTime); if ($retrievedDateTime['time'] != $expectedDateTime['time'][1] and $retrievedDateTime['time'] != $expectedDateTime['time'][2] and $retrievedDateTime['time'] != $expectedDateTime['time'][3] and - $retrievedDateTime['time'] != $expectedDateTime['time'][4]) fatalError("Datetimeoffset tested, times do not match!"); + $retrievedDateTime['time'] != $expectedDateTime['time'][4]) mismatchError('datetimeoffset', 'time', $retrievedDateTime, $expectedDateTime); if ($retrievedDateTime['datetime'] != $expectedDateTime['datetime'][1] and $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][2] and - $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][3]) fatalError("Datetimeoffset tested, datetimes do not match!"); + $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][3]) mismatchError('datetimeoffset', 'datetime', $retrievedDateTime, $expectedDateTime); if ($retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][1] and $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][2] and $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][3] and - $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][4]) fatalError("Datetimeoffset tested, datetime2s do not match!"); + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][4]) mismatchError('datetimeoffset', 'datetime2', $retrievedDateTime, $expectedDateTime); if ($retrievedDateTime['datetimeoffset'] != $expectedDateTime['datetimeoffset'][1] and $retrievedDateTime['datetimeoffset'] != $expectedDateTime['datetimeoffset'][2] and $retrievedDateTime['datetimeoffset'] != $expectedDateTime['datetimeoffset'][3] and - $retrievedDateTime['datetimeoffset'] != $expectedDateTime['datetimeoffset'][4]) fatalError("Datetimeoffset tested, datetimeoffsets do not match!"); - if ($retrievedDateTime['smalldatetime'] != $expectedDateTime['smalldatetime'][0]) fatalError("Datetimeoffset tested, smalldatetimes do not match!"); + $retrievedDateTime['datetimeoffset'] != $expectedDateTime['datetimeoffset'][4]) mismatchError('datetimeoffset', 'datetimeoffset', $retrievedDateTime, $expectedDateTime); + if ($retrievedDateTime['smalldatetime'] != $expectedDateTime['smalldatetime'][0]) mismatchError('datetimeoffset', 'smalldatetime', $retrievedDateTime, $expectedDateTime); break; case 'smalldatetime': - if ($retrievedDateTime['date'] != $expectedDateTime['date'][0]) fatalError("Smalldatetime tested, dates do not match!"); + if ($retrievedDateTime['date'] != $expectedDateTime['date'][0]) mismatchError('smalldatetime', 'date', $retrievedDateTime, $expectedDateTime); if ($retrievedDateTime['time'] != $expectedDateTime['time'][1] and $retrievedDateTime['time'] != $expectedDateTime['time'][2] and $retrievedDateTime['time'] != $expectedDateTime['time'][3] and - $retrievedDateTime['time'] != $expectedDateTime['time'][4]) fatalError("Smalldatetime tested, times do not match!"); + $retrievedDateTime['time'] != $expectedDateTime['time'][4]) mismatchError('smalldatetime', 'time', $retrievedDateTime, $expectedDateTime); if ($retrievedDateTime['datetime'] != $expectedDateTime['datetime'][1] and $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][2] and - $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][3]) fatalError("Smalldatetime tested, datetimes do not match!"); + $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][3]) mismatchError('smalldatetime', 'datetime', $retrievedDateTime, $expectedDateTime); if ($retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][1] and $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][2] and $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][3] and - $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][4]) fatalError("Smalldatetime tested, datetime2s do not match!"); + $retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][4]) mismatchError('smalldatetime', 'datetime2', $retrievedDateTime, $expectedDateTime); if ($ret_date_time != $expectedDateTime['datetimeoffset'][1] and $ret_date_time != $expectedDateTime['datetimeoffset'][2] and $ret_date_time != $expectedDateTime['datetimeoffset'][3] and - $ret_date_time != $expectedDateTime['datetimeoffset'][4]) fatalError("Smalldatetime tested, datetimeoffsets do not match!"); - if ($retrievedDateTime['smalldatetime'] != $expectedDateTime['smalldatetime'][0]) fatalError("Smalldatetime tested, smalldatetimes do not match!"); + $ret_date_time != $expectedDateTime['datetimeoffset'][4]) mismatchError('smalldatetime', 'datetimeoffset', $retrievedDateTime, $expectedDateTime); + if ($retrievedDateTime['smalldatetime'] != $expectedDateTime['smalldatetime'][0]) mismatchError('smalldatetime', 'smalldatetime', $retrievedDateTime, $expectedDateTime); break; } } @@ -282,6 +287,7 @@ function FetchDatesAndOrTimes($conn, $dateTimeType, &$expectedDateTime, $returnD } CompareDateTimeString($dateTimeType, $expectedDateTime, $datetime); + if ($dateTimeType == 'time') echo "id = $idnum dt = $datetime\n"; } // retrieve date time fields as DateTime objects @@ -313,6 +319,7 @@ function FetchDatesAndOrTimes($conn, $dateTimeType, &$expectedDateTime, $returnD ); CompareDateTimeObject($dateTimeType, $expectedDateTime, $datetimeArray); + if ($dateTimeType == 'time') {echo "id = $idnum dt = ";print_r($datetime);} } // retrieve date time fields without explicitly requesting the type From 410e8ebf813f213c9061efe102873056beadc679 Mon Sep 17 00:00:00 2001 From: David Puglielli Date: Tue, 20 Mar 2018 14:10:37 -0700 Subject: [PATCH 09/10] Debugging datetime test --- test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt index 50b771b5..c97311bc 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt @@ -318,8 +318,8 @@ function FetchDatesAndOrTimes($conn, $dateTimeType, &$expectedDateTime, $returnD 'smalldatetime'=>date_format($datetime, 'Y-m-d H:i').":00", ); + if ($dateTimeType == 'time') {echo "id = $idnum dt = ";print_r($datetime);print_r($datetimeArray);} CompareDateTimeObject($dateTimeType, $expectedDateTime, $datetimeArray); - if ($dateTimeType == 'time') {echo "id = $idnum dt = ";print_r($datetime);} } // retrieve date time fields without explicitly requesting the type From e8cc0d5c980b81ba06b9bd883ed15d503003a42d Mon Sep 17 00:00:00 2001 From: David Puglielli Date: Tue, 20 Mar 2018 15:33:20 -0700 Subject: [PATCH 10/10] Debugging datetime test --- .../sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt index c97311bc..1ad1cecd 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt @@ -142,7 +142,8 @@ function CompareDateTimeObject($dateTimeType, &$expectedDateTime, &$retrievedDat $retrievedDateTime['time'] != $expectedDateTime['time'][2] and $retrievedDateTime['time'] != $expectedDateTime['time'][3] and $retrievedDateTime['time'] != $expectedDateTime['time'][4]) mismatchError('time', 'time', $retrievedDateTime, $expectedDateTime); - if (explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][1])[1] and + if (explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][0])[1] and + explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][1])[1] and explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][2])[1] and explode(" ", $retrievedDateTime['datetime'])[1] != explode(" ", $expectedDateTime['datetime'][3])[1]) mismatchError('time', 'datetime', $retrievedDateTime, $expectedDateTime); if (explode(" ", $retrievedDateTime['datetime2'])[1] != explode(" ", $expectedDateTime['datetime2'][1])[1] and @@ -184,7 +185,8 @@ function CompareDateTimeObject($dateTimeType, &$expectedDateTime, &$retrievedDat $retrievedDateTime['time'] != $expectedDateTime['time'][2] and $retrievedDateTime['time'] != $expectedDateTime['time'][3] and $retrievedDateTime['time'] != $expectedDateTime['time'][4]) mismatchError('datetime2', 'time', $retrievedDateTime, $expectedDateTime); - if ($retrievedDateTime['datetime'] != $expectedDateTime['datetime'][1] and + if ($retrievedDateTime['datetime'] != $expectedDateTime['datetime'][0] and + $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][1] and $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][2] and $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][3]) mismatchError('datetime2', 'datetime', $retrievedDateTime, $expectedDateTime); if ($retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][1] and @@ -203,7 +205,8 @@ function CompareDateTimeObject($dateTimeType, &$expectedDateTime, &$retrievedDat $retrievedDateTime['time'] != $expectedDateTime['time'][2] and $retrievedDateTime['time'] != $expectedDateTime['time'][3] and $retrievedDateTime['time'] != $expectedDateTime['time'][4]) mismatchError('datetimeoffset', 'time', $retrievedDateTime, $expectedDateTime); - if ($retrievedDateTime['datetime'] != $expectedDateTime['datetime'][1] and + if ($retrievedDateTime['datetime'] != $expectedDateTime['datetime'][0] and + $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][1] and $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][2] and $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][3]) mismatchError('datetimeoffset', 'datetime', $retrievedDateTime, $expectedDateTime); if ($retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][1] and @@ -222,7 +225,8 @@ function CompareDateTimeObject($dateTimeType, &$expectedDateTime, &$retrievedDat $retrievedDateTime['time'] != $expectedDateTime['time'][2] and $retrievedDateTime['time'] != $expectedDateTime['time'][3] and $retrievedDateTime['time'] != $expectedDateTime['time'][4]) mismatchError('smalldatetime', 'time', $retrievedDateTime, $expectedDateTime); - if ($retrievedDateTime['datetime'] != $expectedDateTime['datetime'][1] and + if ($retrievedDateTime['datetime'] != $expectedDateTime['datetime'][0] and + $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][1] and $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][2] and $retrievedDateTime['datetime'] != $expectedDateTime['datetime'][3]) mismatchError('smalldatetime', 'datetime', $retrievedDateTime, $expectedDateTime); if ($retrievedDateTime['datetime2'] != $expectedDateTime['datetime2'][1] and @@ -287,7 +291,6 @@ function FetchDatesAndOrTimes($conn, $dateTimeType, &$expectedDateTime, $returnD } CompareDateTimeString($dateTimeType, $expectedDateTime, $datetime); - if ($dateTimeType == 'time') echo "id = $idnum dt = $datetime\n"; } // retrieve date time fields as DateTime objects @@ -318,7 +321,6 @@ function FetchDatesAndOrTimes($conn, $dateTimeType, &$expectedDateTime, $returnD 'smalldatetime'=>date_format($datetime, 'Y-m-d H:i').":00", ); - if ($dateTimeType == 'time') {echo "id = $idnum dt = ";print_r($datetime);print_r($datetimeArray);} CompareDateTimeObject($dateTimeType, $expectedDateTime, $datetimeArray); }