Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net UTC和夏令时场景_.net_Datetime_Time_Timezone_Dst - Fatal编程技术网

.net UTC和夏令时场景

.net UTC和夏令时场景,.net,datetime,time,timezone,dst,.net,Datetime,Time,Timezone,Dst,我使用UTC在数据库中存储数据和时间值。这些值在客户端或每个客户端时区上转换为localtime。我从中了解了这些场景,在夏令时显示UTC的时间似乎会带来问题 住在美国东海岸的人 美国输入一个值 比如“2003年10月26日凌晨01:10:00” 1) 由于 夏令时,凌晨2:00 本地时钟重置为凌晨1:00, 创造一个25小时的工作日。既然 凌晨1:00之间的时钟时间值 凌晨2点在那一天发生两次 至少在大部分时间里是这样的早晨 美国和加拿大 计算机真的没有办法知道 上午1点10分是指 在开关之前

我使用UTC在数据库中存储数据和时间值。这些值在客户端或每个客户端时区上转换为localtime。我从中了解了这些场景,在夏令时显示UTC的时间似乎会带来问题

住在美国东海岸的人 美国输入一个值 比如“2003年10月26日凌晨01:10:00”

1) 由于 夏令时,凌晨2:00 本地时钟重置为凌晨1:00, 创造一个25小时的工作日。既然 凌晨1:00之间的时钟时间值 凌晨2点在那一天发生两次 至少在大部分时间里是这样的早晨 美国和加拿大 计算机真的没有办法知道 上午1点10分是指 在开关之前发生,或 这发生在事故发生10分钟后 夏令时开关

2) 类似地,问题发生在 春天的时候,在某个特定的季节 早上好,没有2:10这样的时间 是原因是那天下午2点 特别是早上,时间就在当地 时钟突然变为凌晨3点。 整个2:00小时都不会发生在 这是一天23小时

您是如何处理这种情况的#1,当您在夏令时可能有4笔交易,两笔在切换前,两笔在切换后?如何向用户显示事务的时间,因为由于班次的原因,最后两个事务显示的时间可能早于前两个事务。?有时,它可能被证明是不合逻辑的,例如:在邮件链中

增加:

要添加有关上下文的更多信息,客户端上运行的Silverlight/Flash等RIA应用程序(或通过Web服务与服务器对话的任何客户端应用程序)允许用户选择交付时间或使用pc本地时间安排

如果我可以检查给定的输入时间是否为无效时间,我可能会提醒用户。此外,对于旅行者来说,时区需要在时间点找到,而不是基于用户选择,因为他们可能在区域之间移动,而在用户配置文件中保存他们的时区也没有帮助

一些用于评估输入时间的C#测试样本:

//2:30 am CT to UTC --> 8:30 am  
DateTime dt = new DateTime(2009, 03, 08, 2, 30, 00, DateTimeKind.Local);  

//8:30 am UTC to CT --> 3:30 am.. which is as expected  
DateTime dt1 = new DateTime(2009, 03, 08, 8, 30, 00, DateTimeKind.Utc);  

//check for daylight saving time returns false.. ??  
TimeZoneInfo.Local.IsDaylightSavingTime(dt);  

//check for daylight saving time returns true  
TimeZoneInfo.Local.IsInvalidTime(dt);  

这些场景是提倡使用DST的案例。只要在UTC中存储和排序值,显示什么并不重要。也就是说,如果正确使用UTC,这些场景中出现的问题就会得到解决

是的,看到这样的记录会让人困惑:12:30、1:20、1:10、3:30,但如果这是按照UTC(实际发生的情况)进行排序的方式,我认为这是正确的方式

因此,通过在UTC中记录所有内容,然后在UTC或相对时间(如“17分钟前…”)中显示所有内容,可以完全避免此问题


如果你指的是评论中建议的用户提供的日期/时间,我有一些坏消息要告诉你:它糟透了。我认为最好、最明显的解决办法是选择一条规则并执行它。如果您真的需要完美地处理它,您的UI将需要扩展到学究式地处理这种每年仅发生1小时的边缘情况,然后只处理非实时创建的事务(因为如果它们是实时的,您将知道DST等价物)

如何向用户显示事务的时间,因为由于班次的原因,最后两个事务显示的时间可能早于前两个事务。?有时,它可能被证明是不合逻辑的,例如:在邮件链中

按UTC排序,并在本地时间显示

因此,用户可能会看到如下列表:

01:10:00
01:50:00
01:05:00
01:20:00

或者按UTC显示和排序数据。

如果您有人手动输入数据,祝您好运,除非他们在UTC时间输入数据。没有一个“正确”的方法来处理这个问题。如果您处理的日期不是用户输入的,比如交易发生的时间,只需将这些日期全部存储为UTC,生活就好了。:)

SQL Server有一个新类型“datetimeoffset”,它可以很好地处理这个问题,因为您可以使用不同的偏移量来处理相同的时间。对于我的SQLServer2005DB,我使用该类型的字符串文字,形式为“YYYY-MM-DD hh:MM:ss hh:MM”的nvarchar(25)


为此,我创建了一些例程,将这些字符串转换为正确的时间。

一般来说,问题分为两部分:

  • 接收用户输入
  • 向用户显示数据
  • 这两个问题应该以类似的方式处理,但在某些方面有一些不同的解决办法。对于1,最简单的选择是找出您的业务是否真的需要一种明确的方式来指定特定时间的时间。许多应用程序只是忽略了它(上次您使用的日期选择器是什么时候提供的?)。如果输入了不存在的小时,您应该提供保护(即抛出错误)


    至于2,跳过的小时并不重要,因为您的数据库是UTC。重复一小时可能会让人困惑,特别是在一系列时间戳中。如果值得的话,考虑用时区标识符格式化日期字符串,其中包含对夏时制偏移量的引用。大多数老式的时区名称(即非奥尔森时区)都包含此名称(EST与EDT、GMT与BST等)。这将足以在必要时消除歧义。这可能就是您所需要的,因为这种边界情况可能不值得在显示上做太多的麻烦。如果您需要更多的输出,还可以使用UTC偏移量格式化时间戳,这将使转换在时间戳序列中非常明确。

    您需要存储时间偏移量

    目前东海岸的时间为(往返格式)

    即使东海岸被认为是-5,在夏时制期间,时间也将是-4

    10月26日凌晨1:10,时间为

    2009-10-26T1:10:00.0000000-04:00
    
    但是,当时钟超过02:00,我们切换回正常时间时,您的时间将是

    2009-10-26T1:10:00.0000000-05:00
    
    为了
    2009-10-26T1:10:00.0000000-05:00
    
    DateTime.Now.ToString("o")
    
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    -- =============================================
    -- Author:      Vivi Woolford
    -- Create date: 27-09-2016
    -- Description: This procedure only Works in New Zealand
    -- =============================================
    CREATE FUNCTION [dbo].[udf_GetLocalTimeFromUTC] 
    (   
        @UTCTime DATETIME
    )
    RETURNS DATETIME
    AS
    BEGIN
        --Daylight Saving commences on the last Sunday in September, when 2.00am becomes 3.00am. 
        --It ends on the first Sunday in April, when 3.00am becomes 2.00am.
        DECLARE @LocalTime DATETIME 
        DECLARE @OffSet INT = 12
    
        SELECT @LocalTime = DATEADD(HOUR, @OffSet, @UTCTime)
    
        IF @LocalTime BETWEEN 
        /*FINISH DAY LIGHT SAVINGS*/
        DATEADD(HOUR, 2, DATEADD(dd, (6-(DATEDIFF(dd,0,DATEADD(mm,(YEAR(@LocalTime)-1900) * 12 + 3,0))%7)),DATEADD(mm,(YEAR(@LocalTime)-1900) * 12 + 3,0)))
        AND     
        /*START DAY LIGHT SAVINGS*/
        DATEADD(HOUR, 2, DATEADD(dd, -1*(DATEPART(dw, DateAdd(day, -1, DateAdd(month, DateDiff(month, 0, @LocalTime)+1, 0)))-1),DateAdd(day, -1, DateAdd(month, DateDiff(month, 0, @LocalTime)+1, 0))))     
        BEGIN
            SELECT @LocalTime = @LocalTime 
        END 
        ELSE
        BEGIN
            SELECT @LocalTime = DATEADD(HOUR, 1, @LocalTime)
        END
    
        RETURN @LocalTime
    
    END
    
    GO
    
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    -- =============================================
    -- Author:      Vivi Woolford
    -- Create date: 27-09-2016
    -- Description: This procedure only Works in New Zealand
    -- =============================================
    ALTER FUNCTION [dbo].[udf_GetUTCFromLocalTime]
    (   
        @LocalTime DATETIME
    )
    RETURNS DATETIME
    AS
    BEGIN
        --Daylight Saving commences on the last Sunday in September, when 2.00am becomes 3.00am. 
        --It ends on the first Sunday in April, when 3.00am becomes 2.00am.
        DECLARE @UTCTime DATETIME   
        DECLARE @OffSet INT = 12
    
        IF @LocalTime BETWEEN 
        /*FINISH DAY LIGHT SAVINGS*/
        DATEADD(HOUR, 2, DATEADD(dd, (6-(DATEDIFF(dd,0,DATEADD(mm,(YEAR(@LocalTime)-1900) * 12 + 3,0))%7)),DATEADD(mm,(YEAR(@LocalTime)-1900) * 12 + 3,0)))
        AND     
        /*START DAY LIGHT SAVINGS*/
        DATEADD(HOUR, 2, DATEADD(dd, -1*(DATEPART(dw, DateAdd(day, -1, DateAdd(month, DateDiff(month, 0, @LocalTime)+1, 0)))-1),DateAdd(day, -1, DateAdd(month, DateDiff(month, 0, @LocalTime)+1, 0))))
        BEGIN
            SELECT @UTCTime = DATEADD(HOUR, -@OffSet, @LocalTime)
        END 
        ELSE 
        BEGIN
            SELECT @UTCTime = DATEADD(HOUR, -1-@OffSet, @LocalTime)
        END
    
        RETURN @UTCTime
    
    END
    go