С отместване на нулева дата. Коректна работа с дата и час

С отместване на нулева дата. Коректна работа с дата и час

Проблемът няма нищо общо с базата данни. Ако зададете точка на прекъсване или въведете изход някъде, трябва да можете да видите изрязването на отместването малко след този код:

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# тип данни, който е просто дата без време. В него има чист тип дата Системно времепакет в corefxlab, но все още не е напълно готов за типично производствено приложение. Има LocalDate в библиотеката Noda Time, която можете да използвате днес, но все пак трябва да конвертирате обратно към собствен тип, преди да запазите в базата данни. Така че междувременно най-доброто нещо, което можете да направите е:

  • Промени своя SQL сървърза да използвате типа дата в полето.
  • Във вашия .NET код използвайте DateTime с час 00:00:00 и DateTimeKind.Unspecified. Трябва да запомните да игнорирате часовата част (тъй като има валидни дати без местна полунощ в определени часови зони).
  • Променете тестовите подпори да бъдат DateTime, а не DateTimeOffset.

Като цяло, докато DateTimeOffset е подходящ за голям брой сценарии (напр. времеви отпечатъцисъбития), не се вписва добре за стойности само за дата.

Искам текуща дата от нулево отместване.

Ако ти наистина искамтова е като DateTimeOffset, можете да направите:

TestDateAndTime = нов 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 . Обърнете внимание на промяната на датата в преобразуването. Това вероятно не е поведението, което бихте искали да използвате във вашето приложение.

Почти всички проекти се сблъскват с проблеми, причинени от неправилна обработка и съхранение на дати и часове. Дори ако проектът се използва в една часова зона, пак можете да получите неприятни изненади след преминаване към зимно / лятно време. В същото време малко хора са озадачени от прилагането на правилния механизъм от самото начало, защото изглежда, че не може да има проблеми с това, тъй като всичко е тривиално. За съжаление по-късната реалност показва, че това не е така.

Логично могат да се разграничат следните видове стойности, свързани с дата и час:


Помислете за всеки елемент поотделно, без да забравяте.

дата и час

Да предположим, че лабораторията, която е събрала материала за анализ, е в +2 часова зона, а централният клон, който следи навременното завършване на анализите, е в +1 часова зона. Времето, дадено в примера, е отбелязано, когато материалът е събран от първата лаборатория. Възниква въпросът - каква цифра от време трябва да вижда централния офис? Очевидно софтуерът централен офистрябва да покаже 15 януари 2014 г. 12:17:15 - час по-малко, тъй като според часовника им събитието е станало точно в този момент.

Помислете за една от възможните вериги от действия, през които данните преминават от клиента към сървъра и обратно, което ви позволява винаги да показвате правилно датата / часа според текущата часова зона на клиента:

  1. Стойността се създава на клиента, например 2 март 2016 г 15 :13:36, клиентът е в +2 часова зона.
  2. Стойността се преобразува в представяне на низ за предаване към сървъра - „2016-03-02T 15 :13:36+02:00”.
  3. Сериализираните данни се изпращат на сървъра.
  4. Сървърът десериализира времето в обект за дата/час, прехвърляйки го към текущата му часова зона. Например, ако сървърът работи на +1, тогава обектът ще съдържа 2 март 2016 г 14 :13:36.
  5. Сървърът записва данни в базата данни, но не съдържа никаква информация за часовата зона - най-често използваните типове дата / час просто не знаят нищо за това. Така базата данни ще бъде запазена на 2 март 2016 г 14 :13:36 в "неизвестна" часова зона.
  6. Сървърът чете данните от базата данни и създава съответния обект със стойност 2 март 2016 г. 14 :13:36. И тъй като сървърът работи в +1 часова зона, тази стойност също ще се интерпретира в рамките на същата часова зона.
  7. Стойността се преобразува в представяне на низ за предаване на клиента - „2016-03-02T 14 :13:36+01:00”.
  8. Сериализираните данни се изпращат на клиента.
  9. Клиентът десериализира получената стойност в обект за дата/час, прехвърляйки го към текущата му часова зона. Например, ако е -5, тогава показаната стойност трябва да бъде 2 март 2016 г 09 :13:36.
Всичко изглежда холистично, но нека помислим какво може да се обърка в този процес. Всъщност проблеми тук могат да възникнат на почти всяка стъпка.
  • Часът на клиента може да се формира изобщо без часова зона - например типът DateTime в .NET с DateTimeKind.Unspecified.
  • Машината за сериализация може да използва формат, който не включва отместване на часовата зона.
  • При десериализиране към обект, отместването на часовата зона може да бъде игнорирано, особено в "самоделни" десериализатори - както на сървъра, така и на клиента.
  • Когато се чете от база данни, обект за дата/час може да се формира изобщо без часова зона - например типът DateTime в .NET с DateTimeKind.Unspecified. Освен това с DateTime в .NET на практика точно това се случва, ако не укажете изрично друг DateTimeKind веднага след изваждането.
  • Ако сървърите на приложения, работещи с обща база данни, са в различни часови зони, ще има сериозно объркване във времевите отмествания. Стойността за дата/час, записана в базата данни от сървър A и прочетена от сървър B, ще бъде значително различна от същата оригинална стойност, записана от сървър B и прочетена от сървър A.
  • Прехвърлянето на сървъри на приложения от една зона в друга ще интерпретира погрешно вече съхранените стойности за дата/час.
Но най-сериозният недостатък в описаната по-горе верига е използването на местната часова зона на сървъра. Ако няма преход към лятно / зимно време, тогава не допълнителни проблеминяма да бъде. Но в противен случай можете да получите много неприятни изненади.

Правилата за преминаване към лятно/зимно часово време са, строго погледнато, нещо променливо. Различните държави могат да променят правилата си от време на време и тези промени трябва да бъдат включени в системните актуализации доста по-рано. На практика често е имало ситуации неправилна работатози механизъм, които в крайна сметка бяха решени чрез инсталиране на актуални корекции или операционна система, или използвани библиотеки на трети страни. Вероятността за повтаряне на същите проблеми не е нула, така че е по-добре да имате начин да ги избегнете с гаранция.

Имайки предвид описаните по-горе съображения, нека формулираме най-надеждния и прост подход за прехвърляне и съхранение на време: на сървъра и в базата данни всички стойности трябва да бъдат преобразувани в часовата зона UTC.

Помислете какво ни дава това правило:

  • Когато изпраща данни към сървъра, клиентът трябва да предаде отместването на часовата зона, така че сървърът да може правилно да конвертира времето в UTC. Алтернативен вариант е да принудите клиента да направи тази трансформация, но първият вариант е по-гъвкав. Когато получава данни обратно от сървъра, клиентът ще преведе датата и часа в своята местна часова зона, знаейки, че така или иначе ще пристигне в UTC.
  • В UTC няма преходи съответно към лятно и зимно време, проблемите, свързани с това, ще бъдат без значение.
  • На сървъра, когато четете от базата данни, не е необходимо да конвертирате стойностите на времето, достатъчно е изрично да посочите, че отговаря на UTC. В .NET, например, това може да се постигне чрез задаване на DateTimeKind на обекта за време на DateTimeKind.Utc.
  • Разликата в часовите зони между сървърите, работещи с обща база данни, както и прехвърлянето на сървъри от една зона в друга, няма да повлияят на коректността на получените данни.
За да приложите такова правило, е достатъчно да се погрижите за три неща:
  1. Направете механизма за сериализация и десериализация така, че стойностите за дата/час да се превеждат правилно от UTC в местната часова зона и обратно.
  2. Уверете се, че десериализаторът от страна на сървъра създава обекти за дата/час в UTC.
  3. Направете го така, че при изваждане от базата данни обектите за дата / час да се създават в UTC. Този елемент понякога се предоставя без промени в кода - само системната часова зона на всички сървъри е зададена на UTC.
Горните съображения и препоръки работят чудесно с комбинация от две условия:
  • Няма нужда в системните изисквания да се показва местното време и/или отместването на часовата зона точно както е било съхранено. Например в самолетните билети часовете на излитане и пристигане трябва да бъдат отпечатани в часовата зона, съответстваща на местоположението на летището. Или ако сървърът отпечата фактури, създадени в различни страни, всеки трябва да завърши с местно време, а не преобразувано в часовата зона на сървъра.
  • Всички стойности за дата и час в системата са "абсолютни" - т.е. описват момент от времето в бъдещето или миналото, който има една единствена стойност в UTC. Например „изстрелването на ракетата-носител се състоя в 23:00 часа киевско време“ или „срещата ще продължи от 13:30 до 14:30 часа в Минск“. В различните часови зони числата за тези събития ще бъдат различни, но те ще описват една и съща точка във времето. Но може да се случи изискванията за софтуерпредполагат "относително" местно време за някои случаи. Например, "това телевизионно предаване ще се излъчва от 9:00 сутринта до 10:00 часа сутринта във всяка страна, където има клон на телевизионния канал." Оказва се, че шоуто на програмата не е едно събитие, а няколко и потенциално всички те могат да се появят в различни периоди от време според „абсолютната“ скала.
В случаите, когато първото условие е нарушено, проблемът може да бъде решен с типове данни, съдържащи часовата зона - както на сървъра, така и в базата данни. По-долу е даден малък списък с примери за различни платформи и СУБД.
.NET datetimeoffset
Java org.joda.time.DateTime, java.time.ZonedDateTime
MS SQL datetimeoffset
Oracle, PostgreSQL ЧАСОВ ПЕЧАТ С ЧАСОВА ЗОНА
MySQL

Нарушаването на второто условие е по-сложен случай. Ако това „относително“ време трябва да се съхрани просто за показване и няма задача да се определи „абсолютният“ момент във времето, когато събитието е настъпило или ще се случи за дадена часова зона, достатъчно е просто да деактивирате преобразуването на времето . Например, потребителят е въвел началото на предаването за всички клонове на телевизионната компания на 25 март 2016 г. в 9:00 часа и то ще бъде предавано, съхранявано и показвано в този вид. Но може да се случи някой планировчик автоматично да извършва специални действия един час преди началото на всяко предаване (изпращане на известия или проверка за наличието на някои данни в базата данни на оператора). Надеждното внедряване на такъв планировчик не е тривиална задача. Да кажем, че планировчикът знае в каква часова зона е всеки от клоновете. И една от страните, където има клон, решава да промени часовата зона след известно време. Случаят не е толкова рядък, колкото може да изглежда - през тази и предните две години преброих над 10 подобни събития (http://www.timeanddate.com/news/time/). Оказва се, че или потребителите трябва да поддържат обвързванията към часовите зони актуални, или планировчикът трябва автоматично да вземе тази информация от глобални източници, като API на Google Maps Time Zone. Не се наемам да предлагам универсално решение за такива случаи, просто отбелязвам, че такива ситуации изискват сериозно проучване.

Както се вижда от горното, няма единен подход, който да покрива 100% от случаите. Следователно, първо трябва ясно да разберете от изискванията коя от ситуациите, споменати по-горе, ще бъде във вашата система. С голяма вероятност всичко ще бъде ограничено до първия предложен подход със съхранение в UTC. Е, описаните изключителни ситуации не го отменят, а просто добавят други решения за специални случаи.

дата без време

Да кажем с правилен дисплейдата и час, като се вземе предвид часовата зона на избрания клиент. Да преминем към дати без час и дадения за случая пример в началото – „новият договор влиза в сила от 2 февруари 2016 г.“. Какво ще се случи, ако се използват същите типове и същият механизъм за такива стойности като за "обикновени" дати с време?

Не всички платформи, езици и СУБД имат типове само за дата. Например в .NET има само тип DateTime, няма отделен "само Date". Дори ако при създаването на такъв обект е била посочена само дата, часът все още е налице и е равен на 00:00:00. Ако преведем стойността „2 февруари 2016 00:00:00“ от зоната с отместване +2 в +1, тогава получаваме „1 февруари 2016 23:00:00“. За примера по-горе това би било еквивалентно на факта, че в една часова зона новият договор ще започне на 2 февруари, а в другата на 1 февруари. От правна гледна точка това е абсурдно и, разбира се, не трябва да е така. Общо правилоза „чистите“ дати е изключително просто - такива стойности не трябва да се преобразуват на нито една стъпка от записване и четене.

Има няколко начина да избегнете преобразуването за дати:

  • Ако платформата поддържа тип, който представлява дата без час, тогава това трябва да се използва.
  • Добавете специална функция към метаданните на обекта, която ще каже на сериализатора какво да прави дадена стойностчасовата зона трябва да се игнорира.
  • Предайте датата от клиента и обратно като низ и я запазете като дата. Този подход е неудобен, ако трябва не само да покажете датата на клиента, но и да извършите някои операции върху нея: сравнение, изваждане и др.
  • Предавайте и съхранявайте като низ и конвертирайте в дата само за форматиране, като вземете предвид регионалните настройки на клиента. Има дори повече недостатъци от предишната версия - например, ако частите от датата в съхранения низ не са в реда "година, месец, ден", тогава ще бъде невъзможно да се направи ефективно индексирано търсене по диапазон от дати.
Можете, разбира се, да се опитате да дадете контрапример и да кажете, че договорът има смисъл само в рамките на държавата, в която е сключен, страната е в същата часова зона и следователно е възможно недвусмислено да се определи моментът на неговото влизане в сила. Но дори и в този случай потребителите от други часови зони няма да се интересуват в кой момент от тяхното местно време ще се случи това събитие. И дори да е необходимо да се покаже тази точка във времето, тогава ще е необходимо да се покаже не само датата, но и часът, което противоречи на първоначалното състояние.

Времеви интервал

Със съхранението и обработката на времеви интервали всичко е просто: тяхната стойност не зависи от часовата зона, така че тук няма специални препоръки. Те могат да се съхраняват и предават като брой единици време (цяло число или с плаваща запетая, в зависимост от изискваната точност). Ако втората точност е важна, тогава като брой секунди, ако точността на милисекунди, тогава като брой милисекунди и т.н.

Но изчисляването на интервала може да има клопки. Да приемем, че имаме някакъв общ C# код, който отчита интервала от време между две събития:

DateTime start = DateTime.Now; //... DateTime end = DateTime.Now; двойни часове = (край - начало).TotalHours;
На пръв поглед тук няма проблеми, но не е така. Първо, може да има проблеми с модулното тестване на такъв код, но ще говорим за това малко по-късно. Второ, нека си представим, че началният час е зимно време, а крайният час е лятно време (например броят на работните часове се измерва по този начин, а работниците имат нощна смяна).

Да приемем, че кодът работи в часова зона, където лятното часово време през 2016 г. настъпва през нощта на 27 март, и симулирайте описаната по-горе ситуация:

DateTime start = DateTime.Parse("2016-03-26T20:00:15+02"); DateTime край = DateTime.Parse("2016-03-27T05:00:15+03"); двойни часове = (край - начало).TotalHours;
Този код ще доведе до 9 часа, въпреки че всъщност са изминали 8 часа между тези времена. Това може лесно да се провери чрез промяна на кода по следния начин:

DateTime start = DateTime.Parse("2016-03-26T20:00:15+02").ToUniversalTime(); DateTime край = DateTime.Parse("2016-03-27T05:00:15+03").ToUniversalTime(); двойни часове = (край - начало).TotalHours;
Оттук и заключението е, че всяка аритметични операциис дата и час трябва да го направите, като използвате UTC стойности или типове, които съхраняват информация за часовата зона. И след това обратно, за да преведете на местен, ако е необходимо. От тази гледна точка оригиналният пример е лесен за коригиране чрез промяна на DateTime.Now на DateTime.UtcNow.

Този нюанс не зависи от конкретна платформа или език. Ето подобен Java код със същия недостатък:

Начало на LocalDateTime = LocalDateTime.now(); //... LocalDateTime end = LocalDateTime.now(); дълги часове = ChronoUnit.HOURS.between(начало, край);
Освен това е лесно да се коригира - например, като се използва ZonedDateTime вместо LocalDateTime.

График на планираните събития

Планирането на планирани събития е по-сложна ситуация. Няма общ тип, който ви позволява да съхранявате графици в стандартните библиотеки. Но такава задача не е толкова рядка, така че решения до ключможе да се намери без проблеми. Добър пример е форматът на планировчика на cron, който се използва под една или друга форма от други решения, като например Quartz: http://quartz-scheduler.org/api/2.2.0/org/quartz/CronExpression.html. Той покрива почти всички нужди за планиране, включително опциите за „втори петък от месеца“.

В повечето случаи писането на собствен планировчик няма смисъл, тъй като има гъвкави, изпитани във времето решения, но ако по някаква причина има нужда да създадете свой собствен механизъм, тогава поне форматът за планиране може да бъде заимстван от cron.

В допълнение към препоръките, описани по-горе относно съхранението и обработката на различни типове времеви стойности, има няколко други, за които бих искал да говоря.

Първо, относно използването на статични членове на класа за получаване на текущия час - DateTime.UtcNow, ZonedDateTime.now() и т.н. Както споменахме, използването им директно в кода може сериозно да усложни модулното тестване, тъй като без специални макетни рамки, които да заменят текущо временяма да работи. Следователно, ако планирате да пишете модулни тестове, трябва да се погрижите внедряването на такива методи да може да бъде заменено. Има поне два начина за решаване на този проблем:

  • Посветете интерфейса IDateTimeProvider с един метод, който връща текущия час. След това добавете зависимост към този интерфейс във всички кодови единици, където трябва да получите текущото време. По време на нормалното изпълнение на програмата във всички тези места ще бъде инжектирана имплементацията по подразбиране, която връща реалното текущо време, а при модулни тестове - всяка друга необходима реализация. Този метод е най-гъвкавият по отношение на тестването.
  • Направете свой собствен статичен клас с метод за получаване на текущото време и възможност да зададете всяка имплементация на този метод отвън. Например, в случай на C# код, този клас може да изложи свойството UtcNow и SetImplementation(Func impl). Използването на статично свойство или метод за получаване на текущото време елиминира необходимостта от изрично указване на зависимостта от допълнителен интерфейс навсякъде, но от гледна точка на принципите на ООП това не е идеалното решение. Въпреки това, ако по някаква причина предишната опция не е подходяща, тогава можете да използвате тази.
Допълнителен проблем, който трябва да бъде решен при мигриране към вашата собствена реализация на текущия доставчик на време, е да се уверите, че никой "по старомодния начин" не продължава да използва стандартните класове. Тази задача е лесна за решаване в повечето системи за контрол на качеството на кода. По същество това се свежда до търсене на „нежелан“ подниз във всички файлове, с изключение на тези, където е декларирано изпълнението „по подразбиране“.

Вторият нюанс с получаването на текущото време е това на клиента не може да се вярва. Текущото време на компютрите на потребителите може да бъде много различно от реалното и ако има логика, свързана с него, тогава тази разлика може да съсипе всичко. Всички места, където е необходимо да се получи текущото време, трябва, ако е възможно, да се извършват от страната на сървъра. И както споменахме по-рано, всички аритметични операции с времето трябва да се извършват или в UTC стойности, или с помощта на типове, които съхраняват отместването на часовата зона.

И още нещо, което исках да спомена, е стандартът ISO 8601, който описва формата за дата и час за обмен на информация. По-специално, низовото представяне на дата и час, използвани в сериализацията, трябва да отговаря на този стандарт, за да се предотвратят потенциални проблеми със съвместимостта. На практика е изключително рядко да се наложи сами да прилагате форматиране, така че самият стандарт може да бъде полезен главно за информационни цели.

Тагове: Добавете тагове

DateTimeOffset testDateAndTime = нов DateTimeOffset(2008, 5, 1, 8, 6, 32, нов TimeSpan(1, 0, 0)); //ИЗЧИСТВАНЕ НА ВРЕМЕ И ДАТА 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 (от код преди запазване)?

Опитах:

Обществена задача SetTimeZoneOffsetToZero(DateTimeOffset dateTimeOffSetObj) ( TimeSpan zeroOffsetTimeSpan = new TimeSpan(0, 0, 0, 0, 0); return dateTimeOffSetObj.ToOffset(zeroOffsetTimeSpan); )

Той не прави нищо.

Крайната цел е просто да имате дата без време или отместване на часовата зона. НЕ искам да конвертирам часа в друга часова зона (т.е. 00:00:00.0000000 не искам да изважда 4 часа от 00:00:00.0000000 време и 00:00:00.0000000 да компенсира зададеното време с +00: 00, просто искам да зададе отместването на +00:00). Искам текущата дата с нулево отместване.

Редактиране:

Ето какво можете да предложите другаде:

DateTimeOffset testDateAndTime = нов DateTimeOffset(2008, 5, 1, 8, 6, 32, нов TimeSpan(1, 0, 0)); testDateAndTime = testDateAndTime.DateTime.Date; //Нулиране на част от времето testDateAndTime = DateTime.SpecifyKind(testDateAndTime.Date, DateTimeKind.Utc); // "Нулева" компенсирана част

Бях сигурен, че SpecifyKind ще бъде SpecifyKind на моя dateTimeOffset, ще промени И ДВАТА отместването на часа и часовата зона например, но при тестване изглежда просто променя отместването на часовата зона, което е, което искам. Има ли проблем с това?

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, както описахте,

Ти каза:

Крайната цел е просто да имате дата без време или отместване на часовата зона.

Е, в момента няма естествен C# тип данни, който е просто дата без час. Има чист тип Date в пакета System.Time на corefxlab, но това не е съвсем готово за типично производствено приложение. Има LocalDate в библиотеката за време на Noda, която можете да използвате днес, но все пак трябва да конвертирате обратно към родния тип, преди да го съхраните в базата данни. Така че междувременно най-доброто нещо, което можете да направите е:

  • Променете вашия SQL Server, за да използвате типа дата в това поле.
  • Във вашия .NET код използвайте DateTime с час 00:00:00 и DateTimeKind.Unspecified. Трябва да запомните да игнорирате часовата част (тъй като има валидни дати без местна полунощ в определени часови зони).
  • Променете тестовия сигнал да бъде DateTime, а не DateTimeOffset.

Като цяло, докато DateTimeOffset е подходящ за Голям бройсценарии (напр. събития с клеймо за време), не е подходящо за стойности само за дата.

Искам текущата дата с нулево отместване.

Ако наистина го искате като DateTimeOffset, бихте направили:

TestDateAndTime = нов 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 . Обърнете внимание на промяната на датата в преобразуването. Това вероятно не е поведението, което бихте искали да използвате във вашето приложение.