Làm cách nào để sử dụng TimeZoneInfo để lấy giờ địa phương trong Giờ tiết kiệm ánh sáng ban ngày?


84

Tôi đang cố gắng sử dụng DateTimeOffsetđể truyền tải một thời điểm cụ thể trong bất kỳ múi giờ nào. Tôi không thể tìm ra cách sử dụng TimeZoneInfođể đối phó với thời gian tiết kiệm ánh sáng ban ngày.

var dt = DateTime.UtcNow;
Console.WriteLine(dt.ToLocalTime());

var tz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var utcOffset = new DateTimeOffset(dt, TimeSpan.Zero);
Console.WriteLine(utcOffset.ToOffset(tz.BaseUtcOffset));

Điều này in ra:

6/2/2010 4:37:19 CH
6/2/2010 3:37:19 PM -06: 00

Tôi đang ở múi giờ trung tâm và chúng tôi hiện đang sử dụng thời gian tiết kiệm ánh sáng ban ngày. Tôi đang cố đọc dòng thứ hai:

6/2/2010 4:37:19 PM -05: 00

BaseUtcOffset dường như không thay đổi dựa trên DST.

Làm thế nào tôi có thể nhận được đúng thời điểm với giá trị bù đắp thích hợp?


13
1 - nó làm tôi điên mà TimeZoneInfo.ConvertTimeBySystemTimeZoneId không chỉ làm việc cho :) này
James Manning

@JamesManning - Có, giả sử dt.Kindđược đặt chính xác.
Matt Johnson-Pint

Câu trả lời:


61

Bạn cần lấy UtcOffset từ TimeZoneInfo, sau đó chuyển nó vào phương thức ToOffset ():

var dt = DateTime.UtcNow;
Console.WriteLine(dt.ToLocalTime());

var tz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var utcOffset = new DateTimeOffset(dt, TimeSpan.Zero);
Console.WriteLine(utcOffset.ToOffset(tz.GetUtcOffset(utcOffset)));

tôi hiểu rồi ... bạn phải nhận được phần bù UTC cho ngày cụ thể đó trong múi giờ. cảm ơn.
jaminto

5
Đây không phải là cách tốt nhất so với câu trả lời của Karl Gjertsen sử dụng một hàm .Net duy nhất để thực hiện công việc thay vì trích xuất phần bù bằng cách tạo mới, loại bỏ DateTimeOffset.
ErikE

59

Bạn cũng có thể sử dụng TimeZoneInfo.ConvertTimeFromUtc, cho phép tiết kiệm thời gian ban ngày:

DateTime utc = DateTime.UtcNow;
TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(utc, zone);

Điều gì sẽ xảy ra nếu múi giờ của quốc gia tôi là EEST vào mùa hè và EET vào mùa đông? Điều đó sẽ hoạt động như thế nào với Tiết kiệm ánh sáng ban ngày?
Rami Zebian,

1
Windows biết thông tin múi giờ, cùng với ngày giờ tiết kiệm ánh sáng ban ngày. Nó sẽ hoạt động tốt hoặc bạn nếu bạn chọn một trong các múi giờ được xác định trước.
Karl Gjertsen

11

Hoặc tốt hơn, nếu bạn không muốn mã hóa khó nhận dạng múi giờ :

TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(TimeZoneInfo.Local.Id);
DateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tzi);

2
Bạn không thể chỉ sử dụng TimeZoneInfo.Localtrực tiếp? Tại sao bạn cần cuộc gọi đến FindSystemTimeZoneById?
CoderDennis

4
Bạn đúng, chúng tôi không cần nó. Chúng tôi chỉ có thể làm điều đó như thế nàyDateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(networkDateTime, TimeZoneInfo.Local);
Pabinator

1
Nhưng sau đó bạn được cố định vào một múi giờ duy nhất. Tôi đoán tùy thuộc vào cách bạn muốn sử dụng mã. :-)
Karl Gjertsen

9
Điều này không an toàn lắm. Nếu bạn đang gia công ứng dụng của mình trên môi trường đám mây, bạn không biết múi giờ nào là cục bộ.
Tom,

5

Tôi là người mới bắt đầu cả .NET và stackoverflow, vì vậy tôi có thể sai, nhưng đây là:

Sử dụng TimeZoneInfo.ConvertTimeFromUtc sẽ cho phép tiết kiệm ánh sáng ban ngày và chuyển đổi thành thời gian chính xác theo múi giờ + độ lệch DST có thể có. Tuy nhiên - bản thân độ lệch trong đối tượng kết quả sẽ hiển thị độ lệch cho thời gian chuẩn và không tính đến thời gian tiết kiệm ánh sáng ban ngày. Vì vậy, nếu bạn muốn thực hiện ToString trên đối tượng, bạn sẽ kết thúc với thời gian chính xác (tính theo giờ và phút), nhưng bù đắp sai trong thời gian tiết kiệm ánh sáng ban ngày, có thể dẫn đến sai thời điểm sau này trong mã.

Thay vào đó, nếu bạn sử dụng GetUtcOffset để lấy phần bù cho một thời gian cụ thể, sau đó thực hiện ToOffset trên đối tượng DateTimeOffset, cả giờ / phút và bản thân offset sẽ được chuyển đổi chính xác và bạn có thể thực hiện ToString một cách an toàn.

string ExpectedDateTimePattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss''zzz";
string timeZoneId = "FLE Standard Time";
string dateTimestr = "2017-10-09T09:00:00+02:00";

DateTimeOffset dto = DateTimeOffset.Parse(dateTimeStr);
TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
TimeSpan offset = zone.GetUtcOffset(dto);
dto = dto.ToOffset(offset);
string localTime = dto.ToString(ExpectedDateTimePattern);

localTime sẽ trả về "2017-10-09T10: 00: 00 + 03: 00".


Theo OP đây là câu trả lời chính xác. Điều chính cần hiểu là UtcOffset cho một múi giờ không phải là hằng số, thay vào đó nó phụ thuộc vào chính ngày tháng mà chúng ta đang nói đến do các quy tắc tiết kiệm ánh sáng ban ngày . Vì vậy, sai lầm duy nhất mà OP đã làm là anh ấy đã sử dụng BaseUtcOffset không đổi thay vì GetUtcOffset (myDate)
g.pickardou
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.