2010-01-11 4 views
2

J'ai une table qui stocke les storecodes et leur fuseau horaire. Maintenant, basé sur une date locale donnée, j'ai besoin de savoir si cette date convertie en magasins date locale était un dans un week-end ou non. Maintenant, je sais déjà comment obtenir la partie week-end. Je me bats avec la conversion. Je suis vraiment confus. Ma table a par exemple les deux valeurs suivantes:sql timezone calcul

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

Notre serveur SQL est situé à LA. J'ai utilisé le code suivant pour obtenir la date UTC:

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

Si je comprends tout juste, je peux maintenant ajouter simplement les heures nécessaires à la @UTCDate pour obtenir le @UTCDate de ce fuseau horaire local, correct?

Pour francfort, il serait:

print DATEADD(HOUR, 1, @UTCDate) 

Maintenant, cela me renvoie le UTCDate pour Francfort. Comment aurais-je la date locale de Francfort?

Edit: J'utilise Sql 2005.

Edit2: exemple complet est encore confus pour moi:

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) 

Sortie:

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

Maintenant, est-ce dire, que si son 12:32 PM à Los Angeles, puis son 05h32 à Franfurt? Cela semble être incorrect cependant. Il devrait être 21h32 à Franfurt.

+0

ce que le moteur et la version s'il vous plaît? – gbn

+0

Désolé, j'ai oublié de mentionner - sql 2005. – vikasde

Répondre

4

Vous ne devriez pas commencer par l'heure locale. Commencez directement avec le temps UTC:

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

Francfort est à une heure d'avance sur UTC (GMT + 1) l'heure d'été est pas en vigueur de sorte que vous ajoutez un heure:

print DATEADD(HOUR, 1, @UTCDate); 

Rappelez-vous que les fuseaux horaires ne sont pas sur des intervalles de 60 minutes, Mumbai est UTC + 5:30 et Népal est UTC + 5:45. Vous devez également tenir compte de l'heure d'été, et ceux-ci changent régulièrement. L'Argentine, par exemple, choisit d'utiliser la lumière du jour chaque année en fonction de la quantité d'eau stockée dans ses centrales hydroélectriques. Pour résumer: utilisez toujours l'heure UTC et laissez la localisation de l'heure à l'affichage et aux rapports du client.

2

Si vous avez un UTCDate, il en est de même pour tous les fuseaux horaires ... C'est-à-dire, quand il est 1 heure UTC à New York, il est aussi 1 heure UTC à Frankfort. Pour obtenir l'heure locale pour n'importe quel timnezone, ajoutez simplement le décalage (c'est la valeur que vous avez dans votre table) de la date UTC ... c'est-à-dire, quand il est 1 heure UTC, il est 2 heures du matin à Frankfort. Pour se rappeler s'il faut ajouter ou soustraire, rappelez-vous juste que c'est toujours Plus tôt Est.

+0

hm ... s'il vous plaît voir edit2. Je suis toujours confus. – vikasde

0

Voici une implémentation SQL seulement que j'ai récemment mis en place que vous pouvez utiliser (Les forums suggèrent que CLR est la seule méthode depuis TSQL est inutilement compliquée pour y parvenir - pas vraiment afaik).J'ai implémenté via une fonction inline qui évite RBAR (Vous pouvez profiler et tester ceci pour confirmer).

Les performances sont excellentes même sur les vues partitionnées distribuées de la vieille école. Assurez-vous que votre indexation est bonne pour elle, même sur les manipulations de chaîne sur les champs DateTime (Pour contourner les dépendances Année DatePart) Je reçois les recherches souhaitées. Certaines tables partitionnées sous-jacentes ont une taille supérieure à 80 Go.

Bien sûr, vous devrez ajouter vos lignes de fuseau horaire comme vous le souhaitez et n'oubliez pas de garder les dates de début et de fin de l'heure d'été actualisées (elles peuvent changer). Dans les deux cas de fuseau horaire et d'heure d'été, les décalages sont en minutes, donc cela fonctionne pour tous les scénarios que j'ai rencontrés jusqu'à présent.

Enfin, les économies d'Daylight décalage est toujours un nombre positif, notez la fonction s'adresse à ce à la suite de la règle générale (Spring Forward, Fall Back)

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. Nous devions mettre en œuvre en fonction de la préférence de l'utilisateur pour TimeZones en fonction des utilisateurs, ou en fonction de la branche dans laquelle les entités de reporting existent. –