2012-09-05 1 views
6

Мое приложение должно собирать покупки «во вторник» для всех мест по всему миру, где «Tueday» - это вторник во вторник (независимо от часового пояса). И если пользователю нужно повторно запустить отчет на следующей неделе, мне нужно все же получить данные «последнего вторника». Все наши данные хранятся с использованием DateTimeOffset.SQL Server DateTimeOffset соответствует одному и тому же «дню»

Так 9/4/12 00:00:00 -7 через 9/4/12 23:59:59 -7 должен СООТВЕТСТВУЕТ 9/4/12 00:00:00 +11 через 9/4/12 23:59:59 +11 , когда я выполняю предложение WHERE.

Я не могу конвертировать в UTC в предложение WHERE, потому что это заберет данные для «Вторника» в Лондоне (в зависимости от DST), а не во вторник.

Я пробовал конвертировать из DateTimeOffset в DateTime, но это, похоже, конвертируется в UTC. (В моих тестах, прохождение 9/1/12 по 9/30/12 взяло данные 8/31/12.)

Есть ли трюк, чтобы сделать что-то подобное с TSQL?

Спасибо!

+0

Чтобы уточнить, у каждого местоположения 'datetime' есть другой часовой пояс? – Kermit

ответ

2

ИМХО

DateTimeOffset = DateTime + Offset (от UTC)

Так что ваши данные уже представляющие местное время и дату Клиента. Просто добавьте его в DateTime, и вы получите локальную дату и время клиента.

Но в-том случае, если вы хотите добавить Offset к DateTime и хотите результирующую DATETIME затем

DECLARE @PurchaseDate DATETIMEOFFSET(7) = CAST('2007-05-08 12:30:29.1234567 +5:00' AS datetimeoffset(7)) 

SELECT CAST(SWITCHOFFSET (@PurchaseDate , '+00:00') AS DATETIME) 

взглянуть на этот блог для получения дополнительной информации.

http://blogs.msdn.com/b/bartd/archive/2009/03/31/the-death-of-datetime.aspx

+2

'SWITCHOFFSET' настраивает' DATETIMEOFFSET' в другой часовой пояс, но по-прежнему относится к одному и тому же фактическому моменту времени.Я считаю, что ваш пример SELECT на самом деле просто покажет время UTC для первоначальной покупки, а не местное время по мере необходимости. (Первая часть вашего ответа верна для вопроса. Вторая часть, возможно, не связана, но может вводить в заблуждение по заданному вопросу.) –

+0

Как, черт возьми, это можно сделать в Entity Framework 6? Кажется, нет никакого способа получить или сравнить DateTime часть DateTimeOffset. Он не поддерживает DateTime.Date и DateTimeOffset.DateTime, поэтому нет возможности сделать это. Самое близкое к этому - DbFunctions.TruncateTime (но не TruncateOffset), и он все равно создает неприятный SQL. – Triynko

1

При наложении DATETIMEOFFSET, как DATETIME он принимает дату и время , как смещение в значении и просто падает часовой пояс. То же самое верно при литье как DATE или TIME. Так что, я думаю, вы можете просто бросить столбец как DATE и сравнить его с даты только значение, которое вы хотите, чтобы соответствовать:

DECLARE @targetDate DATETIME2 = '2012-09-04' --Or we could use DATE here 
SELECT [PurchaseId], [PurchaseTime], CAST([PurchaseTime] AS DATE) AS "PurchaseDate" 
FROM [Purchases] 
WHERE CAST([PurchaseTime] AS DATE) = @targetDate 

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

DECLARE @targetDate DATETIME2 = '2012-09-04' --DATETIME2 so we can adjust by hours 
SELECT [PurchaseId], [PurchaseTime], CAST([PurchaseTime] AS DATE) AS "PurchaseDate" 
FROM [Purchases] 
WHERE CAST([PurchaseTime] AS DATE) = @targetDate --Keep only the local-date matches 
    AND [PurchaseTime] >= DATEADD(hh, -14, @targetDate) --Up to 14-hour time zone offset 
    AND [PurchaseTime] <= DATEADD(hh, 38, @targetDate) --24 hours later plus 14 

это должно эффективно индекс вниз к набору возможностей, а затем фильтровать должным образом на переход на локальную дату. Обратите внимание, что смещения часовых поясов могут составлять до 14 часов (Новая Зеландия наиболее далека, я знаю по +13: 00, но они могут идти до +/- 14:00 в соответствии с MSDN), а @targetDate будет в начале день, поэтому он сравнивается с 14 часами ранее и 24 + 14 = 38 часов спустя. DATETIME2 имеет тот же диапазон и точность, что и DATETIMEOFFSET, поэтому для этой цели лучше, чем исходный DATETIME (но он может также работать нормально с DATETIME).

+0

Как это влияет на индексы в поле DateTimeOffset? Как только вы бросаете столбец, разве это не предотвращает использование индекса? Я начинаю думать, что DateTimeOffset бесполезен, и нам лучше хранить как локальные DateTime, так и UTC DateTime. – Triynko

+0

@ Трийнко, поэтому я предложил ограничить исходное значение столбца. В моем примере используется DATETIME2, инициализированный как простая дата (означающая Midnight, начинающаяся с этой даты) и скорректированная с максимальным смещением часового пояса на обоих концах, чтобы сузить столбец '[PurchaseTime] DATETIMEOFFSET' (предположительно индексированный) до диапазона' @ targetDate' может подпадать под любое местное время покупки. DATETIMEOFFSET сравниваются друг с другом по абсолютному (UTC) времени не по местному представлению времени, поэтому он должен работать. Тест локального преобразования применяется к этим совпадениям. Экспериментируйте дальше, если вам интересно. –