miércoles, 6 de julio de 2011

Fechas relativas en Blogger

Las fechas relativas son algo que se puso de moda hace ya tiempo y que vemos mucho en las redes sociales.

Una fecha relativa, en lugar de mostrar dia, mes y año de cierta entrada, lo que indica es el tiempo transcurrido desde su publicación hasta el momento actual; por ejemplo: "hace 2 minutos" o "dos dias atrás" o "hace un año"; cualquier texto que a uno se le ocurra.

Quienes usan Wordpress disponen de muchos plugins ya pensados para eso (la mayoría en inglés, of course) pero, en Blogger no es algo que se vea muy seguido. En Blog and Web hay una explicación de cómo hacerlo en este tipo de blogs y se trata de una adaptación de, justamente, un plugin de WordPress. Basándome en eso, vamos a ver si se pueden generar otras posibilidades.

Lo primero que pienso es que, para que este tipo de cosas funcione correctamente lo que debo usar es una fecha perfecta ¿A qué me refiero? A que JavaSprit posee muchas funciones para manejar fechas pero si quiero hacer un cálculo preciso, necesito un formato de fecha de esos que, a primera vista, es completamente ilegible así que no puedo usar ni <data:post.dateHeader/> ni <data:post.timestamp/> que son los dos datos que puedo configurar, tanto en el blog como en el widget de las entradas; necesito otro que no usamos nunca pero que está allí y se llama: <data:post.timestampISO8601/>

Ese dato me dará como resultado una fecha de este tipo:

2010-03-25T15:30:20-03:00

¿Que es eso? El año, el mes, el dia; seguido de la letra T que indica la hora, los minutos y los segundos, seguido de un valor (-03:00 en mi caso) que es la Zona Horaria establecida en Configuración | Formato.


Lo voy a usar pro dos razones, primero, porque manejar fechas en JavaScript que no están en inglés resulta complicado y segundo, porque de ese modo, no necesito modificar nada de la configuración del blog. Entonces, debería crear una función que lea ese dato y lo convierta en un número.

Suponiendo que la variable dato contenga esa fecha :
// la fecha y hora de publicación del post, expresada en segundos
var fechapost = new Date(dato).getTime()/1000;

// la fecha y hora actual expresada en segundos
var ahora = new Date().getTime()/1000;

// si la fecha es mayor que "ahora" es un post con fecha futura así que debería hacer algo distinto o no hacer nada
if(fechapost>ahora) { return; }

// estos son los segundos transcurridos entre el momento actual y el momento en que se publicó el post
var segundos = ahora - fechapost;
Teniendo el valor de los segundos, ahora es cuestión de usar aritmética para calcular las fracciones es decir, expresar segundos de otra manera. La solución clásica es algo así:
var calctiempo = segundos;
var salida = "";
var bucle = 6;
var t;

var p = [];
p['año'] = 31536000;
p['semana'] = 604800;
p['dia'] = 86400;
p['hora'] = 3600;
p['minuto'] = 60;
p['segundo'] = 1;

for(var periodo in p) {
var valor = p[periodo];
if(calctiempo>=valor) {
t = Math.floor(calctiempo/valor);
calctiempo%=valor;
salida += t; // es el valor
salida += " "; // un caracter espacio
salida += periodo; // el texto
if(t>1){ salida += "s"; } // los plurales
}
salida += " "; // otro caracter espacio
bucle--;
if(bucle==0){ break; }
}

document.write(salida);
Esto mostraría algo así:

2 dias 17 horas 59 minutos 10 segundos

Ahora bien, sería mejor usar algo menos matemático y poner textos más humanos, ya sea "hace instantes", "hace más de un hora" o "hace tanto tiempo que ya no me acuerdo". Para eso puede usarse el mismo tipo de esquema que utilizan los scripts de Twitter así me voy a crear una función similar donde, usando aritmética, podamos ir estableciendo fracciones de tiempo a gusto de cada uno; nada grave, por ejemplo:

minutos = segundos / 60
horas = segundos / 60*60 = segundos / 3600
dias = segundos / 60*60*24 = segundos / 86400
semanas = segundos / 60*60*24*7 = segundos / 604800

Los meses ya son complicados de calcular así que voy por lo fácil, hago de cuenta que todos tienen 31 dias y a otra cosa:

meses = segundos / 60*60*24*31 = segundos / 2678400

Algo similar pasaría con los años bisiestos pero acá no se trata de precisión sino de redondeos así que:

años = segundos / 60*60*24*365 = segundos / 31536000

La función que pongo antes de </head>
<script type='text/javascript'>
//<![CDATA[
function fecharelativa(dato) {
var fechapost = new Date(dato).getTime()/1000; // fecha y hora de la publicación
var ahora = new Date().getTime()/1000; // fecha y hora actual
if(fechapost>ahora) { return; } // si la fecha es incongruente no hago nada
// los segundos transcurridos entre esas dos fechas
var segundos = ahora - fechapost;

// calculo toods los datos
var minutos = (parseInt(segundos / 60)).toString();
var horas = (parseInt(segundos / 3600)).toString();
var dias = (parseInt(segundos / 86400)).toString();
var semanas = (parseInt(segundos / 604800)).toString();
var meses = (parseInt(segundos / 2678400)).toString();
var anios = (parseInt(segundos / 31536000)).toString();

// y comienzo a armar lo que será el texto teneindo en cuenta que debo redondear ciertas fracciones
var salida = "";

if (minutos < 1) { // menos de un minuto
salida = "hace menos de un minuto";
} else if(minutos == 1) { // un minuto y algo más, menos de dos minutos
salida = "hace poco más de un minuto";
} else if(horas < 1) { // menos de una hora
salida = "hace " + minutos + " minutos";
} else if(horas == 1) { // una hora y algo más, menos de dos horas
salida = "hace poco más de una hora";
} else if(dias < 1) { // menos de un dia
salida = "hace " + horas + " horas";
} else if(dias == 1) { // un dia y algo más, menos de dos dias
salida = "hace poco más de un dia";
} else if(semanas < 1) { // menos de una semana
salida = "hace menos de una semana";
} else if(semanas == 1) { // una semana y algo más, menos de dos semanas
salida = "hace una semana";
} else if(meses < 1) { // aproximadamente menos de un mes
salida = "hace " + dias + " días";
} else if(meses == 1) { // un mes ... con un cierto margen
salida = "hace un mes";
} else if(anios < 1) { // menos de un año
salida = "hace " + meses + " meses";
} else if(anios == 1) { // aproximadamente un año
salida = "hace un año";
} else { // más de un año
salida = "hace " + anios + " años";
}

// y escribo ese texto
document.write(salida);
}
//]]>
</script>
¿Cómo lo uso en Blogger? Tengo que llamar a al función en alguna parte; por ejemplo, podría hacerlo en el mismo lugar donde coloco el nombre del autor; busco <data:post.author/> y lo cambio así:

Publicado por <data:post.author/>
<script type='text/javascript'>fecharelativa(&#39;<data:post.timestampISO8601/>&#39;);</script>

Como no voy a usar este esquema de fechas de entradas, no hay un ejemplo pero, no sólo es posible utilizarlo para mostrar la fecha de las entradas, también podríamos usarlo para mostrar la fecha de los comentarios que suele ser uno de esos datos que uno no personaliza y en el que solemos ver la hora.

Para esto, el script es exactamente el mismo pero, debo ir a Configuración | Comentarios y establecer un formato de fecha adecuado; en este caso, elijo este que es el más completo:


Luego, debo llamar a la función así que busco esta parte:
<dd class='comment-footer'>
<span class='comment-timestamp'>
<a expr:href='&quot;#comment-&quot; + data:comment.id' rel='nofollow' title='comment permalink'><data:comment.timestamp/></a>
<b:include data='comment' name='commentDeleteIcon'/>
</span>
</dd>
Y hago lo mismo que antes, cambio <data:comment.timestamp/> por el script:
<script type="text/javascript">fecharelativa(&#39;<data:comment.timestamp/>&#39;);</script>

ACTUALIZACION:

Como Blogger parece haber cambaido las opciones de formato y las fechas que antes se mostraban como:
7/17/2011 00:30:00 AM o 7/17/2011 00:30:00 PM
ahora se muestran como:
7/17/2011 00:30:00 a.m. o 7/17/2011 00:30:00 p.m.
debería modificar el inico del script para que puedan ser interpretadas y la funcion debería comenzar así:
dato=dato.replace("a.m.","AM");
dato=dato.replace("p.m.","PM");
var fechapost = new Date(dato).getTime()/1000; // fecha y hora de la publicación

No hay comentarios:

Publicar un comentario