Правильная работа с датой и временем. Удаление Смещение часового пояса От DateTimeOffset Нулевое смещение дат sql server
Проблема не имеет ничего общего с базой данных. Если установить точку останова или войти выход где-то, вы должны быть в состоянии видеть смещение быть пристегивается вскоре после этого кода:
TestDateAndTime = testDateAndTime.DateTime.Date;
Давайте сломаем это вниз:
- Вы начали с DateTimeOffset значение 2008-05-01T08:06:32+01:00
- Затем вы назвали.DateTime , что привело к значению DateTime 2008-05-01T08:06:32 с DateTimeKind.Unspecified .
- Затем вы позвонили.Date , что привело к значению DateTime 2008-05-01T00:00:00 с DateTimeKind.Unspecified .
- Вы назначаете результат на testDateAndTime , который имеет тип DateTimeOffset . Это вызывает неявный литой от DateTime до DateTimeOffset - , который применяет местный часовой пояс . В вашем случае представляется, что смещение для этого значения в вашем местном часовом поясе составляет -04:00 , поэтому полученное значение равно DateTimeOffset из 2008-05-01T00:00:00-04:00 , как вы описали.
Вы сказали:
Конечной целью является просто иметь дату без времени или часового пояса смещения.
Ну, есть в настоящее время не родной C# типа данных, который просто дата без времени.Существует чистый Date тип в System.Time пакет в corefxlab , но это еще не совсем готово для типичного производственного приложения. Там LocalDate в библиотеке Noda Time , которую вы можете использовать сегодня, но перед сохранением в базу данных вам все равно придется преобразовать обратно в собственный тип. Таким образом, в то же время, самое лучшее, что вы можете сделать:
- Измените свой SQL Server на использование типа date в поле.
- В вашем коде.NET используйте DateTime со временем 00:00:00 и DateTimeKind.Unspecified . Вы должны помнить, чтобы игнорировать временную часть (так как есть действительно даты без локальной полуночи в определенных часовых поясах).
- Изменить test опоры, чтобы быть DateTime , а не DateTimeOffset .
В целом, в то время как DateTimeOffset подходит большое количество сценариев (например, меток времени событий), она не подходит хорошо для даты только значения.
Я хочу текущую дату с нулевым смещением.
Если вы действительно хотите это как DateTimeOffset , вы могли бы сделать:
TestDateAndTime = new DateTimeOffset(testDateAndTime.Date, TimeSpan.Zero);
Однако я не рекомендую этого делать. Поступая таким образом, вы берете местную дату первоначального значения и утверждаете, что она находится в UTC. Если исходным смещением является ничего, кроме нуля, это будет ложное утверждение. Он впоследствии приведет к другим ошибкам, поскольку вы на самом деле говорите о другом моменте времени (с потенциально другой датой), чем тот, который вы создали.
Относительно дополнительного вопроса, заданного в вашем правлении. Указание DateTimeKind.Utc изменяет поведение неявного приведения. Вместо использования местного часового пояса используется время UTC, которое всегда имеет смещение нуля. Результат такой же, как и более явный вид, который я дал выше. Я по-прежнему рекомендую против этого по тем же причинам.
Рассмотрите пример, начинающийся с 2016-12-31T22:00:00-04:00 . По вашему подходу вы должны сохранить в базе данных 2016-12-31T00:00:00+00:00 . Однако это два разных момента времени. Первый, нормализованный к UTC, будет 2017-01-01T02:00:00+00:00 , а второй, преобразованный в другой часовой пояс, будет 2016-12-30T20:00:00-04:00 . Обратите внимание на изменение дат в конверсии. Вероятно, это не то поведение, которое вы хотели бы использовать в своем приложении.
Вариант гуманный ([необходимо зарегистрироваться для просмотра ссылки]).
Суть проблемы в чем.. Если Вы случайно развернули базу на сервере SQL со «смещением даты» 0 то возникла проблема, когда в базе встречается реквизит с типом ВРЕМЯ т.е.в этот реквизит ставится 01.01.0001 10:30:00 или дата записалась пустой 01.01.0001 00:00:00. При записи такого реквизита не происходит его запись.
В интернете предлагают создать новую базу со смещением 2000.
Но новую базу создавать не очень хотелось. И менять у всех пользователях путь к базе.
Тогда я пошел по пути, а где ж хранится это значение в SQL-е. Нашел и поменял на 2000 и все стало ок..
А теперь по шагово, где поменять.
Выгнать всех пользователей.
ВНИМАНИЕ!!!
1. Сначала сделайте резервную копию средствами 1С т.е. выгрузите ее в *.dt
Это нужно делать до того как поменяете «смещение»
Если этого не сделать то во всей вашей базе спр., док, и т.д.
где есть есть реквизит дата будет стоять допустим 02.10.0009
ЧТО НЕ ДОПУСТИМО….
Итак Вы сделали выгрузку в *.dt
2. Заходим в SQL Server Management Studio
Находим Вашу базу в списку нажимаем плюсик.
Находи там папочку «Таблицы» и раскрываем ее.
Откроется куча таблиц, идем в самый низ, находим таблицу
_YearOffset, становимся на нее и правой клавишей выбираем пункт «Открыть таблицу» см. рис.1
Меняем значение 0 на 2000
Закрываем SQL Server Management Studio
3. Заходим в конфигуратор и загружаем ранее сохраненную базу.
Если это не сделать, то все даты будут с годом 0009.
После того как база загрузилась… Можно зайти в 1С и удостоверится что даты нормальные.
Результат мы поменяли «смещение дата с 0 на 2000»
Иногда бывает так, что этот вариант использовать не получается по тем или иным причинам. Тогда есть более хардкорный вариант ([необходимо зарегистрироваться для просмотра ссылки]):
Declare TablesAndFields cursor for
SELECT
objects.name as
Tablename, columns.name as
columnname
FROM
dbo.sysobjects
as
objects
left
join
dbo.syscolumns
as
columns on
objects.id =
columns.id
where
objects.xtype =
"U"
and
columns.xtype =
61
open TablesAndFields
WHILE @@FETCH_STATUS =
0
BEGIN
Exec ("update
"
+
@TableName +
"
set " +
@ColumnName +
"
=
""2000-
01-
01 00:00:00"
"
where
" +
@ColumnName +
"
>
""3999-
12-
31 23:59:59"
"")
This is executed as
long as
the previous fetch succeeds.
FETCH NEXT FROM
TablesAndFields
into
@TableName, @ColumnName
END
close TablesAndFields
deallocate TablesAndFields
go
Перед любыми манипуляциями не забывайте делать копии баз данных!
DateTimeOffset testDateAndTime = new DateTimeOffset(2008, 5, 1, 8, 6, 32, new TimeSpan(1, 0, 0)); //CLEAN TIME AND DATE testDateAndTime = testDateAndTime.DateTime.Date; var datesTableEntry = db.DatesTable.First(dt => dt.Id == someTestId); datesTableEntry.test= testDateAndTime; db.SaveChangesAsync();
РЕЗУЛЬТАТ В БАЗА ДАННЫХ: 2008-05-01 00:00:00.0000000 -04:00
Как включить -4:00 в +00:00 (из кода перед сохранением)?
Я пытался:
Public Task
Он ничего не делает.
Конечная цель - просто иметь дату без смещения времени или часового пояса. Я НЕ хочу преобразовывать время в другой часовой пояс (т. 00:00:00.0000000 Я не хочу, чтобы он вычитал 4 часа из 00:00:00.0000000 времени и 00:00:00.0000000 смещение установленного времени на +00:00 , я просто хочу, чтобы он установил смещение к +00:00). Я хочу текущую дату с нулевым смещением.
Редактировать:
Вот что можно предложить в другом месте:
DateTimeOffset testDateAndTime = new DateTimeOffset(2008, 5, 1, 8, 6, 32, new TimeSpan(1, 0, 0)); testDateAndTime = testDateAndTime.DateTime.Date; //Zero out time portion testDateAndTime = DateTime.SpecifyKind(testDateAndTime.Date, DateTimeKind.Utc); //"Zero out" offset portion
Я был уверен, что SpecifyKind будет SpecifyKind моей dateTimeOffset, например, измените BOTH время и смещение часового пояса, но при тестировании, похоже, просто изменит смещение часового пояса, что и есть то, что я хочу. Есть ли проблема с этим?
1 ответ
Проблема не имеет ничего общего с базой данных. Если вы установили точку останова или зарегистрировали выход где-нибудь, вы должны увидеть, как смещение будет привязано вскоре после этого кода:
TestDateAndTime = testDateAndTime.DateTime.Date;
Позвольте сломать это:
- Вы начали с значения DateTimeOffset 2008-05-01T08:06:32+01:00
- Затем вы вызывали.DateTime , в результате чего значение DateTime 2008-05-01T08:06:32 с DateTimeKind.Unspecified .
- Затем вы вызывали.Date , что привело к значению DateTime 2008-05-01T00:00:00 с DateTimeKind.Unspecified .
- Вы возвращаете результат в testDateAndTime , который имеет тип DateTimeOffset . Это вызывает неявное преобразование из DateTime в DateTimeOffset которое применяет локальный часовой пояс . В вашем случае представляется, что смещение для этого значения в вашем локальном часовом поясе - -04:00 , поэтому итоговое значение - это DateTimeOffset 2008-05-01T00:00:00-04:00 , как вы описали,
Ты сказал:
Конечная цель - просто иметь дату без смещения времени или часового пояса.
Ну, в настоящее время нет собственного типа данных С#, который является просто датой без времени. Существует чистый тип Date в пакете System.Time в corefxlab , но это не совсем готово для типичного производственного приложения. Там LocalDate в библиотеке времени Noda, которую вы можете использовать сегодня, но вам все равно придется преобразовать обратно в родной тип перед сохранением в базе данных. Таким образом, в то же время, самое лучшее, что вы можете сделать, это:
- Измените свой SQL Server на использование типа date в этом поле.
- В вашем коде.NET используйте DateTime со временем 00:00:00 и DateTimeKind.Unspecified . Вы должны помнить, чтобы игнорировать временную часть (так как есть действительно даты без локальной полуночи в определенных часовых поясах).
- Измените test оповещение как DateTime , а не DateTimeOffset .
В общем случае, в то время как DateTimeOffset подходит для большого количества сценариев (например, событий timestamping), он не подходит для значений только даты.
Я хочу текущую дату с нулевым смещением.
Если вы действительно хотите, чтобы это как DateTimeOffset , вы бы сделали:
TestDateAndTime = new DateTimeOffset(testDateAndTime.Date, TimeSpan.Zero);
Однако я советую против этого. Поступая таким образом, вы берете локальную дату исходного значения и утверждаете, что она находится в UTC. Если исходным смещением является ничего, кроме нуля, это будет ложное утверждение. Он впоследствии приведет к другим ошибкам, поскольку вы на самом деле говорите о другом моменте времени (с потенциально другой датой), чем тот, который вы создали.
Что касается дополнительного вопроса, заданного в вашем редактировании - указание DateTimeKind.Utc изменяет поведение неявного приведения. Вместо использования локального часового пояса используется время UTC, которое всегда имеет смещение нуля. Результат такой же, как и более явный вид, который я дал выше. Я по-прежнему рекомендую против этого по тем же причинам.
Рассмотрим пример начала с 2016-12-31T22:00:00-04:00 . По вашему подходу вы должны сохранить в базе данных 2016-12-31T00:00:00+00:00 . Однако это два разных момента времени. Первый, нормализованный к UTC, будет 2017-01-01T02:00:00+00:00 , а второй, преобразованный в другой часовой пояс, будет 2016-12-30T20:00:00-04:00 . Обратите внимание на изменение дат в конверсии. Вероятно, это не то поведение, которое вы хотели бы использовать в своем приложении.