UTC / GMT saatini yerel saate dönüştürme


301

Bir web hizmeti istemcisi için bir C # uygulaması geliştiriyoruz. Bu, Windows XP bilgisayarlarda çalışacaktır.

Web hizmeti tarafından döndürülen alanlardan biri bir DateTime alanıdır. Sunucu GMT biçiminde, sonunda "Z" olan bir alan döndürür.

Ancak, .NET'in bir tür örtük dönüşüm yaptığını ve zamanın her zaman 12 saat olduğunu gördük.

Aşağıdaki kod örneği, bunu bir dereceye kadar çözer, çünkü 12 saatlik fark ortadan kalkmıştır, ancak NZ gün ışığından yararlanma için herhangi bir izin vermez.

CultureInfo ci = new CultureInfo("en-NZ");
string date = "Web service date".ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);            

Gereğince bu tarih sitede :

UTC / GMT Uzaklığı

Standart saat dilimi: UTC / GMT +12 saat
Yaz saati uygulaması: +1 saat
Geçerli saat dilimi uzaklığı: UTC / GMT +13 saat

Fazladan bir saat için nasıl ayar yapabiliriz? Bu programlı olarak yapılabilir mi veya bu PC'lerde bir tür ayar mıdır?


2
ZZaman UTC değil GMT ifade eder. İkisi 0,9 saniyeye kadar değişebilir.
mc0e

Yanıtlar:


374

Gibi dizeleri için 2012-09-19 01:27:30.000, DateTime.Parsetarih ve saat alındığı zaman dilimi söyleyemem.

DateTimeüç saat dilimi seçeneğinden birine sahip olabilen bir Tür özelliğine sahiptir :

  • belirtilmemiş
  • Yerel
  • UTC

NOT UTC veya yerel saat diliminiz dışında bir tarih / saati temsil etmek istiyorsanız, bunu kullanmalısınız DateTimeOffset.


Sorunuzdaki kod için:

DateTime convertedDate = DateTime.Parse(dateStr);

var kind = convertedDate.Kind; // will equal DateTimeKind.Unspecified

Ne tür olduğunu bildiğini söylüyorsun, söyle.

DateTime convertedDate = DateTime.SpecifyKind(
    DateTime.Parse(dateStr),
    DateTimeKind.Utc);

var kind = convertedDate.Kind; // will equal DateTimeKind.Utc

Şimdi, sistem UTC saatinde olduğunu öğrendikten sonra şunları arayabilirsiniz ToLocalTime:

DateTime dt = convertedDate.ToLocalTime();

Bu size ihtiyacınız olan sonucu verecektir.


19
bu tür belirtmek için sadece başka bir yol:DateTime convertedTime = new DateTime(DateTime.Parse(dateStr).Ticks), DateTimeKind.Utc);
Brad

ToLocalTime () değil mi? @Brad - ebeveynleriniz uyuşmuyor.
TrueWill

2
Bu çözüm yaz saatinden sorumlu mu? Denediğimde bir saatim yok.
Boynuz

7
Değiştirilmesi aşaması Kindarasında DateTimegelen Unspecifiediçin UTCgereksizdir. Unspecifiedşu UTCamaçlarla kabul edilir ToLocalTime: msdn.microsoft.com/en-us/library/…
CJ7

16
@ CJ7: Evet, ancak açık olmak, kodu korumak zorunda kalabilecek diğer geliştiriciler için özellikle yararlıdır.
Ryan

121

.NET 3.5 iseniz System.TimeZoneInfo sınıfını kullanarak bakmak istiyorum. Bkz. Http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx . Bu, gün ışığından yararlanma değişikliklerini doğru bir şekilde dikkate almalıdır.

// Coordinated Universal Time string from 
// DateTime.Now.ToUniversalTime().ToString("u");
string date = "2009-02-25 16:13:00Z"; 
// Local .NET timeZone.
DateTime localDateTime = DateTime.Parse(date); 
DateTime utcDateTime = localDateTime.ToUniversalTime();

// ID from: 
// "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Time Zone"
// See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.id.aspx
string nzTimeZoneKey = "New Zealand Standard Time";
TimeZoneInfo nzTimeZone = TimeZoneInfo.FindSystemTimeZoneById(nzTimeZoneKey);
DateTime nzDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, nzTimeZone);

Kendi saat diliminizde (bu durumda tr-NZ) çalışıyorsanız, TimeZoneInfo ile uğraşmanız gerekmez. Bu sadece gereksiz karmaşıklık. Daha fazla ayrıntı için cevabıma bakın.
Drew Noakes

11
Ve herhangi birinin ihtiyacı varsa, TimeZoneInfo.FindSystemTimeZoneById için bulduğum zaman dilimlerinin listesi - codeproject.com/Messages/3867850/…
nikib3ro

Parlak! Bu yazı için teşekkürler Dan. Bu düzeltmeyi 3 gündür arıyordum.
Kevin Moore

58
TimeZone.CurrentTimeZone.ToLocalTime(date);

8
Bu yalnızca sistem, dönüştürülmekte olan tarihin UTC olduğunu biliyorsa çalışır. Lütfen cevabımı görün.
Drew Noakes

1
Ama UTC varsayılan değil mi? Bu nedenle CJ7'nin cevabında olduğu gibi "belirtilmemiş" için çalışır.
NickG

25

DateTimenesneler var Kindve Unspecifiedamaçları doğrultusunda varsayılan olarak ToLocalTimeolduğu varsayılır UTC.

Bir Unspecified DateTimenesnenin yerel saatini almak için , bunu yapmanız yeterlidir:

convertedDate.ToLocalTime();

Değiştirilmesi aşaması Kindarasında DateTimegelen Unspecifiediçin UTCgereksizdir. Unspecifiedolarak kabul edilir UTCamaçları için ToLocalTime: http://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime.aspx


6
Ve tam tersi: convertedDate.FromLocalTime();dönüştürür UTC.
R. Schreurs

16

Bunun daha eski bir soru olduğunu biliyorum, ama benzer bir durumla karşılaştım ve muhtemelen kendim de dahil olmak üzere gelecekteki araştırmacılar için bulduğum şeyi paylaşmak istedim :).

DateTime.Parse()zor olabilir - buraya bakın örneğin .

Eğer DateTimebir Web hizmeti veya bilinen biçimiyle başka bir kaynaktan geliyor, gibi bir şey düşünebilirsiniz

DateTime.ParseExact(dateString, 
                   "MM/dd/yyyy HH:mm:ss", 
                   CultureInfo.InvariantCulture, 
                   DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)

veya daha da iyisi,

DateTime.TryParseExact(...)

AssumeUniversalBayrak tarihi / saati zaten UTC olduğunu ayrıştırıcı söyler; kombinasyonu AssumeUniversalve AdjustToUniversalsonucu varsayılan olarak yapmaya çalışacağı sonucu "yerel" zamana dönüştürmemesini söyler. (Ben şahsen sadece iş / uygulama / hizmet katmanlarında UTC ile uğraşmaya çalışıyorum. Ancak yerel saate dönüştürmeyi atlamak da işleri hızlandırıyor - testlerimde% 50 veya daha fazla, aşağıya bakın.)

Daha önce yaptığımız şey:

DateTime.Parse(dateString, new CultureInfo("en-US"))

Uygulamayı geliştirdik ve DateTime.Parse öğesinin CPU kullanımının önemli bir yüzdesini temsil ettiğini bulduk. (Bu arada, CultureInfoyapıcı olarak değil CPU kullanımı ciddi katkılarda.)

Bu yüzden bir tarih / saat dizesini çeşitli şekillerde 10000 kez ayrıştırmak için bir konsol uygulaması kurdum. Sonuç:
Parse()10 sn
ParseExact(), 20-45 ms (yerel dönüştürme)
ParseExact()(yerel dönüşmüyorsa) 10-15 ms
... ve Evet, sonuçları Parse()olan saniye diğerleri bulunmaktadır, oysa milisaniye .


14

Sadece genel bir uyarı notu eklemek istiyorum.

Yaptığınız tek şey, ekrana veya rapora bir tarih / saat koymak için geçerli saati bilgisayarın dahili saatinden alıyorsa, her şey yolunda demektir. Ama eğer tasarruf sonra başvurmak üzere tarih / saat bilgileri veya edilir hesaplama tarih / süreleri, dikkat!

Diyelim ki bir kruvaziyer gemisinin Honolulu'ya 20 Aralık 2007 saat 15:00 UTC de vardığını belirlediniz. Ve yerel saatin ne olduđunu bilmek istiyorsun.
1. Muhtemelen en az üç “yerli” yer almaktadır. Yerel Honolulu anlamına gelebilir veya bilgisayarınızın bulunduğu yer anlamına gelebilir veya müşterinizin bulunduğu yer anlamına gelebilir.
2. Dönüştürmeyi yapmak için yerleşik işlevleri kullanırsanız, büyük olasılıkla yanlış olacaktır. Bunun nedeni, yaz saati uygulamasının (muhtemelen) şu anda bilgisayarınızda geçerli olmasıdır, ancak Aralık ayında geçerli DEĞİLDİR. Ancak Windows bunu bilmiyor ... elindeki tek şey, gün ışığından yararlanma saatinin geçerli olup olmadığını belirlemek için bir bayrak. Ve şu anda yürürlükte ise, Aralık ayında bir tarihe bile bir saat ekleyecektir.
3.Gün ışığından yararlanma saati, çeşitli siyasi alt bölümlerde farklı (veya hiç değil) uygulanır. Ülkenizin belirli bir tarihte değişmesi nedeniyle diğer ülkelerin de değişeceğini düşünmeyin.


6
Aslında # 2 tamamen doğru değil. Bilgisayarınızın bilginin yüklü olup olmadığını (ve güncellendiğini) bildiği her saat diliminde DST ile ilgili kurallar vardır. Birçok bölge için bu kurallar sabittir. Diğerleri "dinamik DST" uygular. Brezilya bunun için benim evcil hayvanım. Özetle, aracınız yerel zamanınızın Aralık ayında DST olup olmayacağını hesaplayabilir ve şu an ile o zaman arasında hiçbir değişikliğin yasaya geçirilmediğini varsayar.
Roger Willcocks

Brezilya'da yaşamasanız bile, DST politikacıların istediği zaman değiştirebilmeleri için "dinamik" dir (birkaç yıl önce ABD'de yapıldığı gibi). Çoğu yazılım gelecekteki kullanım dikkate alınarak yazıldığından, hangi DST kurallarının geçerli olacağını bilmenin pratik, öngörülebilir ve hatta teorik bir yolu olmadığını fark etmek önemlidir. Yaklaşabilirsiniz, ancak mükemmellikten vazgeçerek kendinizi biraz hayal kırıklığına uğratın.
DaveWalley


5

Zaten bir DateTime nesneniz varsa ve UTC veya Yerel olup olmadığından emin değilseniz, nesne üzerindeki yöntemleri doğrudan kullanmak için yeterince kolaydır:

DateTime convertedDate = DateTime.Parse(date);
DateTime localDate = convertedDate.ToLocalTime();

Fazladan bir saat için nasıl ayar yapabiliriz?

Aksi belirtilmedikçe .net yerel pc ayarlarını kullanacaktır. Şunu okuyacağım: http://msdn.microsoft.com/en-us/library/system.globalization.daylighttime.aspx

Görünüşe göre kod şöyle görünebilir:

DaylightTime daylight = TimeZone.CurrentTimeZone.GetDaylightChanges( year );

Yukarıda belirtildiği gibi, sunucunuzun hangi saat dilimi ayarının açık olduğunu iki kez kontrol edin. Ağda IIS'deki değişiklikleri güvenli bir şekilde nasıl etkileyebileceğinizle ilgili makaleler bulunmaktadır.


Sisteme, tarihinizin ne tür olduğunu (yerel / utc / belirtilmemiş) anlatmanız koşuluyla, sistem sizin için bu esnekliği ele alacaktır.
Drew Noakes

2

Dana'nın önerisine cevap olarak:

Kod örneği şimdi şöyle görünüyor:

string date = "Web service date"..ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);            
DateTime dt = TimeZone.CurrentTimeZone.ToLocalTime(convertedDate);

Orijinal tarih 20/08/08 idi; tür UTC'ydi.

Hem "convertedDate" hem de "dt" aynıdır:

21/08/08 10:00:26; tür yereldi


Bunun açıklaması için lütfen cevabıma bakın.
Drew Noakes

1

DataColumn's DateType alanı yerel olarak ayarlandığından, otomatik olarak değişecek tel (istemci webservice) üzerinden itilen bir veri kümesinde olma sorunu vardı. DataSets'i itiyorsanız DateType'ın ne olduğunu kontrol ettiğinizden emin olun.

Değişmesini istemiyorsanız, Belirtilmemiş olarak ayarlayın


1

Ben twitter API (bir durum üzerinde oluşturulan_at alanı) aracılığıyla geri UTC tarihleriyle ilgili bir sorun yaşıyordu gibi bu soru geldi; Onları DateTime'a dönüştürmem gerekiyor. Bu sayfadaki cevaplardaki cevapların / kod örneklerinin hiçbiri, "String geçerli bir DateTime olarak tanınmadı" hatası almamı durdurmak için yeterli değildi (ancak SO'da doğru cevabı bulmam gereken en yakın şey)

Başka birine yardımcı olması durumunda bu bağlantıyı buraya gönderiyorum - ihtiyacım olan cevap bu blog gönderisinde bulundu: http://www.wduffy.co.uk/blog/parsing-dates-when-aspnets-datetimeparse-doesnt-work/ - temel olarak DateTime.Parse yerine bir biçim dizesiyle DateTime.ParseExact kullanın

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.