2010-01-11 84 views
2

我有一個表存儲商店代碼和他們的時區。現在基於給定的當地日期,我需要知道轉換爲商店本地日期的日期是否在週末。現在我已經知道如何獲得週末部分。我正在努力改變。我實際上很困惑。我的表格有例如以下兩個值:SQL時區計算

Store/TimeZone(Standard) 
100/1 (This is frankfurt) 
200/2 (This is tel aviv) 

我們的sql服務器位於洛杉磯。我用下面的代碼來獲取UTC日期:

DECLARE @LocalDate DATETIME, @UTCDate DATETIME 
SET @LocalDate = GetDate() 
-- convert local date to utc date 
SET @UTCDate = DATEADD(Hour, DATEDIFF(Hour, GETUTCDATE(), GETDATE()), @LocalDate) 

如果我明白了一切正確的,我現在可以簡單地添加所需的時間到@UTCDate得到當地時區的@UTCDate,是否正確?

法蘭克福這將是:

print DATEADD(HOUR, 1, @UTCDate) 

現在這個返回我UTCDate法蘭克福。我怎樣才能得到法蘭克福的當地日期?

編輯:我使用SQL 2005

EDIT2:完整的例子仍撲朔迷離對我說:

DECLARE @LocalDate DATETIME, @UTCDate DATETIME 
SET @LocalDate = GetDate() 
-- convert local date to utc date 
SET @UTCDate = DATEADD(Hour, DATEDIFF(Hour, GETUTCDATE(), GetDate()), @LocalDate) 
print GetDate() 
print @UTCDate 
print DATEADD(HOUR, 1, @UTCDate) 

輸出:

Jan 11 2010 12:32PM 
Jan 11 2010 4:32AM 
Jan 11 2010 5:32AM 

現在做到這一點意思是說,如果它在洛杉磯12:32 PM,那麼它在法蘭克福的5:32 AM?這似乎是不正確的,但。它應該是9點32分在法蘭克福。

+0

什麼引擎和版本嗎? – gbn

+0

對不起,我忘了提及 - sql 2005. – vikasde

回答

4

你不應該與本地時間啓動。直接與UTC時間啓動:

DECLARE @UTCDate DATETIME 
SET @UTCDate = GETUTCDATE(); 

法蘭克福比UTC早一個小時(UTC + 1)當夏天的時候沒有生效所以你添加1小時:

print DATEADD(HOUR, 1, @UTCDate); 

記住時區不在60分鐘的時間間隔內,孟買是UTC + 5:30,尼泊爾是UTC + 5:45。您還必須考慮夏令時,並定期更換。例如,阿根廷選擇根據其水電廠儲存的水量逐年使用日光。

綜上所述:總是使用UTC和離開時間的本地化客戶端顯示和報告。

2

如果你有UTCDate,它是所有時區相同......即,當它在紐約的凌晨1點UTC,它也是在法蘭克福凌晨1點UTC。要獲得任何timnezone的本地時間,只需從UTC日期時間添加偏移量(這是您在表格中的值)即,當它是凌晨1點UTC時,它是法蘭克福當地時間凌晨2點。要記住的是加還是減,只記得它總是早些時候東

+0

hm ...請參閱edit2。我仍然困惑。 – vikasde

0

這裏是一個SQL-唯一實現最近,我放在一起,你可以使用(論壇表明,CLR是唯一的方法,因爲TSQL不必要地複雜,在實現這一點 - 不是真的據我所知)。我通過內聯函數實現,避免了RBAR(您可以通過配置文件和測試來確認)。

即使在老派的分佈式分區視圖上,性能也很棒。 確保您的索引對它有用,即使在DateTime字段上的字符串操作(繞過YearPart DatePart依賴項),我也會得到所需的查找。一些底層分區表的大小超過80GB。

當然,您需要根據需要添加您的時區行,並記住更新夏令時開始和結束日期(可以更改)。 在時區和夏令時這兩種情況下,偏移都是在幾分鐘內完成的,所以這適用於迄今爲止我遇到的所有情況。

最後,夏令偏移始終是一個正數,注意功能迎合了這種適合拇指法則(春進,回退)

If Not Exists (Select Name from sys.objects where name = 'tblTimeZones' and type = 'U') 
     Begin 
     Create Table tblTimeZones(
      [ID] Int Identity (0,1) NOT NULL, 
      [UserID] Int NOT NULL, 
      [Description] NVarchar(128) NOT NULL, 
      [TZ_OffSet_Mins] Int NOT NULL, 
      [Use_DST] Bit NOT NULL, 
      [DST_AddOffSet] Int NOT NULL, 
      [DST_StartDate] DateTime NOT NULL Constraint DF_DST_StartDate Default ('1900-01-01 00:00:00.000'), 
      [DST_EndDate] DateTime NOT NULL Constraint DF_DST_EndDate Default ('1900-01-01 00:00:00.000'), 
      Constraint PK_tblTimeZones Primary Key NonClustered (ID), 
      Constraint UQ_tblTimeZones_Description Unique Clustered ([Description]) 
     ) 
     End 
     Go 

    If Exists (Select Name from sys.objects where name = 'fncV1_iCalcDateInTimeZone' and type = 'IF') 
    Begin 
     Drop Function fncV1_iCalcDateInTimeZone 
    End 
    Go 

    Create Function fncV1_iCalcDateInTimeZone 
    (
     @UserID Int, @DateAndTime DateTime, @EntID Int 
    ) 
     Returns Table 
     With SchemaBinding 
    As 

     Return (

      Select TZDateAndTime = 

       DateAdd(
        mi, 
        tz.TZ_OffSet_Mins + 
        -- Daylight Savings STARTS earlier in the Year than Ends (So, Northern Hemisphere), In Daylight Savings Time Period and Daylight Savings In Use 
         Case when 
          tz.Use_DST = 1 
          And SubString(Convert(Varchar(23),tz.DST_StartDate,21), 6, 18) < SubString(Convert(Varchar(23),tz.DST_EndDate,21), 6, 18) 

          And SubString(Convert(Varchar(23),@DateAndTime,21), 6, 18) >= SubString(Convert(Varchar(23),tz.DST_StartDate,21), 6, 18) 
          And SubString(Convert(Varchar(23),@DateAndTime,21), 6, 18) < SubString(Convert(Varchar(23),tz.DST_EndDate,21), 6, 18) 

         then tz.DST_AddOffSet 
         Else 0 
         End 
        + 
        -- Daylight Savings STARTS later in the Year than Ends (So, Southern Hemisphere), In Daylight Savings Surround Period 
         Case when 
          tz.Use_DST = 1 
          And SubString(Convert(Varchar(23),tz.DST_StartDate,21), 6, 18) > SubString(Convert(Varchar(23),tz.DST_EndDate,21), 6, 18) 
          And 
          (
           SubString(Convert(Varchar(23),@DateAndTime,21), 6, 18) >= SubString(Convert(Varchar(23),tz.DST_StartDate,21), 6, 18) 
           Or 
           SubString(Convert(Varchar(23),@DateAndTime,21), 6, 18) < SubString(Convert(Varchar(23),tz.DST_EndDate,21), 6, 18) 
          ) 
         then tz.DST_AddOffSet 
         Else 0 
         End 
        ,@DateAndTime 
       ) 

      From dbo.tblSomeEntityTable rd 
      Inner Join dbo.tblBranch b on rd.BranchID = b.ID 
      Inner Join dbo.tblUsers u on u.ID = @UserID 
      Inner Join dbo.tblTimeZones tz on tz.ID = case when u.UserTZOverBranchTZ = 1 then u.TimeZoneID else b.TimeZoneID End 
      Where 
       rd.ID   = Case when ISNULL(@EntID, -1)  = -1 then rd.ID   else @EntID End 
     ) 

    Go 
+0

P.S.我們需要根據用戶對用戶時區的偏好實施,或根據報告實體所在的分公司來實施。根據需要將其除外...... –