Pergunta

Os exemplos para Cache.Adicionar usa DateTime.Now.Add para calcular a data de validade, i.é.ele passa:

 DateTime.Now.AddSeconds(60)

como o valor do absoluteExpiration o parâmetro.

Eu teria pensado que a computação é em relação à DateTime.UtcNow seria mais correto [como não há nenhuma ambigüidade se o Horário de Verão começa no decorrer do tempo entre agora e o ponto de expiração].

Antes da introdução do DateTimeKind, Eu teria adivinhado que há alguns truques feios no gerenciamento de cache para ele fazer algo apropriado se o tempo não foi de uma hora UTC.

Em .NET 2.0 e, mais tarde, eu estou supondo que ele deve lidar com um DateTime calculado como DateTime.UtcNow.AddSeconds(60) corretamente, dado que ele tem DateTime.Kind para utilização como insumo em suas inferências.

Eu tenho confiança, usando DateTime.UtcNow como base para anos, mas não era capaz de vir até com uma lógica que, definitivamente, esta é a coisa correta a fazer, na ausência de algo apontando a documentação foi altamente enganosa, por 4 anos.

Perguntas?

  1. Apesar de muito bingage e pesquisando eu não era capaz de encontrar qualquer autoritário discussão sobre isso a partir do MS - alguém pode localizar algo sobre isso?
  2. Há alguma razão por que usar UtcNow não seria mais correto e/ou seguro?

(Sim, eu poderia examinar a origem e/ou o Refletor gostaria de origem, mas estou olhando para um total de golpe por golpe de verdade!)

Foi útil?

Solução

EU relatou este bug na Microsoft Connect Algum tempo atrás, mas foi fechado como não será corrigido.

Você ainda tem um problema no .NET 2.0 se especificar sua expiração absoluta no horário local.

Durante uma hora no final do horário de verão, sua hora local é ambígua, para que você possa obter resultados inesperados, ou seja, a expiração absoluta pode ser uma hora a mais do que o esperado.

Na Europa, o horário de verão terminou às 02:00 de 25 de outubro de 2009. A amostra abaixo ilustra que, se você colocasse um item no cache às 01:59 com uma expiração de 2 minutos, permaneceria no cache por uma hora e dois minutos.

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());

A solução alternativa para .NET 2.0 ou posterior é especificar o tempo de validade absoluto no UTC, conforme apontado por Ruben.

A Microsoft talvez deva recomendar o UTC nos exemplos de expiração absoluta, mas acho que existe o potencial de confusão, pois essa recomendação é válida apenas para .NET 2.0 e posterior.

EDITAR

Dos comentários:

Mas a exposição ocorre apenas se a conversão ocorrer durante a sobreposição. A única conversão que realmente ocorre é quando você apresenta o item com cache.add

O problema só acontecerá se você inserir um item no cache com um tempo absolutexpirexpirante no horário local durante aquela hora ambígua no final do horário de verão.

Por exemplo, se o seu fuso horário local for a Europa Central (GMT+1 no inverno, GMT+2 no verão) e você executa o seguinte código às 01:59:00 em 25 de outubro de 2009:

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

Em seguida, o item permanecerá no cache por uma hora e dois minutos, em vez dos dois minutos que você normalmente esperaria. Isso pode ser um problema para algumas aplicações altamente críticas (por exemplo, ticker de ações, quadro de partidas aéreas).

O que está acontecendo aqui é (assumindo o tempo europeu, mas o princípio é o mesmo para qualquer fuso horário):

  • DateTime.now = 2009-10-25 01:59:00 Local. Local = GMT+2, então UTC = 2009-10-24 23:59:00

  • .Addminutes (2) = 2009-10-25 02:01:00 Local. Local = GMT+1, então UTC = 2009-11-25 01:01:00

  • Cache.add Converte internamente o tempo de expiração para UTC (2009-11-25 01:01:00), portanto a expiração é uma hora e dois minutos antes do horário atual do UTC (23:59:00).

Se você usar o DateTime.utcnow no lugar do DateTime.now, a expiração do cache será de dois minutos (.NET 2.0 ou posterior):

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

Dos comentários:

Ou eu estou esquecendo de alguma coisa?

Não, você não é. Sua análise está no local e se o seu aplicativo for crítico e executar durante esse período no final do DST, você está certo em usar o DateTime.utcNow.

A declaração na resposta de Ruben que:

você é seguro para usar desde que o tipo no tempo que você forneça seja definido

está incorreto.

Outras dicas

Cache.Add converte a data de validade no UTC antes de armazená -lo.

Do refletor (eu omiti a maioria dos parâmetros para facilitar a leitura):

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

Dentro CacheExpires.FlushExpiredItems, utcAbsoluteExpiration é comparado a DateTime.UtcNow. Como Joe observa em sua resposta, isso causa comportamento inesperado quando a adição e a expiração de um item de cache abrangem o final do horário de verão.

[Altamente derivados de percepções de Jeff Esternal a resposta, que eu tenho um +1 no pagamento incompleto :D]

Parece que em 1.1 (não se parecia em 1.0, mas eu suponho que seu similar), na ausência de um DateTime.Kind e tendo publicado exemplos com um DateTime.Now-tempo relativo, eles se sentem confortáveis imediatamente chamar ToUniversalTime() imediatamente.

Daí...

  1. em 1.x, você vai acabar com a bagunça, se você [o usuário da API] uso DateTime.UtcNow (e há uma sensibilidade ao horário de partida durante a chamada para Cache.Add)

  2. no 2.0 [e 3.x], você está seguro (a) para utilizar enquanto a Kind o tempo de abastecimento é definida [que normalmente seria se você tem o tempo de DateTime.Now ou UtcNow].[Ver Joe comentários e resposta para a plena justificação], Definitivamente, prefiro UtcNow como ambigüidade para 1 hora de DST transição.

  3. O exemplo permanece como-é assim que as pessoas que trabalham contra 1.x não seja enganado [e as pessoas podem continuar fingindo que DST é um maluco caso de borda :P].[Idem, como apontado por Joe], Mas isso é muito discutível postura, pois isso pode resultar em coisas ficam no cache por uma hora extra.

Eu ainda estou muito interessado em ouvir mais detalhes, incluindo qualquer partir de qualquer Pôneis lá fora.

EDITAR:Eu sei que a partir de Joe comentários que eu não chamar explicitamente o fato de que ele é definitivamente mais correto usar UtcNow se utilizar 2.0 ou posterior como a pessoa está exposta ao risco de o item ser armazenada em cache para uma hora extra durante a hora de verão 'marmota hora'.Eu também acho que a MS doc deve apontar este fato fora (com a ressalva de que eles precisam de mencionar que esta não se aplicar ao 1.1 [independentemente se a página está marcada 2.0+ específico].Graças A Joe.

EDITAR:Noda Vez, vai ter arrumado wrapper para fazer este infalível :D

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top