Biblioteca Javascript para formatação de data relativa amigável [fechado]

94

Eu gostaria de exibir algumas datas como relativas à data atual em um formato amigável para humanos.

Exemplos de datas relativas amigas do ser humano:

  • 10 segundos atrás
  • 20 minutos a partir de agora
  • 1 dia atrás
  • 5 semanas atrás
  • 2 meses atrás

Basicamente preservando fielmente a ordem mais alta de magnitude (e de preferência, apenas mudando as unidades para cima ao passar por 2 dessas unidades - 5 semanas em vez de 1 mês).

Embora eu pudesse viver com uma biblioteca que tivesse menos controle e datas ainda mais amigáveis ​​como:

  • ontem
  • amanhã
  • Semana Anterior
  • há alguns minutos atrás
  • em algumas horas

Alguma biblioteca popular para isso?

rampion
fonte
Por que "1 dia atrás" é mais "amigável" do que simplesmente apresentar a data e a hora reais?
RobG de
5
@RobG Eu diria que é mais para evitar a mudança de contextos, por exemplo, em uma página que é principalmente de texto e sendo lida, a mudança de contexto para, por exemplo, mm / dd / aa pode causar uma pausa. Em uma tabela de dados, usar esse formato pode ser mais legível. Também depende do que o leitor precisa fazer com a data, por exemplo, se "isso aconteceu n dias atrás" ou "isso aconteceu antes de 01/01/1972" é acionável ou apropriado para o contexto do leitor.
wprl
Talvez, mas é confuso ver uma lista de eventos como "Ontem ... 3 dias atrás ... 10 / maio ...". Eu ainda preciso convertê-los todos em datas na minha cabeça para obter uma imagem de quando eles ocorreram. As datas são concisas e precisas, os valores de "tempo atrás" são coloquiais, não têm precisão e geralmente são úteis apenas com a data associada. Talvez seja só eu, mas talvez não. :-)
RobG de
6
Eu diria que depende do contexto. Afinal, você não diria "Fui pescar no dia 17 de fevereiro de 2014" se fosse ontem. Há muito mais uma pausa cerebral aqui. Esse tipo de texto é perfeito para uma lista de eventos recentes.
Simon Williams de
2
@RobG Só nerds como nós pensam assim, não são pessoas normais.

Respostas:

92

Desde que escrevi esta resposta, uma biblioteca conhecida disponível é moment.js .


Existem bibliotecas disponíveis , mas é trivial implementá-las você mesmo. Basta usar um punhado de condições.

Suponha que dateseja um Dateobjeto instanciado para o tempo com o qual deseja fazer uma comparação.

// 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';
}

Você precisaria adaptar isso para lidar com datas futuras.

alex
fonte
9
Ontem é antes da última meia-noite, não entre 24 e 48 horas atrás.
mxcl de
@mmaclaurin O meu nunca foi concebido para ser uma solução completa, apenas um indicador na direção certa. Vou fazer uma nota para atualizá-lo mais tarde, ou se quiser, fique à vontade para editar a resposta.
alex
Por favor, também dê uma olhada no date-fns ! É uma ótima biblioteca se você gosta de manter sua base de código pequena, porque ela ocupa muito menos espaço do que os momentjs!
mesqueeb
1
Mudei este código para criar uma getTimeAgofunção de estilo do Twitter gist.github.com/pomber/6195066a9258d1fb93bb59c206345b38
pomber
85

Escrevi moment.js , uma biblioteca de datas que faz isso. Tem cerca de 5 KB (2011), 52 KB ( 2019) e funciona em navegadores e no Node. Também é provavelmente a biblioteca de datas mais popular e famosa para JavaScript.

Ele suporta timeago, formatação, análise, consulta, manipulação, i18n, etc.

Timeago (tempo relativo) para datas no passado é concluído moment().fromNow(). Por exemplo, para exibir 1º de janeiro de 2019 no 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>

As strings timeago são personalizáveis ​​com moment.updateLocale(), portanto, você pode alterá-las como quiser.

Os cortes não são o que a pergunta pede ("5 semanas" vs. "1 mês"), mas é documentado quanto a quais strings são usadas em qual intervalo de tempo.

Timrwood
fonte
1
Parabéns por fazê-lo funcionar no navegador e no nó !!!!
wprl
48
ha essa atualização de tamanho embora!
Askdesigners
1
Por favor, também dê uma olhada no date-fns ! É uma ótima biblioteca se você gosta de manter sua base de código pequena, porque ela ocupa muito menos espaço do que os momentjs!
mesqueeb
Por melhor que seja esta biblioteca, a resposta não inclui uma explicação sobre como formatar um número de uma maneira amigável para humanos usando-a
Code Whisperer
16

Aqui está algo do John Resig - http://ejohn.org/blog/javascript-pretty-date/

EDITAR (27/06/2014): Seguindo o comentário de Sumurai8 - embora a página do link ainda funcione, aqui está o trecho do link pretty.jspara do artigo acima:

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

Trecho do artigo sobre o uso:

Exemplo de uso

Nos exemplos a seguir, faço com que todas as âncoras no site, que têm um título com uma data nele, tenham uma data bonita como seu texto interno. Além disso, continuo a atualizar os links a cada 5 segundos após o carregamento da página.

Com 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);

Com jQuery:

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

Faiz: Fez algumas alterações no código original, correções de bugs e melhorias.

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
fonte
1
Olá, Floyd, adicionei algumas alterações (correção de bug, melhorias) à sua resposta. Espero que não se importe ..
Faiz
Um bom! Mas não funciona com tipo numérico de carimbo de data / hora, talvez precise de um filtro melhor, como if (typeof time == 'string') {time = time.replace (/ - / g, "/").replace(/[TZ]/ g, "")); }
Arthur Araújo
15

sugar.js tem ótimas funções de formatação de data.

Além disso, ele também fornece funções de uso geral comuns, como formatação de strings, formatação de números, etc., que são convenientes de usar.

Hendy Irawan
fonte
1
concordo, sugar.js merece mais atenção aqui.
citykid
5

aqui um exemplo de açúcar vs momento: para um calendário que exibe semanas, eu precisava do valor da última segunda-feira:

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

Eu prefiro muito mais açúcar e depois de alguns meses com moment.js agora mudo para sugar.js. é mais claro e se integra bem com a classe Date do Javascripts.

Os casos de OP são cobertos por ambas as libs, para sugar.js veja http://sugarjs.com/dates

garoto da cidade
fonte
4

Este script js é muito bom. Tudo que você precisa fazer é executá-lo. Todas as <time>tags serão alteradas para datas relativas e atualizadas a cada poucos minutos, de modo que a hora relativa estará sempre atualizada.

http://timeago.yarp.com/

Boreq
fonte
1
Acho que essa é a melhor solução. A biblioteca é mantida de forma muito ativa, é baseada / inspirada no código do Resig, é muito pequena, tem toneladas de localizações, é trivial de integrar.
John Bachir
4

Parece que você poderia usar http://www.datejs.com/

Eles têm um exemplo na página principal que faz exatamente o que você está descrevendo!

EDIT: Na verdade, acho que inverti sua pergunta na minha cabeça. Em qualquer caso, acho que você poderia dar uma olhada, pois é uma ótima biblioteca de qualquer maneira!

EDIT x2: Vou repetir o que os outros disseram que http://momentjs.com/ é provavelmente a melhor escolha disponível agora.

EDIT x3: Não uso date.js há mais de um ano. Estou usando o momentjs exclusivamente para todas as minhas necessidades relacionadas a encontros.

RoboKozo
fonte
Boa sugestão de lib. A internacionalização é definitivamente uma vantagem.
Stephen,
Date.js também foi meu primeiro pensamento, mas não vejo nenhuma maneira de ir do número ao formato com ele - embora possa estar oculto em algum lugar nos documentos.
rampion
Date.js é conhecido por ter erros graves e não é confiável em ambientes de produção. Muitos frameworks estão mudando de Date.js para Moment.js
John Zabroski
Aprendi da maneira mais difícil que datejs não funciona no Linux :(
fat fantasma