SqlBulkCopy — неправильное преобразование даты и времени

#c# #sql-server #ado.net #sqlbulkcopy

#c# #sql-сервер #ado.net #sqlbulkcopy

Вопрос:

Я получаю результаты запроса из Azure Log Analytics. Результаты находятся в Table объекте. Все это в строковом формате. В базе данных таблица имеет столбец PeriodStart , который является smalldatetime типом.

Приведенный ниже код работает нормально — он вставляет все данные. Но он преобразует PeriodStart неправильно. Например, у меня есть строковое значение в строке для PeriodStart столбца "2019-03-26T00:00:00Z" — и в базе данных оно будет выглядеть "2019-03-26 02:00:00" . Похоже, что он использует мой часовой пояс — преобразует в местное время. Как этого избежать?

 public async Task BulkInsertMetrics(Table metrics)
{
    var metricsDt = new DataTable();
    metricsDt.Columns.AddRange(metrics.Columns
        .Select(c => new DataColumn(c.Name)).ToArray());
    foreach (var row in metrics.Rows)
    {
        metricsDt.Rows.Add(row.ToArray());
    }

    using (var connection = new SqlConnection(_databaseSettings.ConnectionString))
    {
        await connection.OpenAsync();
        using (var transaction = connection.BeginTransaction())
        using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
        {
            bulkCopy.DestinationTableName = "Metrics";
            foreach (var column in metrics.Columns)
            {
                bulkCopy.ColumnMappings.Add(column.Name, column.Name);
            }

            await bulkCopy.WriteToServerAsync(metricsDt);
            transaction.Commit();
        }
    }
}
  

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

1. Используйте строго типизированный столбец datetime в качестве исходного DataTable, чтобы избежать проблем с синтаксическим анализом и форматированием строк.

2. Хорошо, преобразование вручную помогло. Я использовал ToUniversalTime() после разбора строки. Спасибо.

3. Я расширил ваше решение ответом.

Ответ №1:

Когда вы передаете строку даты и времени, она должна быть проанализирована клиентским API и преобразована в целевой smalldatetime тип данных, который не имеет понятия о часовом поясе. .NET распознает строку даты и времени ISO 8601 с буквой «Z», обозначающей UTC, и по умолчанию преобразует ее в ваше местное время. А именно:

 DateTime.Parse("2019-03-26T00:00:00Z") //converted to your local time
DateTime.Parse("2019-03-26T00:00:00") //no conversion
  

Одним из обходных путей является использование ToUniversalTime() метода, позволяющего избежать преобразования в ваш местный часовой пояс:

 DateTime.Parse("2019-03-26T00:00:00Z").ToUniversalTime()
  

Обычно рекомендуется использовать DataTable с собственными типами данных, содержащими желаемое значение, чтобы вы имели полный контроль над фактическим значением, вставленным в базу данных.