--TEST-- Test various date and time types with AE and ReturnDatesAsStrings set to true --SKIPIF-- --FILE-- 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 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"); } CompareDateTimeString($dateTimeType, $expectedDateTime, $datetime); } else { // ReturnDatesAsStrings is false if (!($datetime instanceof DateTime)) { fatalError("DateTime object expected, not a 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); } } // 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"); } CompareDateTimeString($dateTimeType, $expectedDateTime, $row[1]); } else { // ReturnDatesAsStrings is false if (!($row[1] instanceof DateTime)) { fatalError("DateTime object expected, not a 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); } } } // 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. // 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'; $month_abbr = 'Jan'; $day = '31'; $hour = '23'; $hour12 = '11'; $meridian = 'PM'; $minute = '59'; $second = '29'; $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 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() $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/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 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++) { 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', 1); sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL); sqlsrv_configure('LogSubsystems', SQLSRV_LOG_SYSTEM_OFF); $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', $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); $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', $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); ?> --EXPECT-- Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: Select fields as strings: Select fields as DateTime objects: Select fields with no type information provided: Select using fetch_array: