2009-05-07 87 views
44

[Cập nhật: Định dạng thông số không giống với chuỗi định dạng; một trình định dạng định dạng là một phần của chuỗi định dạng tùy chỉnh, trong đó chuỗi định dạng là 'chứng khoán' và không cung cấp tùy chỉnh. Vấn đề của tôi là với các định danh không phải là định dạng]Trình định dạng định dạng DateTime 'Z' ở đâu?

Tôi đã cố gắng thực hiện các chuyển đổi theo thời gian của DateTime với chuỗi định dạng sử dụng định dạng 'zzz' mà tôi biết là ràng buộc theo giờ địa phương. Vì vậy, nếu tôi cố gắng làm tròn chuyến đi với thời gian ngày UTC, nó sẽ ném ra một ngoại lệ DateTimeInvalidLocalFormat, mà nó nên, với văn bản này:

Một giờ UTC đang được chuyển thành văn bản ở định dạng chỉ đúng cho giờ địa phương . Điều này có thể xảy ra khi gọi DateTime.ToString bằng cách sử dụng định dạng 'z' định dạng, trong đó sẽ bao gồm một múi giờ địa phương bù đắp trong đầu ra. Trong trường hợp đó, hãy sử dụng trình định dạng định dạng 'Z', chỉ định thời gian UTC hoặc sử dụng chuỗi định dạng 'o', đây là cách được khuyến nghị để duy trì DateTime trong văn bản. Điều này cũng có thể xảy ra khi chuyển một DateTime được xê-ri hóa bởi XmlConvert hoặc DataSet. Nếu sử dụng XmlConvert.ToString, vượt qua trong XmlDateTimeSerializationMode.RoundtripKind để tuần tự một cách chính xác. Nếu sử dụng DataSet, hãy đặt DateTimeMode trên đối tượng DataColumn thành DataSetDateTime.Utc.

Dựa trên đề xuất này, tất cả những gì tôi cần làm để mã của tôi hoạt động là thay thế 'zzz' bằng 'ZZZ' để tôi có thể ở định dạng UTC. Vấn đề là, 'Z' không được tìm thấy ở bất kỳ nơi nào trong tài liệu và bất kỳ sự kết hợp định dạng 'Z' nào tôi thử, tức là 'Z', 'ZZ', 'ZZZ', luôn chuyển đổi phiên bản DateTime với những chữ Z được xử lý như chữ .

Có ai đó quên triển khai 'Z' mà không nói cho tác giả thông báo ngoại lệ hay tôi không biết cách hoán đổi khoảng thời gian địa phương hợp lệ bằng "+0000" mà không bị hack?

Mã số Ví dụ:

// This is the format with 'zzzzz' representing local time offset 
const string format = "ddd MMM dd HH:mm:ss zzzzz yyyy"; 

// create a UTC time 
const string expected = "Fri Dec 19 17:24:18 +0000 2008"; 
var time = new DateTime(2008, 12, 19, 17, 24, 18, 0, DateTimeKind.Utc); 

// If you're using a debugger this will rightfully throw an exception 
// with .NET 3.5 SP1 because 'z' is for local time only; however, the exception 
// asks me to use the 'Z' specifier for UTC times, but it doesn't exist, so it 
// just spits out 'Z' as a literal. 
var actual = time.ToString(format, CultureInfo.InvariantCulture); 

Assert.AreEqual(expected, actual); 
+0

lẽ bạn có thể cung cấp cho chúng với một mẫu mã thực tế về những gì bạn đang cố gắng để làm, vì vậy chúng tôi không cần phải dành nhiều thời gian cố gắng đoán nó? –

+0

Tôi vừa cập nhật một mẫu. Tôi đang bối rối vì tôi biết 'Z' không được hỗ trợ theo MSDN, nhưng ngoại lệ yêu cầu tôi sử dụng nó. Và những gì tôi muốn có thể làm là chuyển đổi với chuỗi tùy chỉnh này, ngay cả khi đó là UTC và nhận được "+0000" trong kết quả, như tôi sẽ nhận được "-04: 00" nếu tôi sử dụng 'zzz' với giờ địa phương. –

+0

Tôi thấy bạn đang gặp vấn đề; cảm ơn bạn đã cập nhật mã. Sẽ đi sâu vào nó một lúc và đăng một cái gì đó nếu tôi tìm thấy nó. –

Trả lời

48

Có thể sử dụng một số định dạng "K". Đây là cái duy nhất có vẻ đề cập đến việc sử dụng vốn "Z".

"Z" là loại trường hợp duy nhất cho Ngày giờ. Chữ "Z" theo nghĩa đen thực sự là một phần của tiêu chuẩn thời gian chuẩn ISO 8601 cho thời gian UTC. Khi "Z" (Zulu) được tacked vào cuối một thời gian, nó chỉ ra rằng thời gian đó là UTC, vì vậy thực sự Z chữ là một phần của thời gian. Điều này có thể tạo ra một vài vấn đề cho thư viện định dạng ngày trong .NET, vì nó thực sự là một chữ, chứ không phải là một trình định dạng định dạng.

+2

Sử dụng 'K' trớ trêu thay đầu ra 'Z' trong chuỗi của tôi thay vì "+0000". –

+1

@Dimebrain, chữ "Z" trong chuỗi tương đương trực tiếp với "+0000" theo ISO8601. Nếu bạn cần phải có "+0000" chứ không phải là "Z" thì tôi nghi ngờ bạn sẽ cần phải làm một thay thế trên chuỗi định dạng. – LukeH

+3

@Dimebrain, tôi nghĩ rằng đề cập đến "Z" như là một định dạng specifier trong thông báo ngoại lệ là một sai lầm, "K" gần như chắc chắn là specifier mà bạn cần. – LukeH

2

This page trên MSDN liệt kê tiêu chuẩn định dạng chuỗi DateTime, dây uncluding bằng cách sử dụng 'Z'.

Cập nhật: bạn sẽ cần phải đảm bảo rằng phần còn lại của chuỗi ngày theo mẫu chính xác (bạn chưa cung cấp ví dụ về nội dung bạn gửi, vì vậy thật khó để nói bạn có làm hay không). Đối với định dạng UTC làm việc nó sẽ giống như thế này:

// yyyy'-'MM'-'dd HH':'mm':'ss'Z' 
DateTime utcTime = DateTime.Parse("2009-05-07 08:17:25Z"); 
+0

Có, tôi biết có một chuỗi định dạng 'Z'. Nhưng câu hỏi này là về lý do tại sao ngoại lệ cho thấy một định dạng 'Z' định dạng, đó là một điều hoàn toàn khác nhau. –

+0

Tôi nghĩ bạn có thể trộn chúng lên; chuỗi định dạng cho UTC không phải là 'Z', đó là 'u' (theo thông tin trong liên kết tôi đăng). Vì vậy, nếu bạn muốn một biểu thức DateTime được định dạng như là định dạng UTC chuẩn (như chuỗi định dạng trong mẫu của tôi ở trên), bạn có thể sử dụng. ToString ("u") –

+0

Tôi đang sử dụng một chuỗi * tùy chỉnh * với specifiers không phải là một chuỗi định dạng. –

2
Label1.Text = dt.ToString("dd MMM yyyy | hh:mm | ff | zzz | zz | z"); 

chí đầu ra:

07 Mai 2009 | 08:16 | 13 | +02:00 | +02 | +2 

Tôi ở Đan Mạch, tôi offset từ giờ là 2 giờ, phù thủy là đúng .

nếu bạn cần nhận số BỐI CẢNH KHÁCH HÀNG, tôi khuyên bạn nên kiểm tra little trick mà tôi đã làm. Trang này nằm trong Máy chủ ở Vương quốc Anh, nơi GMT là 00: 00, và bạn có thể thấy bạn sẽ nhận được bù giờ GMT địa phương của mình.


Về bạn nhận xét, tôi đã làm:

DateTime dt1 = DateTime.Now; 
DateTime dt2 = dt1.ToUniversalTime(); 

Label1.Text = dt1.ToString("dd MMM yyyy | hh:mm | ff | zzz | zz | z"); 
Label2.Text = dt2.ToString("dd MMM yyyy | hh:mm | FF | ZZZ | ZZ | Z"); 

và tôi có được điều này:

07 Mai 2009 | 08:24 | 14 | +02:00 | +02 | +2 
07 Mai 2009 | 06:24 | 14 | ZZZ | ZZ | Z 

tôi nhận được không có ngoại lệ, chỉ là ... nó không làm gì với vốn Z :(

Tôi xin lỗi, nhưng tôi có thiếu gì đó không?


Đọc kỹ MSDN trên Custom Date and Time Format Strings

không có sự hỗ trợ cho hoa 'Z'.

+0

Không phải câu hỏi của tôi; Tôi biết 'định dạng' zzz 'làm việc với offsets địa phương. Tôi hỏi về việc thay thế 'zzz' bằng 'ZZZ' như trường hợp ngoại lệ gợi ý, nếu tôi xử lý thời gian UTC. Nếu bạn thay đổi dt thành UTC bằng dt.ToUniversalTime(), sau đó cố gắng định dạng nó với chuỗi của bạn, nó sẽ làm tăng ngoại lệ mà tôi đang nói đến. –

+0

Tôi không chắc chắn lý do tại sao bạn không nhận được ngoại lệ, bạn đã từng bước gỡ rối chưa? Nếu bạn không, bạn sẽ không bắt được nó. Nhưng vâng, đúng là 'Z' không được hỗ trợ, nhưng nếu không thì ngoại lệ sẽ không bảo tôi sử dụng nó. –

3

Ngày cắt vòng thông qua các chuỗi luôn luôn là một nỗi đau ... nhưng các tài liệu để chỉ ra rằng 'o' specifier là một trong những để sử dụng cho vòng vấp mà chụp trạng thái UTC. Khi phân tích cú pháp kết quả thường sẽ có Kind == Utc nếu bản gốc là UTC. Tôi đã tìm thấy rằng điều tốt nhất cần làm là luôn luôn chuẩn hóa ngày thành UTC hoặc địa phương trước khi sắp xếp theo thứ tự rồi hướng dẫn trình phân tích cú pháp mà bạn đã chọn chuẩn hóa.

DateTime now = DateTime.Now; 
DateTime utcNow = now.ToUniversalTime(); 

string nowStr = now.ToString("o"); 
string utcNowStr = utcNow.ToString("o"); 

now = DateTime.Parse(nowStr); 
utcNow = DateTime.Parse(nowStr, null, DateTimeStyles.AdjustToUniversal); 

Debug.Assert(now == utcNow); 
+0

Tôi tốt với điều đó bình thường nhưng tôi không kiểm soát nguồn của DateTime, nó đến với tôi trong một cuộc gọi REST XML, và tôi phải deserialize nó trên mặt của tôi, nhưng cũng có thể trở lại chính xác định dạng được sử dụng, nếu không tôi sẽ gắn bó với thực hành tốt nhất và sử dụng 'o'. Đây là định dạng không chuẩn và mã của tôi hoạt động với giờ địa phương nhưng tôi không thể thực hiện tác vụ này mà không cần hack, tức là format.Replace ("zzzzz", "+0000"); –

5

Khi bạn sử dụng DateTime, bạn có thể lưu trữ ngày và thời gian bên trong biến.

Ngày có thể là giờ địa phương hoặc giờ UTC, tùy thuộc vào bạn.

Ví dụ, tôi đang ở Ý (2 UTC)

var dt1 = new DateTime(2011, 6, 27, 12, 0, 0); // store 2011-06-27 12:00:00 
var dt2 = dt1.ToUniversalTime() // store 2011-06-27 10:00:00 

Vì vậy, những gì xảy ra khi tôi in dt1 và dt1 bao gồm múi giờ?

dt1.ToString("MM/dd/yyyy hh:mm:ss z") 
// Compiler alert... 
// Output: 06/27/2011 12:00:00 +2 

dt2.ToString("MM/dd/yyyy hh:mm:ss z") 
// Compiler alert... 
// Output: 06/27/2011 10:00:00 +2 

dt1 và dt2 chỉ chứa thông tin ngày và giờ. dt1 và dt2 không chứa chênh lệch múi giờ.

Vì vậy, nơi "+2" xuất phát nếu nó không có trong biến dt1 và dt2?

Nó đến từ cài đặt đồng hồ máy của bạn.

Trình biên dịch cho bạn biết rằng khi bạn sử dụng định dạng 'zzz' bạn đang viết chuỗi kết hợp "DATE ​​+ TIME" (được lưu trữ trong dt1 và dt2) + "TIMEZONE OFFSET" (không được chứa trong dt1 và dt2 vì chúng là kiểu DateTyme) và nó sẽ sử dụng độ lệch của máy chủ mà nó thực thi mã.

Trình biên dịch cho bạn biết "Cảnh báo: đầu ra của mã của bạn phụ thuộc vào đồng hồ máy bù đắp"

Nếu tôi chạy mã này trên một máy chủ được đặt tại London (+1 UTC) kết quả sẽ là hoàn toàn khác nhau: thay vì "" nó sẽ viết ""

... 
dt1.ToString("MM/dd/yyyy hh:mm:ss z") 
// Output: 06/27/2011 12:00:00 +1 

dt2.ToString("MM/dd/yyyy hh:mm:ss z") 
// Output: 06/27/2011 10:00:00 +1 

các giải pháp đúng là sử dụng kiểu dữ liệu DateTimeOffset ở vị trí của DateTime. Có sẵn trong sql Server bắt đầu từ phiên bản 2008 và trong khung .Net bắt đầu từ phiên bản 3.5

0

Tôi đã giao dịch với DateTimeOffset và tiếc là "o" in ra "+0000" chứ không phải "Z".

Vì vậy, tôi đã kết thúc với:

dateTimeOffset.UtcDateTime.ToString("o") 
Các vấn đề liên quan