Korrekt munkavégzés dátummal és idővel. Időzóna-eltolás eltávolítása a DateTimeOffset-ből Null date offset sql server

A probléma semmi köze az adatbázishoz. Ha beállít egy töréspontot vagy beír egy kimenetet valahova, akkor látnia kell, hogy az eltolás röviddel a kód után megtörténik:

TestDateAndTime = testDateAndTime.DateTime.Date;

Bontsuk szét:

  • A DateTimeOffset értékkel kezdted: 2008-05-01T08:06:32+01:00
  • Ezután meghívta a .DateTime értéket, ami a DateTime 2008-05-01T08:06:32 értéket eredményezte 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 értékhez rendeli, amely DateTimeOffset típusú. Ez a DateTime-ről a DateTimeOffset-re való implicit leadást okoz - , 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 DateTimeOffset 2008-05-01T00:00:00-04:00, ahogyan Ön leírta.

Azt 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 egy dátum idő nélkül. Van egy tiszta dátum típus Rendszer.Idő csomag a corefxlabban, 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:

  • Módosítsa az SQL Servert, hogy dátumtípust használjon 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 valóban vannak dátumok helyi éjfél nélkül).
  • Módosítsa a tesztprofilt DateTime értékre DateTimeOffset helyett.

Általánosságban elmondható, hogy 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.

akarom aktuális dátum nulla eltolással.

Ha te nagyon akarom 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 nullától eltérő, ez hamis állítás lesz. Ez később más hibákhoz vezet, mivel valójában egy másik időpontról beszél (potenciálisan más dátummal), mint amit Ön hozott létre.

A testületnek feltett további 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 nézet. Továbbra is ezt ellenjavaslom, ugyanezen okok miatt.

Vegyünk egy 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 mentenie az adatbázisba. Ez azonban két különböző időpont. 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 lenne. Kérjük, vegye figyelembe az átalakítás dátumainak változását. Valószínűleg nem ezt a viselkedést szeretné az alkalmazásában.

Szinte minden projektben problémák merülnek fel a dátum és az idő helytelen kezelése és tárolása miatt. Még ha a projektet ugyanabban az időzónában használják is, akkor is érhetnek kellemetlen meglepetések a téli/nyári időszámításra váltás után. Ugyanakkor kevesen értetlenkednek eleve 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 pontot 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 található, a központi ág pedig, amely az elemzések időben történő befejezését figyeli, a +1 zónában található. A példában megadott időpontokat 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 irodának? Nyilván a szoftver központi iroda 2014. január 15. 12:17:15-öt kell mutatnia - egy órával kevesebbet, mivel az ő nézésük szerint éppen abban a pillanatban történt az esemény.

Tekintsük az egyik lehetséges műveleti láncot, amelyen keresztül az adatok áthaladnak a klienstől a szerverig és vissza, ami lehetővé teszi, hogy mindig helyesen jelenítse meg a dátumot/idő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-es 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 az aktuális időzónába hozza. 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 elmenti az adatokat az adatbázisba, de 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 2016. március 2. el lesz mentve az adatbázisba 14 :13:36 „ismeretlen” idõzónában.
  6. A szerver beolvassa az adatokat az adatbázisból, és létrehoz egy megfelelő objektumot 2016. március 2. értékkel 14 :13:36. És mivel a szerver +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, hogy minden sértetlen, 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 az idő időzóna nélkül is előállítható – például a DateTime típus a .NET-ben a DateTimeKind.Unspecified paraméterrel.
  • A sorosító motor olyan formátumot használhat, amely nem tartalmaz időzóna-eltolást.
  • Objektummá 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 előállítható – például a DateTime típus a .NET-ben a DateTimeKind.Unspecified használatával. Sőt, a .NET-ben található DateTime esetében a gyakorlatban pontosan ez történik, ha nem adunk meg kifejezetten egy másik DateTimeKind-et közvetlenül a lektorálás után.
  • Ha a közös adatbázissal dolgozó alkalmazásszerverek különböző időzónákban helyezkednek el, komoly zavarok léphetnek fel az időeltolások terén. 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 átvitele a már tárolt dátum/idő értékek helytelen értelmezéséhez vezet.
De a fent leírt lánc legsúlyosabb hátránya a helyi időzóna használata a szerveren. Ha nem áll át a nyári/téli időszámításra, akkor nem lesz további probléma. 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 figyelembe kell venni a rendszerfrissítéseknél. A gyakorlatban többször találkoztunk olyan helyzetekkel, amikor ez a mechanizmus nem működött megfelelően, amelyeket végül gyorsjavítások telepítésével, ill. operációs rendszer, vagy harmadik féltől származó könyvtárakat használt. Annak a valószínűsége, hogy ugyanazok a problémák ismétlődjenek, nem nulla, ezért jobb, ha van mód arra, hogy elkerüljük őket.

A fent leírt szempontokat figyelembe véve megfogalmazzuk a legmegbízhatóbb és legegyszerűbb módszert az idő továbbítására és tárolására: a szerveren és az adatbázisban minden értéket át kell konvertálni UTC időzónára.

Nézzük, 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 szerverről, a kliens a dátumot és az időt a helyi időzónára konvertálja, tudva, hogy minden esetben UTC-ben fogja megkapni az időt.
  • Az UTC-ben nincs átmenet a nyári és a téli időszámítás között, így az ezzel kapcsolatos problémák nem lesznek relevánsak.
  • A szerveren az adatbázisból való olvasáskor nem kell időértékeket konvertálni, csak kifejezetten jelezni kell, hogy az UTC-nek felel meg. A .NET-ben például ez ú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 semmilyen módon 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 szerializálási mechanizmust úgy állítsa be, hogy a dátum/idő értékek helyesen legyenek lefordítva UTC-ből a helyi időzónába és vissza.
  2. Győződjön meg arról, hogy a szerveroldali deszerializáló dátum/idő objektumokat hoz létre UTC-ben.
  3. Ügyeljen arra, hogy az adatbázisból való olvasás során a dátum/idő objektumok UTC-ben legyenek létrehozva. Ez az elem néha kódmódosítás nélkül érhető el – egyszerűen 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 ha két feltétel kombinálódik:
  • A rendszerkövetelmények nem követelik meg, hogy a helyi idő és/vagy az időzóna eltolása pontosan úgy legyen megjelenítve, ahogyan azt eltárolta. Például a repülőjegyekre ki kell nyomtatni az indulási és érkezési időt a repülőtér helyének megfelelő időzónában. Vagy ha a szerver különböző országokban készített nyomtatási számlákat küld, mindegyiknek a helyi idő szerint 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, amely egyetlen UTC-értéknek felel meg. Például „a hordozórakéta kijevi idő szerint 23:00-kor történt”, vagy „a találkozó minszki idő szerint 13:30 és 14:30 között lesz”. Ezeknek az eseményeknek a számai eltérőek lesznek a különböző időzónákban, 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 televíziós program 9:00 és 10:00 óra között fog sugározni minden olyan országban, ahol van TV-csatorna társult vállalkozása”. Kiderül, hogy egy műsor sugárzása nem egy esemény, hanem több, és potenciálisan mindegyik előfordulhat „abszolút” léptékben különböző időpontokban.
Az első feltétel megsértése esetén a probléma megoldható az időzónát tartalmazó adattípusok használatával - 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.
.NETTÓ DateTimeOffset
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 összetettebb 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 bekövetkezett vagy bekövetkezik, 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 televíziós társaság összes fióktelepére beírta a műsor kezdetét, és 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 műsorok kezdete előtt automatikusan speciális műveleteket kell végrehajtaniuk (értesítéseket küldeni vagy ellenőrizni bizonyos adatok jelenlétét a tévétársaság 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 hasonló 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óna-kötéseket, vagy az ütemezőnek automatikusan át kell vennie ezeket az információkat globális forrásokból, pl. Google Maps Time Zone API. 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 is világosan meg kell értenie a követelményekből, hogy a fent említett helyzetek közül melyik fog előfordulni az Ön rendszerében. Valószínűleg minden az első javasolt megközelítésre korlátozódik, UTC 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

Tegyük fel, hogy az ügyfél időzónáját figyelembe véve kiválasztottuk a dátum és az idő helyes megjelenítésé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 „szokásos” dátumokhoz és időpontokhoz?

Nem minden platform, nyelv és DBMS rendelkezik csak dátumtípussal. Például a .NET-ben csak a DateTime típus létezik, nincs külön „csak dátum” típus. Még ha csak egy dátumot adtunk meg egy ilyen objektum létrehozásakor, az idő akkor is jelen van, és egyenlő 00:00:00-val. Ha a „2016. február 2. 00:00:00” értéket egy +2 és +1 eltolású zónából visszük át, akkor „2016. február 1. 23:00:00”-at kapunk. A fenti példában ez az egyik időzónában február 2-án, a másikban február 1-jén kezdődő új szerződésnek felel meg. 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 attribútumot az objektum metaadataihoz, amely közli a sorosítóval, hogy az időzónát egy adott értéknél 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 bizonyos műveleteket is el kell végeznie rajta: összehasonlítás, kivonás stb.
  • Adja át és tárolja karakterláncként, és csak az ügyfél regionális beállításain alapuló formázáshoz konvertálja dátummá. Még több hátránya van, mint az előző opciónak - például ha a tárolt karakterláncban a dátum részei nem az „év, hónap, nap” sorrendben vannak, akkor lehetetlen lesz hatékony indexelt keresést végezni 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 hatálybalépés időpontja. 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 lenne is ennek a pillanatnak 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. Tárolhatók és továbbíthatók több időegységben (egész szám vagy lebegőpont, a szükséges pontosságtól függően). Ha fontos a másodperces pontosság, akkor a másodpercek számaként, ha az ezredmásodperces pontosság, akkor az ezredmásodpercek számaként stb.

De az intervallum kiszámítása buktatókkal járhat. Tegyük fel, hogy van néhány minta C# kódunk, amely kiszámítja 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 ez nem így van. 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 az idő kezdeti pillanata a téli időszámításra, a végső pillanat a nyári időszámításra esett (például így mérik a munkaórák számát, és a dolgozóknak éjszakai műszakjuk van).

Tegyük fel, hogy a kód olyan időzónában fut, amelyben 2016-ban a nyári időszámítás március 27-én van, és szimuláljuk 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 valójában 8 óra telt el ezen pillanatok között. Ezt egyszerűen ellenőrizheti 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 következik a következtetés: minden dátummal és idővel végzett aritmetikai műveletet UTC-értékekkel vagy időzóna-információkat tároló típusokkal kell végrehajtani. Majd ha szükséges, térjen vissza a helyihez. Ebből a szempontból az eredeti példa könnyen javítható a DateTime.Now módosításával DateTime.UtcNow-ra.

Ez az árnyalat nem egy adott platformtól vagy nyelvtől függ. Itt van egy hasonló kód Java-ban, amely ugyanazzal a problémával rendelkezik:

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

A tervezett események ütemezése

Az ütemezett események ütemezése bonyolultabb helyzet. Nincs olyan univerzális típus, amely lehetővé tenné az ütemezések tárolását szabványos könyvtárakban. De egy ilyen feladat nem nagyon ritkán merül fel, így a kész megoldások probléma nélkül megtalálhatók. 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 az olyan lehetőségeket is, mint a „hónap második péntekje”.

A legtöbb esetben nincs értelme saját ütemezőt írni, hiszen vannak rugalmas, időtálló megoldások, de ha valamilyen oknál fogva szükség van saját mechanizmus létrehozására, akkor legalább az ütemezési formátumot kölcsönözhetjük 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ást is szeretnék megemlíteni.

Először is, ami a statikus osztálytagok használatát illeti az aktuális idő megszerzéséhez - DateTime.UtcNow, ZonedDateTime.now() stb. Mint elhangzott, a kódban való közvetlen felhasználásuk komolyan megnehezítheti az egységtesztelést, mivel speciális gúnyos keretrendszerek nélkül nem lehet lecserélni az aktuális időt. Ezért, ha egységtesztek írását tervezi, meg kell győződnie arról, hogy az ilyen módszerek megvalósítása helyettesíthető. A probléma megoldásának legalább két módja van:

  • Adjon meg egy 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éghez, 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ó kerül beinjektálásra, amely 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 tesztelési szempontbó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ő telepítésének lehetőségével. Például C# kód esetén ez az osztály felfedheti az UtcNow tulajdonságot és a SetImplementation(Func) metódust impl). Ha statikus tulajdonságot vagy metódust használunk az aktuális idő lekérésére, akkor szükségtelenné válik mindenhol explicit módon megadni egy további interfész függőségét, 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 a jelenlegi időszolgáltató megvalósítására való átálláskor meg kell oldani, annak biztosítása, hogy senki ne használja tovább a szabványos osztályokat a „régi módon”. 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 azt, amelyikben az „alapértelmezett” megvalósítás van deklarálva.

A második figyelmeztetés az aktuális idő meghatározásához 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 megtenni. És amint azt korábban említettük, az idővel végzett összes aritmetikai műveletet vagy UTC értékekben, vagy olyan típusok használatával kell végrehajtani, 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-megjelenítésének kell megfelelnie 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

A humánus opció ([a link megtekintéséhez regisztrálnia kell]).

A probléma lényege a következő.. Ha véletlenül egy adatbázist telepített egy SQL szerverre 0 „dátumeltolás”-val, akkor probléma merült fel, amikor az adatbázis egy TIME típusú attribútumot tartalmaz, azaz ez az attribútum 01-re van állítva. /01/0001 10:30:00 vagy üresen bejegyzett dátum 01.01.0001 00:00:00. Ilyen részletek rögzítésekor nem kerül rögzítésre.
Az interneten egy új adatbázis létrehozását javasolják 2000-es eltolással.
De nem igazán akartam új bázist létrehozni. És módosítsa az adatbázis elérési útját minden felhasználó számára.
Ezután követtem azt az utat, hogy hol van ez az érték az SQL-ben tárolva. Megtaláltam és 2000-re cseréltem és minden rendben volt..
És most lépésről lépésre hol kell változtatni.

Rúgd ki az összes felhasználót.

FIGYELEM!!!

1. Először csináld meg biztonsági másolat 1C segítségével, azaz töltse fel a *.dt-be
Ezt meg kell tenni az „eltolás” megváltoztatása előtt
Ha ez nem történik meg, akkor a teljes adatbázisodban lesznek hivatkozások, dokumentumok stb.
ahol van igény, az időpont mondjuk 0009.10.02
MIT NEM TILOS...
Tehát feltöltötte a *.dt

2. Nyissa meg az SQL Server Management Studio alkalmazást
Keresse meg a bázist a listában, és nyomja meg a plusz jelet.
Keresse meg a „Táblázatok” mappát, és nyissa meg.
Egy csomó asztal kinyílik, menjen a legaljára, keresse meg az asztalt
_YearOffset, álljon rá, és válassza ki az „Asztal megnyitása” pontot a jobb gombbal, lásd 1. ábra.
Módosítsa a 0 értéket 2000-re
Zárja be az SQL Server Management Studio alkalmazást

3. Lépjen a konfigurátorba, és töltse be a korábban elmentett adatbázist.

Ha ez nem történik meg, akkor minden dátum a 0009-es évszámmal fog szerepelni.
Az adatbázis betöltése után... Léphet az 1C-be és győződjön meg arról, hogy a dátumok normálisak.
Az eredmény az, hogy megváltoztattuk a „dátumeltolást 0-ról 2000-re”

Néha előfordul, hogy ez a lehetőség valamilyen okból nem használható. Ezután van egy keményebb lehetőség ([a link megtekintéséhez regisztrálnia kell]):

A TablesAndFields kurzor deklarálása ehhez

SELECT objektumok.név mint Táblanév, oszlopok.név oszlopnévként
FROM dbo.sysobjects mint tárgyakat
balra csatlakozik a dbo.syscolumns oszlopokhoz az objects.id = oszlopok.id ponton
ahol az objektumok.xtype = "U" és az oszlopok.xtípus = 61

nyissa meg a TablesAndFields alkalmazást

WHILE @@FETCH_STATUS = 0
BEGIN Exec(" frissítés"+ @TableName + "
készlet" + @Oszlopnév + " = ""2000- 01- 01 00:00:00" "
hol" + @Oszlopnév + " > ""3999- 12- 31 23:59:59" "")

Ez mindaddig végrehajtódik, amíg az előző lekérés sikeres.
KÖVETKEZŐ KERESÉS A TablesAndFields-ből a @TableName, @ColumnName
VÉGE

zárja be a TablesAndFields alkalmazást
deallocateTablesAndFields
megy

Bármilyen manipuláció előtt ne felejtsen el másolatot készíteni az adatbázisokról!

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 ADATBÁZISBAN: 2008-05-01 00:00:00.0000000 -04:00

Hogyan lehet engedélyezni -4:00 és +00:00 között (a mentés előtti kódból)?

Kipróbáltam:

Nyilvános feladat

SetTimeZoneOffsetToZero(DateTimeOffset dateTimeOffSetObj) ( TimeSpan zeroOffsetTimeSpan = new TimeSpan(0, 0, 0, 0, 0); return dateTimeOffSetObj.ToOffset(zeroOffsetTimeSpan); )

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 meg fogja határozni a dateTimeOffset-emet, például megváltoztatja az időt és az időzóna eltolását is, de tesztelve úgy tűnik, hogy csak az időzóna eltolását változtatja meg, amit én akarok. Van ezzel valami probléma?

1 válasz

A probléma semmi köze az adatbázishoz. Ha beállít egy töréspontot vagy regisztrált valahol egy kimenetet, akkor röviddel ez után a kód után látnia kell az eltolást:

TestDateAndTime = testDateAndTime.DateTime.Date;

  • Bontsuk szét:
  • A DateTimeOffset 2008-05-01T08:06:32+01:00 beállítással 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 alkalmazza

. 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,

Azt mondtad:

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

  • Nos, jelenleg nincs olyan natív C# adattípus, amely csak egy dátum idő nélkül. A corefxlab System.Time csomagjában van egy tiszta dátum típus, de ez még nem teljesen kész egy tipikus éles alkalmazáshoz. A Noda időkönyvtárában található a LocalDate, amelyet ma is használhat, de még mindig vissza kell konvertálnia natív típusra, mielőtt az adatbázisban tárolná. Tehát addig is a legjobb, amit tehetsz:
  • 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 valóban vannak dátumok helyi éjfél nélkül).
  • Módosítsa az SQL Servert, hogy a dátumtípust használja ebben a mezőben.

Módosítsa a tesztriasztást DateTime értékre DateTimeOffset helyett. Általában, míg a DateTimeOffset alkalmas nagy mennyiségben

forgatókönyvek (például 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.

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

Ezt 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 nullától eltérő, ez hamis állítás lesz. Ez később más hibákhoz vezet, mivel valójában egy másik időpontról beszél (potenciálisan más dátummal), mint amit Ön hozott létre.

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 nézet. Továbbra is ezt ellenjavaslom, ugyanezen okok miatt.

Nézzük meg a 2016-12-31T22:00:00-04:00 időponttól kezdődő példát. Az Ön megközelítése szerint 2016-12-31T00:00:00+00:00 kell mentenie az adatbázisba. Ez azonban két különböző időpont. 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 lenne. Kérjük, vegye figyelembe az átalakítás dátumainak változását. Valószínűleg nem ezt a viselkedést szeretné az alkalmazásában.