5

自分のロケールで夏時間が切り替わる日付を Oracle で選択する方法はありますか?

これと漠然と同等の何かがいいでしょう:

SELECT CHANGEOVER_DATE
FROM SOME_SYSTEM_TABLE
WHERE DATE_TYPE = 'DAYLIGHT_SAVINGS_CHANGEOVER'
  AND TO_CHAR(CHANGEOVER_DATE,'YYYY') = TO_CHAR(SYSDATE,'YYYY');  -- in the current year

編集: 2007 年に行ったように、議会が DST 法を調整するときに変更を必要としない解決策を望んでいました。ただし、投稿された解決策は機能します。

4

7 に答える 7

3

次の2つの関数を使用して、任意の年(2007年以降、米国)の開始日と終了日を計算します。

Function DaylightSavingTimeStart (p_Date IN Date)
Return Date Is
   v_Date       Date;
   v_LoopIndex  Integer;
Begin
   --Set the date to the 8th day of March which will effectively skip the first Sunday.
   v_Date := to_date('03/08/' || to_char(p_Date,'YYYY') || '02:00:00 AM','MM/DD/YYYY HH:MI:SS PM');
   --Advance to the second Sunday.
   FOR v_LoopIndex IN 0..6 LOOP
      If (RTRIM(to_char(v_Date + v_LoopIndex,'DAY')) = 'SUNDAY') Then
         Return v_Date + v_LoopIndex;
      End If;
   END LOOP;
End;

Function DaylightSavingTimeEnd (p_Date IN Date)
Return Date Is
   v_Date       Date;
   v_LoopIndex  Integer;
Begin
   --Set Date to the first of November this year
   v_Date := to_date('11/01/' || to_char(p_Date,'YYYY') || '02:00:00 AM','MM/DD/YYYY HH:MI:SS PM');
   --Advance to the first Sunday
   FOR v_LoopIndex IN 0..6 LOOP
      If (RTRIM(to_char(v_Date + v_LoopIndex,'DAY')) = 'SUNDAY') Then
         Return v_Date + v_LoopIndex;
      End If;
   END LOOP;
End;

おそらくもっと簡単な方法がありますが、これらは私たちのために働いています。もちろん、このクエリでは、現在の場所で夏時間が採用されているかどうかはわかりません。そのためには、位置データが必要になります。

于 2008-11-13T18:51:10.027 に答える
2

次の日曜日を取得するためにループする代わりに、oracle の next_day(date, 'SUN') 関数を使用することもできます。

于 2010-05-31T08:55:29.673 に答える
1

タイムゾーンが夏時間の開始と終了を決定するかどうかについてのオラクルの内部知識を使用する方法を次に示します。それの複雑さと一般的な奇妙さは別として、2 つのタイムゾーンが、夏時間が有効でないときは同じ時間であり、夏時間が有効なときは異なる時間であることを知る必要があります。そのため、サマータイムが発生したときの議会の変更には回復力がありますが (データベースがパッチで最新であると仮定すると)、キーオフされたタイムゾーンに影響を与える地域の変更には回復力がありません。これらの警告とともに、ここに私が持っているものがあります。

ALTER SESSION SET time_zone='America/Phoenix';
DROP TABLE TimeDifferences;
CREATE TABLE TimeDifferences(LocalTimeZone TIMESTAMP(0) WITH LOCAL TIME ZONE);
INSERT INTO TimeDifferences
(
   SELECT to_date('01/01/' || to_char(sysdate-365,'YYYY') || '12:00:00','MM/DD/YYYYHH24:MI:SS')+rownum-1 
   FROM dual CONNECT BY rownum<=365
);
COMMIT;

ALTER SESSION SET time_zone='America/Edmonton';
SELECT LocalTimeZone-1 DaylightSavingTimeStartAndEnd
FROM
(
   SELECT LocalTimeZone, 
      to_char(LocalTimeZone,'HH24') Hour1,
      LEAD(to_char(LocalTimeZone,'HH24')) OVER (ORDER BY LocalTimeZone) Hour2 
   FROM TimeDifferences
)
WHERE Hour1 <> Hour2;  

私はそれが奇妙だとあなたに言いました。コードは変更日のみを把握しますが、時間を表示するように拡張できます。現在、09-MAR-08 と 02-NOV-08 を返します。また、実行される時期にも敏感であるため、-365...+365 を実行する必要がありました。全体として、このソリューションはお勧めしませんが、調査するのは楽しかったです。他の誰かがもっと良いものを持っているかもしれません。

于 2008-11-14T04:05:22.403 に答える
1

In the United States, Daylight Savings Time is defined as beginning on the second Sunday in March, and ending on the first Sunday in November, for the areas that observe DST, for years after 2007.

I don't think there's an easy way to get this information from Oracle, but based on the standard definition, you should be able to write a stored procedure that calculates the beginning and ending date using the Doomsday Algorithm.

于 2008-11-13T18:20:08.183 に答える
0

これが上記の私のバージョンです。その利点は、2 番目の「セッション セットのタイム ゾーンの変更」を必要とせず、アプリケーションからより簡単に使用できることです。ストアド関数を作成したら、次を使用するだけです: ALTER SESSION SET time_zone='Asia/Jerusalem'; デュアルから GetDSTDates(2012,1) DSTStart,GetDSTDates(2012,2) DSTEnd,SessionTimeZone TZ を選択します。

これは、指定された年の dst 開始日、dst 終了日、タイムゾーンを返します。

create or replace function GetDSTDates
(
  year integer,
  GetFrom integer
)
return Date
as
  cursor c is
    select 12-to_number(to_char(LocalTimeZone at time zone '+00:00','HH24')) offset,
    min(to_char(LocalTimeZone at time zone '+00:00','DD/MM/YYYY')) fromdate,
    max(to_char(LocalTimeZone at time zone '+00:00','DD/MM/YYYY')) todate 
        from (
        SELECT cast((to_date('01/01/'||to_char(year)||'12:00:00','MM/DD/YYYYHH24:MI:SS')+rownum-1) as timestamp with local time zone) LocalTimeZone
        FROM dual CONNECT BY rownum<=365
        )
    group by 12-to_number(to_char(LocalTimeZone at time zone '+00:00','HH24'));
  dstoffset integer;
  offset integer;
  dstfrom date;
  dstto date;
begin
  offset := 999;
  dstoffset := -999;
  for rec in c
  loop 
    if rec.offset<offset
    then
      offset := rec.offset;
    end if;
    if rec.offset>dstoffset
    then
      dstoffset := rec.offset;
      dstfrom := to_date(rec.fromdate,'DD/MM/YYYY');
      dstto :=to_date(rec.todate,'DD/MM/YYYY');
    end if;
  end loop;
  if (offset<999 and dstoffset>-999 and offset<>dstoffset)
  then
    if GetFrom=1
    then
      return dstfrom;
    else 
      return dstto;
    end if;
  else
    return null;
  end if;
end;
/
ALTER SESSION SET time_zone='Asia/Jerusalem';
select GetDSTDates(2012,1) DSTStart,
       GetDSTDates(2012,2) DSTEnd,
       SessionTimeZone TZ from dual;
于 2012-05-24T19:18:34.957 に答える