2013-03-08 89 views
42

TimeZoneInfo không cung cấp tên viết tắt hoặc tên viết tắt của một Múi giờ cụ thể. Cách tốt nhất để làm điều đó là có một từ điển sẽ ánh xạ các từ viết tắt cho các thuộc tính Timezone.id, StandardName hoặc DaylightName. Tuy nhiên, tất cả các nguồn tôi đã tìm kiếm trong danh sách các từ viết tắt có các tên múi giờ khác nhau, tức là không giống như trong Windows.Viết tắt múi giờ

Làm cách nào để bạn hiển thị người dùng không phải là tên đầy đủ, id hoặc bất kỳ tên nào khác trong .NET? Tôi không muốn các UtcOffset nhưng Timezone viết tắt - PST cho Thái Bình Dương, UTC - cho Universal, EST - cho Eastern Standard và vv Có bất kỳ danh sách tương thích C# hoặc cơ sở dữ liệu với tất cả các múi giờ có thể và chữ viết tắt của họ tương thích với những người mà TimeZoneInfo.GetSystemTimeZones() cho bạn?

+4

Như bạn đã nói - vấn đề với tên múi giờ viết tắt là chúng có nhiều ý nghĩa. Chúng tốt nhất nên tránh trong một ứng dụng quốc tế. [EST] (http://en.wikipedia.org/wiki/EST) có ít nhất 5 ý nghĩa múi giờ khác nhau, chẳng hạn. – Oded

+0

bạn luôn có thể viết tắt và bù đắp. Nhưng hầu hết thời gian chỉ cho thấy sự bù đắp đơn giản là không đủ. – Agzam

Trả lời

12

Đây là một yêu cầu phức tạp, tốt nhất bạn có thể làm là lấy danh sách lựa chọn của mình và tạo phương pháp mở rộng/trợ giúp để viết tắt cho TimeZoneInfo đã cho.

Khi địa điểm bắt đầu là http://www.timeanddate.com/library/abbreviations/timezones/ có phiên bản danh sách bao gồm các khu vực mà tôi biết.

Vấn đề sẽ là chọn một từ viết tắt thích hợp có nhiều hơn một từ khóa tồn tại trong một múi giờ nhất định. Ví dụ UTC có thể được biểu diễn dưới dạng UTC hoặc WET (Tây Âu Time) hoặc WEZ (Westeuropäische Zeit) hoặc WT (Tây Sahara Giờ chuẩn).

Bạn có thể muốn đồng ý với các bên liên quan của mình về quy ước đặt tên bạn sẽ tuân theo các lựa chọn đã cho.

+1

nhưng chưa có giải pháp "đã nấu" - từ điển hoặc tệp ánh xạ ID múi giờ của hệ thống thành chữ viết tắt? Tôi đã thử kéo dữ liệu từ trang web mà bạn đang trỏ quá, nhưng nó cho tôi nhiều nhất là 14 giá trị có thể. Phải có nhiều hơn thế ... – Agzam

+0

Tôi vừa đưa ra một ví dụ, bạn có thể nhận được các danh sách mở rộng trên mạng cũ: http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations. Nhưng vấn đề là biết tập hợp các từ viết tắt bạn muốn sử dụng. –

50

CẬP NHẬT ĐÁP

phản ứng ban đầu của tôi là dưới đây, và vẫn còn hiệu lực. Tuy nhiên, hiện có một cách dễ dàng hơn, sử dụng the TimeZoneNames library. Sau khi cài đặt from Nuget, bạn có thể làm như sau:

string tzid = theTimeZoneInfo.Id;    // example: "Eastern Standard time" 
string lang = CultureInfo.CurrentCulture.Name; // example: "en-US" 
var abbreviations = TZNames.GetAbbreviationsForTimeZone(tzid, lang); 

Đối tượng kết quả sẽ có các tính chất tương tự như:

abbreviations.Generic == "ET" 
abbreviations.Standard == "EST" 
abbreviations.Daylight == "EDT" 

Bạn cũng có thể sử dụng thư viện này cùng để có được những tên cục bộ hoàn toàn thời gian vùng. Thư viện sử dụng một bản sao tự nhúng của dữ liệu CLDR.

ĐÁP ORIGINAL

Như những người khác đã đề cập, Time khu viết tắt là mơ hồ. Nhưng nếu bạn thực sự muốn một màn hình hiển thị, bạn cần một cơ sở dữ liệu múi giờ IANA/Olson.

Bạn có thể chuyển từ múi giờ Windows sang múi giờ IANA/Olson và hướng khác. Nhưng lưu ý rằng có thể có nhiều vùng IANA/Olson cho bất kỳ vùng Windows cụ thể nào. Các ánh xạ này được duy trì trong CLDR here.

NodaTime có cả cơ sở dữ liệu lẫn ánh xạ. Bạn có thể đi từ một .Net DateTime hoặc DateTimeOffset với số TimeZoneInfo, đến số NodaTime InstantDateTimeZone. Từ đó, bạn có thể lấy tên viết tắt.

// starting with a .Net TimeZoneInfo 
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"); 

// You need to resolve to a specific instant in time - a noda Instant 
// For illustrative purposes, I'll start from a regular .Net UTC DateTime 
var dateTime = DateTime.UtcNow; 
var instant = Instant.FromDateTimeUtc(dateTime); 

// note that if we really wanted to just get the current instant, 
// it's better and easier to use the following: 
// var instant = SystemClock.Instance.Now; 


// Now let's map the Windows time zone to an IANA/Olson time zone, 
// using the CLDR mappings embedded in NodaTime. This will use 
// the *primary* mapping from the CLDR - that is, the ones marked 
// as "territory 001". 

// we need the NodaTime tzdb source. In NodaTime 1.1.0+: 
var tzdbSource = TzdbDateTimeZoneSource.Default; 

// in previous NodaTime releases: 
// var tzdbSource = new TzdbDateTimeZoneSource("NodaTime.TimeZones.Tzdb"); 

// map to the appropriate IANA/Olson tzid 
var tzid = tzdbSource.MapTimeZoneId(timeZoneInfo); 

// get a DateTimeZone from that id 
var dateTimeZone = DateTimeZoneProviders.Tzdb[tzid]; 


// Finally, let's figure out what the abbreviation is 
// for the instant and zone we have. 

// now get a ZoneInterval for the zone and the instant 
var zoneInterval = dateTimeZone.GetZoneInterval(instant); 

// finally, you can get the correct time zone abbreviation 
var abbreviation = zoneInterval.Name; 

// abbreviation will be either PST or PDT depending 
// on what instant was provided 
Debug.WriteLine(abbreviation); 
+1

Để tham khảo, bạn cần phải gắn thêm một TimeZoneNames với phiên bản thư viện hiện tại.'var abbrZoneName = TimeZoneNames.TimeZoneNames.GetAbbreviationsForTimeZone (zoneName, lang);' –

+0

Vâng, có lẽ tôi nên đặt tên miền và tên lớp khác nhau. Quá muộn rồi, nhưng tốt thôi. :) –

+0

@KurtWagner - Chỉ cần thêm một loạt nội dung cho 2.0.0 và quyết định thực hiện thay đổi đột phá để khắc phục sự cố đặt tên. Lớp này được đổi tên thành 'TZNames', vì vậy nó không xung đột với không gian tên. –

2

Dưới đây là một đoạn mã sử dụng NodaTime:

NodaTime.ZonedDateTime hereAndNow = NodaTime.SystemClock.Instance.Now.InZone(
    NodaTime.DateTimeZoneProviders.Tzdb.GetSystemDefault()); 

System.TimeSpan zoneOffset = hereAndNow.ToDateTimeOffset().Offset; 

string sTimeDisplay = string.Format("{0:G} {1} (UTC{2}{3:hh\\:mm} {4})", 
    hereAndNow.ToDateTimeOffset(), 
    hereAndNow.Zone.GetZoneInterval(hereAndNow.ToInstant()).Name, 
    zoneOffset < TimeSpan.Zero ? "-" : "+", 
    zoneOffset, 
    hereAndNow.Zone.Id); 

Trên hệ thống của tôi sản lượng này: "2013/04/11 17:03:23 CDT (UTC-05: 00 Châu Mỹ/Chicago)"

(Nhờ câu trả lời Matt Johnson cho đầu mối rằng chữ viết tắt sống ở TimeZoneInterval)

sẽ dễ dàng hơn nếu NodaTime.ZonedDateTime đã có một phương pháp GetZoneInterval, nhưng có lẽ tôi là thiếu someth ing.

10

Câu hỏi của bạn không cho biết múi giờ nào ứng dụng của bạn phải hoạt động bên trong, nhưng trong trường hợp cụ thể của tôi, tôi chỉ cần phải quan tâm đến múi giờ và UTC của Hoa Kỳ.

Chữ viết tắt của múi giờ ở Hoa Kỳ luôn là ký tự đầu tiên của mỗi từ trong tên múi giờ. Ví dụ: từ viết tắt của "Giờ chuẩn miền núi" là "MST" và viết tắt của "Giờ ban ngày miền đông" là "EDT".

Nếu bạn có yêu cầu tương tự, bạn có thể dễ dàng lấy từ viết tắt múi giờ của múi giờ địa phương trực tiếp từ tên múi giờ địa phương, như sau (lưu ý: ở đây tôi xác định tên thích hợp dựa trên ngày hiện tại và thời gian):

string timeZoneName = TimeZone.CurrentTimeZone.IsDaylightSavingTime(DateTime.Now) 
          ? TimeZone.CurrentTimeZone.DaylightName 
          : TimeZone.CurrentTimeZone.StandardName; 

string timeZoneAbbrev = GetTzAbbreviation(timeZoneName); 

Mã cho chức năng GetTzInitials() khá đơn giản. Một điều đáng nói đến là một số múi giờ có thể được đặt thành Mexico hoặc Canada và các tên múi giờ cho những tên này sẽ đi qua với tên quốc gia trong dấu ngoặc đơn, chẳng hạn như "Giờ chuẩn Thái Bình Dương (Mexico)". Để đối phó với điều này, bất kỳ dữ liệu được lồng dấu nào đều được truyền trực tiếp trở lại. Chữ viết tắt được trả lại cho phần trên sẽ là "PST (Mexico)", có tác dụng đối với tôi.

string GetTzAbbreviation(string timeZoneName) { 
    string output = string.Empty; 

    string[] timeZoneWords = timeZoneName.Split(' '); 
    foreach (string timeZoneWord in timeZoneWords) { 
     if (timeZoneWord[0] != '(') { 
      output += timeZoneWord[0]; 
     } else { 
      output += timeZoneWord; 
     } 
    } 
    return output; 
} 
+0

Có hợp lệ cho 135 múi giờ tôi nhận được trong Windows không? – Kiquenet

+0

@Kiquenetu Tôi không biết. Như đã nêu trong câu trả lời, nó hoạt động cho các múi giờ của Hoa Kỳ và UTC. – STLDeveloper

0

Tôi gặp vấn đề tương tự nhưng không muốn sử dụng thư viện của bên thứ ba (như hầu hết các câu trả lời được đề xuất). Nếu bạn chỉ muốn hỗ trợ tên miền múi giờ của Net và quyết định sử dụng bảng tra cứu, hãy xem my answer over here, dựa trên PHP để giúp tạo danh sách các từ viết tắt. Bạn có thể điều chỉnh đoạn mã ở đó và bảng để phù hợp với nhu cầu của bạn.

+0

Vui lòng không đăng liên kết tới [câu trả lời trùng lặp] (// meta.stackexchange.com/a/211726/206345). Thay vào đó, hãy xem xét các hành động khác có thể giúp người dùng trong tương lai tìm thấy câu trả lời họ cần, như được mô tả trong bài đăng được liên kết. Ngoài ra, tạo ra một câu trả lời khép kín phù hợp với vấn đề cụ thể. – Mogsdad

+0

@Mogsdad Tôi không hiểu vấn đề. Đó là bài meta địa chỉ sao chép/dán câu trả lời trên nhiều câu hỏi. Tôi đã điều chỉnh câu trả lời cho câu hỏi này, nhưng vì câu hỏi được liên kết giải quyết các yêu cầu hơi khác nhau, tôi đã tham chiếu nó ở đây trong trường hợp nó có thể giúp người đọc trong tương lai. Tôi đặc biệt chỉ ra trong câu trả lời của tôi rằng nó khác với những người khác bởi vì nó không sử dụng thư viện của bên thứ ba. – QuickDanger

0

Điều này hữu ích cho bất kỳ ai sử dụng Xamarin cho iOS hoặc Android vì theo tài liệu "Tên hiển thị được bản địa hóa dựa trên nền văn hóa được cài đặt với hệ điều hành Windows." Khi sử dụng điều này trong múi giờ trung tâm, cho DateTime "2016-09-01 12:00:00 GMT", hàm này trả về "CDT", đó chính xác là những gì tôi cần khi tôi đưa ra câu hỏi này.

public static string GetTimeZoneAbbreviation(DateTime time) 
{ 
    string timeZoneAbbr; 
    if(time.IsDaylightSavingTime() == true) 
    { 
     timeZoneAbbr = TimeZoneInfo.Local.DaylightName; 
    } 
    else 
    { 
     timeZoneAbbr = TimeZoneInfo.Local.StandardName; 
    } 

    return timeZoneAbbr; 
} 
Các vấn đề liên quan