我有一个存储商店代码及其时区的表格。现在根据给定的本地日期,我需要知道转换为商店本地日期的日期是否是一个周末。现在我已经知道如何度过周末。我正在努力进行转换。我其实很困惑。我的表有例如以下两个值:
Store / TimeZone(Standard)
100 / 1 (This is frankfurt)
200 / 2 (This is tel aviv)
我们的sql server位于洛杉矶。我使用以下代码来获取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,那么它在弗兰福特上午5:32?这似乎是不正确的。应该是法兰克福的下午9:32。
答案 0 :(得分:4)
你不应该从当地时间开始。直接从UTC时间开始:
DECLARE @UTCDate DATETIME
SET @UTCDate = GETUTCDATE();
法兰克福比UTC(UTC + 1)提前一小时夏令时无效所以你添加一小时:
print DATEADD(HOUR, 1, @UTCDate);
请记住,时区间隔不是60分钟,孟买是UTC + 5:30,尼泊尔是UTC + 5:45。您还必须考虑夏令时,并定期更改。例如,阿根廷选择根据其水电站储存的水量逐年使用日光。
总结:始终使用UTC并将时间本地化留给客户端显示和报告。
答案 1 :(得分:2)
如果你有一个UTCDate,那么对于所有时区都是一样的...即,当它在纽约的UTC时间凌晨1点时,它也是法兰克福的UTC时间凌晨1点。要获得任何timnezone的本地时间,只需从UTC DateTime添加偏移量(即您在表中的值)...即,当它在UTC时间上午1点时,它在法兰克福当地时间凌晨2点。要记住是添加还是减去,请记住它始终 早期东部 。
答案 2 :(得分:0)
这是我最近放在一起的SQL-Only实现,你可以使用(论坛建议CLR是唯一的方法,因为TSQL实现这一点是不必要的复杂 - 不是真正的afaik)。我通过内联函数实现了避免RBAR(您可以对其进行分析和测试以确认)。
即使是老式的分布式分区视图,性能也很出色。 确保您的索引对它有好处,即使在DateTime字段上的字符串操作(绕过Year DatePart依赖项)我得到了所需的搜索。一些底层分区表的大小超过80GB。
当然,您需要根据需要添加时区行,并记住保持夏令时的开始和结束日期更新(它们可以更改)。 在时区和夏令时这两种情况下,偏移都是几分钟,所以这适用于我到目前为止遇到的所有情况。
最后,夏令时偏移总是一个正数,请注意该功能可以满足这一要求(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