Библиотека Javascript для удобного для человека форматирования относительной даты [закрыто]

96

Я хотел бы отображать некоторые даты относительно текущей даты в удобном для человека формате.

Примеры дружественных человеку относительных свиданий:

  • 10 секунд назад
  • Через 20 минут
  • 1 день назад
  • 5 недель назад
  • 2 месяца назад

В основном добросовестно сохраняя наивысший порядок величины (и предпочтительно сдвигать единицы только при прохождении 2 из этих единиц - 5 недель вместо 1 месяца).

Хотя я мог бы жить с библиотекой, в которой меньше контроля и даже более дружеские свидания, например:

  • вчера
  • завтра
  • прошлая неделя
  • Несколько минут назад
  • через пару часов

Какие-нибудь популярные библиотеки для этого?

рамп
источник
Почему «1 день назад» более «дружелюбно» для людей, чем просто представление фактических даты и времени?
RobG
5
@RobG Я бы сказал, что это больше касается избежания переключения контекстов, например, на странице, которая в основном текстовая и читается, переключение контекста, например, на mm / dd / yy может вызвать паузу. В таблице данных использование этого формата может быть более читаемым. Это также зависит от того, что читателю нужно делать с датой, например, является ли фраза «это произошло n дней назад» или «это произошло до 01.01.1972» применимыми или иным образом соответствуют контексту читателя.
wprl
Возможно, но сбивает с толку видеть в списке событий «Вчера ... 3 дня назад ... 10 / мая ...». Мне все еще нужно преобразовать их все в даты в моей голове, чтобы получить представление о том, когда они произошли. Даты краткие и точные, значения «время назад» являются разговорным, нечетким и обычно полезны только с соответствующей датой. Может быть, это только я, а может и нет. :-)
RobG
6
Я бы сказал, это зависит от контекста. В конце концов, вы бы не сказали: «Я ходил на рыбалку 17 февраля 2014 года», если бы это было вчера. Здесь гораздо больше паузы для мозга. Такой текст идеально подходит для списка последних событий.
Саймон Уильямс
2
@RobG Так думают только такие ботаники, как мы, ненормальные люди.

Ответы:

94

Поскольку я написал этот ответ, доступна хорошо известная библиотека moment.js .


Доступны библиотеки , но реализовать их самостоятельно - тривиально. Просто используйте несколько условий.

Предположим, dateчто это экземпляр Dateобъекта на то время, с которым вы хотите провести сравнение.

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

Вам нужно будет адаптировать это для работы с будущими свиданиями.

Алекс
источник
9
Вчера до последней полуночи, а не между 24 и 48 часами назад.
mxcl
@mmaclaurin Mine никогда не задумывался как полное решение, это просто указатель в правильном направлении. Я сделаю заметку, чтобы обновить его позже, или, если хотите, не стесняйтесь редактировать ответ.
Alex
Также обратите внимание на date-fns ! Это отличная библиотека, если вы хотите, чтобы ваша база кода была небольшой, потому что она занимает гораздо меньше места, чем momentjs!
mesqueeb
1
Я изменил этот код , чтобы сделать щебетать стиль getTimeAgoфункции gist.github.com/pomber/6195066a9258d1fb93bb59c206345b38
pomber
88

Я написал moment.js , библиотеку дат, которая делает это. Это около 5 КБ (2011 г.) 52 КБ (2019 г.) и работает в браузерах и в Node. Это также, вероятно, самая популярная и известная библиотека дат для JavaScript.

Он поддерживает timeago, форматирование, синтаксический анализ, запросы, манипулирование, i18n и т. Д.

Timeago (относительное время) для дат в прошлом не используется moment().fromNow(). Например, чтобы отобразить 1 января 2019 г. в формате timeago:

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

Строки timeago можно настроить с помощью moment.updateLocale(), поэтому вы можете изменить их по своему усмотрению.

Ограничения - это не то, что запрашивается в вопросе («5 недель» против «1 месяца»), но они задокументированы относительно того, какие строки используются для какого диапазона времени.

Timrwood
источник
1
Престижность за то, что он работает в браузере и ноде !!!!
wprl
50
Ха, хотя обновите этот размер!
Askdesigners
1
Также обратите внимание на date-fns ! Это отличная библиотека, если вы хотите, чтобы ваша база кода была небольшой, потому что она занимает гораздо меньше места, чем momentjs!
mesqueeb
Как бы хороша ни была эта библиотека, ответ не включает объяснения того, как отформатировать число удобным для человека способом, используя ее
Code Whisperer
Вы тоже собираетесь обновляться с "устареванием"? momentjs.com/docs/#/-project-status
Хуан Де ла Крус
17

Вот что-то от Джона Ресига - http://ejohn.org/blog/javascript-pretty-date/

РЕДАКТИРОВАТЬ (27.06.2014): В продолжение комментария Sumurai8 - хотя связанная страница все еще работает, вот отрывок для pretty.jsссылки из статьи выше:

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

Применение:

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

Выдержка из статьи по использованию:

Пример использования

В следующих примерах я делаю все якоря на сайте, у которых есть заголовок с датой в нем, с красивой датой в качестве внутреннего текста. Кроме того, я продолжаю обновлять ссылки каждые 5 секунд после загрузки страницы.

С помощью 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);

С jQuery:

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

Фаиз: Внесены некоторые изменения в исходный код, исправлены ошибки и улучшены.

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;
}
Хари Пачувеетил
источник
1
Привет, Флойд, я добавил некоторые изменения (исправление ошибок, улучшения) к вашему ответу. Надеюсь, вы не против ..
Faiz
Хороший! Но не работайте с числовым типом timestamp, возможно, понадобится лучший фильтр, например if (typeof time == 'string') {time = time.replace (/ - / g, "/").replace(/[TZ ]/ грамм, " ")); }
Артур Араужо,
Пожалуйста, как учесть будущие даты? Примерно через 2 дня.
Икенна Эмман
15

Sugar.js имеет отличные функции форматирования даты.

Мало того, он также предоставляет общие функции общего назначения, такие как форматирование строк, форматирование чисел и т. Д., Которые удобны в использовании.

Хенди Ираван
источник
1
согласен, здесь больше внимания заслуживает sugar.js.
citykid
5

вот пример сахара против момента: для календаря, который отображает недели, мне нужно значение последнего понедельника:

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

Я предпочитаю сахар, и через несколько месяцев работы с moment.js я перехожу на sugar.js. он более понятен и хорошо интегрируется с классом Date Javascripts.

Случаи OP покрыты как LIBS для sugar.js см http://sugarjs.com/dates

горожанин
источник
4

Этот js-скрипт очень хорош. Все, что вам нужно сделать, это выполнить его. Все <time>теги будут изменены на относительные даты и обновляться каждые несколько минут, поэтому относительное время всегда будет актуальным.

http://timeago.yarp.com/

борек
источник
1
Думаю, это лучшее решение. Библиотека очень активно поддерживается, она основана на / вдохновлена ​​кодом Resig, она очень мала, в ней много локализаций, ее легко интегрировать.
John Bachir
4

Похоже, вы могли бы использовать http://www.datejs.com/

У них есть пример на главной странице, который делает именно то, что вы описываете!

РЕДАКТИРОВАТЬ: На самом деле, я думаю, что перевернул ваш вопрос в своей голове. В любом случае, я думаю, вы можете проверить это, так как это действительно отличная библиотека!

РЕДАКТИРОВАТЬ x2: Я собираюсь повторить то, что сказали другие, http://momentjs.com/ , вероятно, лучший выбор, доступный прямо сейчас.

ИЗМЕНИТЬ x3: я не использовал date.js больше года. Я использую momentjs исключительно для всех моих потребностей, связанных с датами.

РобоКозо
источник
Хорошее предложение lib. Интернационализация определенно плюс.
Стивен
Date.js тоже был моей первой мыслью, но я не вижу способа перейти от числа к форматированию с его помощью - хотя он может быть где-то спрятан в документации.
rampion
Известно, что Date.js содержит серьезные ошибки, и ему нельзя доверять в производственной среде. Многие фреймворки переходят с Date.js на Moment.js
Джон Заброски
Я на собственном горьком опыте узнал, что datejs не работает на linux :(
fat fantasma