Biblioteca de JavaScript para formato de fecha relativa amigable para los humanos [cerrado]

94

Me gustaría mostrar algunas fechas en relación con la fecha actual en un formato amigable para los humanos.

Ejemplos de fechas relativas amigables con los humanos:

  • Hace 10 segundos
  • 20 minutos a partir de ahora
  • Hace 1 día
  • Hace 5 semanas
  • Hace 2 meses

Básicamente, preservando fielmente el orden de magnitud más alto (y, de preferencia, solo cambiando unidades cuando se pasan 2 de esas unidades, 5 semanas en lugar de 1 mes).

Aunque podría vivir con una biblioteca que tuviera menos control y fechas aún más amigables como:

  • ayer
  • mañana
  • la semana pasada
  • Hace pocos minutos
  • en un par de horas

¿Alguna biblioteca popular para esto?

rampion
fuente
¿Por qué "hace 1 día" es más "amigable para los humanos" que simplemente presentar la fecha y hora reales?
RobG
5
@RobG Diría que se trata más de evitar el cambio de contextos, por ejemplo, en una página que es principalmente texto y se está leyendo, el cambio de contexto a, por ejemplo, mm / dd / aa puede causar una pausa. En una tabla de datos, usar ese formato podría ser más legible. También depende de lo que el lector necesite hacer con la fecha, por ejemplo, si "esto sucedió hace n días" o "esto sucedió antes del 1/1/1972" es procesable o apropiado para el contexto del lector.
wprl
Quizás, pero es confuso ver una lista de eventos como "Ayer ... hace 3 días ... 10 / mayo ...". Todavía necesito convertirlos todos en fechas en mi cabeza para tener una idea de cuándo ocurrieron. Las fechas son concisas y precisas, los valores de "hace tiempo" son conversacionales, carecen de precisión y generalmente solo son útiles con la fecha asociada. Tal vez sea solo yo, pero tal vez no. :-)
RobG
6
Diría que depende del contexto. Después de todo, no dirías "Fui a pescar el 17 de febrero de 2014" si eso fuera ayer. Hay mucha más pausa cerebral ahí. Este tipo de texto es perfecto para una lista de eventos recientes.
Simon Williams
2
@RobG Solo los nerds como nosotros pensamos así, no la gente normal.

Respuestas:

92

Desde que escribí esta respuesta, una biblioteca conocida disponible es moment.js .


Hay bibliotecas disponibles , pero es trivial implementarlas usted mismo. Solo use un puñado de condiciones.

Suponga que datees un Dateobjeto instanciado para el tiempo con el que desea realizar una comparación.

// Make a fuzzy time
var delta = Math.round((+new Date - date) / 1000);

var minute = 60,
    hour = minute * 60,
    day = hour * 24,
    week = day * 7;

var fuzzy;

if (delta < 30) {
    fuzzy = 'just then.';
} else if (delta < minute) {
    fuzzy = delta + ' seconds ago.';
} else if (delta < 2 * minute) {
    fuzzy = 'a minute ago.'
} else if (delta < hour) {
    fuzzy = Math.floor(delta / minute) + ' minutes ago.';
} else if (Math.floor(delta / hour) == 1) {
    fuzzy = '1 hour ago.'
} else if (delta < day) {
    fuzzy = Math.floor(delta / hour) + ' hours ago.';
} else if (delta < day * 2) {
    fuzzy = 'yesterday';
}

Debería adaptar esto para manejar fechas futuras.

alex
fuente
9
Ayer es antes de la última medianoche, no entre 24 y 48 horas antes.
mxcl
@mmaclaurin Mine nunca tuvo la intención de ser una solución completa, solo un indicador en la dirección correcta. Tomaré una nota para actualizarlo más tarde, o si lo desea, no dude en editar la respuesta.
alex
¡Por favor, también eche un vistazo a date-fns ! Es una gran biblioteca si desea mantener su base de código pequeña, ¡porque tiene una huella mucho menor que momentjs!
mesqueeb
1
Cambié este código para hacer una getTimeAgofunción de estilo de Twitter gist.github.com/pomber/6195066a9258d1fb93bb59c206345b38
pomber
85

Escribí moment.js , una biblioteca de fechas que hace esto. Tiene aproximadamente 5 KB (2011) 52 KB (2019) y funciona en navegadores y en Node. También es probablemente la biblioteca de fechas más popular y famosa para JavaScript.

Admite tiempo atrás, formateo, análisis, consultas, manipulación, i18n, etc.

Timeago (tiempo relativo) para fechas en el pasado se ha terminado moment().fromNow(). Por ejemplo, para mostrar el 1 de enero de 2019 en el formato timeago:

let date = moment("2019-01-01", "YYYY-MM-DD");
console.log(date.fromNow());
<script src="https://momentjs.com/downloads/moment.min.js"></script>

Las cadenas de tiempo atrás se pueden personalizar con moment.updateLocale(), por lo que puede cambiarlas como mejor le parezca.

Los límites no son los que solicita la pregunta ("5 semanas" frente a "1 mes"), pero se documenta qué cadenas se utilizan para qué intervalo de tiempo.

Timrwood
fuente
1
Felicitaciones por hacerlo funcionar en el navegador y el nodo.
wprl
48
¡Sin embargo, esa actualización de tamaño!
Askdesigners
1
¡Por favor, también eche un vistazo a date-fns ! Es una gran biblioteca si desea mantener su base de código pequeña, ¡porque tiene una huella mucho menor que momentjs!
mesqueeb
A pesar de lo buena que es esta biblioteca, la respuesta no incluye una explicación sobre cómo formatear un número de una manera amigable para los humanos usándolo
Code Whisperer
16

Aquí hay algo de John Resig: http://ejohn.org/blog/javascript-pretty-date/

EDITAR (27/6/2014): Continuando con el comentario de Sumurai8 , aunque la página vinculada todavía funciona, aquí está el extracto delpretty.js vínculo del artículo anterior:

pretty.js

/*
 * JavaScript Pretty Date
 * Copyright (c) 2011 John Resig (ejohn.org)
 * Licensed under the MIT and GPL licenses.
 */

// Takes an ISO time and returns a string representing how
// long ago the date represents.
function prettyDate(time) {
    var date = new Date((time || "").replace(/-/g, "/").replace(/[TZ]/g, " ")),
        diff = (((new Date()).getTime() - date.getTime()) / 1000),
        day_diff = Math.floor(diff / 86400);

    if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31) return;

    return day_diff == 0 && (
    diff < 60 && "just now" || diff < 120 && "1 minute ago" || diff < 3600 && Math.floor(diff / 60) + " minutes ago" || diff < 7200 && "1 hour ago" || diff < 86400 && Math.floor(diff / 3600) + " hours ago") || day_diff == 1 && "Yesterday" || day_diff < 7 && day_diff + " days ago" || day_diff < 31 && Math.ceil(day_diff / 7) + " weeks ago";
}

// If jQuery is included in the page, adds a jQuery plugin to handle it as well
if (typeof jQuery != "undefined") jQuery.fn.prettyDate = function() {
    return this.each(function() {
        var date = prettyDate(this.title);
        if (date) jQuery(this).text(date);
    });
};

Uso:

prettyDate("2008-01-28T20:24:17Z") // => "2 hours ago"
prettyDate("2008-01-27T22:24:17Z") // => "Yesterday"
prettyDate("2008-01-26T22:24:17Z") // => "2 days ago"
prettyDate("2008-01-14T22:24:17Z") // => "2 weeks ago"
prettyDate("2007-12-15T22:24:17Z") // => undefined

Extracto del artículo sobre uso:

Ejemplo de uso

En los siguientes ejemplos, hago que todas las anclas en el sitio, que tienen un título con una fecha, tengan una fecha bonita como texto interno. Además, continúo actualizando los enlaces cada 5 segundos después de que se haya cargado la página.

Con JavaScript:

function prettyLinks(){
    var links = document.getElementsByTagName("a");
    for ( var i = 0; i < links.length; i++ )
        if ( links[i].title ) {
            var date = prettyDate(links[i].title);
            if ( date )
                links[i].innerHTML = date;
        }
}
prettyLinks();
setInterval(prettyLinks, 5000);

Con jQuery:

$("a").prettyDate();
setInterval(function(){ $("a").prettyDate(); }, 5000);

Faiz: Hizo algunos cambios en el código original, correcciones de errores y mejoras.

function prettyDate(time) {
    var date = new Date((time || "").replace(/-/g, "/").replace(/[TZ]/g, " ")),
        diff = (((new Date()).getTime() - date.getTime()) / 1000),
        day_diff = Math.floor(diff / 86400);
    var year = date.getFullYear(),
        month = date.getMonth()+1,
        day = date.getDate();

    if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31)
        return (
            year.toString()+'-'
            +((month<10) ? '0'+month.toString() : month.toString())+'-'
            +((day<10) ? '0'+day.toString() : day.toString())
        );

    var r =
    ( 
        (
            day_diff == 0 && 
            (
                (diff < 60 && "just now")
                || (diff < 120 && "1 minute ago")
                || (diff < 3600 && Math.floor(diff / 60) + " minutes ago")
                || (diff < 7200 && "1 hour ago")
                || (diff < 86400 && Math.floor(diff / 3600) + " hours ago")
            )
        )
        || (day_diff == 1 && "Yesterday")
        || (day_diff < 7 && day_diff + " days ago")
        || (day_diff < 31 && Math.ceil(day_diff / 7) + " weeks ago")
    );
    return r;
}
Hari Pachuveetil
fuente
1
Hola Floyd, agregué algunos cambios (corrección de errores, mejoras) a tu respuesta. Espero que no te importe ...
Faiz
¡Buena! Pero no trabaje con el tipo numérico de marca de tiempo, tal vez necesite un filtro mejor como if (typeof time == 'string') {time = time.replace (/ - / g, "/").replace(/[TZ]/ g, "")); }
Arthur Araújo
15

sugar.js tiene excelentes funciones de formato de fecha.

No solo eso, también proporciona funciones comunes de propósito general como formato de cadena, formato de número, etc. que son convenientes de usar.

Hendy Irawan
fuente
1
de acuerdo, sugar.js merece más atención aquí.
citykid
5

aquí un ejemplo de azúcar vs momento: para un calendario que muestra semanas, necesitaba el valor del último lunes:

moment.js

var m = moment().subtract("days", 1).sod().day(1) // returns a "moment"

sugar.js

var d = Date.past("monday") // returns a js Date object

Prefiero el azúcar y después de algunos meses con moment.js ahora cambio a sugar.js. es más claro y se integra muy bien con la clase Date de Javascripts.

Los casos de OP están cubiertos por ambas bibliotecas, para sugar.js, consulte http://sugarjs.com/dates

ciudad
fuente
4

Este script js es muy bueno. Todo lo que tienes que hacer es ejecutarlo. Todas<time> etiquetas se cambiarán a fechas relativas y se actualizarán cada pocos minutos, por lo que la hora relativa siempre estará actualizada.

http://timeago.yarp.com/

boreq
fuente
1
Creo que esta es la mejor solución. La biblioteca se mantiene muy activamente, está basada en / inspirada en el código de Resig, es muy pequeña, tiene toneladas de localizaciones, es trivial de integrar.
John Bachir
4

Parece que podrías usar http://www.datejs.com/

¡Tienen un ejemplo en la página principal que hace exactamente lo que estás describiendo!

EDITAR: En realidad, creo que invertí tu pregunta en mi cabeza. En cualquier caso, creo que podrías echarle un vistazo, ¡ya que es una gran biblioteca de todos modos!

EDITAR x2: Voy a hacerme eco de lo que han dicho los demás http://momentjs.com/ es probablemente la mejor opción disponible en este momento.

EDITAR x3: No he usado date.js en más de un año. Estoy usando exclusivamente momentjs para todas mis necesidades relacionadas con las citas.

RoboKozo
fuente
Buena sugerencia de lib. La internacionalización definitivamente es una ventaja.
Stephen
Date.js también fue mi primer pensamiento, pero no veo ninguna forma de pasar de un número a otro con él, aunque podría estar oculto en algún lugar de los documentos.
rampion
Se sabe que Date.js tiene errores graves y no se puede confiar en los entornos de producción. Muchos marcos están cambiando de Date.js a Moment.js
John Zabroski
Aprendí por las malas que datejs no funciona en linux :(
fat fantasma