Nulla dátum eltolással. Korrekt munkavégzés dátummal és idővel

Nulla dátum eltolással. Korrekt munkavégzés dátummal és idővel

A probléma semmi köze az adatbázishoz. Ha beállít egy töréspontot vagy beír egy kijáratot valahol, akkor látnia kell, hogy az eltolás röviddel a kód után le van vágva:

TestDateAndTime = testDateAndTime.DateTime.Date;

Bontsuk szét:

  • 2008-05-01T08:06:32+01:00 DateTimeOffset értékkel kezdted
  • Ezután meghívta a .DateTime elemet, aminek eredményeként a DateTime értéke 2008-05-01T08:06:32 a DateTimeKind.Unspecified értékkel.
  • Ezután meghívta a .Date parancsot, aminek eredményeként a DateTime értéke 2008-05-01T00:00:00 a DateTimeKind.Unspecified értékkel.
  • Az eredményt a testDateAndTime elemhez rendeli, amely DateTimeOffset típusú. Ez a DateTime-ből a DateTimeOffsetbe való implicit leadást hívja meg - ami vonatkozik helyi Időzóna. Az Ön esetében úgy tűnik, hogy ennek az értéknek az eltolása a helyi időzónában -04:00 , így a kapott érték egy 2008-05-01T00:00:00-04:00 DateTimeOffset, ahogyan Ön leírta.

Te mondtad:

A végső cél az, hogy egyszerűen legyen egy dátum idő- vagy időzóna-eltolás nélkül.

Hát van jelenleg nem natív C# adattípus, ami csak dátum idő nélkül. Van egy tiszta dátum típus Rendszeridő csomag a corefxlab -ban, de még nem teljesen készen áll egy tipikus éles alkalmazásra. A Noda Time könyvtárban található egy LocalDate, amelyet ma is használhat, de az adatbázisba mentés előtt továbbra is vissza kell konvertálnia natív típusra. Tehát addig is a legjobb, amit tehetsz:

  • Változtasd meg SQL szerver a dátum típusának használatához a mezőben.
  • A .NET kódban használja a DateTime időt 00:00:00 és a DateTimeKind.Unspecified értékkel. Ne felejtse el figyelmen kívül hagyni az időrészt (mivel bizonyos időzónákban vannak érvényes dátumok helyi éjfél nélkül).
  • Módosítsa a teszt kellékeit DateTime értékre, ne DateTimeOffset értékre.

Általánosságban elmondható, hogy míg a DateTimeOffset számos forgatókönyvhöz alkalmas (pl. időbélyegek események), nem illik jól a csak dátumot tartalmazó értékekhez.

Az aktuális dátumot kérem nulla eltolás.

Ha te nagyon akar ez olyan, mint a DateTimeOffset, megteheti:

TestDateAndTime = new DateTimeOffset(tesztDátumÉsIdő.Dátum, Időtartam.Zero);

Ezt azonban nem javaslom. Ezzel elfogadod helyi az eredeti érték dátuma, és állítsa, hogy az UTC-ben van. Ha az eredeti eltolás nem nulla, ez hamis állítás lesz. Ez később különböző hibákhoz vezet, mivel valójában egy másik időpontról beszél (potenciálisan más dátummal), mint amit létrehoztál.

A táblában feltett kiegészítő kérdéssel kapcsolatban. A DateTimeKind.Utc megadása megváltoztatja az implicit cast viselkedését. A helyi időzóna használata helyett az UTC idő kerül felhasználásra, amelynek mindig van nulla eltolása. Az eredmény ugyanaz, mint a fentebb adott explicitebb megjelenés. Továbbra is ellene javaslom ugyanezen okok miatt.

Vegyünk egy példát, amely 2016-12-31T22:00:00-04:00 kezdetű. Az Ön megközelítése szerint 2016-12-31T00:00:00+00:00 kell tárolni az adatbázisban. Ez azonban két különböző időszak. Az első, UTC-re normalizálva, 2017-01-01T02:00:00+00:00, a második pedig egy másik időzónára konvertálva 2016-12-30T20:00:00-04:00 lesz. . Ügyeljen az átalakítás dátumának változására. Valószínűleg nem ezt a viselkedést szeretné alkalmazni az alkalmazásában.

Szinte minden projekt szembesül a dátumok és időpontok nem megfelelő feldolgozása és tárolása miatti problémákkal. Még ha a projektet egy időzónában használják is, a téli/nyári időszámításra való átállás után is érheti kellemetlen meglepetés. Ugyanakkor kevesen értetlenül állnak a kezdetektől fogva a helyes mechanizmus megvalósítása előtt, mert úgy tűnik, ezzel nem lehet probléma, hiszen minden triviális. Sajnos a későbbi valóság azt mutatja, hogy ez nem így van.

Logikusan a következő típusú értékek különböztethetők meg a dátummal és az idővel kapcsolatban:


Tekintsünk minden elemet külön-külön, ne feledkezzünk meg róla.

dátum és idő

Tegyük fel, hogy az elemzéshez szükséges anyagot gyűjtő laboratórium a +2 időzónában, a központi ág pedig, amely az elemzések időben történő befejezését figyeli, a +1 időzónában van. A példában megadott időt az első laboratóriumi anyaggyűjtéskor vették fel. Felmerül a kérdés: milyen időszámítást kell látnia a központi hivatalnak? Nyilván a szoftver központi iroda 2014. január 15. 12:17:15-öt kell mutatnia - egy órával kevesebbet, mivel az órájuk szerint az esemény éppen abban a pillanatban történt.

Tekintsük az egyik lehetséges műveleti láncot, amelyen keresztül az adatok áthaladnak az ügyfélről a szerverre és fordítva, amely lehetővé teszi a dátum / idő helyes megjelenítését az ügyfél aktuális időzónájának megfelelően:

  1. Az érték az ügyfélen jön létre, például 2016. március 2 15 :13:36, az ügyfél a +2 idõzónában van.
  2. Az értéket a rendszer karakterlánc-reprezentációvá konvertálja a szerverre történő továbbításhoz - „2016-03-02T 15 :13:36+02:00”.
  3. A sorosított adatok elküldésre kerülnek a szerverre.
  4. A szerver deszerializálja az időt egy dátum/idő objektummá, és átküldi az aktuális időzónába. Például, ha a szerver +1-en fut, akkor az objektum 2016. március 2-át fogja tartalmazni 14 :13:36.
  5. A szerver az adatokat az adatbázisba menti, miközben az időzónáról nem tartalmaz információt – a leggyakrabban használt dátum/idő típusok egyszerűen nem tudnak róla semmit. Így az adatbázis 2016. március 2-án mentésre kerül 14 :13:36 „ismeretlen” idõzónában.
  6. A szerver beolvassa az adatokat az adatbázisból, és létrehozza a megfelelő objektumot 2016. március 2. értékkel 14 :13:36. És mivel a szerver a +1 időzónában működik, ez az érték is ugyanabban az időzónában lesz értelmezve.
  7. Az értéket a rendszer karakterlánc-reprezentációvá alakítja át az ügyfélnek való továbbításhoz - „2016-03-02T 14 :13:36+01:00”.
  8. A sorosított adatok elküldésre kerülnek az ügyfélnek.
  9. Az ügyfél a kapott értéket egy dátum/idő objektummá deszerializálja, és az aktuális időzónába önti. Ha például -5, akkor a megjelenített értéknek 2016. március 2-nak kell lennie 09 :13:36.
Úgy tűnik, minden holisztikus, de gondoljuk át, mi ronthat el ebben a folyamatban. Valójában itt szinte minden lépésnél előfordulhatnak problémák.
  • Az ügyfélen lévő idő egyáltalán időzóna nélkül alakítható ki – például a DateTime típus a .NET-ben a DateTimeKind.Unspecified értékkel.
  • A sorosító motor olyan formátumot használhat, amely nem tartalmaz időzóna-eltolást.
  • Egy objektumra történő deszerializáláskor az időzóna-eltolás figyelmen kívül hagyható, különösen a "házi" deszerializálóknál – mind a szerveren, mind a kliensen.
  • Adatbázisból történő olvasáskor egy dátum/idő objektum egyáltalán időzóna nélkül is létrehozható - például a .NET-ben a DateTime típus a DateTimeKind.Unspecified-el. Sőt, a .NET-ben található DateTime esetében a gyakorlatban pontosan ez történik, ha nem adunk meg közvetlenül egy másik DateTimeKind-et közvetlenül a kivonás után.
  • Ha a közös adatbázissal dolgozó alkalmazásszerverek különböző időzónákban vannak, akkor az időeltolások terén komoly zavarok léphetnek fel. Az A szerver által az adatbázisba írt és a B szerver által beolvasott dátum/idő érték észrevehetően eltér a B szerver által írt és az A szerver által beolvasott eredeti értéktől.
  • Az alkalmazáskiszolgálók egyik zónából a másikba való átvitele félreértelmezi a már tárolt dátum/idő értékeket.
De a fent leírt lánc legsúlyosabb hátránya a helyi időzóna használata a szerveren. Ha nincs átmenet a nyári/téli időszámításra, akkor nem további problémák nem lesz. De egyébként sok kellemetlen meglepetés érheti.

A nyári/téli időszámításra való átállás szabályai szigorúan véve változóak. A különböző országok időről időre módosíthatják szabályaikat, és ezeket a változtatásokat jó előre be kell építeni a rendszerfrissítésekbe. A gyakorlatban gyakran adódtak helyzetek helytelen munka ezt a mechanizmust, amelyeket végül gyorsjavítások telepítésével, ill operációs rendszer, vagy harmadik fél által használt könyvtárak. Ugyanazon problémák megismétlődésének valószínűsége nem nulla, ezért jobb, ha van mód garanciával elkerülni őket.

A fent leírt szempontokat figyelembe véve fogalmazzuk meg az időátvitel és tárolás legmegbízhatóbb és legegyszerűbb megközelítését: a szerveren és az adatbázisban minden értéket át kell konvertálni az UTC időzónára.

Gondoljuk át, mit ad nekünk ez a szabály:

  • Amikor adatokat küld a szervernek, a kliensnek át kell adnia az időzóna-eltolást, hogy a szerver megfelelően tudja konvertálni az időt UTC-re. Alternatív lehetőség az ügyfél kényszerítése erre az átalakításra, de az első lehetőség rugalmasabb. Amikor visszakapja az adatokat a szervertől, a kliens lefordítja a dátumot és az időt a helyi időzónájába, tudva, hogy az úgyis UTC-ben érkezik.
  • Az UTC-ben nincs átállás a nyári, illetve a téli időszámításra, az ezzel kapcsolatos problémák lényegtelenek lesznek.
  • A szerveren az adatbázisból történő olvasáskor nem kell az időértékeket konvertálni, elég kifejezetten jelezni, hogy az UTC-nek felel meg. A .NET-ben ez például úgy érhető el, hogy az időobjektum DateTimeKind értékét DateTimeKind.Utc értékre állítja.
  • A közös adatbázissal dolgozó szerverek közötti időzónák közötti különbség, valamint a szerverek egyik zónából a másikba való átvitele nem befolyásolja a fogadott adatok helyességét.
Egy ilyen szabály végrehajtásához elegendő három dologra ügyelni:
  1. A szerializálási és deszerializációs mechanizmust úgy állítsa be, hogy a dátum/idő értékek helyesen legyenek lefordítva UTC-ről a helyi időzónára és fordítva.
  2. Győződjön meg arról, hogy a szerveroldali deszerializáló dátum/idő objektumokat hoz létre UTC-ben.
  3. Tegye úgy, hogy az adatbázisból való kivonáskor a dátum/idő objektumok UTC-ben jönnek létre. Ez az elem néha kódmódosítás nélkül érhető el – csak a rendszer időzónája az összes szerveren UTC-re van állítva.
A fenti megfontolások és ajánlások remekül működnek két feltétel kombinációjával:
  • A rendszerkövetelményekben nincs szükség arra, hogy a helyi időt és/vagy az időzóna-eltolást pontosan úgy jelenítsék meg, ahogyan azt tárolták. Például a repülőjegyekben az indulás és érkezés időpontját a repülőtér helyének megfelelő időzónában kell nyomtatni. Vagy ha a szerver kinyomtatja a ben készített számlákat különböző országok, mindegyiknek a helyi időnek kell lennie, nem pedig a szerver időzónájára konvertálva.
  • Minden dátum és idő érték a rendszerben "abszolút" – pl. írjon le egy olyan időpontot a jövőben vagy a múltban, amelynek egyetlen értéke van UTC-ben. Például "a hordozórakéta kilövésére kijevi idő szerint 23:00-kor került sor", vagy "a találkozó minszki idő szerint 13:30-tól 14:30-ig tart". A különböző időzónákban ezeknek az eseményeknek a számai eltérőek lesznek, de ugyanazt az időpontot írják le. De előfordulhat, hogy a követelményeknek szoftver bizonyos esetekben "relatív" helyi időt jelent. Például: "ez a TV-műsor 9:00 és 10:00 óra között fog futni minden olyan országban, ahol van a TV-csatorna fiókja." Kiderül, hogy a program műsora nem egy esemény, hanem több, és potenciálisan mindegyik az „abszolút” skála szerint különböző időszakokban fordulhat elő.
Az első feltétel megsértése esetén a probléma megoldható az időzónát tartalmazó adattípusokkal - mind a szerveren, mind az adatbázisban. Az alábbiakban egy kis példa található a különböző platformokhoz és DBMS-ekhez.
.HÁLÓ datetime offset
Jáva org.joda.time.DateTime, java.time.ZonedDateTime
MS SQL datetime offset
Oracle, PostgreSQL IDŐBÉLYEG IDŐZÓNÁVAL
MySQL

A második feltétel megsértése bonyolultabb eset. Ha ezt a „relatív” időt el kell tárolni pusztán a megjelenítéshez, és nincs feladat meghatározni azt az „abszolút” pillanatot, amikor egy adott időzónában az esemény megtörtént vagy fog bekövetkezni, akkor elég egyszerűen letiltani az időkonverziót. . Például a felhasználó 2016. március 25-én 9:00-kor a tévétársaság összes fióktelepére beírta az adás kezdetét, és ez ebben a formában kerül továbbításra, tárolásra és megjelenítésre. Előfordulhat azonban, hogy egyes ütemezőknek egy órával az egyes adások kezdete előtt automatikusan speciális műveleteket kell végrehajtaniuk (értesítéseket küldeni, vagy ellenőrizni kell, hogy vannak-e adatok a műsorszolgáltató adatbázisában). Egy ilyen ütemező megbízható megvalósítása nem triviális feladat. Tegyük fel, hogy az ütemező tudja, hogy az egyes ágak melyik időzónában vannak. És az egyik ország, ahol van fiók, úgy dönt, hogy egy idő után megváltoztatja az időzónát. Az eset nem olyan ritka, mint amilyennek látszik – ebben és az előző két évben több mint 10 ilyen eseményt számoltam össze (http://www.timeanddate.com/news/time/). Kiderült, hogy vagy a felhasználóknak naprakészen kell tartaniuk az időzónákhoz való kötéseket, vagy az ütemezőnek automatikusan le kell vennie ezeket az információkat globális forrásokból, például a Google Maps Time Zone API-ból. Nem vállalkozom arra, hogy univerzális megoldást kínáljak az ilyen esetekre, egyszerűen megjegyzem, hogy az ilyen helyzetek komoly tanulmányozást igényelnek.

Ahogy a fentiekből is látszik, nincs egyetlen megközelítés, amely az esetek 100%-át lefedi. Ezért először világosan meg kell értenie a követelményekből, hogy a fent említett helyzetek közül melyik lesz az Ön rendszerében. Nagy valószínűséggel minden az első javasolt megközelítésre korlátozódik UTC-ben való tárolással. Nos, a leírt kivételes helyzetek nem szüntetik meg, hanem egyszerűen hozzáadnak más megoldásokat speciális esetekre.

dátum idő nélkül

Mondjuk azzal helyes megjelenítés dátum és idő, figyelembe véve az ügyfél időzónáját. Térjünk át az idő nélküli dátumokra és az erre az esetre az elején adott példára - "az új szerződés 2016. február 2-án lép hatályba". Mi történik, ha ugyanazokat a típusokat és ugyanazt a mechanizmust használják az ilyen értékekhez, mint a "hétköznapi" dátumokhoz?

Nem minden platform, nyelv és DBMS rendelkezik csak dátumtípussal. Például a .NET-ben csak a DateTime típus van, nincs külön "csak dátum". Még ha csak egy dátumot adtunk meg egy ilyen objektum létrehozásakor, az idő továbbra is jelen van, és 00:00:00. Ha a „2016. február 2. 00:00:00” értéket a +2 eltolású zónából +1-re fordítjuk, akkor a „2016. február 1. 23:00:00” értéket kapjuk. A fenti példa esetében ez egyenértékű azzal, hogy az egyik időzónában február 2-án, a másikban február 1-jén lép életbe az új szerződés. Jogi szempontból ez abszurd, és természetesen nem szabad így lennie. Általános szabály a „tiszta” dátumok esetében rendkívül egyszerű - az ilyen értékeket nem szabad a mentés és az olvasás egyetlen lépésében sem konvertálni.

Számos módja van a dátumok átváltásának elkerülésére:

  • Ha a platform támogatja a dátumot idő nélküli típust, akkor ezt kell használni.
  • Adjon hozzá egy speciális funkciót az objektum metaadataihoz, amely megmondja a szerializálónak, hogy mit tegyen adott értéket az időzónát figyelmen kívül kell hagyni.
  • Adja át a dátumot az ügyféltől és vissza karakterláncként, és tárolja dátumként. Ez a megközelítés kényelmetlen, ha nemcsak a dátumot kell megjelenítenie az ügyfélen, hanem néhány műveletet is el kell végeznie rajta: összehasonlítás, kivonás stb.
  • Adja át és tárolja karakterláncként, és csak formázás céljából konvertálja dátummá, figyelembe véve az ügyfél regionális beállításait. Még több hátránya van, mint az előző verziónak - például ha a tárolt karakterláncban a dátum részei nem „év, hónap, nap” sorrendben vannak, akkor lehetetlen lesz hatékony indexelt keresés dátumtartomány szerint.
Lehet persze ellenpéldát hozni, és azt mondani, hogy a szerződésnek csak abban az országban van értelme, amelyben megkötötték, az ország ugyanabban az időzónában van, és ezért egyértelműen meghatározható a belépés időpontja. hatályba lép. De még ebben az esetben sem érdekli a más időzónákból származó felhasználókat, hogy helyi idő szerint melyik pillanatban fog bekövetkezni ez az esemény. És még ha szükség is lenne ennek az időpontnak a megjelenítésére, akkor nem csak a dátumot, hanem az időt is meg kell jeleníteni, ami ellentmond az eredeti feltételnek.

Időintervallum

Az időintervallumok tárolásával és feldolgozásával minden egyszerű: értékük nem függ az időzónától, ezért itt nincs különösebb ajánlás. Ezek több időegységben tárolhatók és továbbíthatók (egész vagy lebegőpontos, a kívánt pontosságtól függően). Ha fontos a másodperc pontosság, akkor másodpercek számaként, ha ezredmásodperces pontosság, akkor ezredmásodpercek számaként stb.

Az intervallum kiszámításának azonban lehetnek buktatói. Tegyük fel, hogy van egy általános C# kódunk, amely számolja a két esemény közötti időintervallumot:

DateTime start = DateTime.Now; //... DateTime end = DateTime.Now; double hours = (vége - kezdete).TotalHours;
Első pillantásra nincs itt semmi probléma, de nem az. Először is problémák adódhatnak az ilyen kódok tesztelésével, de erről egy kicsit később fogunk beszélni. Másodszor képzeljük el, hogy a kezdési időpont a téli idő, a befejezés a nyári idő (például a munkaórák számát így mérik, és a dolgozóknak éjszakai műszakjuk van).

Tegyük fel, hogy a kód egy olyan időzónában fut, ahol a 2016-os nyári időszámítás március 27-én van, és szimulálja a fent leírt helyzetet:

DateTime start = DateTime.Parse("2016-03-26T20:00:15+02"); DateTime end = DateTime.Parse("2016-03-27T05:00:15+03"); double hours = (vége - kezdete).TotalHours;
Ez a kód 9 órát eredményez, bár ténylegesen 8 óra telt el ezek között az idők között. Ez könnyen ellenőrizhető a kód módosításával:

DateTime start = DateTime.Parse("2016-03-26T20:00:15+02").ToUniversalTime(); DateTime vége = DateTime.Parse("2016-03-27T05:00:15+03").ToUniversalTime(); double hours = (vége - kezdete).TotalHours;
Ebből a következtetés az, hogy bármelyik aritmetikai műveletek dátummal és idővel ezt UTC-értékekkel vagy időzóna-információkat tároló típusokkal kell megtennie. Aztán vissza, hogy lefordítsa helyire, ha szükséges. Ebből a szempontból az eredeti példa könnyen javítható a DateTime.Now módosításával DateTime.UtcNow értékre.

Ez az árnyalat nem egy adott platformtól vagy nyelvtől függ. Itt van egy hasonló Java kód, ugyanazzal a hátránnyal:

LocalDateTime start = LocalDateTime.now(); //... LocalDateTime end = LocalDateTime.now(); hosszú órák = ChronoUnit.HOURS.between(kezdet, vége);
Ez is könnyen javítható - például a ZonedDateTime használatával a LocalDateTime helyett.

A tervezett események ütemezése

A tervezett események ütemezése összetettebb helyzet. Nincs olyan általános típus, amely lehetővé tenné az ütemezések tárolását a szabványos könyvtárakban. De egy ilyen feladat nem olyan ritka, így kulcsrakész megoldások probléma nélkül megtalálható. Jó példa erre a cron ütemező formátum, amelyet ilyen vagy olyan formában használnak más megoldások, például a Quartz: http://quartz-scheduler.org/api/2.2.0/org/quartz/CronExpression.html . Szinte az összes ütemezési igényt lefedi, beleértve a "hónap második pénteki" opcióit is.

A legtöbb esetben nincs értelme saját ütemezőt írni, hiszen vannak rugalmas, időn tesztelt megoldások, de ha valamiért saját mechanizmus létrehozására van szükség, akkor legalább az ütemezési formátumot kölcsönözhetjük a crontól.

A különbözõ típusú idõértékek tárolására és feldolgozására vonatkozó, fentebb ismertetett ajánlásokon túlmenõen több másról is szeretnék beszélni.

Először is, a statikus osztálytagok használatáról az aktuális idő lekéréséhez - DateTime.UtcNow, ZonedDateTime.now() stb. Amint már említettük, közvetlenül a kódban történő felhasználásuk komolyan megnehezítheti az egységtesztelést, mivel speciális ál keretrendszerek nélkül aktuális idő nem fog működni. Ezért, ha egységtesztek írását tervezi, ügyeljen arra, hogy az ilyen módszerek megvalósítása helyettesíthető legyen. A probléma megoldásának legalább két módja van:

  • Dedikálja az IDateTimeProvider felületet egyetlen metódussal, amely az aktuális időt adja vissza. Ezután adjon hozzá egy függőséget ehhez az interfészhez az összes kódegységben, ahol meg kell kapnia az aktuális időt. A normál programvégrehajtás során ezekre a helyekre az alapértelmezett implementációt injektálják, ami a valós aktuális időt adja vissza, az egységteszteknél pedig minden egyéb szükséges implementációt. Ez a módszer a legrugalmasabb a tesztelés szempontjából.
  • Készítse el saját statikus osztályát az aktuális idő lekérésére szolgáló metódussal, és a módszer bármely implementációjának kívülről történő beállításával. Például C# kód esetén ez az osztály felfedheti az UtcNow tulajdonságot és a SetImplementation(Func impl). Ha statikus tulajdonságot vagy metódust használunk az aktuális idő lekérésére, akkor nem kell mindenhol kifejezetten megadni a további interfésztől való függést, de az OOP elvek szempontjából ez nem ideális megoldás. Ha azonban valamilyen okból az előző lehetőség nem megfelelő, akkor használhatja ezt.
Egy további probléma, amelyet meg kell oldani az aktuális időszolgáltató saját megvalósítására való áttéréskor, hogy megbizonyosodjon arról, hogy senki sem használja "a régimódi módon" továbbra is a szabványos osztályokat. Ez a feladat a legtöbb kódminőség-ellenőrző rendszerben könnyen megoldható. Lényegében a „nem kívánt” részkarakterlánc keresése minden fájlban, kivéve azokat, amelyekben az „alapértelmezett” megvalósítás van deklarálva.

A második árnyalat az aktuális idő megállapításánál az az ügyfélben nem lehet megbízni. A felhasználók gépein az aktuális idő nagyon eltérhet a valóstól, és ha logika kötődik hozzá, akkor ez a különbség mindent elronthat. Minden olyan helyet, ahol szükség van az aktuális idő lekérésére, lehetőség szerint a szerver oldalon kell végrehajtani. És amint korábban említettük, az idővel végzett összes aritmetikai műveletet vagy UTC-értékekben kell végrehajtani, vagy olyan típusokkal, amelyek tárolják az időzóna eltolását.

És még egy dolog, amit meg akartam említeni, az az ISO 8601 szabvány, amely leírja az információcsere dátum- és időformátumát. A lehetséges kompatibilitási problémák elkerülése érdekében különösen a szerializálás során használt dátum és idő karakterlánc-ábrázolása kell, hogy megfeleljen ennek a szabványnak. A gyakorlatban rendkívül ritka, hogy a formázást saját kezűleg kell megvalósítani, így maga a szabvány elsősorban információs célokat szolgálhat.

Címkék: Címkék hozzáadása

DateTimeOffset tesztDateAndTime = new DateTimeOffset(2008, 5, 1, 8, 6, 32, new TimeSpan(1, 0, 0)); //TISZTÍTÁSI IDŐ ÉS DÁTUM testDateAndTime = testDateAndTime.DateTime.Date; var datesTableEntry = db.DatesTable.First(dt => dt.Id == someTestId); datesTableEntry.test=testDateAndTime; db.SaveChangesAsync();

EREDMÉNY AZ ADATBÁZISBAN: 2008-05-01 00:00:00.0000000 -04:00

Hogyan lehet a -4:00-at +00:00-ra változtatni (a mentés előtti kódból)?

Megpróbáltam:

Nyilvános feladat SetTimeZoneOffsetToZero(DateTimeOffset dateTimeOffSetObj) ( TimeSpan zeroOffsetTimeSpan = new TimeSpan(0, 0, 0, 0, 0); return dateTimeOffSetObj.ToOffset(zeroOffsetTimeSpan); )

Nem csinál semmit.

A végcél csak az, hogy legyen egy dátum idő- vagy időzóna-eltolás nélkül. NEM szeretném átváltani az időt egy másik időzónára (azaz 00:00:00.0000000 Nem akarom, hogy 00:00:00.0000000 időből levonjon 4 órát, és a 00:00:00.0000000 +00-val eltolja a beállított időt: 00 , csak azt akarom, hogy az eltolást +00:00-ra állítsa. Az aktuális dátumot szeretném nulla eltolással.

Szerkesztés:

Íme, amit máshol kínálhat:

DateTimeOffset tesztDateAndTime = new DateTimeOffset(2008, 5, 1, 8, 6, 32, new TimeSpan(1, 0, 0)); testDateAndTime = testDateAndTime.DateTime.Date; //Zero out time rész testDateAndTime = DateTime.SpecifyKind(testDateAndTime.Date, DateTimeKind.Utc); //"Nulla ki" eltolási rész

Biztos voltam benne, hogy a SpecifyKind lesz a SpecifyKind a dateTimeOffset-emben, változtassa meg például az időt és az időzóna-eltolást is, de a tesztelés során úgy tűnik, hogy csak az időzóna eltolását módosítja, amit szeretnék. Van ezzel valami probléma?

1 válasz

A probléma semmi köze az adatbázishoz. Ha töréspontot állított be vagy kilépést naplózott valahol, az eltolást röviddel a kód után kell látnia:

TestDateAndTime = testDateAndTime.DateTime.Date;

Bontsuk szét:

  • A DateTimeOffset 2008-05-01T08:06:32+01:00 dátummal kezdted
  • Ezután meghívta a .DateTime értéket, ami a DateTime értéket 2008-05-01T08:06:32 DateTimeKind.Unspecified értékkel eredményezte.
  • Ezután meghívta a .Date parancsot, aminek eredményeként a DateTime értéke 2008-05-01T00:00:00 a DateTimeKind.Unspecified értékkel.
  • Az eredményt a testDateAndTime mezőben adja vissza, amely DateTimeOffset típusú. Ez implicit konverziót okoz DateTime-ről DateTimeOffset-re amely a helyi időzónát használja. Az Ön esetében úgy tűnik, hogy ennek az értéknek az eltolása a helyi időzónában -04:00 , így a kapott érték DateTimeOffset 2008-05-01T00:00:00-04:00, ahogyan Ön leírta,

Te mondtad:

A végcél csak az, hogy legyen egy dátum idő- vagy időzóna-eltolás nélkül.

Nos, jelenleg nincs natív C# adattípus, ami csak egy dátum idő nélkül. Van egy tiszta dátum típus a corefxlab System.Time csomagjában, de ez még nem teljesen kész egy tipikus éles alkalmazáshoz. A Noda időkönyvtárában van egy LocalDate, amelyet ma is használhat, de még mindig vissza kell konvertálnia a natív típusra, mielőtt az adatbázisban tárolná. Tehát addig is a legjobb, amit tehetsz:

  • Módosítsa az SQL Servert, hogy a dátumtípust használja ebben a mezőben.
  • A .NET kódban használja a DateTime időt 00:00:00 és a DateTimeKind.Unspecified értékkel. Ne felejtse el figyelmen kívül hagyni az időrészt (mivel bizonyos időzónákban vannak érvényes dátumok helyi éjfél nélkül).
  • Módosítsa a teszt riasztást DateTime értékre, ne DateTimeOffset értékre.

Általában, míg a DateTimeOffset alkalmas egy nagy szám forgatókönyvek (pl. időbélyegzési események) esetén nem alkalmas csak dátumértékekre.

Az aktuális dátumot szeretném nulla eltolással.

Ha valóban DateTimeOffsetként szeretné használni, tegye a következőket:

TestDateAndTime = new DateTimeOffset(tesztDátumÉsIdő.Dátum, Időtartam.Zero);

Én azonban nem tanácsolom. Ezzel az eredeti érték helyi dátumát veszi, és azt állítja, hogy az UTC-ben van. Ha az eredeti eltolás nem nulla, ez hamis állítás lesz. Ez később különböző hibákhoz vezet, mivel valójában egy másik időpontról beszél (potenciálisan más dátummal), mint amit létrehoztál.

Ami a szerkesztésben feltett további kérdést illeti – a DateTimeKind.Utc megadása megváltoztatja az implicit cast viselkedését. A helyi időzóna használata helyett az UTC idő kerül felhasználásra, amelynek mindig van nulla eltolása. Az eredmény ugyanaz, mint a fentebb adott explicitebb megjelenés. Továbbra is ellene javaslom ugyanezen okok miatt.

Tekintsük a 2016-12-31T22:00:00-04:00 kezdetű példát. Az Ön megközelítése szerint 2016-12-31T00:00:00+00:00 kell tárolni az adatbázisban. Ez azonban két különböző időszak. Az első, UTC-re normalizálva, 2017-01-01T02:00:00+00:00, a második pedig egy másik időzónára konvertálva 2016-12-30T20:00:00-04:00 lesz. . Ügyeljen az átalakítás dátumának változására. Valószínűleg nem ezt a viselkedést szeretné alkalmazni az alkalmazásában.