Cache.Add абсолютный срок действия - на основе UTC или нет?

Примеры дляCache.Add использованияDateTime.Now.Add чтобы вычислить срок действия, то есть он передает:

 DateTime.Now.AddSeconds(60)

в качестве значенияabsoluteExpiration parameter.I»

Я думал, что вычисление его относительноDateTime.UtcNow было бы более правильно [так как нет никакой двусмысленности, если летнее время начинается в промежуточное время между настоящим моментом и точкой истечения срока].

До введенияDateTimeKindЯя бы догадался, чтоНекоторые уродливые хаки в управлении кешем заставляют его делать что-то подходящее, если время не было временем UTC.

В .NET 2.0 и более позднихЯ предполагаю, что он должен обрабатыватьDateTime рассчитывается какDateTime.UtcNow.AddSeconds(60) правильно, учитывая, что он имеетDateTime.Kind использовать в качестве входных данных в своих выводах.

уверенно использовалDateTime.UtcNow в качестве базы в течение многих лет, но не смог придумать обоснование того, что это определенно правильная вещь, если ничего не указывать на то, что документация вводит в заблуждение более 4 лет.

Вопросы?

Несмотря на то, что я много гулял и гуглил, мне не удалось найти какого-либо авторитетного обсуждения этого вопроса от MS - может кто-нибудь найти что-нибудь по этому поводу?Есть ли причина, по которой использование UtcNow не будет более правильным и / или безопасным?

(Да, я мог бы просмотреть источник и / или рефлекторd источник, но я ищу полное снижение за ударом!) Я

Ответы на вопрос(3)

Cache.Add преобразует дату истечения срока в UTC перед сохранением.

От отражателя (ямы пропустили большинство параметров, чтобы их было легче читать):

public object Add(... DateTime absoluteExpiration ...)
{
    DateTime utcAbsoluteExpiration = DateTimeUtil.ConvertToUniversalTime(absoluteExpiration);
    return this._cacheInternal.DoInsert(... utcAbsoluteExpiration ...);
}

В ,CacheExpires.FlushExpiredItemsutcAbsoluteExpiration по сравнению сDateTime.UtcNow, КакДжо отмечает в своем ответе, это вызывает неожиданное поведение, когда элемент кэшаs добавление и истечение срока действия в конце летнего времени.

 Ruben Bartelink06 нояб. 2009 г., 17:46
Хорошо сделано! Я так понимаю,на 3.5SP1. Есть идеи по 2.0 raw, 1.0? Есть лиDateTimeUtil.ConvertToUniversalTime делать что-то большее, чем простой призыв кDateTime.ToUniversalTime когдаKind==DateTimeKind.Local? Да, я должен загрузить Reflector. Loading ...
 Jeff Sternal06 нояб. 2009 г., 17:49
Благодарю. У меня действительно есть постоянный интерес к внутренним действиям cahce:stackoverflow.com/questions/1434284/..., :) Это был фактически фреймворк 2.0. У меня нетЯ посмотрел на остальных, но я жду результатов вашего расследования!
 Ruben Bartelink06 нояб. 2009 г., 17:53
Ах,DateTime.ToUniversalTime и у друзей есть стека хаков столько, сколько ваша рука, которая молча исправляет вещи (в 1.x безDateTime.KindЯя уверен, что это было более интересно - IIRC всегда корректировался, и, следовательно, вам нужно было быть более осторожным, называя это?).

[Высоко производная идеи от Джеффа Стернала 'ответ, который яве +1 'г в неполный платеж: D]

Кажется, что в 1.1 (не смотрел на 1.0, но я предполагаю, что это похоже), в отсутствиеDateTime.Kind и опубликовав примеры сDateTime.Now-относительно времени, они чувствуют себя комфортно, сразу звонятToUniversalTime() немедленно.

Следовательно ...

в 1.х тыВы получите беспорядок, если вы [пользователь API] используетеDateTime.UtcNow (и там'чувствительность к летнему времени, начинающаяся во время разговора с)Cache.Add

в 2.0 [и 3.x], вы 'безопасно использовать либо до тех пор, покаKind на время, которое вы поставляете установлено [что обычно было бы, если вы получили время отDateTime.Now или жеUtcNow]. [Смотрите Джоs комментарии и ответ для полного обоснования] Определенно предпочитаюUtcNow как неопределенность в течение 1 часа переключения DST.

Пример остается неизменным, поэтому люди, работающие против 1.x, не будут введены в заблуждение [и люди могут продолжать притворяться, что DST - дурацкий крайний случай: P]. [То же самое, как отметил Джо] Но это очень спорная позиция, поскольку это может привести к тому, что материал останется в кеше в течение дополнительного часа.

Мне по-прежнему очень интересно услышать больше подробностей, в том числе от Пони.

РЕДАКТИРОВАТЬ: я понимаю, от Джокомментарии, которые я не сделалт явно напомнить тот факт, что этоявляется определенно правильнее использоватьUtcNow при использовании 2.0 или более поздней версии, поскольку существует риск кэширования элемента в течение дополнительного часа в течение летнего времени.час сурка ', Я также думаю, что документ MS должен указать на этот факт (при условии, что им нужно упомянуть, что это не относится к 1.1 [независимо от того, помечена ли страница как 2.0+). Спасибо, Джо.

РЕДАКТИРОВАТЬ: Noda Time будет иметь аккуратную оболочку, чтобы сделать это надежно: D

 Ruben Bartelink07 нояб. 2009 г., 14:32
Перечитывая ... @Joe: AIUI [через Reflector] преобразование, которое использует ToUniversalTime, учитывает разницу во времени, следовательно, до тех пор, пока не произойдет переключение между точкой, в которой вы вызываете DateTime.Now (которая всегда будет корректироваться для Летнее время) и когда вызывается DateTime.ToUniversalTime, вы 'безопасно. то есть, существует путаница в том, что 2:05 означает для человека после факта, но не для машины, которая выполняет преобразование в определенный момент времени. Или ты все еще чувствуешь меняя не прав?
 Ruben Bartelink07 нояб. 2009 г., 14:21
@Joe: AIUI единственная проблема заключается в том, что вы помещаете запись absoluteExpiration с местным временем в 1: 59: 59.999 и Cache.Add [косвенно] выполняет преобразование после переключения. Во всех других случаях он знает DateTimeKind того времени, когда выпереопределяет и использует это, чтобы преобразовать (или нет) время в Utc для его внутреннего использования. Вы смотрели на код?
 Joe07 нояб. 2009 г., 15:21
... ToUniversalTime ... учитывает разницу во времени ", Нет, он учитывает дифференциал, относящийся кDateTime вы 'переконвертировать, а не текущая разница во время вызова ToUniversalTime. "
 Jeff Sternal06 нояб. 2009 г., 18:05
Интересно, яПридется присмотреться к 1.1, когда у меня будет время на этих выходных ».
 Ruben Bartelink08 нояб. 2009 г., 00:00
Ах, я снял это слишком быстро. Вы'на 100% правильно (и я должен был понять это из вашего примера, извините!).
 Joe07 нояб. 2009 г., 15:25
Существует путаница в том, что 2:05 означает для человека ", Для машины тоже есть неясность. Следуя примеру европейского времени, 02:05 в конце летнего времени может быть 00:05 UTC (GMT + 2) или 01:05 UTC (GMT + 1). Когда вы конвертируете 02:05 локальный в UTC, он должен выбрать один из них - фактически он выбирает 01:05 (без DST).
 Joe07 нояб. 2009 г., 11:30
n 2.0 ... тыбезопасно использовать либо - нет В конце летнего времени местное время неоднозначно для одного часа в год, поэтому, если вы укажете местное время в течение этого часа, вы можете выйти на один час. Смотри мой ответ.
Решение Вопроса

сообщил об этой ошибке в Microsoft Connect некоторое время назад, но этобыл закрыт как выигралт исправить.

У вас все еще есть проблема в .NET 2.0, если вы указываете свое абсолютное истечение по местному времени.

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

В Европе переход на летнее время закончился 25 октября 2009 года в 02:00. Пример ниже показывает, что если вы поместите элемент в кэш в 01:59 с истечением 2 минут, он будет оставаться в кэше в течение одного часа и пару минут.

DateTime startTime = new DateTime(2009, 10, 25, 1, 59,0);
DateTime endTime = startTime.AddMinutes(2);
// end time is two minutes after start time

DateTime startUtcTime = startTime.ToUniversalTime();
DateTime endUtcTime = endTime.ToUniversalTime();
// end UTC time is one hour and two minutes after start UTC time

Console.WriteLine("Start UTC time = " + startUtcTime.ToString());
Console.WriteLine("End UTC time = " + endUtcTime.ToString());

Обходной путь для .NET 2.0 или более поздней версии - указать абсолютное время истечения в UTC, как указал Рубен.

Возможно, Microsoft следует рекомендовать использовать UTC в примерах для абсолютного истечения срока действия, но я предполагаю, что существует вероятность путаницы, поскольку эта рекомендация действительна только для .NET 2.0 и более поздних версий.

РЕДАКТИРОВАТЬ

Из комментариев:

Но экспозиция происходит только в том случае, если преобразование происходит во время перекрытия. Единственное преобразование, которое действительно происходит, - это когда вы помещаете элемент в Cache.Add

Проблема возникнет только в том случае, если вы вставите элемент в кэш со временем AbsoluteExpiration по местному времени в течение этого одного неоднозначного часа в конце летнего времени.

Например, если ваш местный часовой пояс - центральноевропейский (GMT + 1 зимой, GMT + 2 летом), и вы выполните следующий код в 01:59:00 25 октября 2009 года:

DateTime absoluteExpiration = DateTime.Now.AddMinutes(2);
Cache.Add(... absoluteExpiration ...)

затем элемент останется в кеше в течение одного часа и двух минут, а не двух минут, которые вы обычно ожидаете. Это может быть проблемой для некоторых срочных приложений (например, биржевой тикер, табло вылетов авиакомпаний).

Какие'здесь происходит (при условии европейского времени, но принцип одинаков для любого часового пояса):

DateTime.Now = 2009-10-25 01:59:00 по местному времени. местное = GMT + 2, поэтому UTC = 2009-10-24 23:59:00

.AddMinutes (2) = 2009-10-25 02:01:00 по местному. местное = GMT + 1, поэтому UTC = 2009-11-25 01:01:00

Cache.Add внутренне преобразует время истечения в UTC (2009-11-25 01:01:00), поэтому срок истечения на один час и две минуты опережает текущее время UTC (23:59:00).

Если вместо DateTime.Now вы используете DateTime.UtcNow, срок действия кэша составит две минуты (.NET 2.0 или более поздняя версия):

DateTime absoluteExpiration = DateTime.UtcNow.AddMinutes(2);
Cache.Add(... absoluteExpiration ...)

Из комментариев:

Или я что-то упустил?

Не ты'нет. Ваш анализ точен, и если ваше приложение критично ко времени и работает в течение этого периода в конце летнего времени, вы 'правильно использовать DateTime.UtcNow.

Утверждение в Рубенеответь что:

вы'Вы можете безопасно использовать любой из них, пока установлен Вид на время, которое вы предоставляете

это неверно.

 Jeff Sternal08 нояб. 2009 г., 02:17
@ Джо - ты неправильно объяснил мне несколько вещей, поэтому яотредактировал ваш ответ, чтобы исправить их (кроме этого, хорошая находка).
 Canacourse09 сент. 2011 г., 11:01
В .net 4.0 поток, который удаляет элементы, которые достигли или прошли AbsoluteExpirationTime, работает только в LocalTime.
 Ruben Bartelink07 нояб. 2009 г., 14:46
@Joe: +1 повторяю ссылку на элемент Connect: я согласен, что это ошибка с документом
 Jordan Rieger01 авг. 2011 г., 20:35
MSDN теперь обновил документацию по этому методу, чтобы предложить, чтобы все абсолютные истечения времени были переданы в формате UTC ... Кроме того, на случай, если кто-то из них задался вопросом, как и я: после просмотра кода в ILSpy я могу подтвердить Метод ToUniversalTime достаточно умен, чтобы сначала проверить, указано ли время в формате UTC, и, если это так, вернуть его без изменений. Таким образом, нет недостатка в преобразовании времени в UTC перед его передачей.
 Ruben Bartelink07 нояб. 2009 г., 14:28
@Joe: я согласен, что случай, который вы представили выше, является правильным. Но экспозиция происходит только в том случае, если преобразование происходит во время перекрытия. Единственное преобразование, которое действительно происходит, - это когда вы помещаете элемент в Cache.Add. Я'Я не уверен, что вы указываетеВы приписываете Джеффу лучшую политику - указывать срок действия на основе Utc или как документы должны покрывать его - разве это не точка, которую я сделал в своем ответе [для себя]? Или я что-то упустил? (Я понимаю коренную проблему, поэтому я поднял вопрос в первую очередь)

Ваш ответ на вопрос