¿Qué sucede si desea calcular un tiempo relativo desde ahora hasta el futuro?
Jhonny D. Cano -Leftware-
2
moment.js es una muy buena biblioteca de análisis de fechas. Puede considerar usar eso (lado del servidor o del lado del cliente), dependiendo de sus necesidades. solo para tu información porque nadie lo mencionó aquí
Odio esas constantes con pasión. ¿Esto le parece mal a alguien? Thread.Sleep(1 * MINUTE)? Porque está mal por un factor de 1000.
Roman Starkov
31
const int SECOND = 1;Tan extraño un segundo es un segundo.
seriousdev
62
Este tipo de código es casi imposible de localizar. Si su aplicación solo necesita permanecer en inglés, entonces está bien. Pero si saltas a otros idiomas, te odiarás por hacer una lógica como esta. Sólo para que todos saben ...
Nik Reiman
73
Creo que si las constantes fueran renombradas para describir con precisión el valor que hay en ellas, sería más fácil de entender. Entonces SecondsPerMinute = 60; MinutesPerHour = 60; SecondsPerHour = MinutesPerHour * SecondsPerHour; etc. Simplemente llamarlo MINUTO = 60 no permite al lector determinar cuál es el valor.
slolife
14
¿Por qué a nadie (excepto a Joe) le importa el valor incorrecto 'Ayer' o 'hace días'? Ayer no es un cálculo de hora, sino un cálculo diario. Entonces sí, este es un código incorrecto al menos en dos casos frecuentes.
Evite las marcas de tiempo con fecha "hace 1 minuto" aunque la página se abrió hace 10 minutos; timeago se actualiza automáticamente.
Puede aprovechar al máximo el almacenamiento en caché de páginas y / o fragmentos en sus aplicaciones web, porque las marcas de tiempo no se calculan en el servidor.
Puedes usar microformatos como los niños geniales.
Simplemente adjúntelo a sus marcas de tiempo en DOM listo:
Seb, si tiene Javascript deshabilitado, se muestra la cadena que colocó originalmente entre las etiquetas abbr. Por lo general, esta es solo una fecha u hora en cualquier formato que desee. Timeago se degrada con gracia. No se vuelve mucho más simple.
Je, gracias Rob. Esta bien. Apenas se nota, especialmente cuando solo un número cambia durante la transición, aunque las páginas SO tienen muchas marcas de tiempo. Sin embargo, habría pensado que al menos habría apreciado los beneficios del almacenamiento en caché de la página, incluso si elige evitar las actualizaciones automáticas. Estoy seguro de que Jeff podría haber proporcionado comentarios para mejorar el complemento también. Me consuela saber que sitios como arstechnica.com lo usan.
Ryan McGeary
19
@Rob Fonseca-Ensor: ahora también me está haciendo llorar. ¿Cómo se actualiza una vez por minuto, para mostrar información precisa, de alguna manera relacionada con el parpadeo de texto una vez por segundo?
Daniel Earwicker
25
La pregunta es sobre C #, no veo cómo un complemento jQuery es relevante.
"<48 * 60 * 60s" es una definición poco convencional de "ayer". Si son las 9 de la mañana del miércoles, ¿realmente pensarías en las 9:01 de la mañana del lunes como "ayer". Pensé que un algoritmo para ayer o "hace n días" debería considerar antes / después de la medianoche.
Joe
139
Los compiladores suelen ser bastante buenos para calcular previamente las expresiones constantes, como 24 * 60 * 60, por lo que puede usarlas directamente en lugar de calcularlas como 86400 y poner la expresión original en comentarios
zvolkov
11
@bzlm Creo que lo hice para un proyecto en el que estaba trabajando. Mi motivación aquí fue alertar a otros de que se omitieron semanas de este ejemplo de código. En cuanto a cómo hacer eso, me pareció bastante sencillo.
jray
99
Creo que una buena manera de mejorar el algoritmo es mostrar 2 unidades como "Hace 2 meses y 21 días", "Hace 1 hora y 40 minutos" para aumentar la precisión.
Evgeny Levin
55
@ Jeffy, te perdiste el cálculo del año bisiesto y los controles relacionados
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"";}
Prefiero esta versión por su concisión y capacidad de agregar nuevos puntos de verificación. Esto podría encapsularse con una Latest()extensión de Timespan en lugar de ese largo 1 liner, pero por razones de brevedad en la publicación, esto servirá.
Esto soluciona el problema hace una hora, hace 1 hora, al proporcionar una hora hasta que hayan transcurrido 2 horas
Tengo todo tipo de problemas al usar esta función, por ejemplo, si te burlas de 'theDate = DateTime.Now.AddMinutes (-40);' Recibo '40 horas atrás ', pero con la respuesta refactormycode de Michael, ¿regresa correcto a '40 minutos atrás'?
GONeale
creo que le falta un cero, intente: hace mucho tiempo = (DateTime.Now.Ticks - theDate.Ticks) / 10000000;
robnardo
8
Hmm, aunque este código puede funcionar, es incorrecto e inválido suponer que el orden de las claves en el Diccionario estará en un orden específico. El diccionario utiliza Object.GetHashCode () que no devuelve un valor largo, sino un int. Si desea que estos se ordenen, debe usar SortedList <long, string>. ¿Qué tiene de malo que los umbrales se evalúen en un conjunto de if / else if /.../ else? Obtienes el mismo número de comparaciones. Para su información el hash por mucho tiempo. MaxValue resulta ser lo mismo que int.MinValue!
CodeMonkeyKing
OP olvidó t. ¿Días> 30? t.Days / 30:
Lars Holm Jensen el
Para solucionar el problema mencionado por @CodeMonkeyKing, puede usar un en SortedDictionarylugar de un simple Dictionary: el uso es el mismo, pero asegura que las claves estén ordenadas. Pero incluso entonces, el algoritmo tiene fallas, porque RelativeDate(DateTime.Now.AddMonths(-3).AddDays(-3))devuelve "hace 95 meses" , independientemente del tipo de diccionario que esté utilizando, lo cual es incorrecto (debería devolver "hace 3 meses" o "hace 4 meses" dependiendo de qué umbral usted " re use) - incluso si -3 no crea una fecha en el último año (lo probé en diciembre, por lo que en este caso no debería suceder).
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;}
esto es muy bueno IMO :) ¿Esto también podría ser refactorizado como un método de extensión? ¿podría el diccionario volverse estático para que solo se cree una vez y se haga referencia a partir de ese momento?
Probablemente desee sacar ese diccionario a un campo para reducir la creación de instancias y la rotación de GC. Tendrías que cambiar Func<string>a Func<double>.
Drew Noakes el
49
Aquí hay una implementación que agregué como método de extensión a la clase DateTime que maneja fechas futuras y pasadas y proporciona una opción de aproximación que le permite especificar el nivel de detalle que está buscando ("hace 3 horas" frente a "3 horas, Hace 23 minutos, 12 segundos "):
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 amistosa: En .net 4.5 o superior no instale completa ... Humanizer instalar sólo Humanizer.Core parte de ella .. otros paquetes de idioma de causa no se admiten en esta versión
Ahmad
¡Tan útil! Esta respuesta debe ser mucho más alta en esta lista. Si tuviera 100 votos, se lo daría a esto. Aparentemente (viniendo de JS-land), buscar este paquete no fue fácil.
kumarharsh
29
@jeff
En mi humilde opinión el tuyo parece un poco largo. Sin embargo, parece un poco más robusto con soporte para "ayer" y "años". Pero en mi experiencia, cuando se usa esto, es más probable que la persona vea el contenido en los primeros 30 días. Son solo las personas realmente hardcore las que vienen después de eso. Por eso, por lo general, elijo mantener esto breve y simple.
Este es el método que estoy usando actualmente en uno de mis sitios web. Esto solo devuelve un día relativo, hora, hora. Y luego el usuario tiene que abofetear "ago" en la salida.
Un par de años tarde a la fiesta, pero tenía el requisito de hacerlo para las fechas pasadas y futuras, así que combiné a Jeff y Vincent en esto. Es una extravagancia ternarytastic! :)
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 el mundo y su esposo parecen estar publicando ejemplos de código, esto es lo que escribí hace un tiempo, basado en un par de estas respuestas.
Tenía una necesidad específica de que este código fuera localizable. Así que tengo dos clases Grammar, que especifica los términos localizables y FuzzyDateExtensionsque contiene varios métodos de extensión. No tuve necesidad de lidiar con fechas futuras, por lo que no se hace ningún intento de manejarlos con este código.
Dejé parte del XMLdoc en la fuente, pero eliminé la mayoría (donde sería obvio) por razones de brevedad. Tampoco he incluido a todos los miembros de la clase aquí:
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){...}}
Una de las principales cosas que quería lograr, así como la localización, fue que "hoy" sólo significaría "el día del calendario", por lo que el IsToday, IsThisMonth, IsThisYearmétodos tener este aspecto:
Pensé darle una oportunidad a esto usando clases y polimorfismo. Tuve una iteración anterior que usaba subclases que terminaron teniendo demasiada sobrecarga. He cambiado a un modelo de objeto de propiedad pública / delegado más flexible que es significativamente mejor. Mi código es un poco más preciso, ojalá pudiera encontrar una mejor manera de generar "hace meses" que no pareciera demasiado ingenierilizada.
Creo que todavía me quedaría con la cascada si-entonces de Jeff porque es menos código y es más simple (definitivamente es más fácil asegurarse de que funcione como se esperaba).
Para el siguiente código PrintRelativeTime.GetRelativeTimeMessage (hace TimeSpan) devuelve el mensaje de tiempo relativo (por ejemplo, "ayer").
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: facilidad de lectura y modificación en comparación con una declaración de cambio o una pila de declaraciones if / else. El diccionario estático significa que él y los objetos Func <,> no tienen que crearse cada vez que queremos usar ToRelativeDate; se crea solo una vez, en comparación con el que vinculé en mi respuesta.
Chris Charabaruk
Veo. Estaba pensando, ya que la documentación Dictionaryindica que "El orden en que se devuelven los elementos no está definido" ( msdn.microsoft.com/en-us/library/xfhwa508.aspx ) tal vez esa no sea la mejor estructura de datos para usar cuando no te importan los tiempos de búsqueda tanto como que las cosas se mantengan en orden.
StriplingWarrior
StriplingWarrior: Creo que LINQ toma eso en cuenta cuando se usa con Dictionarys. Si todavía te sientes incómodo con él, puedes usarlo SortedDictionary, pero mi propia experiencia demuestra que eso es innecesario.
Chris Charabaruk 01 de
12
Cuando conozca la zona horaria del espectador, puede ser más claro usar días calendario en la escala de días. No estoy familiarizado con las bibliotecas .NET, así que desafortunadamente no sé cómo lo haría en C #.
En los sitios de consumo, también puede ser más pesado en menos de un minuto. "Hace menos de un minuto" o "justo ahora" podría ser lo suficientemente bueno.
La pregunta está etiquetada con C # . ¿Por qué este código Java ? En mi humilde opinión, solo se aplica el código C #
Kiquenet
9
@Jeff
var ts =newTimeSpan(DateTime.UtcNow.Ticks- dt.Ticks);
Hacer una resta en DateTimedevuelve un de TimeSpantodos modos.
Entonces puedes hacer
(DateTime.UtcNow- dt).TotalSeconds
También me sorprende ver que las constantes se multiplican a mano y luego se agregan comentarios con las multiplicaciones. ¿Fue alguna optimización equivocada?
Aquí está el algoritmo que utiliza stackoverflow, pero reescrito de manera más concisa en pseudocódigo con una corrección de errores (no "hace una hora"). La función toma un número (positivo) de segundos atrás y devuelve una cadena amigable para los humanos como "hace 3 horas" o "ayer".
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;}
Puede reducir la carga del lado del servidor realizando esta lógica del lado del cliente. Vea la fuente en algunas páginas de Digg como referencia. Hacen que el servidor emita un valor de tiempo de época que es procesado por Javascript. De esta manera, no necesita administrar la zona horaria del usuario final. El nuevo código del lado del servidor sería algo como:
Esto lo obtuve de uno de los blogs de Bill Gates. Necesito encontrarlo en el historial de mi navegador y te daré el enlace.
El código Javascript para hacer lo mismo (según lo 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';}}
Creo que ya hay una serie de respuestas relacionadas con esta publicación, pero se puede usar esto, que es fácil de usar al igual que el complemento y también fácil de leer para los programadores. Envíe su fecha específica y obtenga su valor en forma de cadena:
Proporcionaría algunos métodos de extensiones útiles para esto y haría que el código sea más legible. Primero, un par de métodos de extensión para Int32.
Respuestas:
Jeff, tu código es bueno, pero podría ser más claro con constantes (como se sugiere en Code Complete).
fuente
Thread.Sleep(1 * MINUTE)
? Porque está mal por un factor de 1000.const int SECOND = 1;
Tan extraño un segundo es un segundo.Complemento jquery.timeago
Jeff, debido a que Stack Overflow usa jQuery ampliamente, recomiendo el complemento jquery.timeago .
Beneficios:
Simplemente adjúntelo a sus marcas de tiempo en DOM listo:
Esto convertirá todos los
abbr
elementos con una clase de tiempo atrás y una marca de tiempo ISO 8601 en el título:en algo como esto:
que rinde: hace 4 meses. A medida que pasa el tiempo, las marcas de tiempo se actualizarán automáticamente.
Descargo de responsabilidad: escribí este complemento, por lo que soy parcial.
fuente
Así es como lo hago
Sugerencias? Comentarios? ¿Formas de mejorar este algoritmo?
fuente
Prefiero esta versión por su concisión y capacidad de agregar nuevos puntos de verificación. Esto podría encapsularse con una
Latest()
extensión de Timespan en lugar de ese largo 1 liner, pero por razones de brevedad en la publicación, esto servirá. Esto soluciona el problema hace una hora, hace 1 hora, al proporcionar una hora hasta que hayan transcurrido 2 horasfuente
SortedDictionary
lugar de un simpleDictionary
: el uso es el mismo, pero asegura que las claves estén ordenadas. Pero incluso entonces, el algoritmo tiene fallas, porqueRelativeDate(DateTime.Now.AddMonths(-3).AddDays(-3))
devuelve "hace 95 meses" , independientemente del tipo de diccionario que esté utilizando, lo cual es incorrecto (debería devolver "hace 3 meses" o "hace 4 meses" dependiendo de qué umbral usted " re use) - incluso si -3 no crea una fecha en el último año (lo probé en diciembre, por lo que en este caso no debería suceder).Aquí una reescritura de Jeffs Script para PHP:
fuente
http://refactormycode.com/codes/493-twitter-esque-relative-dates
Versión C # 6:
fuente
Func<string>
aFunc<double>
.Aquí hay una implementación que agregué como método de extensión a la clase DateTime que maneja fechas futuras y pasadas y proporciona una opción de aproximación que le permite especificar el nivel de detalle que está buscando ("hace 3 horas" frente a "3 horas, Hace 23 minutos, 12 segundos "):
fuente
También recomendaría calcular esto en el lado del cliente. Menos trabajo para el servidor.
La siguiente es la versión que uso (de Zach Leatherman)
fuente
También hay un paquete llamado Humanizr en Nuget, y en realidad funciona muy bien, y está en .NET Foundation.
Scott Hanselman tiene un artículo escrito en su blog
fuente
@jeff
En mi humilde opinión el tuyo parece un poco largo. Sin embargo, parece un poco más robusto con soporte para "ayer" y "años". Pero en mi experiencia, cuando se usa esto, es más probable que la persona vea el contenido en los primeros 30 días. Son solo las personas realmente hardcore las que vienen después de eso. Por eso, por lo general, elijo mantener esto breve y simple.
Este es el método que estoy usando actualmente en uno de mis sitios web. Esto solo devuelve un día relativo, hora, hora. Y luego el usuario tiene que abofetear "ago" en la salida.
fuente
Un par de años tarde a la fiesta, pero tenía el requisito de hacerlo para las fechas pasadas y futuras, así que combiné a Jeff y Vincent en esto. Es una extravagancia ternarytastic! :)
fuente
¿Hay una manera fácil de hacer esto en Java? La
java.util.Date
clase parece bastante limitada.Aquí está mi solución Java rápida y sucia:
fuente
iPhone Objective-C Version
fuente
Dado que el mundo y su esposo parecen estar publicando ejemplos de código, esto es lo que escribí hace un tiempo, basado en un par de estas respuestas.
Tenía una necesidad específica de que este código fuera localizable. Así que tengo dos clases
Grammar
, que especifica los términos localizables yFuzzyDateExtensions
que contiene varios métodos de extensión. No tuve necesidad de lidiar con fechas futuras, por lo que no se hace ningún intento de manejarlos con este código.Dejé parte del XMLdoc en la fuente, pero eliminé la mayoría (donde sería obvio) por razones de brevedad. Tampoco he incluido a todos los miembros de la clase aquí:
La
FuzzyDateString
clase contiene:Una de las principales cosas que quería lograr, así como la localización, fue que "hoy" sólo significaría "el día del calendario", por lo que el
IsToday
,IsThisMonth
,IsThisYear
métodos tener este aspecto:y los métodos de redondeo son así (lo he incluido
RoundedMonths
, ya que es un poco diferente):Espero que la gente encuentre esto útil y / o interesante: o)
fuente
En PHP, lo hago de esta manera:
fuente
usando Fluent DateTime
fuente
Pensé darle una oportunidad a esto usando clases y polimorfismo. Tuve una iteración anterior que usaba subclases que terminaron teniendo demasiada sobrecarga. He cambiado a un modelo de objeto de propiedad pública / delegado más flexible que es significativamente mejor. Mi código es un poco más preciso, ojalá pudiera encontrar una mejor manera de generar "hace meses" que no pareciera demasiado ingenierilizada.
Creo que todavía me quedaría con la cascada si-entonces de Jeff porque es menos código y es más simple (definitivamente es más fácil asegurarse de que funcione como se esperaba).
Para el siguiente código PrintRelativeTime.GetRelativeTimeMessage (hace TimeSpan) devuelve el mensaje de tiempo relativo (por ejemplo, "ayer").
fuente
Lo mismo que otra respuesta a esta pregunta pero como un método de extensión con un diccionario estático.
fuente
Dictionary
indica que "El orden en que se devuelven los elementos no está definido" ( msdn.microsoft.com/en-us/library/xfhwa508.aspx ) tal vez esa no sea la mejor estructura de datos para usar cuando no te importan los tiempos de búsqueda tanto como que las cosas se mantengan en orden.Dictionary
s. Si todavía te sientes incómodo con él, puedes usarloSortedDictionary
, pero mi propia experiencia demuestra que eso es innecesario.Cuando conozca la zona horaria del espectador, puede ser más claro usar días calendario en la escala de días. No estoy familiarizado con las bibliotecas .NET, así que desafortunadamente no sé cómo lo haría en C #.
En los sitios de consumo, también puede ser más pesado en menos de un minuto. "Hace menos de un minuto" o "justo ahora" podría ser lo suficientemente bueno.
fuente
puedes probar esto. Creo que funcionará correctamente.
fuente
Java para uso de gwt del lado del cliente:
fuente
@Jeff
Hacer una resta en
DateTime
devuelve un deTimeSpan
todos modos.Entonces puedes hacer
También me sorprende ver que las constantes se multiplican a mano y luego se agregan comentarios con las multiplicaciones. ¿Fue alguna optimización equivocada?
fuente
Aquí está el algoritmo que utiliza stackoverflow, pero reescrito de manera más concisa en pseudocódigo con una corrección de errores (no "hace una hora"). La función toma un número (positivo) de segundos atrás y devuelve una cadena amigable para los humanos como "hace 3 horas" o "ayer".
fuente
Puede usar la extensión TimeAgo, que tiene el siguiente aspecto:
O use el complemento jQuery con la extensión Razor de Timeago.
fuente
Puede reducir la carga del lado del servidor realizando esta lógica del lado del cliente. Vea la fuente en algunas páginas de Digg como referencia. Hacen que el servidor emita un valor de tiempo de época que es procesado por Javascript. De esta manera, no necesita administrar la zona horaria del usuario final. El nuevo código del lado del servidor sería algo como:
Incluso podría agregar un bloque NOSCRIPT allí y simplemente realizar un ToString ().
fuente
Esto lo obtuve de uno de los blogs de Bill Gates. Necesito encontrarlo en el historial de mi navegador y te daré el enlace.
El código Javascript para hacer lo mismo (según lo solicitado):
Básicamente, trabajas en términos de segundos ...
fuente
Creo que ya hay una serie de respuestas relacionadas con esta publicación, pero se puede usar esto, que es fácil de usar al igual que el complemento y también fácil de leer para los programadores. Envíe su fecha específica y obtenga su valor en forma de cadena:
fuente
fuente
Si desea tener una salida como
"2 days, 4 hours and 12 minutes ago"
, necesita un intervalo de tiempo:Luego puede acceder a los valores que desee:
etc ...
fuente
Proporcionaría algunos métodos de extensiones útiles para esto y haría que el código sea más legible. Primero, un par de métodos de extensión para
Int32
.Entonces, uno para
DateTime
.Ahora, puedes hacer algo como a continuación:
fuente