8

TDateTime一部の値が自分のタイムゾーンの夏時間の範囲内にあるかどうかを何らかの形で判断する必要があります (C# では、同じことがDateTime.IsDaylightSavingTime()メソッドを実行します)。

Delphiにはタイムゾーンに関する情報が含まれていないため、Delphiには同様の機能がないことはわかっていTDateTimeますが、Win32 APIを使用してこれを行う方法があると思います。

GetTimeZoneInformationWin32のAPIや関数を見てみましたが、GetTimeZoneInformationForYear使い方がよくわからないので、教えていただきたいです。ヒントをお寄せいただきありがとうございます。

編集:

例:

私のタイムゾーン (中央ヨーロッパ) では、今年の夏時間は 3 月 28 日の午前 2 時に始まり、2010 年 10 月 31 日の午前 3 時に終了します。

ヘッダー付きの関数が必要です:

function IsDaylightSavingTime(input: TDateTime): boolean;

true入力日が 2010 年 3 月 28 日 2:00 から 2010 年 10 月 31 日 3:00 の間にある場合、そうでない場合は返されfalseます。

(例は2010年のものですが、すべての年で機能する必要があります。)

繰り返しになりますが、TDateTime に保存された情報だけでは不十分であることはわかっていますが、Win32 API 関数を使用すると、Windows の設定から現在のタイムゾーンに関する情報などを取得できるはずです。

4

7 に答える 7

3

思ったほど簡単ではありません。理由は次のとおりです。

1)DSTと標準時の間の切り替え日は、すべての国で同じではありません

2)DSTと標準時の間の切り替え日は、すべての年で同じ国の同じアルゴリズムではありません(たとえば、中央ヨーロッパでは、以前は4月の第1日曜日、IIRCでしたが、現在は3月の最終日曜日です)。2007年以降、米国は4月の第1日曜日から3月の第2日曜日に変更されました。

つまり、単純な日付では不十分であり、地理的な場所も必要になります。

ただし、実際に対応できる場合は、現在のロケール(国)の現在の年の現在のアルゴリズムから計算できる切り替え日に制限し、これは両方の日付で間違っている可能性があります。将来および過去の場合、TIME_ZONE_INFORMATIONの情報を使用して、切り替え日を計算できます。

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;

私のPC(中央ヨーロッパ時間帯)で2000年から2020年までループすると、次の日付が表示されます。

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

しかし、リストされた年にアルゴリズムが私のロケールから変更されたため、これらの年の少なくともいくつかは正しくありません。

その場合、関数は次のようになります。

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

  BEGIN
    Result:=GetDaylightSavingsSwitchOverDates(YearOf(Input),Start,Stop) AND (Input>=Start) AND (Input<Stop)
  END;
于 2010-08-10T14:47:09.183 に答える
3

特定のアプリケーションではやり過ぎかもしれませんが、オープン ソース プロジェクト「Olson Time Zone Database for Delphi 」では、 tz データベースプロジェクトでサポートされているすべてのタイム ゾーンにアクセスできます。tz データベースは、最新の夏時間の変更または修正で定期的に更新されます。

TZDB は、Delphi 6、7、8、9、10、2007、2009、2010、および XE または FreePascal 2.0 以降でコンパイルできます。TZDB は、TTimeZone クラスを RTL に導入する Delphi XE で使用するのが最適です。

于 2010-11-21T17:24:53.340 に答える
1

オンドラ C. -

はい、あなたは正しいです。必要がある:

  1. Delphi TDateTime 変数を希望の日付/時刻に設定します

  2. Windows SystemTime に変換する

  3. GetTimeZoneInformation() を呼び出して TTimeZoneInformation を取得する

  4. TTimeZoneInformation 構造体で GetTimeZoneInformationForYear() を呼び出して、タイムゾーンの DST 情報を取得します (任意のタイムゾーンの TTimeZoneInformation をどこで取得できるかはわかりませんが、MSDN で見つけることができるはずです)。

  5. 算術を実行して、システム時刻が TTZI.StandardDate の後に発生するか (この場合は標準時間)、または TTZI.DaylightDate の後に発生するか (この場合は DST) を確認します。

あるいは...

おそらく、これを Delphi テーブルに変換できます。

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

任意のタイムゾーンの任意の日時について、指定された日時が DST 内にあるか、または外にあるかを確認してください。出来上がり!Microsoft API はありません - シンプルなテーブル ルックアップまたは if/else ケース ブロックのみです。

「それが役立つことを願っています.. pSM

于 2010-08-15T22:00:08.593 に答える
0

.netリフレクターを使用して、.netでのこの関数の実装を表示しました。それは次のように定義されています、多分あなたは数学をDelphiに変換することができますか?これをさらに掘り下げる必要がある場合は、Reflectorを自分で開くことをお勧めします。私はそれがあなたを助けると思います!

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;
}
于 2010-08-12T21:34:00.317 に答える
0

あなたが言うように、その情報はDelphiの日時にバンドルされていないため、単純に移植することはできません. tdatetime を処理するすべてのルーチンは、この情報を追加する必要がありますが、Delphi ではそうではありません。

たぶん、あなたが実際にやろうとしていることをもっと説明し、類推によって問題を説明するのをやめるべきでしょう。

于 2010-08-10T13:00:21.450 に答える
0

この例は、JEDI コード ライブラリ(オープン ソース) の JclDateTime.pas ユニットの LocalDateTimeToDateTime 関数にあります。夏時間情報が取得され、UTC 時間との間の変換に使用されます。

于 2010-08-13T11:47:12.660 に答える
0

これがあなたの質問に対する答えではないことは承知していますが、次の 2 つの機能に興味があるかもしれません:SystemTimeToTzSpecificLocalTime()TzSpecificLocalTimeToSystemTime(). 最初のものは、世界時を指定されたタイム ゾーンの対応する時間に変換します (nil はローカル タイム ゾーンを意味します)。もう 1 つは逆に機能しますが、Borland Help によると、Windows XP 以降にのみ含まれています。タイムゾーンに依存する時間変換のみを行う場合は、問題ありません。また、指定された UTC 時間が DST か標準時間かをチェックすることを知っておくとよいでしょう。でも、どこかで読んだことはありません。自分で調べただけなので、間違っていたらごめんなさい。

次の関数を参照してください。どこでも使用できるかどうかはわかりませんが、それが正しいかどうかはわかりませんが、一見の価値があるかもしれません。そして、私はそれを知っているので、それがばかげた方法だと私に言わないでください:-)。

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;
于 2010-10-10T08:45:59.027 に答える