PHP7.3 SQLSRV — Формат даты и времени отличается при запросе и сохранении

#php #sql-server #sqlsrv

#php #sql-сервер #sqlsrv

Вопрос:

Мы должны обновить нашу систему для использования PHP7.3 (перейти с MSSQL на драйвер базы данных SQLSRV и SQLSRV с PDO)

Моя проблема в том, что я не понимаю это поведение и как его правильно решить.

Когда я запрашиваю DateTime столбец из базы данных, я получаю:

 2019-03-26 00:00:00.000
  

Когда я пытаюсь сохранить одно и то же значение в DateTime столбце базы данных, это не работает. Моя база данных принимает этот формат, например:

  26-03-2019 00:00:00.000
  

по этой причине наш существующий уровень базы данных не работает должным образом.

мне нужна помощь, чтобы понять это поведение и как сообщить базе данных использовать один и тот же формат для запроса и ВСТАВКИ / ОБНОВЛЕНИЯ

В используемых нами запросах нет специальных преобразований, простой ВЫБОР / ОБНОВЛЕНИЕ / ВСТАВКА.

Версия PHP: PHP 7.3.3-1 ubuntu18.04.1 deb.sury.org 1 (cli) (собран: 7 марта 2019 20:31:49) (NTS )
Авторское право (c) 1997-2018 PHP Group Zend Engine v3.3.3, Авторское право (c) 1998-2018 Zend Technologies с Zend OPcache v7.3.3-1 ubuntu18.04.1 deb.sury.org 1, Авторское право (c) 1999-2018, автор Zend Technologies

SQLServer: MSSQL Server 2014

спасибо за любую подсказку

Комментарии:

1. пожалуйста, объясните, почему -1?

2. Ваш вопрос неясен. Формат неверен при выборе его ИЗ SQL или вставке в SQL?

Ответ №1:

1. Как получить значения даты и времени с SQL Server:

1.1. Извлеките значения даты и времени из пользовательского интерфейса SQL Server с PDO_SQLSRV-версией драйвера PHP для SQL Server:

При использовании драйвера PDO_SQLSRV значения из столбцов даты и времени возвращаются в виде строк до версии драйвера 5.6.0. В этом случае единственным вариантом является переформатирование значений даты и времени (например, с '2019-03-26 00:00:00.000' на '26-03-2019 00:00:00.000' ). Начиная с версии 5.6.0, вы можете изменить это поведение с помощью атрибута PDO::SQLSRV_ATTR_FETCHES_DATETIME_TYPE соединения или инструкции PDO::SQLSRV_ATTR_FETCHES_DATETIME_TYPE и извлекать значения полей даты и времени в качестве переменной PHP DateTime. Затем вы можете легко отформатировать эту переменную как строку, используя DateTime::format.

 <?php

// Connection
$server   = "serverinstanse";
$database = "database";
$username = "username";
$password = "password";
try {
   $conn = new PDO("sqlsrv:server=$server;Database=$database", $username, $password);
   $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
   $conn->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_SYSTEM);
} catch( PDOException $e ) {
   die( "Error connecting to SQL Server".$e->getMessage());
}    

// Datetime values as PHP DateTime object
try {
   $query = "SELECT GETDATE() AS DateTimeColumn";
   $stmt = $conn->prepare($query);
   $stmt->setAttribute(PDO::SQLSRV_ATTR_FETCHES_DATETIME_TYPE, true);
   $stmt->execute();
} catch( PDOException $e ) {
   die( "Error connecting to SQL Server".$e->getMessage());
}
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { 
   echo $row["DateTimeColumn"]->format('Y-m-d H:i:s.v') . "<br>";
}
$stmt = null;

// Datetime values as text
try {
   $query = "SELECT GETDATE() AS DateTimeColumn";
   $stmt = $conn->prepare($query);
   $stmt->setAttribute(PDO::SQLSRV_ATTR_FETCHES_DATETIME_TYPE, false);
   $stmt->execute();
} catch( PDOException $e ) {
   die( "Error connecting to SQL Server".$e->getMessage());
}
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { 
   echo $row["DateTimeColumn"] . "<br>";
}
$stmt = null;

// End
$conn = null;

?>
  

1.2. Извлеките значения даты и времени выходных параметров из хранимой процедуры SQL Server, используя PDO_SQLSRV версию драйвера PHP для SQL Server:

Примечание из документации объясняет, что PDO::SQLSRV_ATTR_FETCHES_DATETIME_TYPE атрибут connection или statement применяется только к обычной выборке типов даты и времени, поскольку объекты DateTime не могут быть указаны в качестве выходных параметров. В этой ситуации единственным возможным вариантом является передача datetime выходного параметра хранимой процедуры в виде строковой переменной PHP. Возвращаемое значение зависит от языковой среды для сеанса.

Хранимая процедура:

 CREATE PROCEDURE spReturnDateTime
    @datetime datetime OUTPUT
AS
BEGIN
    SET NOCOUNT ON
    SELECT GETDATE() AS [DateTime]
    SET @datetime = GETDATE()
END
  

PHP:

 <?php
// Connnection
$server   = "serverinstanse";
$database = "database";
$username = "username";
$password = "password";
try {
    $conn = new PDO("sqlsrv:server=$server;Database=$database", $username, $password);
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $conn->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_SYSTEM);
} catch( PDOException $e ) {
    die( "Error connecting to SQL Server".$e->getMessage());
}

// Output parameters from stored procedure
try {
    // 
    $sql = "
        SET LANGUAGE 'English'
        EXEC :errcode = spReturnDateTime @datetime = :datetime
    ";
    $errcode = 0;
    $datetime = "";
    $stmt = $conn->prepare($sql);
    $stmt->bindParam(':errcode', $errcode, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
    $stmt->bindParam(':datetime', $datetime, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 50);
    $stmt->execute();
    do {
        while ($row = $stmt->fetch( PDO::FETCH_ASSOC) ){
            echo $row["DateTime"]."<br>";
        }
    } while ($stmt->nextRowset());  
    $stmt = null;
    echo $datetime."<br>";
    //
    $sql = "
        SET LANGUAGE 'Bulgarian'
        EXEC :errcode = spReturnDateTime @datetime = :datetime
    ";
    $errcode = 0;
    $datetime = "";
    $stmt = $conn->prepare($sql);
    $stmt->bindParam(':errcode', $errcode, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
    $stmt->bindParam(':datetime', $datetime, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 50);
    $stmt->execute();
    do {
        while ($row = $stmt->fetch( PDO::FETCH_ASSOC) ){
            echo $row["DateTime"]."<br>";
        }
    } while ($stmt->nextRowset());  
    $stmt = null;
    echo $datetime."<br>";
} catch (PDOException $e) {
    die ("Error executing query. ".$e->getMessage());
}

// End
$conn = null;
?>
  

Результаты:

 2021-06-10 10:05:54.580
Jun 10 2021 10:05AM
2021-06-10 10:05:54.580
юни 10 2021 10:05AM
  

1.3. Извлеките значения даты и времени из SQL Server, используя SQLSRV-версию драйвера PHP для SQL Server:

По умолчанию типы smalldatetime , datetime date , time datetime2 , datetimeoffset 'ReturnDatesAsStrings' ,,, будут возвращены как объекты PHP DateTime, но это поведение может быть изменено путем установки,, опции в строке подключения или на уровне инструкции:

 <?php

// Connection
$server   = "serverinstanse";
$database = "database";
$username = "username";
$password = "password";
$cinfo = array(
   "Database" => $database, 
   "UID" => $username, 
   "PWD" => $password
);
$conn = sqlsrv_connect($server, $cinfo);
if ($conn === false) {
   echo "Error (sqlsrv_connect): ".print_r(sqlsrv_errors(), true);
   exit;
}

// Datetime values as PHP DateTime object
$query = "SELECT GETDATE() AS DateTimeColumn";
$options = array('ReturnDatesAsStrings' => false);
$stmt = sqlsrv_query($conn, $query, null, $options);
if ($stmt === false) {
   echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);
   exit;
}
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
   echo $row["DateTimeColumn"]->format('Y-m-d H:i:s.v') . "<br>";
}
sqlsrv_free_stmt($stmt);

// Datetime values as text
$query = "SELECT GETDATE() AS DateTimeColumn";
$options = array('ReturnDatesAsStrings' => true);
$stmt = sqlsrv_query($conn, $query, null, $options);
if ($stmt === false) {
   echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);
   exit;
}
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
   echo $row["DateTimeColumn"] . "<br>";
}
sqlsrv_free_stmt($stmt);

// End
sqlsrv_close($conn);

?>
  

1.4. Извлекать значения даты и времени из расширения SQL Server uisng MSSQL PHP (расширение было удалено в PHP 7.0.0):

При использовании расширения MSSQL значения даты и времени возвращаются в виде текста, но формат зависит от mssql.datetimeconvert настройки в php.ini файле. Когда этот параметр установлен ON , значения даты и времени преобразуются на основе настроек SQL Server, а когда установлен OFF , значения даты и времени преобразуются в YYYY-MM-DD hh:mm:ss формат.

 <?php
$server   = "serverinstanse";
$database = "database";
$username = "username";
$password = "password";

$conn = mssql_connect($server);
if ($conn === false) {
    echo "Error (mssql_connect): ".mssql_get_last_message();
    exit;
}
mssql_select_db($database, $conn);

$query = "SELECT DateTimeColumn FROM OneTable";
$stmt = mssql_query($sql, $conn);
if ($stmt === false) {
    echo "Error (mssql_query): ".mssql_get_last_message();
    exit;
}

while ($row = mssql_fetch_assoc($stmt)) {
   echo print_r($row, true);
}

mssql_free_result($stmt);
mssql_close($conn);
?>
  

В качестве дополнительного примечания, похоже, что этот параметр находится ON в вашей серверной среде, потому что вы можете отправлять подобные даты '26-03-2019 00:00:00.000' без ошибок.

2. Как передать значения даты и времени на SQL Server:

Как правило, значения даты и времени могут быть переданы SQL Server с использованием однозначного формата datetime ( yyyymmdd или yyyy-mm-ddThh:mm:ss ) и параметризованного оператора.

2.1. Передать значения даты и времени в пользовательский интерфейс SQL Server с PDO_SQLSRV-версией драйвера PHP для SQL Server:

 <?php
$server   = "serverinstanse";
$database = "database";
$username = "username";
$password = "password";

try {
   $conn = new PDO("sqlsrv:server = $server; Database = $database", $username, $password);
   $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch( PDOException $e ) {
   die( "Error connecting to SQL Server".$e->getMessage());
}

try {
   $query = "INSERT INTO OneTable (DateTimeColumn) VALUES (?)";
   $datetime = (new DateTime())->format("Y-m-dTH:i:s");
   $stmt = $conn->prepare($query);
   $stmt->bindParam(1, $datetime);
   $stmt->execute();
} catch( PDOException $e ) {
   die( "Error connecting to SQL Server".$e->getMessage());
}

$stmt = null;
$conn = null;
?>
  

2.2. Передавать значения даты и времени в SQL Server, используя SQLSRV-версию драйвера PHP для SQL Server:

В этой версии драйвера вы можете использовать синтаксис расширенных параметров и передавать значение datetime как объект PHP DateTime с информацией о типах данных параметра PHP и SQL Server.

 <?php
$server   = "serverinstanse";
$database = "database";
$username = "username";
$password = "password";

$cinfo = array(
   "Database" => $database, 
   "UID" => $username, 
   "PWD" => $password
);
$conn = sqlsrv_connect($server, $cinfo);
if ($conn === false) {
   echo "Error (sqlsrv_connect): ".print_r(sqlsrv_errors(), true);
   exit;
}

$query = "INSERT INTO OneTable (DateTimeColumn) VALUES (?)";
$datetime = new DateTime();
$params = array(
   array($datetime, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_DATETIME, SQLSRV_SQLTYPE_DATETIME)
); 
// or as usual, pass datetime values as text
//$params = array($datetime->format("Y-m-dTH:i:s")); 
$stmt = sqlsrv_query($conn, $query, $params);
if ($stmt === false) {
   echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);
   exit;
}

sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
?>