E se você quiser calcular um tempo relativo de agora para o futuro?
Jhonny D. Cano -Leftware-
2
moment.js é uma biblioteca de análise de datas muito boa. Você pode considerar usá-la (servidor ou cliente), dependendo de suas necessidades. apenas fyi porque ninguém mencionou aqui #
Eu odeio essas constantes com uma paixão. Isso parece errado para alguém? Thread.Sleep(1 * MINUTE)? Porque está errado por um fator de 1000.
Roman Starkov
31
const int SECOND = 1;Um segundo tão estranho é um segundo.
seriousdev
62
Esse tipo de código é quase impossível de localizar. Se seu aplicativo precisar permanecer apenas em inglês, tudo bem. Mas se você pular para outros idiomas, você se odiará por fazer uma lógica como essa. Só assim vocês sabem ...
Nik Reiman
73
Eu acho que se as constantes fossem renomeadas para descrever com precisão o valor que está nelas, seria mais fácil entender. Então SecondsPerMinute = 60; MinutesPerHour = 60; SecondsPerHour = MinutesPerHour * SecondsPerHour; etc. Apenas chamá-lo de MINUTE = 60 não permite que o leitor determine qual é o valor.
Slolife 29/08/12
14
Por que ninguém (exceto Joe) se importa com o valor errado de 'Ontem' ou 'dias atrás' ??? Ontem não é um cálculo de hora, mas um cálculo diário. Então, sim, este é um código errado, pelo menos em dois casos frequentes.
Jeff, como o Stack Overflow usa o jQuery extensivamente, eu recomendo o plugin jquery.timeago .
Benefícios:
Evite carimbos de data e hora datados de "1 minuto atrás", mesmo que a página tenha sido aberta há 10 minutos; O timeago é atualizado automaticamente.
Você pode aproveitar ao máximo o cache de páginas e / ou fragmentos em seus aplicativos da Web, porque os carimbos de data e hora não são calculados no servidor.
Você pode usar microformatos como as crianças legais.
Basta anexá-lo aos seus registros de data e hora no DOM pronto:
Se você tiver o Javascript desativado, a string que você colocou originalmente entre as tags abbr será exibida. Normalmente, essa é apenas uma data ou hora, em qualquer formato que você desejar. Timeago degrada graciosamente. Não fica muito mais simples.
Heh, obrigado Rob. Tudo bem. É quase imperceptível, especialmente quando apenas um número é alterado durante a transição, embora as páginas SO tenham muitos registros de data e hora. Eu teria pensado que ele teria pelo menos apreciado os benefícios do cache de páginas, mesmo se ele escolher evitar atualizações automáticas. Tenho certeza de que Jeff também poderia ter fornecido feedback para melhorar o plugin. Tomo consolo sabendo que sites como o arstechnica.com o usam.
21719 Ryan McGeary
19
@Rob Fonseca-Ensor - agora está me fazendo chorar também. Como é uma atualização uma vez por minuto, para mostrar informações precisas, de alguma forma relacionadas ao texto piscando uma vez por segundo?
precisa
25
A questão é sobre c #, não consigo ver como um plugin jQuery é relevante.
"<48 * 60 * 60s" é uma definição pouco convencional para "ontem". Se forem 9 da manhã de quarta-feira, você pensaria realmente das 9:01 da segunda-feira como "ontem". Eu pensaria que um algoritmo de ontem ou "n dias atrás" deveria considerar antes / depois da meia-noite.
211 Joe Joe
139
Compiladores são geralmente muito bom em expressões constantes pré-cálculo, como 24 * 60 * 60, para que você pode usar diretamente aqueles em vez de calcular-lo sozinho para ser 86400 e colocando a expressão original em comentários
zvolkov
11
@bzlm Acho que fiz para um projeto em que estava trabalhando. Minha motivação aqui foi alertar outras pessoas que semanas foram omitidas nesse exemplo de código. Quanto a como fazer isso, parecia bastante direto para mim.
Jray #
9
Eu acho que a boa maneira de melhorar o algoritmo é exibir duas unidades como "2 meses 21 dias atrás", "1 hora e 40 minutos atrás" para aumentar a precisão.
Evgeny Levin
5
@ Jeffy, você perdeu o cálculo para ano e relacionados cheques bissextos
Saboor Awan
92
publicstaticstringRelativeDate(DateTime theDate){Dictionary<long,string> thresholds =newDictionary<long,string>();int minute =60;int hour =60* minute;int day =24* hour;
thresholds.Add(60,"{0} seconds ago");
thresholds.Add(minute *2,"a minute ago");
thresholds.Add(45* minute,"{0} minutes ago");
thresholds.Add(120* minute,"an hour ago");
thresholds.Add(day,"{0} hours ago");
thresholds.Add(day *2,"yesterday");
thresholds.Add(day *30,"{0} days ago");
thresholds.Add(day *365,"{0} months ago");
thresholds.Add(long.MaxValue,"{0} years ago");long since =(DateTime.Now.Ticks- theDate.Ticks)/10000000;foreach(long threshold in thresholds.Keys){if(since < threshold){TimeSpan t =newTimeSpan((DateTime.Now.Ticks- theDate.Ticks));returnstring.Format(thresholds[threshold],(t.Days>365? t.Days/365:(t.Days>0? t.Days:(t.Hours>0? t.Hours:(t.Minutes>0? t.Minutes:(t.Seconds>0? t.Seconds:0))))).ToString());}}return"";}
Prefiro esta versão por sua concisão e capacidade de adicionar novos pontos de verificação. Isso pode ser encapsulado com uma Latest()extensão do Timespan em vez do longo forro, mas por uma questão de brevidade na postagem, isso funcionará.
Isso corrige uma hora atrás, uma hora atrás, fornecendo uma hora até duas horas decorridas
Estou recebendo todos os tipos de problemas usando essa função, por exemplo, se você zombar de 'theDate = DateTime.Now.AddMinutes (-40);' Estou recebendo '40 horas atrás', mas com a resposta do código refactormy de Michael, ele retorna correto em '40 minutos atrás'?
GONeale
Eu acho que você está perdendo um zero, tente: desde que = (DateTime.Now.Ticks - theDate.Ticks) / 10000000;
robnardo
8
Hmm, enquanto esse código pode funcionar, é incorreto e inválido supor que a ordem das chaves no Dicionário esteja em uma ordem específica. O dicionário usa o Object.GetHashCode () que não retorna um longo, mas um int !. Se você deseja que elas sejam classificadas, use um SortedList <long, string>. O que há de errado com os limites que estão sendo avaliados em um conjunto de if / else if /.../ else? Você obtém o mesmo número de comparações. FYI o hash por long.MaxValue acaba sendo o mesmo que int.MinValue!
precisa saber é o seguinte
O OP esqueceu t.Dias> 30? t.Days / 30:
Lars Holm Jensen
Para corrigir o problema mencionado por @CodeMonkeyKing, você pode usar um em SortedDictionaryvez de um simples Dictionary: o uso é o mesmo, mas garante que as chaves sejam classificadas. Mas, mesmo assim, o algoritmo tem falhas, porque RelativeDate(DateTime.Now.AddMonths(-3).AddDays(-3))retorna "95 meses atrás" , independentemente do tipo de dicionário que você está usando, o que está incorreto (ele deve retornar "há 3 meses" ou "4 meses atrás", dependendo de qual limite você ' reutilizando) - mesmo que -3 não crie uma data no ano passado (testei isso em dezembro, portanto, nesse caso, isso não deve acontecer).
staticreadonlySortedList<double,Func<TimeSpan,string>> offsets =newSortedList<double,Func<TimeSpan,string>>{{0.75, _ =>"less than a minute"},{1.5, _ =>"about a minute"},{45, x => $"{x.TotalMinutes:F0} minutes"},{90, x =>"about an hour"},{1440, x => $"about {x.TotalHours:F0} hours"},{2880, x =>"a day"},{43200, x => $"{x.TotalDays:F0} days"},{86400, x =>"about a month"},{525600, x => $"{x.TotalDays / 30:F0} months"},{1051200, x =>"about a year"},{double.MaxValue, x => $"{x.TotalDays / 365:F0} years"}};publicstaticstringToRelativeDate(thisDateTime input){TimeSpan x =DateTime.Now- input;stringSuffix= x.TotalMinutes>0?" ago":" from now";
x =newTimeSpan(Math.Abs(x.Ticks));return offsets.First(n => x.TotalMinutes< n.Key).Value(x)+Suffix;}
isso é muito bom IMO :) Isso também pode ser refatorado como um método de extensão? o dicionário pode se tornar estático, de modo que é criado apenas uma vez e referenciado a partir de então?
Você provavelmente desejaria extrair esse dicionário para um campo para reduzir a instanciação e a rotatividade do GC. Você teria que mudar Func<string>para Func<double>.
de Drew Noakes
49
Aqui está uma implementação que eu adicionei como método de extensão à classe DateTime que lida com datas futuras e passadas e fornece uma opção de aproximação que permite especificar o nível de detalhe que você está procurando ("3 horas atrás" vs "3 horas, 23 minutos, 12 segundos atrás "):
usingSystem.Text;/// <summary>/// Compares a supplied date to the current date and generates a friendly English /// comparison ("5 days ago", "5 days from now")/// </summary>/// <param name="date">The date to convert</param>/// <param name="approximate">When off, calculate timespan down to the second./// When on, approximate to the largest round unit of time.</param>/// <returns></returns>publicstaticstringToRelativeDateString(thisDateTimevalue,bool approximate){StringBuilder sb =newStringBuilder();string suffix =(value>DateTime.Now)?" from now":" ago";TimeSpan timeSpan =newTimeSpan(Math.Abs(DateTime.Now.Subtract(value).Ticks));if(timeSpan.Days>0){
sb.AppendFormat("{0} {1}", timeSpan.Days,(timeSpan.Days>1)?"days":"day");if(approximate)return sb.ToString()+ suffix;}if(timeSpan.Hours>0){
sb.AppendFormat("{0}{1} {2}",(sb.Length>0)?", ":string.Empty,
timeSpan.Hours,(timeSpan.Hours>1)?"hours":"hour");if(approximate)return sb.ToString()+ suffix;}if(timeSpan.Minutes>0){
sb.AppendFormat("{0}{1} {2}",(sb.Length>0)?", ":string.Empty,
timeSpan.Minutes,(timeSpan.Minutes>1)?"minutes":"minute");if(approximate)return sb.ToString()+ suffix;}if(timeSpan.Seconds>0){
sb.AppendFormat("{0}{1} {2}",(sb.Length>0)?", ":string.Empty,
timeSpan.Seconds,(timeSpan.Seconds>1)?"seconds":"second");if(approximate)return sb.ToString()+ suffix;}if(sb.Length==0)return"right now";
sb.Append(suffix);return sb.ToString();}
nota amigável: Em .net 4.5 ou superior não instale completa Humanizer ... instalar apenas Humanizer.Core parte dela .. causam outros pacotes de idiomas não são suportados nesta versão
Ahmad
Tão útil! Esta resposta deve ser muito mais alta nesta lista. Se eu tivesse 100 votos, eu daria a isso. Aparentemente (vindo do JS-land), procurar este pacote não foi fácil.
kumarharsh
29
@jeff
IMHO o seu parece um pouco longo. No entanto, parece um pouco mais robusto com suporte para "ontem" e "anos". Mas, na minha experiência, quando isso é usado, é mais provável que a pessoa visualize o conteúdo nos primeiros 30 dias. São apenas as pessoas realmente hardcore que vêm depois disso. É por isso que geralmente escolho manter isso curto e simples.
Esse é o método que estou usando atualmente em um dos meus sites. Isso retorna apenas um dia, hora e hora relativos. E então o usuário tem que dar um tapa em "atrás" na saída.
Alguns anos atrasado para a festa, mas eu tinha um requisito para fazer isso em datas passadas e futuras, então eu combinei Jeff e Vincent nisso. É uma extravagância ternitártica! :)
publicstaticclassDateTimeHelper{privateconstint SECOND =1;privateconstint MINUTE =60* SECOND;privateconstint HOUR =60* MINUTE;privateconstint DAY =24* HOUR;privateconstint MONTH =30* DAY;/// <summary>/// Returns a friendly version of the provided DateTime, relative to now. E.g.: "2 days ago", or "in 6 months"./// </summary>/// <param name="dateTime">The DateTime to compare to Now</param>/// <returns>A friendly string</returns>publicstaticstringGetFriendlyRelativeTime(DateTime dateTime){if(DateTime.UtcNow.Ticks== dateTime.Ticks){return"Right now!";}bool isFuture =(DateTime.UtcNow.Ticks< dateTime.Ticks);var ts =DateTime.UtcNow.Ticks< dateTime.Ticks?newTimeSpan(dateTime.Ticks-DateTime.UtcNow.Ticks):newTimeSpan(DateTime.UtcNow.Ticks- dateTime.Ticks);double delta = ts.TotalSeconds;if(delta <1* MINUTE){return isFuture ?"in "+(ts.Seconds==1?"one second": ts.Seconds+" seconds"): ts.Seconds==1?"one second ago": ts.Seconds+" seconds ago";}if(delta <2* MINUTE){return isFuture ?"in a minute":"a minute ago";}if(delta <45* MINUTE){return isFuture ?"in "+ ts.Minutes+" minutes": ts.Minutes+" minutes ago";}if(delta <90* MINUTE){return isFuture ?"in an hour":"an hour ago";}if(delta <24* HOUR){return isFuture ?"in "+ ts.Hours+" hours": ts.Hours+" hours ago";}if(delta <48* HOUR){return isFuture ?"tomorrow":"yesterday";}if(delta <30* DAY){return isFuture ?"in "+ ts.Days+" days": ts.Days+" days ago";}if(delta <12* MONTH){int months =Convert.ToInt32(Math.Floor((double)ts.Days/30));return isFuture ?"in "+(months <=1?"one month": months +" months"): months <=1?"one month ago": months +" months ago";}else{int years =Convert.ToInt32(Math.Floor((double)ts.Days/365));return isFuture ?"in "+(years <=1?"one year": years +" years"): years <=1?"one year ago": years +" years ago";}}}
Dado que o mundo e seu marido parecem postar amostras de código, eis o que escrevi há pouco, com base em algumas dessas respostas.
Eu tinha uma necessidade específica de esse código ser localizável. Então, eu tenho duas classes - Grammar, que especifica os termos localizáveis e FuzzyDateExtensions, que contém vários métodos de extensão. Como não precisava lidar com datas futuras, não é feita nenhuma tentativa de lidar com eles com esse código.
Deixei alguns dos XMLdoc na fonte, mas removi a maioria (onde eles seriam óbvios) por uma questão de brevidade. Também não incluí todos os alunos aqui:
publicclassGrammar{/// <summary> Gets or sets the term for "just now". </summary>publicstringJustNow{get;set;}/// <summary> Gets or sets the term for "X minutes ago". </summary>/// <remarks>/// This is a <see cref="String.Format"/> pattern, where <c>{0}</c>/// is the number of minutes./// </remarks>publicstringMinutesAgo{get;set;}publicstringOneHourAgo{get;set;}publicstringHoursAgo{get;set;}publicstringYesterday{get;set;}publicstringDaysAgo{get;set;}publicstringLastMonth{get;set;}publicstringMonthsAgo{get;set;}publicstringLastYear{get;set;}publicstringYearsAgo{get;set;}/// <summary> Gets or sets the term for "ages ago". </summary>publicstringAgesAgo{get;set;}/// <summary>/// Gets or sets the threshold beyond which the fuzzy date should be/// considered "ages ago"./// </summary>publicTimeSpanAgesAgoThreshold{get;set;}/// <summary>/// Initialises a new <see cref="Grammar"/> instance with the/// specified properties./// </summary>privatevoidInitialise(string justNow,string minutesAgo,string oneHourAgo,string hoursAgo,string yesterday,string daysAgo,string lastMonth,string monthsAgo,string lastYear,string yearsAgo,string agesAgo,TimeSpan agesAgoThreshold){...}}
Uma das principais coisas que eu queria alcançar, assim como a localização, era que "hoje" seria apenas média "neste dia de calendário", de modo a IsToday, IsThisMonth, IsThisYearmétodos parecido com este:
Eu pensei em dar uma chance a isso usando classes e polimorfismo. Eu tinha uma iteração anterior que usava subclassificação que acabava sobrecarregando demais. Mudei para um modelo de objeto delegado / propriedade pública mais flexível, que é significativamente melhor. Meu código é um pouco mais preciso, eu gostaria de poder encontrar uma maneira melhor de gerar "meses atrás" que não parecesse exagerada demais.
Eu acho que ainda continuaria com a cascata if-then de Jeff, porque é menos código e mais simples (é definitivamente mais fácil garantir que funcione conforme o esperado).
Para o código abaixo, PrintRelativeTime.GetRelativeTimeMessage (TimeSpan ago) retorna a mensagem de tempo relativo (por exemplo, "ontem").
publicclassRelativeTimeRange:IComparable{publicTimeSpanUpperBound{get;set;}publicdelegatestringRelativeTimeTextDelegate(TimeSpan timeDelta);publicRelativeTimeTextDelegateMessageCreator{get;set;}publicintCompareTo(object obj){if(!(obj isRelativeTimeRange)){return1;}// note that this sorts in reverse order to the way you'd expect, // this saves having to reverse a list laterreturn(obj asRelativeTimeRange).UpperBound.CompareTo(UpperBound);}}publicclassPrintRelativeTime{privatestaticList<RelativeTimeRange> timeRanges;staticPrintRelativeTime(){
timeRanges =newList<RelativeTimeRange>{newRelativeTimeRange{UpperBound=TimeSpan.FromSeconds(1),MessageCreator=(delta)=>{return"one second ago";}},newRelativeTimeRange{UpperBound=TimeSpan.FromSeconds(60),MessageCreator=(delta)=>{return delta.Seconds+" seconds ago";}},newRelativeTimeRange{UpperBound=TimeSpan.FromMinutes(2),MessageCreator=(delta)=>{return"one minute ago";}},newRelativeTimeRange{UpperBound=TimeSpan.FromMinutes(60),MessageCreator=(delta)=>{return delta.Minutes+" minutes ago";}},newRelativeTimeRange{UpperBound=TimeSpan.FromHours(2),MessageCreator=(delta)=>{return"one hour ago";}},newRelativeTimeRange{UpperBound=TimeSpan.FromHours(24),MessageCreator=(delta)=>{return delta.Hours+" hours ago";}},newRelativeTimeRange{UpperBound=TimeSpan.FromDays(2),MessageCreator=(delta)=>{return"yesterday";}},newRelativeTimeRange{UpperBound=DateTime.Now.Subtract(DateTime.Now.AddMonths(-1)),MessageCreator=(delta)=>{return delta.Days+" days ago";}},newRelativeTimeRange{UpperBound=DateTime.Now.Subtract(DateTime.Now.AddMonths(-2)),MessageCreator=(delta)=>{return"one month ago";}},newRelativeTimeRange{UpperBound=DateTime.Now.Subtract(DateTime.Now.AddYears(-1)),MessageCreator=(delta)=>{return(int)Math.Floor(delta.TotalDays/30)+" months ago";}},newRelativeTimeRange{UpperBound=DateTime.Now.Subtract(DateTime.Now.AddYears(-2)),MessageCreator=(delta)=>{return"one year ago";}},newRelativeTimeRange{UpperBound=TimeSpan.MaxValue,MessageCreator=(delta)=>{return(int)Math.Floor(delta.TotalDays/365.24D)+" years ago";}}};
timeRanges.Sort();}publicstaticstringGetRelativeTimeMessage(TimeSpan ago){RelativeTimeRange postRelativeDateRange = timeRanges[0];foreach(var timeRange in timeRanges){if(ago.CompareTo(timeRange.UpperBound)<=0){
postRelativeDateRange = timeRange;}}return postRelativeDateRange.MessageCreator(ago);}}
StriplingWarrior: Facilidade de leitura e modificação em comparação com uma instrução switch ou uma pilha de instruções if / else. O dicionário sendo estático significa que ele e os objetos Func <,> não precisam ser criados toda vez que queremos usar ToRelativeDate; ele foi criado apenas uma vez, comparado ao que eu vinculei na minha resposta.
Chris Charabaruk
Eu vejo. Eu estava pensando, já que a documentação Dictionaryafirma que "A ordem na qual os itens são retornados é indefinida" ( msdn.microsoft.com/en-us/library/xfhwa508.aspx ) talvez essa não seja a melhor estrutura de dados a ser usada quando você não se importa com os tempos de pesquisa, mas com as coisas em ordem.
StriplingWarrior
StriplingWarrior: Eu acredito que o LINQ leva isso em consideração quando usado com Dictionarys. Se você ainda não se sente à vontade com isso, pode usar SortedDictionary, mas minha própria experiência mostra que isso é desnecessário.
Chris Charabaruk
12
Quando você conhece o fuso horário do visualizador, pode ser mais claro usar os dias do calendário na escala de dias. Como não conheço as bibliotecas .NET, não sei como você faria isso em C #, infelizmente.
Em sites de consumidores, você também pode ter menos agitação manual em menos de um minuto. "Menos de um minuto atrás" ou "agora" poderia ser bom o suficiente.
A pergunta está marcada com C # . Por que esse código Java ? IMHO, só se aplica código C #
Kiquenet
9
@Jeff
var ts =newTimeSpan(DateTime.UtcNow.Ticks- dt.Ticks);
Fazer uma subtração em DateTimeretorna um de TimeSpanqualquer maneira.
Então você pode fazer
(DateTime.UtcNow- dt).TotalSeconds
Também fico surpreso ao ver as constantes multiplicadas à mão e depois comentários adicionados com as multiplicações. Isso foi uma otimização equivocada?
Aqui está o algoritmo que o stackoverflow usa, mas reescrito de forma mais concisa no pseudocódigo perlish com uma correção de bug (não há "uma hora atrás"). A função leva um número (positivo) de segundos atrás e retorna uma cadeia de caracteres humana como "3 horas atrás" ou "ontem".
Você pode usar a extensão TimeAgo da qual se parece com o seguinte:
publicstaticstringTimeAgo(thisDateTime dateTime){string result =string.Empty;var timeSpan =DateTime.Now.Subtract(dateTime);if(timeSpan <=TimeSpan.FromSeconds(60)){
result =string.Format("{0} seconds ago", timeSpan.Seconds);}elseif(timeSpan <=TimeSpan.FromMinutes(60)){
result = timeSpan.Minutes>1?String.Format("about {0} minutes ago", timeSpan.Minutes):"about a minute ago";}elseif(timeSpan <=TimeSpan.FromHours(24)){
result = timeSpan.Hours>1?String.Format("about {0} hours ago", timeSpan.Hours):"about an hour ago";}elseif(timeSpan <=TimeSpan.FromDays(30)){
result = timeSpan.Days>1?String.Format("about {0} days ago", timeSpan.Days):"yesterday";}elseif(timeSpan <=TimeSpan.FromDays(365)){
result = timeSpan.Days>30?String.Format("about {0} months ago", timeSpan.Days/30):"about a month ago";}else{
result = timeSpan.Days>365?String.Format("about {0} years ago", timeSpan.Days/365):"about a year ago";}return result;}
Ou use o plugin jQuery com extensão Razor do Timeago.
Você pode reduzir a carga do lado do servidor executando essa lógica do lado do cliente. Veja a fonte em algumas páginas do Digg para referência. Eles fazem o servidor emitir um valor de época que é processado por Javascript. Dessa forma, você não precisa gerenciar o fuso horário do usuário final. O novo código do lado do servidor seria algo como:
Eu recebi isso de um dos blogs de Bill Gates. Preciso encontrá-lo no histórico do navegador e fornecerei o link.
O código Javascript para fazer a mesma coisa (conforme solicitado):
function posted(t){var now =newDate();var diff = parseInt((now.getTime()-Date.parse(t))/1000);if(diff <60){return'less than a minute ago';}elseif(diff <120){return'about a minute ago';}elseif(diff <(2700)){return(parseInt(diff /60)).toString()+' minutes ago';}elseif(diff <(5400)){return'about an hour ago';}elseif(diff <(86400)){return'about '+(parseInt(diff /3600)).toString()+' hours ago';}elseif(diff <(172800)){return'1 day ago';}else{return(parseInt(diff /86400)).toString()+' days ago';}}
Eu acho que já existem várias respostas relacionadas a este post, mas pode-se usar isso que é fácil de usar, como o plug-in e também facilmente legível para os programadores. Envie sua data específica e obtenha seu valor na forma de sequência:
Respostas:
Jeff, seu código é bom, mas pode ser mais claro com constantes (como sugerido no Código completo).
fonte
Thread.Sleep(1 * MINUTE)
? Porque está errado por um fator de 1000.const int SECOND = 1;
Um segundo tão estranho é um segundo.plugin jquery.timeago
Jeff, como o Stack Overflow usa o jQuery extensivamente, eu recomendo o plugin jquery.timeago .
Benefícios:
Basta anexá-lo aos seus registros de data e hora no DOM pronto:
Isso transformará todos os
abbr
elementos com uma classe de timeago e um carimbo de data / hora ISO 8601 no título:em algo como isto:
que rende: há 4 meses. Com o passar do tempo, os carimbos de hora serão atualizados automaticamente.
Disclaimer: Eu escrevi este plugin, por isso sou tendencioso.
fonte
Aqui está como eu faço
Sugestões? Comentários? Maneiras de melhorar esse algoritmo?
fonte
Prefiro esta versão por sua concisão e capacidade de adicionar novos pontos de verificação. Isso pode ser encapsulado com uma
Latest()
extensão do Timespan em vez do longo forro, mas por uma questão de brevidade na postagem, isso funcionará. Isso corrige uma hora atrás, uma hora atrás, fornecendo uma hora até duas horas decorridasfonte
SortedDictionary
vez de um simplesDictionary
: o uso é o mesmo, mas garante que as chaves sejam classificadas. Mas, mesmo assim, o algoritmo tem falhas, porqueRelativeDate(DateTime.Now.AddMonths(-3).AddDays(-3))
retorna "95 meses atrás" , independentemente do tipo de dicionário que você está usando, o que está incorreto (ele deve retornar "há 3 meses" ou "4 meses atrás", dependendo de qual limite você ' reutilizando) - mesmo que -3 não crie uma data no ano passado (testei isso em dezembro, portanto, nesse caso, isso não deve acontecer).Aqui, uma reescrita do Jeffs Script for PHP:
fonte
http://refactormycode.com/codes/493-twitter-esque-relative-dates
Versão C # 6:
fonte
Func<string>
paraFunc<double>
.Aqui está uma implementação que eu adicionei como método de extensão à classe DateTime que lida com datas futuras e passadas e fornece uma opção de aproximação que permite especificar o nível de detalhe que você está procurando ("3 horas atrás" vs "3 horas, 23 minutos, 12 segundos atrás "):
fonte
Eu recomendaria computar isso no lado do cliente também. Menos trabalho para o servidor.
A seguir, a versão que eu uso (de Zach Leatherman)
fonte
Há também um pacote chamado Humanizr no Nuget, que realmente funciona muito bem e está no .NET Foundation.
Scott Hanselman escreveu um artigo em seu blog
fonte
@jeff
IMHO o seu parece um pouco longo. No entanto, parece um pouco mais robusto com suporte para "ontem" e "anos". Mas, na minha experiência, quando isso é usado, é mais provável que a pessoa visualize o conteúdo nos primeiros 30 dias. São apenas as pessoas realmente hardcore que vêm depois disso. É por isso que geralmente escolho manter isso curto e simples.
Esse é o método que estou usando atualmente em um dos meus sites. Isso retorna apenas um dia, hora e hora relativos. E então o usuário tem que dar um tapa em "atrás" na saída.
fonte
Alguns anos atrasado para a festa, mas eu tinha um requisito para fazer isso em datas passadas e futuras, então eu combinei Jeff e Vincent nisso. É uma extravagância ternitártica! :)
fonte
Existe uma maneira fácil de fazer isso em Java? A
java.util.Date
turma parece bastante limitada.Aqui está minha solução Java rápida e suja:
fonte
Versão Objective-C do iPhone
fonte
Dado que o mundo e seu marido parecem postar amostras de código, eis o que escrevi há pouco, com base em algumas dessas respostas.
Eu tinha uma necessidade específica de esse código ser localizável. Então, eu tenho duas classes -
Grammar
, que especifica os termos localizáveis eFuzzyDateExtensions
, que contém vários métodos de extensão. Como não precisava lidar com datas futuras, não é feita nenhuma tentativa de lidar com eles com esse código.Deixei alguns dos XMLdoc na fonte, mas removi a maioria (onde eles seriam óbvios) por uma questão de brevidade. Também não incluí todos os alunos aqui:
A
FuzzyDateString
classe contém:Uma das principais coisas que eu queria alcançar, assim como a localização, era que "hoje" seria apenas média "neste dia de calendário", de modo a
IsToday
,IsThisMonth
,IsThisYear
métodos parecido com este:e os métodos de arredondamento são assim (eu incluí
RoundedMonths
, pois isso é um pouco diferente):Espero que as pessoas achem isso útil e / ou interessante: o)
fonte
No PHP, faço da seguinte maneira:
fonte
usando DateTime fluente
fonte
Eu pensei em dar uma chance a isso usando classes e polimorfismo. Eu tinha uma iteração anterior que usava subclassificação que acabava sobrecarregando demais. Mudei para um modelo de objeto delegado / propriedade pública mais flexível, que é significativamente melhor. Meu código é um pouco mais preciso, eu gostaria de poder encontrar uma maneira melhor de gerar "meses atrás" que não parecesse exagerada demais.
Eu acho que ainda continuaria com a cascata if-then de Jeff, porque é menos código e mais simples (é definitivamente mais fácil garantir que funcione conforme o esperado).
Para o código abaixo, PrintRelativeTime.GetRelativeTimeMessage (TimeSpan ago) retorna a mensagem de tempo relativo (por exemplo, "ontem").
fonte
O mesmo que outra resposta a esta pergunta, mas como um método de extensão com um dicionário estático.
fonte
Dictionary
afirma que "A ordem na qual os itens são retornados é indefinida" ( msdn.microsoft.com/en-us/library/xfhwa508.aspx ) talvez essa não seja a melhor estrutura de dados a ser usada quando você não se importa com os tempos de pesquisa, mas com as coisas em ordem.Dictionary
s. Se você ainda não se sente à vontade com isso, pode usarSortedDictionary
, mas minha própria experiência mostra que isso é desnecessário.Quando você conhece o fuso horário do visualizador, pode ser mais claro usar os dias do calendário na escala de dias. Como não conheço as bibliotecas .NET, não sei como você faria isso em C #, infelizmente.
Em sites de consumidores, você também pode ter menos agitação manual em menos de um minuto. "Menos de um minuto atrás" ou "agora" poderia ser bom o suficiente.
fonte
Você pode tentar isso. Acho que funcionará corretamente.
fonte
Java para uso do GWT do lado do cliente:
fonte
@Jeff
Fazer uma subtração em
DateTime
retorna um deTimeSpan
qualquer maneira.Então você pode fazer
Também fico surpreso ao ver as constantes multiplicadas à mão e depois comentários adicionados com as multiplicações. Isso foi uma otimização equivocada?
fonte
Aqui está o algoritmo que o stackoverflow usa, mas reescrito de forma mais concisa no pseudocódigo perlish com uma correção de bug (não há "uma hora atrás"). A função leva um número (positivo) de segundos atrás e retorna uma cadeia de caracteres humana como "3 horas atrás" ou "ontem".
fonte
Você pode usar a extensão TimeAgo da qual se parece com o seguinte:
Ou use o plugin jQuery com extensão Razor do Timeago.
fonte
Você pode reduzir a carga do lado do servidor executando essa lógica do lado do cliente. Veja a fonte em algumas páginas do Digg para referência. Eles fazem o servidor emitir um valor de época que é processado por Javascript. Dessa forma, você não precisa gerenciar o fuso horário do usuário final. O novo código do lado do servidor seria algo como:
Você pode até adicionar um bloco NOSCRIPT lá e apenas executar um ToString ().
fonte
Eu recebi isso de um dos blogs de Bill Gates. Preciso encontrá-lo no histórico do navegador e fornecerei o link.
O código Javascript para fazer a mesma coisa (conforme solicitado):
Basicamente, você trabalha em segundos ...
fonte
Eu acho que já existem várias respostas relacionadas a este post, mas pode-se usar isso que é fácil de usar, como o plug-in e também facilmente legível para os programadores. Envie sua data específica e obtenha seu valor na forma de sequência:
fonte
fonte
Se você deseja obter uma saída como essa
"2 days, 4 hours and 12 minutes ago"
, precisa de um período de tempo:Então você pode acessar os valores que você gosta:
etc ...
fonte
Eu forneceria alguns métodos úteis de extensões para isso e tornaria o código mais legível. Primeiro, alguns métodos de extensão para
Int32
.Então, um para
DateTime
.Agora, você pode fazer algo como abaixo:
fonte