JASoft.org

El blog de José Manuel Alarcón Aguín. Programación web y mucho más...

MENÚ - JASoft: JM Alarcón

Mostrar fechas relativas estilo Facebook en nuestras aplicaciones

Este es un truco sencillo pero útil que puede ayudar a hacer más amigables las fechas de cara a los usuarios.

Generalmente cuando mostramos una fecha y hora en una de nuestras aplicaciones tendemos a mostrar este dato de la forma habitual, es decir, visualizando la fecha y la hora en el formato que sea apropiado para el idioma y país actuales. Sin embargo para la mayoría de los usuarios esta información no les dice gran cosa y tienen que fijarse y hacer cálculos mentales para hacerse una idea de cuándo es exactamente ese evento, sea en el pasado o en el futuro.

En este sentido sería mucho más útil mostrarle al usuario una fecha indicada de un modo más amigable, relativo al momento actual y de forma que resulte más informativa para el usuario medio.

Así, en lugar de mostrarles simplemente la fecha, resultaría mucho más útil decirles cosas como "Hace 3 minutos", "Dentro de 2 días" o expresiones similares. Incluso podríamos mostrarle ambas cosas, por ejemplo expresiones como las anteriores y además la fecha y hora completas en un "Tooltip" por si quieren afinar.

Un gran ejemplo de ello es lo que hace Facebook:

IntervaloRelativoEnTexto

 

Si te fijas muestra la fecha en la que se produjo un evento (en este caso el envío de un post) en un formato amigable y fácil de entender para el usuario, y si dejas el cursor encima muestra la fecha y hora completas en un Tooltip.

Conseguirlo es muy sencillo y además gracias al uso de los métodos extensores es realmente fácil de usar en cualquier página ASPX o aplicación de escritorio, incluso en expresiones enlazadas a datos.

Para ello he construido un método extensor que extiende a la clase DateTime para añadirle un nuevo método DiferenciaEnTexto. Con él para obtener los intervalos de tiempo de manera similar a la de Facebook basta con escribir:

miFecha.DiferenciaEnTexto()

Y obtendremos una cadena igual.

El código necesario en C# es el siguiente:

   1: public static class DateTimeExt
   2: {
   3:     // Método extensor para obtener las fechas en formato relativo de texto (hace 3 segundos...)
   4:     public static string DiferenciaEnTexto(this DateTime fecha)
   5:     {
   6:         //Fecha y hora actuales
   7:         DateTime ahora = DateTime.Now;
   8:         
   9:         //Variables
  10:         TimeSpan diferencia;
  11:         string prefijo = "Hace {0} {1}";    // Para construir, por defecto, "Hace 5 minutos" o similares
  12:         
  13:         diferencia = ahora.Subtract(fecha);
  14:         //Compruebo si es un momento en el pasado o en el futuro
  15:         if (diferencia.Ticks < 0) // Momento en el pasado
  16:         {
  17:             prefijo = "Dentro de {0} {1}"; // para momentos en el futuro, y construir "Dentro de 5 minutos"
  18:             diferencia = diferencia.Negate();    // Lo dejo en positivo para las comprobaciones de rangos
  19:         }
  20:         
  21:         if (diferencia.Days >= 7)    //Hace una semana o más
  22:             return String.Format("El {0} a las {1}", fecha.ToLongDateString(), fecha.ToLongTimeString());
  23:         else if (diferencia.Days >= 2)    //Entre 1 día y una semana
  24:             return String.Format(prefijo, diferencia.Days, "días");
  25:         else if (diferencia.Days == 1) //Hace un día, o sea, ayer
  26:             return "ayer";
  27:         else if (diferencia.Hours >= 2)
  28:             return String.Format(prefijo, diferencia.Hours, "horas");
  29:         else if (diferencia.Minutes >= 2)
  30:             return String.Format(prefijo, diferencia.Minutes, "minutos");
  31:         else 
  32:             return String.Format(prefijo, Math.Floor(diferencia.TotalSeconds), "segundos");
  33:  
  34:     }

Como vemos se trata de un código muy sencillo.

Defino una clase estática que actuará de contenedora del método extensor. el método DiferenciaEnTexto es extensor porque es estático y su único parámetro lleva la palabra clave "this" delante y es de tipo DateTime, así que extiende a este tipo.

El código funciona indistintamente con fechas en el pasado y en el futuro. Si las fechas son negativas (en el futuro) hace uso del método Negate de la clase TimeSpan para actuar sobre el intervalo siempre en positivo, cambiando la frase mostrada.

Sólo se muestra la fecha y hora en formato habitual cuando hay más de 7 días de diferencia, aunque podríamos cambiarlo fácilmente para cualquier intervalo menos o mayor en el primer condicional. Para los segundos entre 0 y 119 (dos minutos) he utilizado la propiedad TotalSeconds de TimeSpan para expresar el intervalo concreto en segundos, y no sólo los segundos que sobran del minuto, que sería lo que obtendríamos usando simplemente la propiedad Seconds. Esto sólo lo hago en los segundos porque en este intervalo tan pequeño sí que se necesita más precisión, pero no así en otros más amplios como minutos y sucesivos. Además se redondea a la fracción mínima de segundo ya que TotalSeconds devuelve valores decimales pues es un cálculo con mucha precisión.

Si quieres puedes descargarte el ejemplo desde DiferenciaEnTexto.zip (894 bytes).

¡Espero que te sea útil!

José Manuel Alarcón José Manuel Alarcón
Fundador de campusMVP.es, el proyecto de referencia en formación on-line para programadores en lengua española. Autor de varios libros y cientos de artículos. Galardonado como MVP de Microsoft desde 2004. Gallego de Vigo, amante de la ciencia y la tecnología, la música y la lectura. Ayudando a la gente en Internet desde 1996.
Descarga GRATIS mi último libro (no técnico): "Tres Monos, Diez Minutos".
Banner

Comentarios (4) -

Hola José Manuel!

En primer lugar gracias por el código, me ha resultado muy útil.

Tan solo comentar que cuando son horas devuelve "Hace 4,28751915697222 horas", esto es debido a que diferencia.TotalHours devuelve un double.
Simplemente pasándolo a entero imagino que ya desaparece el problema:

Convert.ToInt32(diferencia.TotalHours)

Muchas gracias por tu tiempo y enhorabuena por la página, la sigo mediante RSS y así seguiré haciendolo! Publicas mucho contenido interesante.

Un saludo

Responder

Hola Pablo:

gracias por comentar. Se me pasó ese detalle. Ahí, de hecho tenía un "Hours" que es lo que tenía que tener, pero probando lo sustituí por un TotalHours (más preciso) y por eso pasa eso. Lo cambio en el post y en la descarga.

Gracias.

Responder

Chile Iván Ramírez

Hola José Manuel:

Muchas gracias por el ejemplo, ha sido muy util... solo tengo un detalle y eso ocurre cuando la fecha es MAÑANA, según lo que he visto el código tiene un error, ya que si usas el "negate" no es posible determinar si la fecha es Ayer o Mañana, por ende no se debería usar y nos obliga a hacer las preguntas por los rangos positivos y negativos..

Saludos..

Responder

Spain José Manuel Alarcón

Hola Iván,

Es que este código está pensado sólo para trabajar con fechas en el pasado. La verdad es que no se me ocurrió usarlo para fechas en el futuro, pero estaría bien adaptarlo.

Un saludo!

Responder

Agregar comentario