2010-01-11 7 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 во Франкфурте. Как я могу получить местную дату Франкфурта?

Edit: Я использую 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 вечера в Лос-Анджелесе, то его 5:32 утра в Франфурте? Однако это кажется неправильным. Это должно быть 9:32 вечера в Franfurt.

+0

, что двигатель и версию, пожалуйста? – gbn

+0

Извините, я забыл упомянуть - sql 2005. – vikasde

ответ

4

Не стоит начинать работу с местного времени. Начните прямо со временем UTC:

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

Франкфурт один час больше, чем UTC (UTC + 1) , когда летнее время не действует так что вы добавить один час:

print DATEADD(HOUR, 1, @UTCDate); 

Запомнить что часовые пояса не проходят через 60 минут, Мумбаи - UTC + 5:30, а Непал - UTC + 5:45. Вы также должны учитывать дневную экономию, и эти изменения регулярно меняются. Аргентинцы, например, предпочитают использовать дневной свет по годам на основе количества воды, хранящейся на ее гидроэлектростанциях.

Подводя итог: всегда используйте UTC и оставляйте локализацию времени для отображения и отчетности клиента.

2

Если у вас есть UTCDate, это то же самое для всех часовых поясов ... I.e., когда в Нью-Йорке 1:00 UTC, это также 1 am UTC во Франкфурте. Чтобы получить местное время для любой timnezone, просто добавьте смещение (это значение, которое у вас есть в вашей таблице) из UTC DateTime ... т. Е., Когда это 1 час. 00 мин., В Франкфурте 2 часа ночи. Чтобы помнить, следует ли добавлять или вычитать, просто помните, что его всегда Раньше Восток.

+0

hm ... см. Edit2. Я все еще смущен. – vikasde

0

Вот реализация SQL-Only, которую я недавно собрал, вы можете использовать (форумы предполагают, что CLR - единственный метод, поскольку TSQL излишне усложняется для достижения этого - не совсем afaik).Я реализовал с помощью встроенной функции, которая позволяет избежать RBAR (вы можете профилировать и проверить это для подтверждения).

Производительность отличная даже в старых школьных распределенных разделенных представлениях. Убедитесь, что ваша индексация хороша для него, даже при манипуляциях с строками на полях DateTime (чтобы обойти зависимости YearPart), я получаю желаемые запросы. Некоторые из основных разделенных таблиц имеют размер более 80 ГБ.

Конечно, вам нужно будет добавить свои временные ряды по мере необходимости и не забудьте обновить даты начала и окончания летнего времени (они могут измениться). В обоих случаях временного и дневного сбережений смещения находятся в минутах, поэтому это работает для всех сценариев, на которые я столкнулся.

Наконец, экономия Daylight офсетная всегда положительное число, обратите внимание функция обслуживает это номер эмпирического правила (весна вперед, падение назад)

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. Нам нужно было реализовать на основе пользовательских предпочтений для TimeZones в соответствии с Пользователями или в соответствии с Филиалом, что существуют объекты отчетности. Разделите это по необходимости ... –

Смежные вопросы