Вопрос

Я использую UTC для хранения данных и значений времени в БД.Значения преобразуются в локальное время клиента или часового пояса клиента.Я наступил на эти сценарии с Статья MSDN, где отображение времени по всемирному координированному времени создает проблемы при переходе на летнее время.

Кто -то, живущий на восточном побережье Соединенных Штатов, в таком значении, как «26 октября 2003 г. 01:10:00».

1) В это конкретное утро из-за дневного сбережений, в 2:00 утра местные часы сбрасываются в 1:00 утра, создавая 25-часовой день.Поскольку все значения часа с 1:00 до 2:00 утра встречаются дважды в это конкретное утро - по крайней мере, в большинстве Соединенных Штатов и Канады, компьютер действительно не может узнать, какой 1:10 имел в виду - тот, который происходит до переключения, или тот, который происходит через 10 минут после переключения времени сэкономить дневное время.

2) Аналогично, проблема возникает весной, когда в определенное утро нет такого времени, как 2:10.Причина в том, что в 2:00 в это конкретное утро время на местных часах внезапно меняется до 3:00.Весь 2:00 часа никогда не происходит в этот 23-часовой день.

Как вы справились с ситуацией №1, когда у вас могло быть 4 транзакции: две до перехода и две после перехода на летнее время?Как отобразить пользователю время транзакций, поскольку последние две транзакции могут отображаться раньше, чем первые две транзакции из-за сдвига?Иногда это может оказаться нелогичным, например:в почтовой цепочке.

ДОБАВЛЕН:

Чтобы добавить дополнительную информацию о контексте, приложения RIA, такие как Silverlight/Flash, работающие на клиенте (или любое клиентское приложение, взаимодействующее с сервером через веб-сервис), позволяют пользователю выбирать время доставки или планировать ее с использованием местного времени компьютера.

Если бы я мог проверить заданное время ввода на предмет недопустимого времени, я, вероятно, мог бы предупредить пользователя.Кроме того, путешественникам часовой пояс необходимо определять в определенный момент времени, а не на основе выбора пользователя, поскольку они могут перемещаться между поясами, и сохранение часового пояса в профиле пользователя не поможет.

Некоторые тестовые образцы 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);  
Это было полезно?

Решение

Эти сценарии являются случаями, пропагандирующими использование летнего времени.Неважно, что ты отображать до тех пор, как вы магазин и Сортировать значения в формате UTC.То есть, если вы правильно используете UTC, проблемы, представленные в этих сценариях, будут решены.

Да, было бы странно увидеть такие записи:12:30, 1:20, 1:10, 3:30, но если они именно так упорядочены по UTC (что на самом деле произошло), то я думаю, что это правильный способ сделать это.

SO полностью избегает этой проблемы, записывая все в формате UTC, а затем отображая все это в формате UTC или относительном времени (например, «17 минут назад...»).


Если вы имеете в виду дату/время, предоставленные пользователем, как предложено в комментариях, у меня для вас плохие новости:это отстой.Я думаю, что лучшее и наиболее очевидное решение — это выбрать правило и следовать ему.Если вам действительно нужно идеально справиться с этим, ваш пользовательский интерфейс необходимо будет расширить, чтобы педантично обрабатывать этот крайний случай, который происходит всего 1 час каждый год, и то только для транзакций, созданных не в реальном времени (потому что, если бы они были реальными -время, вы знаете эквивалент летнего времени).

Другие советы

Вам необходимо сохранить смещение времени.

В настоящее время время на восточном побережье (формат туда и обратно)

2009-08-11T13:22:13.8493713-04:00

Даже если на восточном побережье считается -5, в летнее время время будет -4.

26 октября в 01:10 время будет

2009-10-26T1:10:00.0000000-04:00

но когда часы перейдут за 02:00 и мы перейдем обратно на обычное время, ваше время будет

2009-10-26T1:10:00.0000000-05:00

Для обработки смещения .NET, начиная с версии 2.0sp1, предлагает тип DateTimeOffset.Microsoft SQL Server 2008 также предлагает тип данных datetimeoffset это поможет вам сохранить это значение.Если вы не используете Microsoft SQL Server 2008, вы можете сохранить дату в виде строки, используя формат туда и обратно:

DateTime.Now.ToString("o")

Как отобразить пользователю время транзакций, поскольку последние две транзакции могут отображаться раньше, чем первые две транзакции из-за сдвига?Иногда это может оказаться нелогичным, например:в почтовой цепочке.

Отсортируйте их по UTC и отобразите по местному времени.

Таким образом, пользователь может увидеть такой список:

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

Либо так, либо покажи и отсортируйте их по UTC.

Если у вас есть кто-то, кто вводит данные вручную, удачи, если только он не введет их по времени UTC.На самом деле не существует «правильного» способа справиться с этим.Если вы имеете дело с датами, которые не вводятся пользователем, например, когда произошла транзакция, просто сохраните их в формате UTC, и жизнь прекрасна.:)

В целом ваш вопрос состоит из двух частей:

  1. Получение пользовательских данных
  2. Отображение данных пользователям

С этими двумя ситуациями следует обращаться одинаково, но в некотором смысле они имеют разные обходные пути.Что касается 1, то самый простой вариант — выяснить, действительно ли ваш бизнес требует однозначного способа указания времени в конкретном часе.Многие приложения просто игнорируют это (когда вы в последний раз использовали селектор даты, в котором была предусмотрена такая возможность?) и просто предполагают, что любого последовательного алгоритма угадывания будет достаточно.Вы должны обеспечить защиту (т.выдать ошибку), если введен несуществующий час.

Что касается 2, пропущенный час не имеет значения, поскольку ваша база данных находится в формате UTC.Час повторения может сбивать с толку, особенно если учесть множество временных меток.Если оно того стоит, рассмотрите возможность форматирования строки даты с использованием идентификатора часового пояса, который включает ссылку на смещение летнего времени.Самый старый стиль, т.е.это не Олсон, названия часовых поясов включают это (EST против EDT, GMT против BST и т. д.).Этого будет достаточно для устранения неоднозначности в крайнем случае.Вероятно, это все, что вам нужно, поскольку этот граничный случай, возможно, не стоит слишком портить дисплей.Если вам нужно немного больше вывода, вы также можете отформатировать временную метку со смещением UTC, что сделает переключение очень однозначным в цепочке временных меток.

В SQL Server есть новый тип datetimeoffset, который хорошо справляется с этой задачей, поскольку вы можете иметь одно и то же время с разными смещениями.Для моей базы данных SQL Server 2005 я использую строковый литерал этого типа, nvarchar(25) формы «ГГГГ-ММ-ДД чч:мм:сс-чч:мм».

Для этого я создал процедуры для преобразования этих строк в правильное время.

Я решил эту проблему для новозеландского времени, как показано ниже:

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top