Aracılığıyla paylaş


.NET Framework DateTime Kullanarak En İyi Yöntemleri Kodlama

 

Dan Rogers
Microsoft Corporation

Şubat 2004

Şunlara uygulanır
   Microsoft® .NET Framework
   Microsoft® ASP.NET Web Hizmetleri
   XML serileştirme

Özet: Microsoft .NET Framework DateTime türünü kullanarak zaman değerlerini depolayan, hesaplamalar yapan ve seri hale getiren programlar yazmak, Windows ve .NET'te kullanılabilen zaman gösterimleriyle ilişkili farklı sorunların farkında olmayı gerektirir. Bu makale, zaman içeren önemli test ve geliştirme senaryolarına odaklanır ve Microsoft'ta DateTime türünü kullanan programlar yazmak için en iyi yöntem önerilerini tanımlar. NET tabanlı uygulamalar ve derlemeler. (18 yazdırılan sayfa)

İçindekiler

Arka Plan
   DateTime nedir?
   Kurallar
Depolama Stratejileri
   En İyi Yöntem #1
   En İyi Yöntem #2
HesaplamaLar Gerçekleştirme
   Bir Daha Kandırmayın
   En İyi Yöntem #3
   DateTime Yöntemlerini Sıralama
XML'nin Özel Durumu
   En İyi Yöntem #4
   En İyi Uygulama #5
Sınıf Kodlayıcıları Quandary
   En İyi Yöntem #6
Yaz Saati Ile ilgilenme
   En İyi Yöntem #7
User-Ready Değerlerini Biçimlendirme ve Ayrıştırma
   Gelecekte Dikkat Edilmesi Gerekenler
DateTime.Now() Yöntemiyle İlgili Sorunlar
   En İyi Yöntem #8
Bilinen Birkaç Ekstra
Sonuç

Arka Plan

Birçok programcı, tarih ve saat bilgilerini içeren verileri doğru bir şekilde depolamalarını ve işlemelerini gerektiren atamalarla karşılaşır. İlk bakışta ortak dil çalışma zamanı (CLR) DateTime veri türü bu görevler için mükemmel görünüyor. Ancak programcıların, büyük olasılıkla test edenlerin bir programın doğru zaman değerlerinin izini kaybettiği durumlarla karşılaşması nadir değildir. Bu makale, DateTime'ı içeren mantıkla ilişkili sorunlara odaklanır ve bunu yaparken DateTime bilgilerini yakalayan, depolayan, alan ve ileten programları yazmak ve test etmek için en iyi yöntemleri ortaya çıkarır.

DateTime nedir?

NET Framework sınıf kitaplığı belgelerine baktığımızda "CLR System.DateTime değer türü, 12:00:00 gece yarısı, 1 Ocak 0001 AD ile 11:59:59, 31 Aralık 9999 AD arasında değişen tarih ve saatleri temsil eder" ifadesini görüyoruz. Daha fazla bilgi edinmek gerekirse, bir DateTime değerinin belirli bir noktada bir anlık değeri temsil ettiğini ve yaygın bir uygulamanın, daha yaygın olarak Greenwich Saati (GMT) olarak bilinen Eşgüdümlü Evrensel Saat'te (UCT) zaman noktası değerlerini kaydetmek olduğunu öğreniriz.

İlk bakışta, sonra programcı bir DateTime türünün iş uygulamaları gibi geçerli günlük programlama sorunlarında karşılaşılabilecek zaman değerlerini depolamada oldukça iyi olduğunu keşfeder. Bu güvenle, pek çok beklenmeyen programcı kodlamaya başlar ve ileriye doğru zaman konusunda ihtiyaç duydukları kadar bilgi edinebileceklerinden emindir. Bu "kullandıkça öğren" yaklaşımı birkaç soruna yol açabilir, bu nedenle bunları tanımlamaya başlayalım. Bunlar, belgelerdeki sorunlardan program tasarımlarınıza hesaba katılması gereken davranışlara kadar uzanmaktadır.

System.DateTime için V1.0 ve 1.1 belgeleri, beklenmeyen programcıyı yolundan çıkarabilecek birkaç genelleştirme yapar. Örneğin, belgelerde şu anda hala DateTime sınıfında bulunan yöntemlerin ve özelliklerin hesaplamalar veya karşılaştırmalar yaparken değerin yerel makine yerel saat dilimini temsil ettiğini varsadığını belirtmektedir. GMT'yi ve yerel saat dilimi görünümünü varsayan bazı Tarih ve Saat hesaplama türleri olduğundan bu genelleştirmenin doğru olmadığı ortaya çıkar. Bu alanlar bu makalenin devamında verilmiştir.

Bu nedenle, kodunuzun ilk seferde düzgün çalışmasını sağlamaya yardımcı olabilecek bir dizi kuralı ve en iyi uygulamayı belirterek DateTime türünü keşfederek başlayalım.

Kurallar

  1. DateTime örneklerinin hesaplamaları ve karşılaştırmaları yalnızca karşılaştırılan veya kullanılan örnekler aynı saat dilimi perspektifinden zaman içindeki noktaların temsilleri olduğunda anlamlıdır.
  2. Bir geliştirici, bir DateTime değeriyle ilişkili saat dilimi bilgilerini bazı dış mekanizmalar aracılığıyla izlemekle sorumludur. Bu genellikle bir DateTime değer türünü depolarken saat dilimi bilgilerini kaydetmek için kullandığınız başka bir alan veya değişken tanımlanarak gerçekleştirilir. Bu yaklaşım (akıllı saat dilimini DateTime değeriyle birlikte depolamak) en doğru yaklaşımdır ve programın yaşam döngüsünde farklı noktalarda bulunan farklı geliştiricilerin DateTime değerinin anlamını her zaman net bir şekilde anlamalarını sağlar. Bir diğer yaygın yaklaşım da tasarımınızda tüm zaman değerlerinin belirli bir saat dilimi bağlamında depolandığı bir "kural" haline getirmektir. Bu yaklaşım, kullanıcının saat dilimi bağlamı görünümünü kaydetmek için ek depolama gerektirmez, ancak kuraldan haberdar olmayan bir geliştirici tarafından bir zaman değerinin yanlış yorumlanması veya yanlış depolanması riskini ortaya çıkarmaktadır.
  3. Makine yerel saatini temsil eden değerlerde tarih ve saat hesaplamaları yapmak her zaman doğru sonucu vermeyebilir. Gün ışığından yararlanma saati uygulayan saat dilimi bağlamlarındaki saat değerleri üzerinde hesaplamalar yaparken, tarih aritmetik hesaplamaları yapmadan önce değerleri evrensel saat gösterimlerine dönüştürmeniz gerekir. İşlemlerin belirli bir listesi ve uygun saat dilimi bağlamları için DateTime Yöntemlerini Sıralama bölümündeki tabloya bakın.
  4. Bir DateTime değerinin örneğindeki hesaplama, örneğin değerini değiştirmez, bu nedenle MyDateTime.ToLocalTime() çağrısı DateTime örneğinin değerini değiştirmez. Date (Visual Basic'te®) ve DateTime (.NET CLR'de) sınıflarıyla ilişkili yöntemler, hesaplama veya işlemin sonucunu temsil eden yeni örnekler döndürür.
  5. .NET Framework sürüm 1.0 ve 1.1 kullanırken,System.XML boyunca UCT saatini temsil eden bir DateTime değeri GÖNDERMEYİN . Serileştirme. Bu, Tarih, Saat ve DateTime değerlerine göre belirlenir. Web hizmetleri ve System.DateTime içeren XML'ye yönelik diğer serileştirme biçimleri için, Her zaman DateTime değerindeki değerin geçerli makine yerel saatini gösterdiğinden emin olun. Seri hale getirici, GMT'de kodlanmış XML Şeması tanımlı DateTime değerinin kodunu düzgün bir şekilde çözer (uzaklık değeri = 0), ancak yerel makine saat görünümüne çözer.
  6. Genel olarak, zaman aşımını ölçme, aritmetik işlem gerçekleştirme veya farklı DateTime değerlerinin karşılaştırmalarını yapma gibi mutlak geçen süreyle ilgileniyorsanız, zaman dilimi ve/veya yaz saati etkisi olmadan mümkün olan en iyi doğruluğu elde edebilmeniz için mümkünse Evrensel saat değerini kullanmayı denemeniz gerekir.
  7. Zamanlama gibi üst düzey, kullanıcıya yönelik kavramlarla ilgilenirken ve her gün kullanıcı açısından 24 saat olduğunu güvenle varsayabilirsiniz; yerel zamanlarda aritmetik ve cetera gerçekleştirerek Kural 6'ya karşı koymak uygun olabilir.

Bu makale boyunca, bu basit kural listesi tarihleri işleyen uygulamalar yazmak ve test etmek için bir dizi en iyi yöntemin temelini oluşturur.

Şu anda, birkaçınız zaten koduna bakıyor ve bu makalenin amacı olan "Aman tanrım, beklediğim şeyi yapmıyor" diyor. Şu ana kadar okumaktan daha önce bilgi edinmeyenler için, datetime değerlerini işlemeyle ilgili sorunlara göz atalım (bundan sonra bunu "tarihler" olarak kısaltacağım). NET tabanlı uygulamalar.

Depolama Stratejileri

Yukarıdaki kurallara göre, tarih değerleriyle ilgili hesaplamalar yalnızca işlemekte olduğunuz tarih değeriyle ilişkili saat dilimi bilgilerini anladığınızda anlamlıdır. Başka bir deyişle, değerinizi geçici olarak bir sınıf üyesi değişkeninde depolar veya topladığınız değerleri bir veritabanına veya dosyaya kaydetmeyi seçerseniz, programcı olarak ilişkili saat dilimi bilgilerinin daha sonra anlaşılmasını sağlayan bir strateji uygulamak sizin sorumluluğunuzdadır.

En İyi Yöntem #1

Kodlama yaparken, bir DateTime türüyle ilişkili saat dilimi bilgilerini bir adjunct değişkeninde depolayın.

Alternatif ancak daha az güvenilir olan strateji, depolanmış tarihlerinizin depolamadan önce her zaman GMT gibi belirli bir saat dilimine dönüştürüleceğini belirten kararlı bir kural oluşturmaktır. Bu mantıklı görünebilir ve birçok ekip bunu çalıştırabilir. Ancak, veritabanındaki bir tablodaki belirli bir DateTime sütununun belirli bir saat diliminde olduğunu belirten bir overt sinyalinin olmaması, sürekli olarak projenin sonraki yinelemelerinde yorumlama hatalarına yol açar.

Farklı bir resmi olmayan ankette görülen ortak bir strateji. NET tabanlı uygulamalar, her zaman evrensel (GMT) saatle temsil edilen tarihlere sahip olma isteğidir. "İstek" diyorum çünkü bu her zaman pratik değildir. Bir Web hizmeti aracılığıyla DateTime üye değişkenine sahip bir sınıfı seri hale getirirken noktada bir durum ortaya çıkar. Bunun nedeni, bir DateTime değer türünün XSD:DateTime türüyle eşlenmesidir (beklediğiniz gibi) ve XSD türü herhangi bir saat dilimindeki zaman noktalarını temsil eder. XML olayını daha sonra ele alacağız. Daha da ilginç olan, bu projelerin iyi bir yüzdesi aslında hedeflerine ulaşmadı ve tarih bilgilerini farkında olmadan sunucu saat diliminde depoluyordu.

Bu gibi durumlarda, ilginç bir gerçek, test edenlerin zaman dönüştürme sorunları görmemeleridir, bu nedenle kimse yerel tarih bilgilerini UCT zamanına dönüştürmesi gereken kodun başarısız olduğunu fark etmedi. Bu özel durumlarda veriler daha sonra XML aracılığıyla seri hale getirilmiştir ve tarih bilgileri makine yerel saatinde olduğundan doğru şekilde dönüştürülmüştür.

Şimdi çalışmayan kodlara bakalım:

Dim d As DateTime
d = DateTime.Parse("Dec 03, 2003 12:00:00 PM") 'date assignment
d.ToUniversalTime()

Yukarıdaki program d değişkenindeki değeri alır ve depolanmış değerin zamanın UCT görünümünü temsil etmelerini bekleyerek bunu bir veritabanına kaydeder. Bu örnek, Ayrıştırma yönteminin, yöntemleri ayrıştırma ailesinin isteğe bağlı bağımsız değişkeni olarak varsayılan olmayan bir kültür kullanılmadığı sürece sonucu yerel saatle işlendiğini algılar.

Daha önce gösterilen kod aslında üçüncü satırda d DateTime değişkenindeki değeri evrensel saate dönüştüremiyor çünkü yazıldıkçe örnek Kural 4'ü ihlal ediyor (DateTime sınıfındaki yöntemler temel alınan değeri dönüştürmez). Not: Bu kod, test edilmiş gerçek bir uygulamada görülmüştür.

Nasıl geçti? İlgili uygulamalar, test sırasında tüm veriler makinelerden aynı saat dilimine ayarlandığı için Kural 1'den memnun kaldığı için depolanan tarihleri başarıyla karşılaştırabildi (karşılaştırılan ve hesaplanan tüm tarihler aynı saat dilimi görünümünde yerelleştirilir). Bu koddaki hata, tespiti zor olan türdür; yürütülen ancak hiçbir şey yapmayan bir deyimdir (ipucu: örnekteki son deyim, yazıldık şekilde işlem yapılmaz).

En İyi Yöntem #2

Test ederken, depolanan değerlerin amaçladığınız saat diliminde amaçladığınız belirli bir nokta değerini temsil ettiğini denetleyin.

Kod örneğini düzeltmek kolaydır:

Dim d As DateTime
d = DateTime.Parse("Dec 03, 2003 12:00:00 PM").ToUniversalTime()

DateTime değer türüyle ilişkili hesaplama yöntemleri hiçbir zaman temel alınan değeri etkilemediğinden, bunun yerine hesaplamanın sonucunu döndürdüğünden, bir programın dönüştürülen değeri depolamayı hatırlaması gerekir (bu isteniyorsa, elbette). Şimdi bu düzgün hesaplamanın bile yaz saatiyle ilgili belirli durumlarda beklenen sonuçları elde edememe durumunu inceleyeceğiz.

Hesaplamalar Yapma

İlk bakışta, System.DateTime sınıfıyla birlikte gelen hesaplama işlevleri gerçekten yararlıdır. Zaman değerlerine aralık ekleme, zaman değerlerinde aritmetik işlemler gerçekleştirme ve hatta .NET zaman değerlerini Win32® API çağrıları ve OLE Otomasyonu çağrıları için uygun karşılık gelen değer türüne dönüştürme desteği sağlanır. DateTime türünü çevreleyen destek yöntemlerine göz atmak, MS-DOS® ve Windows'un® yıllar içinde zaman ve zaman damgalarıyla başa çıkmak için geliştiği farklı yöntemlere nostaljik bir bakış sunar.

Bu bileşenlerin tümünün işletim sisteminin çeşitli bölümlerinde hala mevcut olması, Microsoft'un koruduğu geriye dönük uyumluluk gereksinimleriyle ilgilidir. Bir programcıya göre, dosyalar, dizinler üzerinde zaman damgalarını temsil eden verileri taşıyorsanız veya tarih ve DateTime değerlerini içeren COM/OLE Birlikte Çalışma yapıyorsanız, Windows'ta mevcut olan farklı zaman nesilleri arasındaki dönüşümlerle başa çıkma konusunda yetkin olmanız gerekir.

Bir Daha Kandırmayın

Büyük olasılıkla saat dilimi uzaklığını (ve Pasifik Standart Saati veya PST gibi saat diliminin kullanıcı bakışlı bir görünümünü) depolamak zorunda kalmamak için "her şeyi UCT zamanında depolarız" stratejisini benimsemiş olduğunuzu varsayalım. UCT süresini kullanarak hesaplamalar gerçekleştirmenin çeşitli avantajları vardır. Aralarındaki şef, evrensel zamanda temsil edildiğinde, her günün sabit bir uzunluğa sahip olması ve başa çıkabilecek saat dilimi uzaklıkları olmamasıdır.

Bir günün farklı uzunluklara sahip olabileceğini okuduğunuza şaşırdıysanız, gün ışığından yararlanmaya izin veren herhangi bir saat diliminde, yılın iki gününde (genellikle) günlerin farklı bir uzunluğa sahip olduğunu unutmayın. Bu nedenle, Pasifik Standart Saati (PST) gibi yerel bir saat değeri kullanıyor olsanız bile belirli bir DateTime örnek değerine zaman aralığı eklemeye çalışırsanız, eklenen aralık gün ışığından yararlanma saatinin başladığı veya sona erdiği bir tarihteki değişim süresini geçerse, düşünmeniz gereken sonucu alamayabilirsiniz.

şimdi Birleşik Devletler Pasifik Saat diliminde çalışmayan bir kod örneğine bakalım:

Dim d As DateTime
d = DateTime.Parse("Oct 26, 2003 12:00:00 AM") 'date assignment
d = d.AddHours(3.0)
' - displays 10/26/2003 03:00:00 AM – an ERROR!
MsgBox(d.ToString)

Bu hesaplamada görüntülenen sonuç ilk bakışta doğru görünebilir; ancak, 26 Ekim 2003 tarihinde, 01:59 PST'yi bir dakika sonra, yaz saati değişikliği etkili oldu. Doğru yanıt 26.10.2003, 02:00:00 olmalıdır, bu nedenle yerel saat değerine dayalı bu hesaplama doğru sonucu veremedi. Ama kural 3'e bakarsak bir çelişkimiz var gibi görünüyor ama yok. Yaz saati kullanımınızı kutlayan saat dilimlerinde Ekle/Çıkar yöntemlerini kullanmak için özel bir durum diyelim.

En İyi Uygulama #3

Kodlama sırasında, yaz saati uygulaması yapan saat dilimlerini temsil eden değerler üzerinde DateTime hesaplamaları (ekleme/çıkarma) yapmanız gerekiyorsa dikkatli olun. Beklenmeyen hesaplama hataları oluşabilir. Bunun yerine, yerel saat değerini evrensel saate dönüştürün, hesaplamayı yapın ve en yüksek doğruluğu elde etmek için geri dönüştürün.

Bu bozuk kodu düzeltmek basittir:

Dim d As DateTime
d = DateTime.Parse("Oct 26, 2003 12:00:00 AM") 'date assignment
d = d.ToUniversalTime().AddHours(3.0).ToLocalTime()
' - displays 10/26/2003 02:00:00 AM – Correct!
MsgBox(d.ToString)
  

Zaman aralıklarını güvenilir bir şekilde eklemenin en kolay yolu, yerel saat tabanlı değerleri evrensel saate dönüştürmek, hesaplamaları yapmak ve sonra değerleri geri dönüştürmektir.

DateTime Yöntemlerini Sıralama

Bu makale boyunca farklı System.DateTime sınıf yöntemleri ele alınıyor. Bazıları, temel alınan örnek yerel saati temsil ettiğinde, bazıları Evrensel saati temsil ettiğinde ve bazıları hala temel alınan örneğe ihtiyaç duymadığında doğru sonucu verir. Ayrıca bazıları saat dilimine (örneğin, AddYear, AddMonth) tamamen bağımsızdır. En sık karşılaşılan DateTime destek yöntemlerinin ardındaki varsayımların genel olarak anlaşılmasını basitleştirmek için aşağıdaki tablo sağlanır.

Tabloyu okumak için başlangıç (giriş) ve bitiş (döndürülen değer) bakış açısını göz önünde bulundurun. Her durumda, bir yöntemi çağırmanın bitiş durumu yöntemi tarafından döndürülür. Temel alınan veri örneğine dönüştürme yapılmaz. Özel durumları veya yararlı yönergeleri açıklayan uyarılar da sağlanır.

Yöntem Adı Görünüm Noktası Başlatılıyor Bitiş Bakış Noktası Uyarılar
Touniversaltime Yerel Saat UTC Evrensel Saati zaten temsil eden bir DateTime örneğinde arama yapma
Tolocaltime UTC Yerel Saat Yerel saati zaten temsil eden bir DateTime örneğinde arama yapma
Tofiletime Yerel Saat   Yöntem, Win32 dosya süresini (UCT saati) temsil eden bir INT64 döndürür
FromFileTime   Yerel Saat Statik yöntem— örnek gerekmez. Giriş olarak BIR INT64 UCT süresi alır
ToFileTimeUtc

(yalnızca V1.1)

UTC   Yöntem, Win32 dosya süresini (UCT saati) temsil eden bir INT64 döndürür
FromFileTimeUtc

(yalnızca V1.1)

  UTC Yöntem, INT64 Win32 dosya saatini DateTime UCT örneğine dönüştürür
Now   Yerel Saat Statik yöntem— örnek gerekmez. Yerel makine saatinde geçerli saati temsil eden bir DateTime döndürür
UtcNow   UTC Statik yöntem— örnek gerekmez
Isleapyear Yerel Saat   Yerel saat örneğinin yıl bölümünün artık yıl olması durumunda true değerini gösteren Boole değerini döndürür.
Bugün   Yerel Saat Statik yöntem— örnek gerekmez. Yerel makine saatinde geçerli günün Gece yarısı olarak ayarlanmış bir DateTime döndürür.

XML'nin Özel Durumu

Yakın zamanda konuştuğum birkaç kişi, DateTime'ı temsil eden XML'nin GMT'de biçimlendirilmesi (örneğin, sıfır uzaklık ile) gibi zaman değerlerini Web hizmetleri üzerinden seri hale getirmek için tasarım amacına sahipti. İstemcide görüntülenecek bir metin dizesi olarak alanı ayrıştırma isteğinden Web hizmetlerini çağıranlara sunucuda var olan "UCT'de depolanmış" varsayımlarını korumak istemeye kadar çeşitli nedenler duydum, ancak kablodaki sıralama biçimini bu dereceye kadar denetlemenin iyi bir nedeni olduğuna ikna olmadım. Neden? Bir DateTime türü için XML kodlaması bir anlık zaman gösterimi için mükemmel bir şekilde yeterli olduğundan ve .NET Framework yerleşik XML seri hale getirici, zaman değerleriyle ilişkili serileştirme ve seri durumdan çıkarma sorunlarını yönetmek için iyi bir iş yapar.

Ayrıca, System.XML zorladığı ortaya çıktı. Tel üzerinde GMT'de bir tarih değerini kodlamak için seri hale getirme seri hale getirici .NET'te mümkün değildir, en azından bugün değil. Programcı, tasarımcı veya proje yöneticisi olarak işiniz, uygulamanıza geçirilen verilerin en düşük maliyetle doğru bir şekilde gerçekleştirilmesini sağlar.

Bu makaleye giren araştırmada görüştüğüm grupların birkaçı, özel sınıflar tanımlama ve kendi XML serileştiricilerini yazma stratejisini benimsemişti, böylece kablodaki DateTime değerlerinin XML'lerinde nasıl göründüğü üzerinde tam denetime sahiplerdi. Geliştiricilerin bu cesur işe atlarken sahip olduğu cesareti takdir ederken, özellikle .NET Framework sağlanan mekanizmalar zaman değerlerini seri hale getirmek için mükemmel bir şekilde doğru bir iş yaparken, yaz saati saat ve saat dilimi dönüştürme sorunlarıyla ilgilenmenin nüanslarının tek başına iyi bir yöneticiye "Hiçbir şekilde olmaz" demesi gerektiğinden emin olabilirsiniz.

Bilmeniz gereken tek bir püf noktası vardır ve tasarımcı olarak bunu anlamalı ve kurala uymalısınız (bkz. Kural 5).

Çalışmayan kod:

İlk olarak DateTime üye değişkenine sahip basit bir XML sınıfı tanımlayalım. Tamlık için, bu sınıf makalenin devamında gösterilen önerilen yaklaşımın basitleştirilmiş eşdeğeridir.

<XmlType(TypeName:="timeTestDef", _
    Namespace:= "http://tempuri.org/Timetester.xsd")>), _
    XmlRoot(), Serializable()> _
Public Class timeTestDef
    Private __timeVal As DateTime

    <XmlIgnore()> _
    Public timeValSpecified As Boolean

    <XmlElement(ElementName:="timeVal", IsNullable:=False, _
        Form:=XmlSchemaForm.Qualified, DataType:="dateTime", _
        Namespace:="http://tempuri.org/Timetester.xsd")> _
    Public Property timeVal() As DateTime
        Get
            timeVal = __timeVal
        End Get
        Set(ByVal Value As DateTime)
            __timeVal = Value
            timeValSpecified = True
        End Set
    End Property
End Class

Şimdi bu sınıfı kullanarak bir dosyaya xml yazalım.

' write out to the file
Dim t As Xml.XmlTextWriter
Dim ser As XmlSerializer
Dim tt As New timeTest ' a class that has a DateTime variable
' set the fields in your class
tt.timeVal = DateTime.Parse("12/12/2003 12:01:02 PM")
tt.timeVal = tt.TimeVal.ToUniversalTime()

' get a serializer for the root type, and serialize this UTC time
ser = New XmlSerializer(GetType(timeTest))
t = New Xml.XmlTextWriter("c:\timetest.xml", System.Text.Encoding.UTF8)
ser.Serialize(t, tt)
t.Close()
t = Nothing
tt = Nothing

Bu kod çalıştırıldığında, çıkış dosyasına seri hale getirilen XML aşağıdaki gibi bir XML DateTime gösterimi içerir:

<timeVal>2003-12-12T20:01:02.0000000-08:00</timeVal> 

Bu bir hatadır: XML'de kodlanan değer sekiz saat kapalı! Bu, geçerli makinemin saat dilimi uzaklığı olduğundan kuşkulu olmalıyız. XML'nin kendisine baktığımızda tarih doğrudur ve 20:01:02 tarihi, londra'da kendi öğle saatim için saat saatine karşılık gelir, ancak Uzaklık kısmı Londra tabanlı bir saat için doğru değildir. XML Londra saati gibi göründüğünde, uzaklık aynı zamanda bu kodun başarmadığı Londra bakış açısını da temsil etmelidir.

XML seri hale getirici her zaman seri hale getirilen DateTime değerlerinin yerel makine saatini temsil ettiğini varsayar, bu nedenle makine yerel saat dilimi uzaklığını kodlanmış XML saatinin uzaklık kısmı olarak uygular. Bunu başka bir makinede seri durumdan çıkardığımızda, özgün uzaklık ayrıştırılan değerden çıkarılır ve geçerli makinenin saat dilimi uzaklığı eklenir.

Yerel bir saatle başladığımızda, serileştirmenin sonucu (XML DateTime'a kodlama ve ardından yerel makine zamanına kod çözme) her zaman doğrudur; ancak yalnızca seri hale getirilen başlangıç DateTime değeri serileştirmenin başladığı yerel saati temsil eder. Bu bozuk kod örneğinde timeVal üye değişkenindeki DateTime değerini UCT saatine ayarlamıştık, bu nedenle serileştirdiğimizde ve seri durumdan çıkardığımızda sonuç, kaynak makinenin saat dilimi uzaklığıyla eşit saat sayısı kadar kapalı olur. Bu çok kötü.

En İyi Yöntem #4

Test ederken, test edilen noktanın makine yerel saat görünümü kullanılarak seri hale getirilen XML dizesinde görmeyi beklediğiniz değeri hesaplayın. Serileştirme akışındaki XML farklıysa bir hata günlüğe kaydedilsin!

Bu kodu düzeltmek basittir. ToUniversalTime() öğesini çağıran satırı açıklama satırına açıklama satırı ekleyin.

En İyi Uygulama #5

DateTime üye değişkenlerine sahip sınıfları seri hale getirmek için kod yazarken, değerlerin yerel saati temsil etmesi gerekir. Yerel saat içermiyorlarsa, Web hizmetlerinde DateTime değerleri içeren türleri geçirme veya döndürme dahil olmak üzere herhangi bir serileştirme adımından önce bunları ayarlayın.

Sınıf Kodlayıcıları Quandary

Daha önce bir DateTime özelliğini kullanıma veren oldukça özfistik olmayan bir sınıfa baktık. Bu sınıfta, değerin yerel veya evrensel bir saat bakış açısını temsil edip etmediğine bakılmaksızın bir DateTime'da depoladığımız öğeleri seri hale getirmemiz yeterlidir. Programcılara istedikleri saat dilimi varsayımları konusunda aşırı seçenek sunan ve her zaman düzgün bir şekilde seri hale getiren daha gelişmiş bir yaklaşıma göz atalım.

DateTime türünde bir üye değişkenine sahip olacak bir sınıfı kodlarken, programcının üye değişkenini genel yapma veya üye değişkenini get/set işlemleriyle sarmalayacak özellik mantığını yazma seçeneği vardır. Türü genel yapmayı seçmenin, DateTime türleri söz konusu olduğunda sınıf geliştiricisinin denetimi altında olmayan sonuçlar doğurabilecek çeşitli dezavantajları vardır.

Şimdiye kadar öğrendiklerini kullanarak, bunun yerine her DateTime türü için iki özellik sağlamayı göz önünde bulundurun.

Aşağıdaki örnekte DateTime üye değişkenlerini yönetmek için önerilen yaklaşım gösterilmektedir:

<XmlType(TypeName:="timeTestDef", _
    Namespace:= "http://tempuri.org/Timetester.xsd")>), _
    XmlRoot(), Serializable(), _
    EditorBrowsable(EditorBrowsableState.Advanced)> _
Public Class timeTestDef
    Private __timeVal As DateTime

    <XmlIgnore()> _
    Public timeValSpecified As Boolean

    <XmlElement(ElementName:="timeVal", IsNullable:=False, _
        Form:=XmlSchemaForm.Qualified, DataType:="dateTime", _
        Namespace:="http://tempuri.org/Timetester.xsd")> _
    Public Property timeVal() As DateTime
        Get
            timeVal = __timeVal.ToLocalTime()
        End Get
        Set(ByVal Value As DateTime)
            __timeVal = Value.ToUniversalTime()
            timeValSpecified = True
        End Set
    End Property

    <XmlIgnore()> _
    Public Property timeValUTC() As DateTime
        Get
            timeValUTC = __timeVal
        End Get
        Set(ByVal Value As DateTime)
            __timeVal = Value
            timeValSpecified = True
        End Set
    End Property
End Class

Bu örnek, önceki sınıf serileştirme örneğinin düzeltilmiş eşdeğeridir. Her iki sınıf örneğinde de (bu ve önceki) sınıflar aşağıdaki şemayla açıklanan uygulamalardır:

<?xml version="1.0" encoding="utf-8" ?> 
<xs:schema id="Timetester" 
     targetNamespace="http://tempuri.org/Timetester.xsd"
     elementFormDefault="qualified"
     xmlns="http://tempuri.org/Timetester.xsd"
     xmlns:mstns="http://tempuri.org/Timetester.xsd"
     xmlns:xs="http://www.w3.org/2001/XMLSchema">

     <xs:element name="timeTest" type="timeTestDef"/>
     <xs:complexType name="timeTestDef">
      <xs:sequence>
         <xs:element name="timeVal" type="xs:dateTime"/>
      </xs:sequence>
     </xs:complexType>
</xs:schema>

Bu şemada ve tüm sınıf uygulamalarında, isteğe bağlı bir zaman değerini temsil eden bir üye değişkeni tanımlarız. Önerilen örneğimizde, biri evrensel saat, diğeri yerel saat için olmak üzere hem ayırıcılar hem de ayarlayıcılar ile iki özellik sağladık. Kodda gördüğünüz açılı ayraçlı öznitelikler, XML seri hale getiriciye serileştirme için yerel saat sürümünü kullanmasını söyler ve genellikle sınıf uygulamasının sonucunu şemayla uyumlu çıktı haline getirir. Örneğinde değer ayarlanmadığında sınıfın isteğe bağlı ifade eksikliğiyle düzgün şekilde ilgilenmesini sağlamak için, özellik ayarlayıcıdaki timeValSpecified değişkeni ve ilişkili mantık XML öğesinin serileştirme zamanında ifade edilip edilmeyeceğini denetler. Bu isteğe bağlı davranış, serileştirme alt sistemindeki isteğe bağlı XML içeriğini destekleyecek şekilde tasarlanmış bir özellikten yararlanır.

.NET sınıflarınızda DateTime değerlerini yönetmek için bu yaklaşımı kullanmak size her iki dünyanın da en iyisini sağlar; hesaplamaların doğru olması ve yerel saat görünümlerinin düzgün seri hale getirilmesi için evrensel saate göre depolama erişimi elde edersiniz.

En İyi Yöntem #6

Kodlama yaparken DateTime üye değişkenlerini özel hale getirin ve DateTime üyelerinizi yerel veya evrensel saatte işlemek için iki özellik sağlayın. Getter'larınızdaki ve ayarlayıcılarınızdaki mantığı denetleyerek özel üyedeki depolamayı UCT süresi olarak sapma. Yerel saat değerinin seri hale getirildiğinden emin olmak için yerel saat özelliği bildirimine XML serileştirme özniteliklerini ekleyin (örn. örn. ).

Bu yaklaşımla ilgili uyarılar

Özel üye değişkenlerinizde Evrensel saat'te bir DateTime'ı yönetmek için önerilen yaklaşım, kodlayıcıların en rahat oldukları zaman sürümleriyle başa çıkmalarına izin vermek için çift özellikler sağlama önerisi olduğu gibi, oldukça iyi bir yaklaşımdır. Bir geliştiricinin bunu veya herhangi bir yerel saati bir programın kullanımına sunan başka bir yaklaşımı kullanmasına neden olan sorunlardan biri, yaz saatiyle ilgili 25 saatlik sorun olmaya devam ediyor. Bu, CLR sürüm 1.0 ve 1.1 kullanan programlarda sorun olmaya devam eder. Bu nedenle, programınızın bu özel duruma (temsil edilen süre için eklenen veya eksik saat) dahil olup olmadığını bilmeniz ve el ile ayarlamanız gerekir. Yılda bir saatlik sorun penceresine tolerans gösteremeyenler için geçerli öneri, tarihlerinizi dize olarak veya başka bir kendi kendine yönetilen yaklaşım olarak depolamaktır. (Unix uzun tamsayılar iyi bir seçenektir.)

CLR sürüm 2.0 için (Visual Studio® code'un "Whidbey" adlı sonraki sürümünde kullanılabilir), DateTime'ın yerel saat içerip içermediğine veya .NET Framework evrensel saat değerine eklenip eklenmediğine ilişkin farkındalık. Bu noktada önerilen desen çalışmaya devam eder, ancak UTC özellikleri aracılığıyla üye değişkenleriyle etkileşim kuran programlar için eksik/fazladan saat aralığındaki bu hatalar ortadan kaldırılacaktır. Bu nedenle, programlarınızın CLR sürüm 2.0'a sorunsuz bir şekilde geçirilmesi için çift özellikleri kullanarak kodlamaya yönelik en iyi uygulama bugün kesinlikle önerilir.

Yaz Saati Ile ilgilenme

DateTime değerleri için kodlama ve test uygulamaları konusunu kapatıp bırakmaya hazırlanırken, anlamanız gereken bir özel durum daha vardır. Bu olay yaz saatiyle ilgili belirsizlikleri ve yılda tekrarlanan bir saatlik sorunu içerir. Bu sorun öncelikli olarak yalnızca kullanıcı girişinden zaman değerleri toplayan uygulamaları etkileyen bir sorundur.

Ülke sayımı çoğunluğunda yer alanlar için bu basit bir durumdur çünkü çoğu ülkede yaz saati uygulaması yapılmaz. Ancak etkilenen programların çoğunluğunda bulunanlar için (yani, yaz saati uygulaması yapan yerlerde temsil edilebilecek veya kaynak olarak sağlanacak zaman ile ilgilenmesi gereken uygulamalarınız varsa), bu sorunun var olduğunu bilmeniz ve bunun hesabını vermeniz gerekir.

Yaz saati uygulaması yapılan dünya bölgelerinde her sonbahar ve ilkbaharda bir saat vardır. Saat saatinin standart saatten gün ışığı saatine değiştiği gece, saat bir saat ileri atlar. Bu, ilkbaharda gerçekleşir. Yılın sonbaharında, bir gecede, yerel saat saati bir saat geriye atlar.

Bu günlerde, günün 23 veya 25 saat uzunluğunda olduğu koşullarla karşılaşabilirsiniz. Bu nedenle, tarih değerlerinden zaman aralıklarını ekliyor veya çıkarıyorsanız ve aralık, saatlerin değiştiği bu garip noktayı aşıyorsa, kodunuzun el ile ayarlama yapması gerekir.

Belirli bir tarih ve saatin kullanıcı girişine dayalı bir DateTime değerini hesaplamak için DateTime.Parse() yöntemini kullanan mantık için, belirli değerlerin geçerli olmadığını (23 saatlik günde) ve belirli bir saat tekrarlandığından (25 saatlik günde) belirli değerlerin iki anlamı olduğunu algılamanız gerekir. Bunu yapmak için ilgili tarihleri bilmeniz ve bu saatleri aramanız gerekir. Kullanıcı tarihleri girmek için kullanılan alanlardan çıktığı için yorumlanan tarih bilgilerini ayrıştırmak ve yeniden görüntülemek yararlı olabilir. Kural olarak, kullanıcıların girişlerinde gün ışığından yararlanma saati belirtmelerini sağlayın.

Zaman aralığı hesaplamaları için en iyi yöntemi zaten ele aldık. Hesaplamalarınızı gerçekleştirmeden önce yerel saat görünümlerinizi evrensel saate dönüştürerek zaman doğruluğu sorunlarını aşabilirsiniz. Yönetilmesi zor olan durum, ilkbahar ve sonbaharda bu büyülü saatte ortaya çıkan kullanıcı girişini ayrıştırma ile ilişkili belirsizlik durumudur.

Şu anda bir kullanıcının zaman görünümünü temsil eden ve doğru bir evrensel saat değeri atamış olan bir dizeyi ayrıştırma imkanı yoktur. Bunun nedeni, gün ışığından yararlanma saati yaşayan kişilerin saat diliminin Greenwich Saati olduğu yerlerde yaşamamalarındandır. Bu nedenle, Birleşik Devletler doğu kıyısında yaşayan birinin "26 Ekim 2003 01:10:00" gibi bir değere sahip olması tamamen mümkündür.

Bu sabah saat 02:00'de yerel saat 01:00'e sıfırlanır ve 25 saatlik bir gün oluşturulur. 01:00 ile 02:00 arasındaki tüm saat değerleri o sabah iki kez gerçekleştiğinden (en azından ABD ve Kanada'nın çoğunda). Bilgisayarın gerçekten hangi 01:10'un (anahtardan önce gerçekleşen veya yaz saati saat anahtarından 10 dakika sonra gerçekleşen saat) anlamına geldiğini bilmesinin hiçbir yolu yoktur.

Benzer şekilde, programlarınızın ilkbaharda, belirli bir sabah 2:10 gibi bir saat olmadığında gerçekleşen sorunla ilgilenmesi gerekir. Bunun nedeni, o sabah saat 2:00'de yerel saatlerin saati aniden 03:00'e dönüşür. 2:00 saatinin tamamı bu 23 saatlik günde asla gerçekleşmez.

Programlarınızın bu durumlarla ilgilenmesi gerekir; büyük olasılıkla belirsizliği algıladığınızda kullanıcıya sorulur. Kullanıcılardan tarih-saat dizeleri toplamaz ve bunları ayrıştırmıyorsanız, büyük olasılıkla bu sorunlarla karşılaşmazsınız. Belirli bir saatin gün ışığından yararlanma saati içinde olup olmadığını belirlemesi gereken programlar aşağıdakilerden yararlanabilir:

Timezone.CurrentTimeZone.IsDaylightSavingTime(DateTimeInstance)

veya

DateTimeInstance.IsDaylightSavingTime

En İyi Yöntem #7

Test sırasında, programlarınız tarih ve saat değerlerini belirten kullanıcı girişini kabul ederse, "spring-ahead", "fall-back" 23 ve 25 saatlik günlerdeki veri kaybını test ettiğinizden emin olun. Ayrıca bir makinede bir saat diliminde toplanan ve başka bir saat dilimindeki bir makinede depolanan tarihleri test edin.

User-Ready Değerlerini Biçimlendirme ve Ayrıştırma

Kullanıcılardan tarih ve saat bilgisi alan ve bu kullanıcı girişini DateTime değerlerine dönüştürmesi gereken programlar için Framework, belirli şekillerde biçimlendirilmiş dizeleri ayrıştırma desteği sağlar. Genel olarak DateTime.Parse ve ParseExact yöntemleri, tarih ve saat içeren dizeleri DateTime değerlerine dönüştürmek için kullanışlıdır. Buna karşılık , ToString, ToLongDateString, ToLongTimeString, ToShortDateString ve ToShortTimeString yöntemlerinin tümü DateTime değerlerini insan tarafından okunabilir dizeler halinde işlemek için kullanışlıdır.

Ayrıştırma işlemini etkileyen iki ana sorun kültür ve biçim dizesidir. DateTime Sık Sorulan Sorular (SSS), kültürle ilgili temel sorunları kapsar, bu nedenle burada DateTime ayrıştırmasını etkileyen en iyi biçim dizesi yöntemlerine odaklanacağız.

DateTime'ı dizelere dönüştürmek için önerilen biçim dizeleri şunlardır:

'yyyy'-'MM'-'dd'T'HH': 'mm': 'ss.fffffff'Z' —UCT değerleri için

'yyyy'-'MM'-'dd'T'HH': 'mm': 'ss.fffffff'zzz' —Yerel değerler için

'yyyy'-'MM'-'dd'T'HH': 'mm': 'ss.fffffff' —Soyut zaman değerleri için

BUNLAR, XML DateTime türü belirtimi ile uyumlu bir çıktı almak istiyorsanız DateTime.ToString yöntemine geçirilecek biçim dizesi değerleridir. Tırnak işaretleri, makinedeki yerel tarih-saat ayarlarının biçimlendirme seçeneklerinizi geçersiz kılmamalarını sağlar. Farklı düzenler belirtmeniz gerekiyorsa, oldukça esnek bir tarih işleme özelliği için diğer biçim dizelerini geçirebilirsiniz, ancak UCT değerlerinden dizeleri işlemek için yalnızca Z gösterimini kullanmaya ve yerel saat değerleri için zzz gösterimini kullanmaya dikkat etmeniz gerekir.

Dizeleri ayrıştırma ve DateTime değerlerine dönüştürme, DateTime.Parse ve ParseExact yöntemleriyle gerçekleştirilebilir. ParseExact kendi Formatter nesne örneğinizi sağlamanızı gerektirdiğinden çoğumuz için Ayrıştırmak yeterlidir. Ayrıştırma oldukça becerikli ve esnektir ve tarih ve saat içeren dizelerin çoğunu doğru bir şekilde dönüştürebilir.

Son olarak, yalnızca iş parçacığının CultureInfo değeriniCultureInfo.InvariantCulture olarak ayarladıktan sonra her zaman Parse ve ToString yöntemlerini çağırmak önemlidir.

Gelecekte Dikkat Edilmesi Gerekenler

Şu anda DateTime.ToString ile kolayca yapabileceğiniz bir şey, bir DateTime değerini rastgele bir saat dilimine biçimlendirmektir. Bu özellik, .NET Framework gelecekteki uygulamaları için dikkate alınıyor. "12:00:00 EST" dizesinin "11:00:00 EDT" ile eşdeğer olduğunu saptayabilmeniz gerekiyorsa, dönüştürmeyi ve karşılaştırmayı kendiniz işlemeniz gerekir.

DateTime.Now() Yöntemiyle İlgili Sorunlar

Now adlı yöntemle ilgilenirken çeşitli sorunlar vardır. Bunu okuyan Visual Basic geliştiricileri için bu, Visual Basic Now işlevi için de geçerlidir. Now yöntemini düzenli olarak kullanan geliştiriciler, geçerli saati almak için yaygın olarak kullanıldığını bilir. Now yöntemi tarafından döndürülen değer geçerli makine saat dilimi bağlamındadır ve sabit bir değer olarak kabul edilemez. Yaygın bir uygulama, makineler arasında depolanacak veya gönderilecek zamanları Evrensel (UCT) saate dönüştürmektir.

Yaz saati uygulaması mümkün olduğunda, kaçınmanız gereken bir kodlama uygulaması vardır. Algılaması zor bir hataya neden olabilecek aşağıdaki kodu göz önünde bulundurun:

Dim timeval As DateTime
timeval = DateTime.Now().ToUniversalTime()  

Bu kodun çalıştırılmasıyla sonuçlanacak değer, sonbaharda gün ışığından yararlanma saati anahtarı sırasında gerçekleşen fazladan bir saat içinde çağrılırsa bir saat kapalı kalır. (Bu yalnızca gün ışığından yararlanma saati uygulayan saat dilimlerindeki makineler için geçerlidir.) Ek saat, aynı değerin (örneğin, 1:10:00) o sabah iki kez gerçekleştiği yere denk geldiğinden, döndürülen değer istediğiniz değerle eşleşmeyebilir.

Bunu düzeltmek için en iyi yöntem, DateTime.Now çağrısı yapmak ve sonra evrensel saate dönüştürmek yerine DateTime.UtcNow() öğesini çağırmaktır.

Dim timeval As DateTime
timeval = DateTime.UtcNow()  

Bu kod her zaman uygun 24 saatlik perspektife sahip olur ve daha sonra güvenli bir şekilde yerel saate dönüştürülebilir.

En İyi Yöntem #8

Kodlama yaparken ve geçerli saati evrensel saat olarak göstermek istediğinizde, DateTime.Now() öğesini ve ardından evrensel saate dönüştürmeyi çağırmaktan kaçının. Bunun yerine DateTime.UtcNow işlevini doğrudan çağırın.

Uyarı: DateTime değeri içeren bir sınıfı seri hale getirecekseniz, seri hale getirilen değerin Evrensel saati temsil etmediğinden emin olun. XML serileştirme, Visual Studio'nun Whidbey sürümüne kadar UCT serileştirmeyi desteklemez.

Birkaç Az Bilinen Ekstra

Bazen BIR API'nin bir bölümüne dalmaya başladığınızda gizli bir mücevher bulursunuz; bu bir hedefe ulaşmanıza yardımcı olur, ancak size bu konuda bilgi verirseniz, günlük seyahatlerinizde ortaya çıkarmazsınız. .NET'teki DateTime değer türü, evrensel saati daha tutarlı bir şekilde kullanmanıza yardımcı olabilecek bu tür taşlara sahiptir.

Birincisi, System.Globalization ad alanında bulunan DateTimeStyles numaralandırmasıdır. Numaralandırma, kullanıcı tarafından belirtilen girişi ve diğer giriş dizesi gösterimi biçimlerini DateTime değerlerine dönüştürmek için kullanılan DateTime.Parse() ve ParseExact işlevlerinin davranışlarını denetler.

Aşağıdaki tabloda DateTimeStyles sabit listesi tarafından etkinleştirilen bazı özellikler vurgulanır.

Sabit Listesi Sabiti Amaç Uyarılar
AdjustToUniversal Parse veya ParseExact yönteminin bir parçası olarak geçirildiğinde, bu bayrak döndürülen değerin evrensel saat olmasına neden olur. Belgeler belirsizdir, ancak bu hem Parse hem de ParseExact ile çalışır.
NoCurrentDateDefault Tarih bileşeni olmadan ayrıştırılan dizelerin geçerli tarihteki saat olan bir DateTime değerinin döndürüleceği varsayımını gizler. Bu seçenek kullanılırsa, döndürülen DateTime değeri 1. yıldaki Gregoryen 1 Ocak tarihinde belirtilen saattir.
AllowWhiteSpaces

Allowtrailingwhite

Allowleadingwhite

AllowInnerWhite

Bu seçeneklerin tümü ayrıştırılmakta olan tarih dizelerinin önünde, arkasında ve ortasında ek boşluklar için tolerans sağlar. Hiçbiri

Diğer ilginç destek işlevleri System.Timezone sınıfında bulunur. Gün ışığından yararlanma saatinin bir DateTime değerini etkileyip etkilemediğini algılamak veya yerel makine için geçerli saat dilimi uzaklığını programlı olarak belirlemek istiyorsanız bunları gözden geçirin.

Sonuç

.NET Framework DateTime sınıfı, zamanla ilgilenen programlar yazmak için tam özellikli bir arabirim sağlar. Sınıfla ilgilenmenin nüanslarını anlamak, IntelliSense'ten® elde ettiğiniz bilgilerin ötesine geçer. Burada, tarihler ve saatlerle ilgilenen programları kodlama ve test etme için en iyi yöntemleri ele aldık. Kodlamanız kutlu olsun!