С#: как остановить добавление смещения часового пояса в System.DateTime при вставке в столбец DateTimeOffset SQL Server

У меня есть код С#, который копирует строки из одной базы данных и вставляет их в другую. Это делается с помощью DataTable и SqlBulkCopy.

При импорте в мое приложение C# столбцы меток времени имеют тип данных System.DateTime внутри DataTable, который вставляется в SQL Server. После выполнения SqlBulkCopy.WriteToServer() значения меток времени внутри целевых таблиц имеют тип datetimeoffset(6) и к ним добавляется смещение часового пояса (... +01:00).

Как мне остановить это? Так было не всегда, только недавно стало происходить.

ОБНОВЛЕНИЕ:

Ожидаемый часовой пояс - UTC, всегда для моих целей. Однако я вынужден хранить это в столбце datetimeoffset по деловым причинам. Так что я ожидаю +00:00

DataTable data = importer.GetDataTable();

using (SqlBulkCopy copy = new SqlBulkCopy(conn)){
   copy.WriteToServer(data);
}

person TurgidWizard    schedule 20.04.2020    source источник
comment
Какой часовой пояс предполагается? datetimeoffset всегда имеет часовой пояс, поэтому, если вы спрашиваете, как его удалить, ответ будет просто нет. Если вам не нужен часовой пояс, не используйте datetimeoffset.   -  person Larnu    schedule 20.04.2020
comment
@Larnu проверить мое обновление вопроса   -  person TurgidWizard    schedule 20.04.2020
comment
@ScottHannen смотрите мое обновление :)   -  person TurgidWizard    schedule 20.04.2020
comment
Итак, покажите нам код, который вы используете для INSERT данных в экземпляр SQL.   -  person Larnu    schedule 20.04.2020
comment
Эта документация может помочь. Он касается того, как SqlBulkCopy преобразует DateTime, и некоторых настроек, которые вы можете изменить.   -  person Scott Hannen    schedule 20.04.2020
comment
Я (и я думаю, что другие) прочитал это слишком быстро. Вопрос не в том, почему DateTimeOffset имеет часовой пояс, а в том, почему DateTime преобразуется в DateTimeOffset.   -  person Scott Hannen    schedule 20.04.2020
comment
@ScottHannen: Следует отметить одну вещь: DateTimeOffset всегда имеет смещение. У него нет часового пояса. Это разные вещи. Два разных места могут временно использовать одно и то же смещение, но по-прежнему находиться в разных часовых поясах.   -  person Jon Skeet    schedule 20.04.2020
comment
Можете ли вы изменить DataTable (в памяти), чтобы преобразовать все значения DateTime в значения DateTimeOffset?   -  person Jon Skeet    schedule 20.04.2020
comment
Обратите внимание, что очень плохая идея полагаться на какой-либо вид преобразования при использовании SqlBulkCopy, потому что вам потенциально придется бороться с двумя уровнями преобразования: один раз в C# при преобразовании типа ввода в тип .NET, соответствующий типу T-SQL. , а затем еще один в SQL Server, когда он преобразует тип .NET в тип T-SQL. Оба из них имеют некоторые неприятные угловые случаи. Чтобы избежать неожиданностей, всегда используйте входную таблицу (или IDataRecord коллекцию) с типами столбцов, точно соответствующими месту назначения, и сами позаботьтесь о преобразованиях.   -  person Jeroen Mostert    schedule 20.04.2020
comment
@JonSkeet Спасибо, это было мое исправление, но я пропустил ваш комментарий :( вы хотите опубликовать ответ, чтобы я его принял?   -  person TurgidWizard    schedule 22.04.2020


Ответы (2)


Если у вас есть DateTime и вы пытаетесь записать его на DateTimeOffset, C# должен выяснить, какой часовой пояс использовать. Существуют явные функции преобразования, которые позволяют вам указывать, но если вы этого не сделаете, предполагается, что DateTime находится в местном часовом поясе (как и в большинстве случаев).

https://docs.microsoft.com/en-us/dotnet/standard/datetime/converting-between-datetime-and-offset содержит несколько примеров преобразования между ними. Обратите внимание, что SpecifyKind не требует наличия типа DateTimeOffset.

person Guvante    schedule 20.04.2020
comment
Преобразование обрабатывается SqlBulkCopy, поэтому я не могу использовать эти явные функции преобразования: / я попытаюсь изменить способ определения DataTable, чтобы использовать это (измените его, чтобы использовать datetimeoffset вместо datetime) - person TurgidWizard; 20.04.2020
comment
@TurgidWizard: я думаю, что вид указан в DateTime, вы можете перезаписать каждый DateTime, вызвав SpecifyKind и сохранив результат обратно в DataTable. - person Guvante; 21.04.2020
comment
отличное предложение, но, похоже, оно не работает :( Я изменил код, который заполняет DataTable, чтобы проверить, является ли столбец System.DateTime, и если это так, то он заполняет значение, используя colArray[i] = DateTime.SpecifyKind(DataReader[i] , DateTimeKind.Utc)... Однако смещение по-прежнему добавляется при вставке на сервер sql - person TurgidWizard; 21.04.2020

Использование DateTime.SpecifyKind() в столбцах меток времени перед их вставкой в ​​Sql Server у меня не сработало.

Я решил это, преобразовав (преобразовав) столбцы System.DateTime в DateTimeOffset с явным смещением new TimeSpan(0, 0, 0). Это избавило C# от необходимости неявно обрабатывать преобразование из DateTime в DbType.DateTimeOffset, которое добавляло нежелательное смещение.

РЕДАКТИРОВАТЬ

Читая комментарии, @JohnSkeet, по сути, рекомендовал это, но я не читал комментарии всех.

person TurgidWizard    schedule 21.04.2020