C # में एक विशिष्ट टाइम ज़ोन में एक डेटटाइम बनाना


162

जब मशीन में टाइमजोन बदलता है तो इसे गलत तरीके से सेट किया गया है और फिर ठीक किया गया है, तो इस मामले की जांच के लिए एक यूनिट टेस्ट बनाने की कोशिश कर रहा हूं।

परीक्षण में, मुझे यह सुनिश्चित करने में सक्षम होना चाहिए कि कोई भी स्थानीय समय क्षेत्र में डेटटाइम ऑब्जेक्ट्स नहीं बना सकता है ताकि यह सुनिश्चित हो सके कि परीक्षण चलाने वाले लोग जहां स्थित हैं, वहां सफलतापूर्वक ऐसा कर सकते हैं।

डेटाइम कंस्ट्रक्टर से जो मैं देख सकता हूं, उसमें से मैं टाइमजोन सेट कर सकता हूं या तो स्थानीय टाइमज़ोन, यूटीसी टाइमज़ोन या निर्दिष्ट नहीं।

मैं पीएसटी जैसे विशिष्ट टाइमज़ोन के साथ डेटटाइम कैसे बना सकता हूं?


संबंधित प्रश्न - stackoverflow.com/questions/2532729/…
Oded

जवाबों:


216

जॉन का जवाब TimeZone के बारे में बात करता है , लेकिन मैं इसके बजाय TimeZoneInfo का उपयोग करने का सुझाव दूंगा

व्यक्तिगत रूप से मुझे यूटीसी में चीजों को रखना पसंद है जहां संभव हो (कम से कम अतीत के लिए; भविष्य के लिए यूटीसी को संचयित करने के लिए संभावित मुद्दे हैं ), इसलिए मैं इस तरह की संरचना का सुझाव दूंगा:

public struct DateTimeWithZone
{
    private readonly DateTime utcDateTime;
    private readonly TimeZoneInfo timeZone;

    public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone)
    {
        var dateTimeUnspec = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified);
        utcDateTime = TimeZoneInfo.ConvertTimeToUtc(dateTimeUnspec, timeZone); 
        this.timeZone = timeZone;
    }

    public DateTime UniversalTime { get { return utcDateTime; } }

    public TimeZoneInfo TimeZone { get { return timeZone; } }

    public DateTime LocalTime
    { 
        get 
        { 
            return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); 
        }
    }        
}

आप चीजों को स्पष्ट करने के लिए "टाइमजोन" नामों को "टाइमजोनइन्फो" में बदलना चाह सकते हैं - मैं खुद ब्रीफ़र नामों को पसंद करता हूं।


5
मैं किसी भी समकक्ष SQL सर्वर निर्माण का नहीं जानता, मुझे डर है। मैं एक स्तंभ के रूप में समय क्षेत्र का नाम, और दूसरे स्तंभ में UTC मान होने का सुझाव दूंगा। उन्हें अलग से लाएं और फिर आप काफी आसानी से उदाहरण बना सकते हैं।
जॉन स्कीट

2
उस निर्माता के अपेक्षित उपयोग के बारे में निश्चित नहीं है जो एक DateTime और TimeZoneInfo को लेता है, लेकिन यह देखते हुए कि आप dateTime.ToUniversalTime () विधि को कॉल कर रहे हैं, मुझे संदेह है कि आप इसे "शायद" स्थानीय समय में होने का अनुमान लगा रहे हैं। उस स्थिति में, मुझे लगता है कि आपको वास्तव में पास किए गए TimeZoneInfo का उपयोग करके इसे UTC में बदलना चाहिए क्योंकि वे आपको बता रहे हैं कि यह उस समयक्षेत्र में होना चाहिए।
आईडीसोपोर्टर

2
@ChrisMoschini: उस समय आप केवल अपनी आईडी योजना का आविष्कार कर रहे हैं - एक ऐसी योजना जो दुनिया में कोई और नहीं उपयोग करता है। मैं उद्योग-मानक जोनइनफो के साथ रहूँगा, धन्यवाद। (यह देखना मुश्किल है कि "यूरोप / लंदन" कैसे व्यर्थ है, उदाहरण के लिए।)
जॉन स्कीट

2
@ क्रिसमोसची: अलग उदाहरण तब: सीएसटी। क्या वह UTC-5 या UTC-6 है? कैसे के बारे में IST - कि इजरायल, भारत या आयरलैंड आपके डेटाबेस में है? (और यदि आप अभी ऑफसेट जानते हैं, तो अलग-अलग देश एक ही संक्षिप्त नाम का अवलोकन अलग-अलग समय पर बदल सकते हैं। इसलिए अभी भी अस्पष्टता है कि इसके बारे में वास्तविक समय क्षेत्र का क्या अर्थ है। समय क्षेत्र! = ऑफसेट।) आपके मामले में वापस जा रहे हैं: आप दावा करते हैं। संक्षेप का उपयोग करने से आपकी समस्या हल हो गई। उद्योग मानक समय क्षेत्र आईडी का उपयोग करना कैसे बदतर होगा?
जॉन स्कीट

6
@ChrisMoschini: वैसे मैं उद्योग-मानक, असंदिग्ध क्षेत्र के आईडी का उपयोग करने की अनुशंसा करना जारी रखूंगा, बजाय अस्पष्ट संक्षिप्तता के। यह कोई बात नहीं है कि किसकी लाइब्रेरी को प्राथमिकता दी जाती है - लाइब्रेरी की लेखकता वास्तव में कोई समस्या नहीं है। यदि कोई पहचानकर्ता के अच्छे विकल्प के साथ किसी अन्य पुस्तकालय का उपयोग करना चाहता है , तो यह ठीक है। एक समय क्षेत्र के लिए पहचानकर्ता के चुनाव में हालांकि एक महत्वपूर्ण एक है, और मुझे लगता है कि यह बहुत महत्वपूर्ण है कि पाठकों को पता है कि लघु रूपों हैं कर रहे हैं , अस्पष्ट रूप में मैं IST उदाहरण के साथ दिखाया गया है।
जॉन स्कीट

54

इस प्रकार के उपयोग के लिए DateTimeOffset संरचना बनाई गई थी।

देखें: http://msdn.microsoft.com/en-us/library/system.datetimeoffset.aspx

यहाँ एक विशिष्ट समय क्षेत्र के साथ DateTimeOffset ऑब्जेक्ट बनाने का एक उदाहरण है:

DateTimeOffset do1 = new DateTimeOffset(2008, 8, 22, 1, 0, 0, new TimeSpan(-5, 0, 0));


1
धन्यवाद, इसे पूरा करने का यह एक अच्छा तरीका है। सही समय-सीमा के भीतर अपनी DateTimeOffset ऑब्जेक्ट प्राप्त करने के बाद, आप अपने द्वारा बनाए गए के लिए UTC समय प्राप्त करने के लिए .UtDateTime प्रॉपर्टी का उपयोग कर सकते हैं। यदि आप UTC में अपनी तिथियां संग्रहीत करते हैं, तो उन्हें प्रत्येक उपयोगकर्ता के लिए स्थानीय समय में परिवर्तित करना कोई बड़ी बात नहीं है :)
Redth

2
मुझे नहीं लगता कि यह डेलाइट सेविंग टाइम को सही ढंग से हैंडल करता है क्योंकि कुछ TimeZones इसे सम्मानित करते हैं जबकि अन्य नहीं करते हैं। इसके अलावा "जिस दिन डीएसटी शुरू / समाप्त होता है, उस दिन के हिस्से बंद हो जाएंगे।
क्रोकसेक

14
सबक। DST एक विशेष समय क्षेत्र का एक नियम है। DateTimeOffset किसी भी समय क्षेत्र से संबद्ध नहीं है। UTC ऑफ़सेट मान को भ्रमित न करें, जैसे -5, टाइम ज़ोन के साथ। यह एक समय क्षेत्र नहीं है, यह एक ऑफसेट है। एक ही ऑफसेट को अक्सर कई समय क्षेत्रों द्वारा साझा किया जाता है, इसलिए यह समय क्षेत्र का संदर्भ देने का एक अस्पष्ट तरीका है। चूंकि DateTimeOffset एक ऑफसेट के साथ जुड़ा हुआ है, टाइमज़ोन नहीं, यह संभवतः DST नियम लागू नहीं कर सकता है। तो 3am साल के हर एक दिन पर 3am होगा, बिना DateTimeOffset संरचना के (जैसे कि इसमें घंटे और TimeOfDay गुण हैं)।
२३:२६ पर त्रिकोको

यदि आप भ्रमित हो सकते हैं यदि आप DateTimeOffset की LocalDateTime संपत्ति को देखें। वह संपत्ति नहीं है एक DateTimeOffset, यह एक DateTime उदाहरण है जिसका प्रकार DateTimeKind.Local है। यह उदाहरण आईएस एक समय क्षेत्र से जुड़ा है ... स्थानीय प्रणाली टाइमजोन जो भी हो। वह संपत्ति दिन की बचत को दर्शाएगी।
त्रिनको

4
तो, DateTimeOffset के साथ असली समस्या यह है कि इसमें पर्याप्त जानकारी शामिल नहीं है। इसमें एक समय क्षेत्र नहीं, एक ऑफसेट शामिल है। ऑफसेट कई समय क्षेत्रों के साथ अस्पष्ट है।
22

41

यहां अन्य उत्तर उपयोगी हैं, लेकिन वे विशेष रूप से प्रशांत तक पहुंचने के तरीके को कवर नहीं करते हैं - यहां आप जाते हैं:

public static DateTime GmtToPacific(DateTime dateTime)
{
    return TimeZoneInfo.ConvertTimeFromUtc(dateTime,
        TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
}

विचित्र रूप से पर्याप्त है, हालांकि "प्रशांत मानक समय" का सामान्य अर्थ "प्रशांत डेलाइट टाइम" से कुछ अलग है, इस मामले में यह सामान्य रूप से प्रशांत समय को संदर्भित करता है। वास्तव में, यदि आप FindSystemTimeZoneByIdइसे लाने के लिए उपयोग करते हैं, तो उपलब्ध गुणों में से एक एक बूल है जो आपको बता रहा है कि यह समय-क्षेत्र वर्तमान में दिन की बचत में है या नहीं।

आप लाइब्रेरी में इसके सामान्यीकृत उदाहरण देख सकते हैं जिन्हें मैंने डेटजाइम से निपटने के लिए एक साथ फेंक दिया था जिनकी मुझे उपयोगकर्ता से पूछ रहा है, आदि के आधार पर अलग-अलग टाइमज़ोन में आवश्यकता है:

https://github.com/b9chris/TimeZoneInfoLib.Net

यह विंडोज के बाहर काम नहीं करेगा (उदाहरण के लिए लिनक्स पर मोनो) क्योंकि विंडोज रजिस्ट्री से समय की सूची आती है: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\

नीचे आपको कुंजियाँ मिलेंगी (रजिस्ट्री संपादक में फ़ोल्डर आइकन); उन कुंजियों के नाम हैं जिन्हें आप पास करते हैं FindSystemTimeZoneById। लिनक्स पर आपको टाइमज़ोन परिभाषाओं के एक अलग लिनक्स-मानक सेट का उपयोग करना होगा, जिसे मैंने पर्याप्त रूप से नहीं खोजा है।


1
TimeZoneInfo.ConvertTimeBySystemTimeZoneId (DateTime.UtcNow, "केंद्रीय मानक समय"): इसके अतिरिक्त है ConvertTimeBySystemTimeZoneId () पूर्व
ब्रेंट

विंडोज़ टाइमज़ोन आईडी लिस्ट में भी इस उत्तर को देख सकते हैं: stackoverflow.com/a/24460750/4573839
यू यांग जियान

7

मैंने विस्तार के साथ वेब के लिए जॉन स्कीट के उत्तर को थोड़ा बदल दिया । यह भी आकर्षण की तरह azure पर काम करता है।

public static class DateTimeWithZone
{

private static readonly TimeZoneInfo timeZone;

static DateTimeWithZone()
{
//I added web.config <add key="CurrentTimeZoneId" value="Central Europe Standard Time" />
//You can add value directly into function.
    timeZone = TimeZoneInfo.FindSystemTimeZoneById(ConfigurationManager.AppSettings["CurrentTimeZoneId"]);
}


public static DateTime LocalTime(this DateTime t)
{
     return TimeZoneInfo.ConvertTime(t, timeZone);   
}
}

2

आपको उसके लिए एक कस्टम ऑब्जेक्ट बनाना होगा। आपकी कस्टम ऑब्जेक्ट में दो मान होंगे:

यकीन नहीं है कि अगर पहले से ही एक सीएलआर प्रदान किया गया डेटा प्रकार है जो कि है, लेकिन कम से कम टाइमजोन घटक पहले से ही उपलब्ध है।


2

मुझे जॉन स्कीट का जवाब पसंद है, लेकिन मैं एक बात जोड़ना चाहूंगा। मुझे यकीन नहीं है कि जॉन उम्मीद कर रहे थे कि हमेशा स्थानीय समयक्षेत्र में ctor पास किया जाएगा। लेकिन मैं इसे उन मामलों के लिए उपयोग करना चाहता हूं जहां यह कुछ और है फिर स्थानीय।

मैं एक डेटाबेस से मान पढ़ रहा हूं, और मुझे पता है कि डेटाबेस किस टाइमज़ोन में है। इसलिए ctor में, मैं डेटाबेस के टाइमज़ोन में पास करूँगा। लेकिन फिर मैं स्थानीय समय में मूल्य चाहूंगा। जॉन की लोकल टाइमिंग स्थानीय समय-सीमा तिथि में परिवर्तित मूल तारीख को वापस नहीं करती है। यह मूल समयक्षेत्र (जो भी आप ctor में उत्तीर्ण हुए थे) में परिवर्तित तारीख को वापस कर देता है।

मुझे लगता है कि ये संपत्ति के नाम इसे स्पष्ट करते हैं ...

public DateTime TimeInOriginalZone { get { return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); } }
public DateTime TimeInLocalZone    { get { return TimeZoneInfo.ConvertTime(utcDateTime, TimeZoneInfo.Local); } }
public DateTime TimeInSpecificZone(TimeZoneInfo tz)
{
    return TimeZoneInfo.ConvertTime(utcDateTime, tz);
}

0

TimeZones क्लास का उपयोग करने से टाइमज़ोन की विशिष्ट तारीख बनाना आसान हो जाता है।

TimeZoneInfo.ConvertTime(DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById(TimeZones.Paris.Id));

1
क्षमा करें, लेकिन यह Asp .NET Core 2.2 पर उपलब्ध नहीं है, VS2017 मुझे आउटलुक नुगेट पैकेज स्थापित करने का सुझाव दे रहा है।
मचाडो

उदाहरण => TimeZoneInfo.ConvertTime (DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById ("प्रशांत मानक समय")
AZ_
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.