Calcular el tiempo relativo en C#
Dado un DateTime
valor específico, ¿cómo muestro el tiempo relativo, como:
2 hours ago
3 days ago
a month ago
Jeff, tu código es bueno pero podría ser más claro con constantes (como se sugiere en Código completo).
const int SECOND = 1;
const int MINUTE = 60 * SECOND;
const int HOUR = 60 * MINUTE;
const int DAY = 24 * HOUR;
const int MONTH = 30 * DAY;
var ts = new TimeSpan(DateTime.UtcNow.Ticks - yourDate.Ticks);
double delta = Math.Abs(ts.TotalSeconds);
if (delta < 1 * MINUTE)
return ts.Seconds == 1 ? "one second ago" : ts.Seconds + " seconds ago";
if (delta < 2 * MINUTE)
return "a minute ago";
if (delta < 45 * MINUTE)
return ts.Minutes + " minutes ago";
if (delta < 90 * MINUTE)
return "an hour ago";
if (delta < 24 * HOUR)
return ts.Hours + " hours ago";
if (delta < 48 * HOUR)
return "yesterday";
if (delta < 30 * DAY)
return ts.Days + " days ago";
if (delta < 12 * MONTH)
{
int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30));
return months <= 1 ? "one month ago" : months + " months ago";
}
else
{
int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365));
return years <= 1 ? "one year ago" : years + " years ago";
}
complemento jquery.timeago
Jeff, debido a que Stack Overflow usa jQuery ampliamente, recomiendo el complemento jquery.timeago .
Beneficios:
- Evite las marcas de tiempo con fecha "hace 1 minuto" aunque la página se haya abierto 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 chicos geniales.
Simplemente adjúntelo a sus marcas de tiempo en DOM listo:
jQuery(document).ready(function() {
jQuery('abbr.timeago').timeago();
});
Esto convertirá todos los abbr
elementos con una clase de timeago y una marca de tiempo ISO 8601 en el título:
<abbr class="timeago" title="2008-07-17T09:24:17Z">July 17, 2008</abbr>
en algo como esto:
<abbr class="timeago" title="July 17, 2008">4 months ago</abbr>
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.
Así es como lo hago
var ts = new TimeSpan(DateTime.UtcNow.Ticks - dt.Ticks);
double delta = Math.Abs(ts.TotalSeconds);
if (delta < 60)
{
return ts.Seconds == 1 ? "one second ago" : ts.Seconds + " seconds ago";
}
if (delta < 60 * 2)
{
return "a minute ago";
}
if (delta < 45 * 60)
{
return ts.Minutes + " minutes ago";
}
if (delta < 90 * 60)
{
return "an hour ago";
}
if (delta < 24 * 60 * 60)
{
return ts.Hours + " hours ago";
}
if (delta < 48 * 60 * 60)
{
return "yesterday";
}
if (delta < 30 * 24 * 60 * 60)
{
return ts.Days + " days ago";
}
if (delta < 12 * 30 * 24 * 60 * 60)
{
int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30));
return months <= 1 ? "one month ago" : months + " months ago";
}
int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365));
return years <= 1 ? "one year ago" : years + " years ago";
¿Sugerencias? ¿Comentarios? ¿Formas de mejorar este algoritmo?
public static string RelativeDate(DateTime theDate)
{
Dictionary<long, string> thresholds = new Dictionary<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 = new TimeSpan((DateTime.Now.Ticks - theDate.Ticks));
return string.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 su capacidad de agregar nuevos puntos de marca. Esto podría resumirse con una Latest()
extensión de Timespan en lugar de esa larga línea 1, pero en aras de la brevedad en la publicación, esto servirá.
Esto soluciona el problema de hace una hora, hace 1 hora, proporcionando una hora hasta que hayan transcurrido 2 horas.