Как отформатировать время с xxx например «4 минуты назад» аналогично сайтам Stack Exchange

Вопрос в том, как отформатировать JavaScript Date в виде строки, указывающей прошедшее время, подобно тому, как вы видите время, отображаемое в Stack Overflow.

e.g.

  • 1 минуту назад
  • 1 час назад
  • 1 день назад
  • 1 месяц назад
  • 1 год назад

person Sky Sanders    schedule 05.07.2010    source источник
comment
momentjs.com   -  person atilkan    schedule 05.05.2015
comment
github.com/catamphetamine/javascript-time-ago   -  person catamphetamine    schedule 09.01.2018
comment
Для этого полезно: _1 _ .   -  person Константин Ван    schedule 08.12.2019
comment
Moment устарел, это устаревший проект в режиме обслуживания. Переключитесь на встроенный Intl.RelativeTimeFormat в javascript или воспользуйтесь другими альтернативами.   -  person Maksim Shamihulau    schedule 13.01.2021


Ответы (25)


В этом случае это может быть излишним, но если возможность показывает, moment.js просто потрясающе!

Moment.js - это библиотека javascript datetime, чтобы использовать ее в таком сценарии, вам нужно:

moment(yourdate).fromNow()

http://momentjs.com/docs/#/displaying/fromnow/

Приложение 2018 г.: Luxon - это новая современная библиотека, которая может быть стоит посмотреть!

person Fabiano Soriani    schedule 16.04.2013
comment
Здравствуйте, я использую ваш ответ для получения разницы во времени. Что делать, если мне нужны только первые буквы даты, например года, как y, месяц и m, и дня, как d? - person Nodirabegimxonoyim; 19.08.2018
comment
как я могу получить только D M s h, а не несколько дней назад, месяцев назад, используя это? - person PirateApp; 01.09.2020

Это покажет вам прошлый и предыдущий форматы времени, такие как «2 дня назад» «10 минут с настоящего момента», и вы можете передать ему либо объект Date, либо числовую метку времени, либо строку даты.

function time_ago(time) {

  switch (typeof time) {
    case 'number':
      break;
    case 'string':
      time = +new Date(time);
      break;
    case 'object':
      if (time.constructor === Date) time = time.getTime();
      break;
    default:
      time = +new Date();
  }
  var time_formats = [
    [60, 'seconds', 1], // 60
    [120, '1 minute ago', '1 minute from now'], // 60*2
    [3600, 'minutes', 60], // 60*60, 60
    [7200, '1 hour ago', '1 hour from now'], // 60*60*2
    [86400, 'hours', 3600], // 60*60*24, 60*60
    [172800, 'Yesterday', 'Tomorrow'], // 60*60*24*2
    [604800, 'days', 86400], // 60*60*24*7, 60*60*24
    [1209600, 'Last week', 'Next week'], // 60*60*24*7*4*2
    [2419200, 'weeks', 604800], // 60*60*24*7*4, 60*60*24*7
    [4838400, 'Last month', 'Next month'], // 60*60*24*7*4*2
    [29030400, 'months', 2419200], // 60*60*24*7*4*12, 60*60*24*7*4
    [58060800, 'Last year', 'Next year'], // 60*60*24*7*4*12*2
    [2903040000, 'years', 29030400], // 60*60*24*7*4*12*100, 60*60*24*7*4*12
    [5806080000, 'Last century', 'Next century'], // 60*60*24*7*4*12*100*2
    [58060800000, 'centuries', 2903040000] // 60*60*24*7*4*12*100*20, 60*60*24*7*4*12*100
  ];
  var seconds = (+new Date() - time) / 1000,
    token = 'ago',
    list_choice = 1;

  if (seconds == 0) {
    return 'Just now'
  }
  if (seconds < 0) {
    seconds = Math.abs(seconds);
    token = 'from now';
    list_choice = 2;
  }
  var i = 0,
    format;
  while (format = time_formats[i++])
    if (seconds < format[0]) {
      if (typeof format[2] == 'string')
        return format[list_choice];
      else
        return Math.floor(seconds / format[2]) + ' ' + format[1] + ' ' + token;
    }
  return time;
}

var aDay = 24 * 60 * 60 * 1000;
console.log(time_ago(new Date(Date.now() - aDay)));
console.log(time_ago(new Date(Date.now() - aDay * 2)));

person TheBrain    schedule 18.09.2012
comment
Замените последнюю строку return time; на format = time_formats[time_formats.length - 1]; return Math.floor(seconds / format[2]) + ' ' + format[1] + ' ' + token;, чтобы получить значения столетий для больших промежутков времени вместо миллисекунд. - person Aquila Sands; 09.06.2015
comment
Очень хорошо! Хотя я заметил в iOS, что при использовании angular в качестве фильтра браузер здесь возвращает NaN. Это исправляет: time = + new Date (time.replace (/ - / g, '/')); - person Tiago; 11.04.2016
comment
Отлично, но назначение в этом цикле while некрасиво и сбивает с толку. Было бы лучше перейти на цикл forEach - person Martin Dawson; 07.01.2018
comment
У меня возникла проблема, из-за которой я не мог видеть «Только что» и продолжал получать 0 секунд назад. Поэтому я изменил строку на if (seconds < 1) { return 'Just now' }, что решило мою проблему. - person Dan Whitehouse; 27.01.2021

Я не проверял (хотя это было несложно), но думаю, что сайты Stack Exchange используют заголовок _ 1_ плагин для создания этих временных строк.


Плагин довольно прост в использовании, он чист и обновляется автоматически.

Вот небольшой пример (с домашней страницы плагина):

Сначала загрузите jQuery и плагин:

<script src="jquery.min.js" type="text/javascript"></script> <script src="jquery.timeago.js" type="text/javascript"></script>

Теперь давайте прикрепим его к вашим временным меткам в DOM:

jQuery(document).ready(function() {
jQuery("abbr.timeago").timeago(); });

Это превратит все abbr элементы с классом timeago и меткой времени ISO 8601 в заголовке: <abbr class="timeago" title="2008-07-17T09:24:17Z">July 17, 2008</abbr> во что-то вроде этого: <abbr class="timeago" title="July 17, 2008">about a year ago</abbr>, что дает: около года назад. По прошествии времени отметки времени будут обновляться автоматически.

person Maxim Zaslavsky    schedule 05.07.2010
comment
Не все используют JQuery. - person ; 10.11.2014
comment
Нет смысла использовать это как плагин jquery. - person AlexG; 03.08.2016

Вот небольшая модификация решения Sky Sander, которая позволяет вводить дату в виде строки и может отображать интервалы, такие как «1 минута» вместо «73 секунды».

var timeSince = function(date) {
  if (typeof date !== 'object') {
    date = new Date(date);
  }

  var seconds = Math.floor((new Date() - date) / 1000);
  var intervalType;

  var interval = Math.floor(seconds / 31536000);
  if (interval >= 1) {
    intervalType = 'year';
  } else {
    interval = Math.floor(seconds / 2592000);
    if (interval >= 1) {
      intervalType = 'month';
    } else {
      interval = Math.floor(seconds / 86400);
      if (interval >= 1) {
        intervalType = 'day';
      } else {
        interval = Math.floor(seconds / 3600);
        if (interval >= 1) {
          intervalType = "hour";
        } else {
          interval = Math.floor(seconds / 60);
          if (interval >= 1) {
            intervalType = "minute";
          } else {
            interval = seconds;
            intervalType = "second";
          }
        }
      }
    }
  }

  if (interval > 1 || interval === 0) {
    intervalType += 's';
  }

  return interval + ' ' + intervalType;
};
var aDay = 24 * 60 * 60 * 1000;
console.log(timeSince(new Date(Date.now() - aDay)));
console.log(timeSince(new Date(Date.now() - aDay * 2)));

person rob    schedule 24.04.2014
comment
Это не работает в течение нескольких секунд, так как интервал оставлен равным 0 от interval = Math.floor(seconds / 60);. Я добавил interval = seconds; в окончательный else, и он отлично работает. - person howard10; 12.06.2014
comment
Если интервал равен 0, вы также должны добавить s. - person JW.; 26.06.2014
comment
Это круто. Для TS мне пришлось добавить унарный оператор на let seconds = Math.floor((+new Date() - date) / 1000); - person Ben Racicot; 22.05.2017
comment
Почему вы проверяете даже interval === 0 в последних if? - person smartmouse; 04.09.2018
comment
@smartmouse, чтобы он показывал 0 секунд вместо 0 секунд - person rob; 04.09.2018
comment
удивительный! это твердо - person PirateApp; 05.11.2019
comment
Я сделал небольшую модификацию, чтобы это работало со временем в будущем. Это идет прямо под линией секунд var. var tense = (seconds >= 0) ? 'ago' : 'from now'; seconds = Math.abs(seconds); затем внизу: if (Math.abs (interval) ›1 || interval === 0) {intervalType + = 's'; } return interval + '' + intervalType + '' + время; - person Adam S; 11.12.2020

Возможно, вы захотите посмотреть humanized_time_span: https://github.com/layam/js_humanized_time_span

Это независимый от фреймворка и полностью настраиваемый.

Просто скачайте / включите скрипт, и тогда вы сможете сделать это:

humanized_time_span("2011-05-11 12:00:00")  
   => '3 hours ago'

humanized_time_span("2011-05-11 12:00:00", "2011-05-11 16:00:00)  
   => '4 hours ago'

или даже это:

var custom_date_formats = {
  past: [
    { ceiling: 60, text: "less than a minute ago" },
    { ceiling: 86400, text: "$hours hours, $minutes minutes and $seconds seconds ago" },
    { ceiling: null, text: "$years years ago" }
  ],
  future: [
    { ceiling: 60, text: "in less than a minute" },
    { ceiling: 86400, text: "in $hours hours, $minutes minutes and $seconds seconds time" },
    { ceiling: null, text: "in $years years" }
  ]
}

humanized_time_span("2010/09/10 10:00:00", "2010/09/10 10:00:05", custom_date_formats) 
  => "less than a minute ago"

Прочтите документацию для получения дополнительной информации.

person Will Tomlins    schedule 11.05.2011
comment
Просто означает, что он не полагается на jQuery или даже на DOM. - person Will Tomlins; 26.11.2012
comment
Это дает мне NaN years ago почему ?? - person ; 11.11.2014
comment
черт возьми, я понял ... ваш пример его использования неверен. вы фактически ограничиваете первые числа косой чертой, а не - .. вот так humanized_time_span("2011/05/11 12:00:00") - person ; 11.11.2014
comment
это может зависеть от вашей местной культуры и различаться между пользователями :) - person mikus; 12.10.2015

Версия кода для ES6, предоставленная @ user1012181:

const epochs = [
    ['year', 31536000],
    ['month', 2592000],
    ['day', 86400],
    ['hour', 3600],
    ['minute', 60],
    ['second', 1]
];

const getDuration = (timeAgoInSeconds) => {
    for (let [name, seconds] of epochs) {
        const interval = Math.floor(timeAgoInSeconds / seconds);
        if (interval >= 1) {
            return {
                interval: interval,
                epoch: name
            };
        }
    }
};

const timeAgo = (date) => {
    const timeAgoInSeconds = Math.floor((new Date() - new Date(date)) / 1000);
    const {interval, epoch} = getDuration(timeAgoInSeconds);
    const suffix = interval === 1 ? '' : 's';
    return `${interval} ${epoch}${suffix} ago`;
};

Отредактировано с учетом предложений @ ibe-vanmeenen. (Спасибо!)

person Geoffroy Warin    schedule 02.11.2015
comment
Вы также должны включить second: 1 в EPOCHS, иначе он сломается, если он был меньше 1 минуты назад :). Последние 3 вара также могут быть постоянным нет? - person Ibe Vanmeenen; 25.08.2016
comment
Кроме того, EPOCHS должен быть массивом, поскольку объекты не гарантируют порядок свойств. Я сохранил свои изменения в gist.github.com/IbeVanmeenen/4e3e58820c91683612e5888 Вы можете скопировать их, чтобы отредактировать этот ответ :) - person Ibe Vanmeenen; 25.08.2016

Укороченная версия, используемая Lokely:

const intervals = [
  { label: 'year', seconds: 31536000 },
  { label: 'month', seconds: 2592000 },
  { label: 'day', seconds: 86400 },
  { label: 'hour', seconds: 3600 },
  { label: 'minute', seconds: 60 },
  { label: 'second', seconds: 1 }
];

function timeSince(date) {
  const seconds = Math.floor((Date.now() - date.getTime()) / 1000);
  const interval = intervals.find(i => i.seconds < seconds);
  const count = Math.floor(seconds / interval.seconds);
  return `${count} ${interval.label}${count !== 1 ? 's' : ''} ago`;
}
person Sam    schedule 29.10.2017
comment
Самый короткий интервал имеет продолжительность ноль секунд - это приводит к ошибке деления на ноль. - person apk; 18.01.2018
comment
@apk правильный. ‹60 секунд он печатает Infinity seconds ago - person leonheess; 29.10.2019

Изменил функцию выше на

function timeSince(date) {

    var seconds = Math.floor(((new Date().getTime()/1000) - date)),
    interval = Math.floor(seconds / 31536000);

    if (interval > 1) return interval + "y";

    interval = Math.floor(seconds / 2592000);
    if (interval > 1) return interval + "m";

    interval = Math.floor(seconds / 86400);
    if (interval >= 1) return interval + "d";

    interval = Math.floor(seconds / 3600);
    if (interval >= 1) return interval + "h";

    interval = Math.floor(seconds / 60);
    if (interval > 1) return interval + "m ";

    return Math.floor(seconds) + "s";
}

В противном случае будет отображаться «75 минут» (от 1 до 2 часов). Также теперь предполагается, что дата ввода - это временная метка Unix.

person PanMan    schedule 23.11.2011
comment
Разделите дату на 1000, пожалуйста. - person ; 10.11.2014
comment
Я использовал это, когда данные поступали из базы данных с отметками времени Unix в секундах. Если это миллисекунды, вам нужно разделить на 1000. - person PanMan; 13.11.2014

Легко читаемый и кроссбраузерный код:

Как предоставлено @Travis

var DURATION_IN_SECONDS = {
  epochs: ['year', 'month', 'day', 'hour', 'minute'],
  year: 31536000,
  month: 2592000,
  day: 86400,
  hour: 3600,
  minute: 60
};

function getDuration(seconds) {
  var epoch, interval;

  for (var i = 0; i < DURATION_IN_SECONDS.epochs.length; i++) {
    epoch = DURATION_IN_SECONDS.epochs[i];
    interval = Math.floor(seconds / DURATION_IN_SECONDS[epoch]);
    if (interval >= 1) {
      return {
        interval: interval,
        epoch: epoch
      };
    }
  }

};

function timeSince(date) {
  var seconds = Math.floor((new Date() - new Date(date)) / 1000);
  var duration = getDuration(seconds);
  var suffix = (duration.interval > 1 || duration.interval === 0) ? 's' : '';
  return duration.interval + ' ' + duration.epoch + suffix;
};

alert(timeSince('2015-09-17T18:53:23'));

person user1012181    schedule 17.09.2015
comment
Обратите внимание, что это делает некоторые ошибочные предположения, например, каждый день составляет 86400 секунд (если часовой пояс не установлен на UTC, это не всегда верно благодаря UTC) - person ItalyPaleAle; 27.12.2017

с этого момента параметр временной метки unix,

function timeSince(ts){
    now = new Date();
    ts = new Date(ts*1000);
    var delta = now.getTime() - ts.getTime();

    delta = delta/1000; //us to s

    var ps, pm, ph, pd, min, hou, sec, days;

    if(delta<=59){
        ps = (delta>1) ? "s": "";
        return delta+" second"+ps
    }

    if(delta>=60 && delta<=3599){
        min = Math.floor(delta/60);
        sec = delta-(min*60);
        pm = (min>1) ? "s": "";
        ps = (sec>1) ? "s": "";
        return min+" minute"+pm+" "+sec+" second"+ps;
    }

    if(delta>=3600 && delta<=86399){
        hou = Math.floor(delta/3600);
        min = Math.floor((delta-(hou*3600))/60);
        ph = (hou>1) ? "s": "";
        pm = (min>1) ? "s": "";
        return hou+" hour"+ph+" "+min+" minute"+pm;
    } 

    if(delta>=86400){
        days = Math.floor(delta/86400);
        hou =  Math.floor((delta-(days*86400))/60/60);
        pd = (days>1) ? "s": "";
        ph = (hou>1) ? "s": "";
        return days+" day"+pd+" "+hou+" hour"+ph;
    }

}
person pkarc    schedule 10.11.2012

Это должно правильно обрабатывать любую допустимую метку времени, включая Date.now (), единичные единицы и будущие даты. Я пропустил месяцы, но их должно быть легко добавить. Я старался сделать его максимально читаемым.

function getTimeInterval(date) {
  let seconds = Math.floor((Date.now() - date) / 1000);
  let unit = "second";
  let direction = "ago";
  if (seconds < 0) {
    seconds = -seconds;
    direction = "from now";
  }
  let value = seconds;
  if (seconds >= 31536000) {
    value = Math.floor(seconds / 31536000);
    unit = "year";
  } else if (seconds >= 86400) {
    value = Math.floor(seconds / 86400);
    unit = "day";
  } else if (seconds >= 3600) {
    value = Math.floor(seconds / 3600);
    unit = "hour";
  } else if (seconds >= 60) {
    value = Math.floor(seconds / 60);
    unit = "minute";
  }
  if (value != 1)
    unit = unit + "s";
  return value + " " + unit + " " + direction;
}

console.log(getTimeInterval(Date.now())); // 0 seconds ago
console.log(getTimeInterval(Date.now() + 1000)); // 1 second from now
console.log(getTimeInterval(Date.now() - 1000)); // 1 second ago
console.log(getTimeInterval(Date.now() + 60000)); // 1 minute from now
console.log(getTimeInterval(Date.now() - 120000)); // 2 minutes ago
console.log(getTimeInterval(Date.now() + 120000)); // 2 minutes from now
console.log(getTimeInterval(Date.now() + 3600000)); // 1 hour from now
console.log(getTimeInterval(Date.now() + 360000000000)); // 11 years from now
console.log(getTimeInterval(0)); // 49 years ago

person Will    schedule 22.11.2019

Простая и удобочитаемая версия:

const NOW = new Date()
const times = [["second", 1], ["minute", 60], ["hour", 3600], ["day", 86400], ["week", 604800], ["month", 2592000], ["year", 31536000]]

function timeAgo(date) {
    var diff = Math.round((NOW - date) / 1000)
    for (var t = 0; t < times.length; t++) {
        if (diff < times[t][1]) {
            if (t == 0) {
                return "Just now"
            } else {
                diff = Math.round(diff / times[t - 1][1])
                return diff + " " + times[t - 1][0] + (diff == 1?" ago":"s ago")
            }
        }
    }
}
person jcrs    schedule 15.10.2018

Для решить это.

import * as dayjs from 'dayjs';
import * as relativeTime from 'dayjs/plugin/relativeTime';

dayjs.extend(relativeTime);
dayjs(dayjs('1990')).fromNow(); // x years ago
person jjbskir    schedule 02.07.2019

Хотя вопрос был задан довольно давно, пишу этот ответ с надеждой, что он кому-то поможет.

Передайте дату, с которой хотите начать отсчет. Использование moment().fromNow() из momentjs: (дополнительную информацию см. здесь )

getRelativeTime(date) {
    const d = new Date(date * 1000);
    return moment(d).fromNow();
}

Если вы хотите изменить информацию, предоставленную для дат, теперь вы указываете свое относительное время для момента.

Например, в моем собственном случае я хотел напечатать 'one month ago' вместо 'a month ago' (предоставляется моментом (d) .fromNow ()). В этом случае вы можете написать то, что указано ниже.

moment.updateLocale('en', {
    relativeTime: {
        future: 'in %s',
        past: '%s ago',
        s: 'a few seconds',
        ss: '%d seconds',
        m: '1 m',
        mm: '%d minutes',
        h: '1 h',
        hh: '%d hours',
        d: '1 d',
        dd: '%d days',
        M: '1 month',
        MM: '%d months',
        y: '1 y',
        yy: '%d years'
    }
});

ПРИМЕЧАНИЕ. Я написал свой код для проекта на Angular 6.

person Nodirabegimxonoyim    schedule 10.09.2018

Я пишу один с js и python, который используется в двух проектах, очень красиво и просто: простая библиотека (менее 2 КБ ) используется для форматирования даты с помощью *** time ago оператора.

простой, компактный, легкий в использовании и хорошо протестированный.

  1. npm install timeago.js

  2. import timeago from 'timeago.js'; // or use script tag

  3. используйте api format.

Образец:

var timeagoIns  = timeago();
timeagoIns .format('2016-06-12');

Также вы можете выполнять рендеринг в реальном времени.

var timeagoIns = timeago();
timeagoIns.render(document.querySelectorAll('time'));
person atool    schedule 24.06.2016
comment
Начиная с 4.0, вместо этого можно использовать деструктурированный импорт: import { format, render, cancel, register } from 'timeago.js'; - person cmfolio; 22.12.2018

Итак, вот моя версия, она работает как с датами в прошлом, так и в будущем. Он использует Intl.RelativeTimeFormat. для предоставления локализованных строк вместо жестко запрограммированных строк. Вы можете передавать даты как метки времени, объекты Date или строки даты, которые можно анализировать.

/**
 * Human readable elapsed or remaining time (example: 3 minutes ago)
 * @param  {Date|Number|String} date A Date object, timestamp or string parsable with Date.parse()
 * @param  {Date|Number|String} [nowDate] A Date object, timestamp or string parsable with Date.parse()
 * @param  {Intl.RelativeTimeFormat} [trf] A Intl formater
 * @return {string} Human readable elapsed or remaining time
 * @author github.com/victornpb
 * @see https://stackoverflow.com/a/67338038/938822
 */
function fromNow(date, nowDate = Date.now(), rft = new Intl.RelativeTimeFormat(undefined, { numeric: "auto" })) {
    const SECOND = 1000;
    const MINUTE = 60 * SECOND;
    const HOUR = 60 * MINUTE;
    const DAY = 24 * HOUR;
    const WEEK = 7 * DAY;
    const MONTH = 30 * DAY;
    const YEAR = 365 * DAY;
    const intervals = [
        { ge: YEAR, divisor: YEAR, unit: 'year' },
        { ge: MONTH, divisor: MONTH, unit: 'month' },
        { ge: WEEK, divisor: WEEK, unit: 'week' },
        { ge: DAY, divisor: DAY, unit: 'day' },
        { ge: HOUR, divisor: HOUR, unit: 'hour' },
        { ge: MINUTE, divisor: MINUTE, unit: 'minute' },
        { ge: 30 * SECOND, divisor: SECOND, unit: 'seconds' },
        { ge: 0, divisor: 1, text: 'just now' },
    ];
    const now = typeof nowDate === 'object' ? nowDate.getTime() : new Date(nowDate).getTime();
    const diff = now - (typeof date === 'object' ? date : new Date(date)).getTime();
    const diffAbs = Math.abs(diff);
    for (const interval of intervals) {
        if (diffAbs >= interval.ge) {
            const x = Math.round(Math.abs(diff) / interval.divisor);
            const isFuture = diff < 0;
            return interval.unit ? rft.format(isFuture ? x : -x, interval.unit) : interval.text;
        }
    }
}

// examples
fromNow('2020-01-01') // 9 months ago
fromNow(161651684156) // 4 days ago
fromNow(new Date()-1) // just now
fromNow(30000 + Date.now()) // in 30 seconds
fromNow(Date.now() + (1000*60*60*24)) // in 1 day
fromNow(new Date('2029-12-01Z00:00:00.000')) // in 9 years

Альтернатива, не использующая Intl.RelativeTimeFormat

/**
 * Human readable elapsed or remaining time (example: 3 minutes ago)
 * @param  {Date|Number|String} date A Date object, timestamp or string parsable with Date.parse()
 * @return {string} Human readable elapsed or remaining time
 * @author github.com/victornpb
 */
function fromNow(date) {
    const SECOND = 1000;
    const MINUTE = 60 * SECOND;
    const HOUR = 60 * MINUTE;
    const DAY = 24 * HOUR;
    const WEEK = 7 * DAY;
    const MONTH = 30 * DAY;
    const YEAR = 365 * DAY;
    const units = [
        { max: 30 * SECOND, divisor: 1, past1: 'just now', pastN: 'just now', future1: 'just now', futureN: 'just now' },
        { max: MINUTE, divisor: SECOND, past1: 'a second ago', pastN: '# seconds ago', future1: 'in a second', futureN: 'in # seconds' },
        { max: HOUR, divisor: MINUTE, past1: 'a minute ago', pastN: '# minutes ago', future1: 'in a minute', futureN: 'in # minutes' },
        { max: DAY, divisor: HOUR, past1: 'an hour ago', pastN: '# hours ago', future1: 'in an hour', futureN: 'in # hours' },
        { max: WEEK, divisor: DAY, past1: 'yesterday', pastN: '# days ago', future1: 'tomorrow', futureN: 'in # days' },
        { max: 4 * WEEK, divisor: WEEK, past1: 'last week', pastN: '# weeks ago', future1: 'in a week', futureN: 'in # weeks' },
        { max: YEAR, divisor: MONTH, past1: 'last month', pastN: '# months ago', future1: 'in a month', futureN: 'in # months' },
        { max: 100 * YEAR, divisor: YEAR, past1: 'last year', pastN: '# years ago', future1: 'in a year', futureN: 'in # years' },
        { max: 1000 * YEAR, divisor: 100 * YEAR, past1: 'last century', pastN: '# centuries ago', future1: 'in a century', futureN: 'in # centuries' },
        { max: Infinity, divisor: 1000 * YEAR, past1: 'last millennium', pastN: '# millennia ago', future1: 'in a millennium', futureN: 'in # millennia' },
    ];
    const diff = Date.now() - (typeof date === 'object' ? date : new Date(date)).getTime();
    const diffAbs = Math.abs(diff);
    for (const unit of units) {
        if (diffAbs < unit.max) {
            const isFuture = diff < 0;
            const x = Math.round(Math.abs(diff) / unit.divisor);
            if (x <= 1) return isFuture ? unit.future1 : unit.past1;
            return (isFuture ? unit.futureN : unit.pastN).replace('#', x);
        }
    }
};

person Vitim.us    schedule 30.04.2021

Я модифицировал версию Скай Сандерса. Операции Math.floor (...) оцениваются в блоке if

       var timeSince = function(date) {
            var seconds = Math.floor((new Date() - date) / 1000);
            var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
            if (seconds < 5){
                return "just now";
            }else if (seconds < 60){
                return seconds + " seconds ago";
            }
            else if (seconds < 3600) {
                minutes = Math.floor(seconds/60)
                if(minutes > 1)
                    return minutes + " minutes ago";
                else
                    return "1 minute ago";
            }
            else if (seconds < 86400) {
                hours = Math.floor(seconds/3600)
                if(hours > 1)
                    return hours + " hours ago";
                else
                    return "1 hour ago";
            }
            //2 days and no more
            else if (seconds < 172800) {
                days = Math.floor(seconds/86400)
                if(days > 1)
                    return days + " days ago";
                else
                    return "1 day ago";
            }
            else{

                //return new Date(time).toLocaleDateString();
                return date.getDate().toString() + " " + months[date.getMonth()] + ", " + date.getFullYear();
            }
        }
person Moses Koledoye    schedule 20.01.2016
comment
опечатка в последнем else if return days + "1 day ago"; должно быть return "1 day ago"; - person Marco Gurnari; 21.01.2016

Отвечаем на вопрос 10-летней давности в помощь новичкам.

Мы можем использовать этот пакет для этого javascript-time-ago

 
// Load locale-specific relative date/time formatting rules.
import en from 'javascript-time-ago/locale/en'
 
// Add locale-specific relative date/time formatting rules.
TimeAgo.addLocale(en)
 
// Create relative date/time formatter.
const timeAgo = new TimeAgo('en-US')
 
timeAgo.format(new Date())
// "just now"
 
timeAgo.format(Date.now() - 60 * 1000)
// "a minute ago"
 
timeAgo.format(Date.now() - 2 * 60 * 60 * 1000)
// "2 hours ago"
 
timeAgo.format(Date.now() - 24 * 60 * 60 * 1000)
// "a day ago"
person Dinindu Kanchana    schedule 10.09.2020

Мой удар по этому поводу основан на других ответах.

function timeSince(date) {
    let minute = 60;
    let hour   = minute * 60;
    let day    = hour   * 24;
    let month  = day    * 30;
    let year   = day    * 365;

    let suffix = ' ago';

    let elapsed = Math.floor((Date.now() - date) / 1000);

    if (elapsed < minute) {
        return 'just now';
    }

    // get an array in the form of [number, string]
    let a = elapsed < hour  && [Math.floor(elapsed / minute), 'minute'] ||
            elapsed < day   && [Math.floor(elapsed / hour), 'hour']     ||
            elapsed < month && [Math.floor(elapsed / day), 'day']       ||
            elapsed < year  && [Math.floor(elapsed / month), 'month']   ||
            [Math.floor(elapsed / year), 'year'];

    // pluralise and append suffix
    return a[0] + ' ' + a[1] + (a[0] === 1 ? '' : 's') + suffix;
}
person Maksim Ivanov    schedule 13.10.2019

Мое решение ..

(function(global){
            const SECOND   = 1;
            const MINUTE   = 60;
            const HOUR     = 3600;
            const DAY      = 86400;
            const MONTH    = 2629746;
            const YEAR     = 31556952;
            const DECADE   = 315569520;

            global.timeAgo = function(date){
                var now = new Date();
                var diff = Math.round(( now - date ) / 1000);

                var unit = '';
                var num = 0;
                var plural = false;

                switch(true){
                    case diff <= 0:
                        return 'just now';
                    break;

                    case diff < MINUTE:
                        num = Math.round(diff / SECOND);
                        unit = 'sec';
                        plural = num > 1;
                    break;

                    case diff < HOUR:
                        num = Math.round(diff / MINUTE);
                        unit = 'min';
                        plural = num > 1;
                    break;

                    case diff < DAY:
                        num = Math.round(diff / HOUR);
                        unit = 'hour';
                        plural = num > 1;
                    break;

                    case diff < MONTH:
                        num = Math.round(diff / DAY);
                        unit = 'day';
                        plural = num > 1;
                    break;

                    case diff < YEAR:
                        num = Math.round(diff / MONTH);
                        unit = 'month';
                        plural = num > 1;
                    break;

                    case diff < DECADE:
                        num = Math.round(diff / YEAR);
                        unit = 'year';
                        plural = num > 1;
                    break;

                    default:
                        num = Math.round(diff / YEAR);
                        unit = 'year';
                        plural = num > 1;
                }

                var str = '';
                if(num){
                    str += `${num} `;
                }

                str += `${unit}`;

                if(plural){
                    str += 's';
                }

                str += ' ago';

                return str;
            }
        })(window);

        console.log(timeAgo(new Date()));
        console.log(timeAgo(new Date('Jun 03 2018 15:12:19 GMT+0300 (FLE Daylight Time)')));
        console.log(timeAgo(new Date('Jun 03 2018 13:12:19 GMT+0300 (FLE Daylight Time)')));
        console.log(timeAgo(new Date('May 28 2018 13:12:19 GMT+0300 (FLE Daylight Time)')));
        console.log(timeAgo(new Date('May 28 2017 13:12:19 GMT+0300 (FLE Daylight Time)')));
        console.log(timeAgo(new Date('May 28 2000 13:12:19 GMT+0300 (FLE Daylight Time)')));
        console.log(timeAgo(new Date('Sep 10 1994 13:12:19 GMT+0300 (FLE Daylight Time)')));
person nikksan    schedule 03.06.2018

Я искал ответ на этот вопрос и почти реализовал одно из этих решений, но коллега напомнил мне проверить библиотеку react-intl, поскольку мы ее уже использовали.

Итак, добавляя решения ... в случае, если вы используете react-intl библиотеку, у них есть <FormattedRelative> компонент для этого.

https://github.com/yahoo/react-intl/wiki/Components#formattedrelative

person ewH    schedule 13.07.2016

Вот что я сделал (объект возвращает единицу времени вместе со своим значением):

function timeSince(post_date, reference)
{
	var reference = reference ? new Date(reference) : new Date(),
		diff = reference - new Date(post_date + ' GMT-0000'),
		date = new Date(diff),
		object = { unit: null, value: null };
	
	if (diff < 86400000)
	{
		var secs  = date.getSeconds(),
			mins  = date.getMinutes(),
			hours = date.getHours(),
			array = [ ['second', secs], ['minute', mins], ['hour', hours] ];
	}
	else
	{
		var days   = date.getDate(),
			weeks  = Math.floor(days / 7),
			months = date.getMonth(),
			years  = date.getFullYear() - 1970,
			array  = [ ['day', days], ['week', weeks], ['month', months], ['year', years] ];
	}

	for (var i = 0; i < array.length; i++)
	{
		array[i][0] += array[i][1] != 1 ? 's' : '';

		object.unit  = array[i][1] >= 1 ? array[i][0] : object.unit;
		object.value = array[i][1] >= 1 ? array[i][1] : object.value;
	}

	return object;
}

person nateclonch    schedule 16.02.2017

Вот немного упрощенная версия ответа @ sky-sanders.

function timeSince(date) {

  var seconds = Math.floor((new Date() - date) / 1000);
  var divisors = [31536000, 2592000, 86400, 3600, 60, 1]
  var description = ["years", "months", "days", "hours", "minutes", "seconds"]
  var result = [];

  var interval = seconds;

  for (i = 0; i < divisors.length; i++) {
    interval = Math.floor(seconds / divisors[i])
    if (interval > 1) {
      result.push(interval + " " + description[i])
    }
    seconds -= interval * divisors[i]
  }

  return result.join(" ")
}
person Kishor V    schedule 10.03.2021

person    schedule
comment
@hello - да, у единственной точки выхода есть свои достоинства, когда она не мешает. Те, кто в наши дни относятся к этому слишком серьезно, неправильно понимают происхождение максимы. - person Sky Sanders; 05.07.2010
comment
Хорошая функция, но некоторые замечания. Изменена первая строка на: var seconds = Math.floor (((new Date (). GetTime () / 1000) - date)) для работы с временными метками unix. И нужно было изменить intval ›1 на intval› = 1, иначе он будет показывать такие вещи, как 75 минут (от 1 до 2 часов). - person PanMan; 23.11.2011
comment
@PanMan, если вы просто измените ›на› =, у вас будет время вроде 1 минуты. Я опубликовал измененную версию этого ответа, в которой условно добавлены s: stackoverflow.com/a/23259289/373655 - person rob; 24.04.2014
comment
Никогда не используйте конкатенацию строк, но используйте String.format, если вам нужно решение, которое может быть интернационализировано. - person rds; 26.06.2014
comment
Что, если я захочу поместить его в класс div? Что я могу сделать? Извините, я не профессионал в JavaScript. Я пробовал этот документ. GetElementsByTagName ('. Sampleclass') [0] .innerHTML = timeSince (date); и этот документ. getElementById ('idname') [0] .innerHTML = timeSince (date); но это не работает. Любая помощь? Спасибо. - person x'tian; 06.05.2016
comment
@PanMan все еще сталкивается с некоторыми проблемами, когда я использую эту функцию, она возвращает 63 секунды вместо 1 минуты, 26 часов вместо 1 дня. - person Anjana; 10.08.2018
comment
@SkySanders, дайте мне знать, как я могу решить вышеуказанную проблему? - person Anjana; 13.08.2018
comment
Если бы мне нужно было отображать в основном свежий контент, я бы переписал эту функцию, чтобы она была в обратном порядке (чтобы избежать бесполезных вычислений, вызовов floor () и «если»). - person Toto; 10.11.2018
comment
как рассчитать дату и время в будущем .. как через 5 дней или 3 часа - person Siddharth; 22.10.2020

person    schedule
comment
Как это улучшает любой из существующих ответов, включая ответ Скай Сандерса десять лет назад? - person Chris; 12.07.2020