我正在更新一个与php 7一起工作的项目。在通过sqlsrv驱动程序使用sql server时遇到了日期比较问题。
以前(php 5),当我传递一个php datetime对象作为查询参数时,它与datetime(sql)列的值进行比较,不包括时区。现在考虑到了时区,这就中断了脚本的工作。如何使它不再被计算?不建议将php时区更改为utc或在每个请求中添加“cast to datetime”。
SQL表db.dbo.table内容:
id dt (datetime)
1 2019-08-31 23:59:00.000
php代码
$sqlc = sqlsrv_connect( $serverName,
[
'Database'=>$dbName,
'UID'=>$userName,
'PWD'=>$userPassword,
'CharacterSet' =>'UTF-8',
'ConnectionPooling' => 1
]);
// date with server timezone (local)
$dtObject = date_create('2019-08-31 23:59:00');
// just for example, we are looking for id by known date
$request = "SELECT [id] FROM DB.dbo.TABLE WHERE [dt] = (?)";
$params = [$dtObject];
$query = sqlsrv_query($sqlc, $request, $params, array("Scrollable"=>"forward"));
if ( $query )
{
while( $row = @sqlsrv_fetch_array($query, SQLSRV_FETCH_ASSOC) )
{
// output id
echo "id {$row['id']}\r\n";
}
}
?>
上面的代码对
PHP5.5
,
MSSQL2005
,
php_sqlsrv 3.1.0.0
并返回期望的结果
id : 1
不分时区
PHP DateTime
反对。
但说到
PHP7.3
,
MSSQL2017
和
php_sqlsrv 5.6.1.11919
,将考虑时区,因此日期不匹配
我认为这是由于
php日期时间
反对
SQL datetimeoffset
,而之前的日期是
SQL datetime
类型。有人知道如何通过避免直接在php代码中进行更改来解决这个问题吗(有很多这样的更改)?
编辑:
为了澄清这种情况,我将给出一些停止正常工作的代码示例
// get date by id (reminder: date stored as datetime)
$request = "SELECT [dt] FROM DB.dbo.TABLE WHERE [id] = (?)";
$params = [1];
$query = sqlsrv_query($sqlc, $request, $params, array("Scrollable"=>"forward"));
$row = @sqlsrv_fetch_array($query, SQLSRV_FETCH_ASSOC);
$dtObject = $row['dt']; // 2019-08-31 23:59:00.000000, !timezone local!
// get id by same date
$request = "SELECT [id] FROM DB.dbo.TABLE WHERE [dt] = (?)";
$params = [$dtObject];
$query = sqlsrv_query($sqlc, $request, $params, array("Scrollable"=>"forward"));
$row = @sqlsrv_fetch_array($query, SQLSRV_FETCH_ASSOC);
$id = $row['id']; // PHP5:OK; PHP7:no result
// PHP7 workaround
$request = "SELECT [id] FROM DB.dbo.TABLE WHERE [dt] = CAST((?) as DATETIME)";
?>
所以,当我这样做的时候
GET date from datetime column
我收到当地时区的准确日期。
但当我在第二个请求中使用此日期时,它与存储的日期不匹配,直到
CAST to datetime
补充。
即使我把所有时区切换到
UTC
下一期没有圆形和附加的类型转换就无法击败:
// create datetime object
// lets imagine now is 2019-08-28 05:55:08.392200 UTC+00:00
$dtObject = date_create('now');
$request = "INSERT INTO DB.dbo.TABLE([id],[dt]) VALUES(?,?)";
$params = [2,$dtObject];
$query = sqlsrv_query($sqlc, $request, $params, array("Scrollable"=>"forward"));
// table now has row
// 2 2019-08-28 05:55:08.393 // NOTE: .393
// get id by same date
$request = "SELECT [id] FROM DB.dbo.TABLE WHERE [dt] = (?)";
$params = [$dtObject];
$query = sqlsrv_query($sqlc, $request, $params, array("Scrollable"=>"forward"));
$row = @sqlsrv_fetch_array($query, SQLSRV_FETCH_ASSOC);
$id = $row['id']; // PHP5:OK; PHP7:no result
// PHP7 workaround
$request = "SELECT [id] FROM DB.dbo.TABLE WHERE [dt] = CAST((?) as DATETIME)";
?>
问题
为什么,当阅读
(选择)
SQL日期时间
,我明白了
php日期时间
写作时使用正确的时区(本地)
(插入)
一切都很好,但是当谈到比较
WHERE [dt] = (PHP DateTime Object)
,日期不匹配?
编辑2
临时解决方案
由于项目中的所有数据库查询都是使用包装类执行的,因此我已将所有datetime参数配置为字符串的一处转换:
foreach ($this->request_params as $key => $value) {
if ( !$this->fulldatetime && $value instanceof DateTime )
# OLD datetime fields compat
$params[$key] = $value->format( "Y-m-d\TH:i:s." ).substr( $value->format( "u" ), 0, 3 );
else
$params[$key] = $value;
}