2010-08-10 24 views
8

Tôi cần bằng cách nào đó để xác định xem giá trị TDateTime có nằm trong phạm vi Thời gian tiết kiệm ánh sáng ban ngày hay không (trong C# tương tự như phương pháp DateTime.IsDaylightSavingTime()).Delphi - tương đương với phương pháp C# DateTime.IsDaylightSavingTime() cần

Tôi biết ở Delphi không có chức năng tương tự, vì Delphi TDateTime không chứa thông tin về múi giờ, nhưng tôi cho rằng có cách nào đó để thực hiện việc này bằng API Win32.

Tôi đã xem các hàm Win32 API GetTimeZoneInformationGetTimeZoneInformationForYear, nhưng tôi không hiểu cách sử dụng chúng, vì vậy tôi muốn yêu cầu bạn trợ giúp. Cám ơn vì đã nhiệt tình hướng dẫn.

Edit:

Ví dụ:

Trong múi giờ của tôi (Trung ương châu Âu) Daylight Saving Time bắt đầu trong năm nay trên 28 Tháng 3 lúc 2 giờ sáng và kết thúc vào ngày 31 tháng 10 năm 2010 lúc 3 giờ sáng.

Tôi cần một chức năng với tiêu đề:

function IsDaylightSavingTime(input: TDateTime): boolean; 

rằng sẽ trở lại true nếu ngày đầu vào là giữa 28 tháng 3 năm 2010 02:00 và 31 Tháng 10 2010 03:00 và false nếu không muốn nói.

(Ví dụ là chỉ dành riêng cho năm 2010, nhưng tôi sẽ cần nó để làm việc cho tất cả các năm.)

Một lần nữa, tôi biết rằng thông tin được lưu trong TDateTime một mình là không đủ, nhưng tôi nghĩ rằng với một số chức năng API Win32 tôi sẽ có thể nhận được ví dụ thông tin về múi giờ hiện tại từ cài đặt Windows.

Trả lời

3

Nó không phải là dễ dàng như nó có vẻ, bởi vì:

1) Ngày chuyển giao giữa DST và giờ chuẩn không giống nhau đối với tất cả các quốc gia

2) Ngày chuyển đổi giữa DST và giờ chuẩn không phải là cùng một thuật toán cho cùng một quốc gia trong tất cả các năm (ví dụ: ở Trung Âu trước đây) Chủ nhật tháng Tư, IIRC, bây giờ là chủ nhật cuối tháng ba). Hoa Kỳ đã thay đổi từ Chủ Nhật đầu tiên vào tháng Tư đến Chủ Nhật thứ hai vào tháng Ba từ năm 2007 trở đi.

Vì vậy - một ngày đơn giản là không đủ, bạn cũng sẽ cần vị trí địa lý.

Nhưng, nếu bạn có thể sống với thực tế, rằng bạn giới hạn mình vào ngày chuyển giao có thể được tính từ HIỆN thuật toán cho HIỆN năm cho HIỆN locale (quốc gia) và rằng đây có thể sai cho những ngày cả hai trong tương lai và trong quá khứ, sau đó bạn có thể sử dụng thông tin trong TIME_ZONE_INFORMATION để tính toán số ngày chuyển giao:

USES Windows,SysUtils,DateUtils; 

FUNCTION GetDaylightSavingsSwitchOverDates(Year : Cardinal ; VAR Start,Stop : TDateTime) : BOOLEAN; 

    VAR 
    TZ : TTimeZoneInformation; 

    FUNCTION DecodeSwitchOverDate(Year : Cardinal ; CONST Time : TSystemTime) : TDateTime; 
    VAR 
     I : Cardinal; 

    BEGIN 
     Result:=EncodeDateTime(Year,Time.wMonth,1,Time.wHour,Time.wMinute,Time.wSecond,0); 
     IF Time.wDay=5 THEN BEGIN 
     Result:=DateOf(EndOfTheMonth(Result))+TimeOf(Result); 
     WHILE PRED(DayOfWeek(Result))<>Time.wDayOfWeek DO 
      Result:=IncDay(Result,-1) 
     END 
     ELSE BEGIN 
     WHILE PRED(DayOfWeek(Result))<>Time.wDayOfWeek DO Result:=IncDay(Result); 
     FOR I:=1 TO PRED(Time.wDay) DO Result:=IncWeek(Result) 
     END 
    END; 

    BEGIN 
    IF GetTimeZoneInformation(TZ)=TIME_ZONE_ID_UNKNOWN THEN 
     Result:=FALSE 
    ELSE BEGIN 
     Start:=DecodeSwitchOverDate(Year,TZ.DaylightDate); 
     Stop:=DecodeSwitchOverDate(Year,TZ.StandardDate); 
     Result:=TRUE 
    END 
    END; 

FUNCTION StartOfDST(Year : Cardinal) : TDateTime; 
    VAR 
    Stop : TDateTime; 

    BEGIN 
    IF NOT GetDaylightSavingsSwitchOverDates(Year,Result,Stop) THEN Result:=0 
    END; 

FUNCTION EndOfDST(Year : Cardinal) : TDateTime; 
    VAR 
    Start : TDateTime; 

    BEGIN 
    IF NOT GetDaylightSavingsSwitchOverDates(Year,Start,Result) THEN Result:=0 
    END; 

Looping qua các năm 2000-2020 trên máy tính của tôi (Múi giờ Trung Âu), tôi nhận được các ngày sau:

DST in 2000: Sun 26 Mar 2000 02:00:00 through Sun 29 Oct 2000 03:00:00 
DST in 2001: Sun 25 Mar 2001 02:00:00 through Sun 28 Oct 2001 03:00:00 
DST in 2002: Sun 31 Mar 2002 02:00:00 through Sun 27 Oct 2002 03:00:00 
DST in 2003: Sun 30 Mar 2003 02:00:00 through Sun 26 Oct 2003 03:00:00 
DST in 2004: Sun 28 Mar 2004 02:00:00 through Sun 31 Oct 2004 03:00:00 
DST in 2005: Sun 27 Mar 2005 02:00:00 through Sun 30 Oct 2005 03:00:00 
DST in 2006: Sun 26 Mar 2006 02:00:00 through Sun 29 Oct 2006 03:00:00 
DST in 2007: Sun 25 Mar 2007 02:00:00 through Sun 28 Oct 2007 03:00:00 
DST in 2008: Sun 30 Mar 2008 02:00:00 through Sun 26 Oct 2008 03:00:00 
DST in 2009: Sun 29 Mar 2009 02:00:00 through Sun 25 Oct 2009 03:00:00 
DST in 2010: Sun 28 Mar 2010 02:00:00 through Sun 31 Oct 2010 03:00:00 
DST in 2011: Sun 27 Mar 2011 02:00:00 through Sun 30 Oct 2011 03:00:00 
DST in 2012: Sun 25 Mar 2012 02:00:00 through Sun 28 Oct 2012 03:00:00 
DST in 2013: Sun 31 Mar 2013 02:00:00 through Sun 27 Oct 2013 03:00:00 
DST in 2014: Sun 30 Mar 2014 02:00:00 through Sun 26 Oct 2014 03:00:00 
DST in 2015: Sun 29 Mar 2015 02:00:00 through Sun 25 Oct 2015 03:00:00 
DST in 2016: Sun 27 Mar 2016 02:00:00 through Sun 30 Oct 2016 03:00:00 
DST in 2017: Sun 26 Mar 2017 02:00:00 through Sun 29 Oct 2017 03:00:00 
DST in 2018: Sun 25 Mar 2018 02:00:00 through Sun 28 Oct 2018 03:00:00 
DST in 2019: Sun 31 Mar 2019 02:00:00 through Sun 27 Oct 2019 03:00:00 
DST in 2020: Sun 29 Mar 2020 02:00:00 through Sun 25 Oct 2020 03:00:00 

nhưng ít nhất một số năm này không chính xác do thuật toán đã thay đổi từ ngôn ngữ của tôi trong những năm được liệt kê.

Chức năng của bạn sau đó sẽ là:

FUNCTION IsDaylightSavingTime(Input : TDateTime) : BOOLEAN; 
    VAR 
    Start,Stop : TDateTime; 

    BEGIN 
    Result:=GetDaylightSavingsSwitchOverDates(YearOf(Input),Start,Stop) AND (Input>=Start) AND (Input<Stop) 
    END; 
+0

tại sao không cập nhật từ xml hoặc cơ sở dữ liệu? có thể dịch vụ web? – none

0

Như bạn tự nói, thông tin đó không được lưu trữ cùng với thời gian biểu trong Delphi, vì vậy bạn không thể chỉ đơn giản là cổng này. Mỗi thói quen mà thủ tục một tdatetime sẽ phải thêm thông tin này, mà không phải là trường hợp trong Delphi.

Có lẽ bạn nên giải thích thêm những gì bạn đang thực sự cố gắng để làm, và mô tả các vấn đề ít bằng cách tương tự

+0

OK, tôi đã thêm một ví dụ, tôi hy vọng nó rõ ràng hơn một chút ... –

+0

Thông tin không được lưu trữ trong .Net, một trong hai. Nó chỉ là kiểu .Net có các phương thức làm cho nó trông giống như nó lưu trữ nhiều thông tin hơn nó. Phương thức này chỉ đơn giản là sử dụng cùng một API Windows cơ bản, đó là lý do tại sao các phương thức .Net hoạt động khác trên Windows XP. –

0

tôi đã sử dụng .net phản xạ để xem việc thực hiện các chức năng này trong .net. Nó được định nghĩa như sau, có lẽ bạn có thể chuyển đổi toán học thành Delphi? Nếu bạn cần phải đào sâu hơn vào điều này, tôi đề nghị mở Reflector cho chính mình. Tôi nghĩ rằng nó sẽ giúp bạn!

public static bool IsDaylightSavingTime(DateTime time, DaylightTime daylightTimes) 
{ 
    return (CalculateUtcOffset(time, daylightTimes) != TimeSpan.Zero); 
} 

internal static TimeSpan CalculateUtcOffset(DateTime time, DaylightTime daylightTimes) 
{ 
    if (daylightTimes != null) 
    { 
     DateTime time4; 
     DateTime time5; 
     if (time.Kind == DateTimeKind.Utc) 
     { 
      return TimeSpan.Zero; 
     } 
     DateTime time2 = daylightTimes.Start + daylightTimes.Delta; 
     DateTime end = daylightTimes.End; 
     if (daylightTimes.Delta.Ticks > 0L) 
     { 
      time4 = end - daylightTimes.Delta; 
      time5 = end; 
     } 
     else 
     { 
      time4 = time2; 
      time5 = time2 - daylightTimes.Delta; 
     } 
     bool flag = false; 
     if (time2 > end) 
     { 
      if ((time >= time2) || (time < end)) 
      { 
       flag = true; 
      } 
     } 
     else if ((time >= time2) && (time < end)) 
     { 
      flag = true; 
     } 
     if ((flag && (time >= time4)) && (time < time5)) 
     { 
      flag = time.IsAmbiguousDaylightSavingTime(); 
     } 
     if (flag) 
     { 
      return daylightTimes.Delta; 
     } 
    } 
    return TimeSpan.Zero; 
} 
0

Bạn có thể tìm thấy một ví dụ về điều này trong các JEDI Code Library (Open Source) trong đơn vị JclDateTime.pas, trong hàm LocalDateTimeToDateTime. Thông tin thời gian tiết kiệm ánh sáng ban ngày được truy xuất và được sử dụng để chuyển đổi đến và từ thời gian UTC.

1

Ondra C. -

Có, bạn đã đúng. Bạn cần phải:

  1. Đặt một biến Delphi TDateTime đến ngày/thời gian bạn muốn

  2. Chuyển đổi nó sang Windows SystemTime

  3. Gọi GetTimeZoneInformation() để có được TTimeZoneInformation

  4. Gọi GetTimeZoneInformationForYear(), với cấu trúc TTimeZoneInformation của bạn, để nhận thông tin DST cho múi giờ của bạn (Tôi không chắc chắn bạn sẽ nhận được TTimeZoneInformation cho một số múi giờ tùy ý - nhưng bạn có thể tìm thấy nó trên MSDN).

  5. Thực hiện phép tính số học để xem liệu thời gian hệ thống của bạn có xảy ra SAU KHI/STIQUALDate (trong trường hợp đó là thời gian chuẩn) hay SAUI.DaylightDate (trong trường hợp đó là DST).

Ngoài ra ...

Có lẽ bạn chỉ có thể chuyển đổi này vào một bảng Delphi:

http://www.twinsun.com/tz/tz-link.htm

Đối với bất kỳ datetime trong, bất kỳ múi giờ, chỉ thấy nếu thác datetime cho trong DST, hoặc bên ngoài nó. Thì đấy! Không có API của Microsoft - chỉ cần tra cứu bảng đơn giản hoặc nếu trường hợp khác bị chặn!

'Hy vọng điều đó sẽ giúp ..pSM

0

Tôi biết đây không phải là câu trả lời cho câu hỏi của bạn, nhưng bạn có thể quan tâm đến hai chức năng sau: SystemTimeToTzSpecificLocalTime()TzSpecificLocalTimeToSystemTime(). Người đầu tiên chuyển đổi thời gian quốc tế thành thời gian tương ứng cho múi giờ được chỉ định (trong đó nil nghĩa là múi giờ địa phương của bạn). Một cách khác hoạt động theo cách khác, nhưng chỉ được bao gồm trong Windows XP trở lên, như Borland Help nói. Nếu bạn sẽ chỉ thực hiện chuyển đổi thời gian phụ thuộc múi giờ, chúng sẽ ổn cho bạn. Và nó là tốt để biết rằng họ kiểm tra xem thời gian UTC đưa ra là một DST hoặc thời gian tiêu chuẩn. Tuy nhiên, tôi không đọc nó ở đâu cả. Tôi chỉ tự mình kiểm tra, vì vậy hãy sửa tôi nếu tôi sai.

Vui lòng xem chức năng sau. Tôi không chắc liệu tôi có sử dụng nó ở đâu không, vì tôi không chắc về tính chính xác của nó, nhưng nó có thể đáng xem. Và xin vui lòng, không cho tôi biết đó là một phương pháp ngu ngốc, vì tôi biết rằng :-).

function IsDaylightSavingTime(lLocalTime: TDateTime): boolean; 
var 
    lUniversalSystemTime: TSystemTime; 
    lLocalSystemTime: TSystemTime; 
    lTimeZoneInfo: TTimeZoneInformation; 
begin 
    case GetTimeZoneInformation(lTimeZoneInfo) of 
    TIME_ZONE_ID_UNKNOWN: 
     begin 
     Result := False; 
     Exit; 
     end; 

    TIME_ZONE_ID_STANDARD, 
    TIME_ZONE_ID_DAYLIGHT: ; 

    else 
    //TIME_ZONE_ID_INVALID: 
    RaiseLastOSError(); 
    end; 

    DateTimeToSystemTime(lLocalTime, lLocalSystemTime); 
    if not TzSpecificLocalTimeToSystemTime(nil, lLocalSystemTime, lUniversalSystemTime) then 
    RaiseLastOSError(); 

    Result := SameTime(SystemTimeToDateTime(lUniversalSystemTime), 
    IncMinute(lLocalTime, lTimeZoneInfo.DaylightBias + lTimeZoneInfo.Bias)); 
end; 
3

Có lẽ nó là quá mức cần thiết cho các ứng dụng cụ thể của bạn, nhưng dự án mã nguồn mở "Olson Time Zone Database for Delphi" cho phép để truy cập tất cả các múi giờ được hỗ trợ bởi dự án tz database. Cơ sở dữ liệu tz được cập nhật thường xuyên với các thay đổi hoặc sửa lỗi tiết kiệm ánh sáng ban ngày mới nhất.

TZDB thể được biên dịch trên Delphi 6, 7, 8, 9, 10, 2007, 2009, 2010 và XE hoặc FreePascal 2.0 và cao hơn. TZDB là được sử dụng tốt nhất với Delphi XE mà giới thiệu lớp TTimeZone vào RTL.

Các vấn đề liên quan