问题是如何将JavaScript Date格式化为一个字符串,声明时间经过,类似于您在Stack Overflow上看到的时间显示方式。
e.g.
1分钟前 1小时前 1天前 1个月前 一年前
问题是如何将JavaScript Date格式化为一个字符串,声明时间经过,类似于您在Stack Overflow上看到的时间显示方式。
e.g.
1分钟前 1小时前 1天前 1个月前 一年前
function timeSince(date) { var seconds = Math.floor((new Date() - date) / 1000); var interval = seconds / 31536000; if (interval > 1) { return Math.floor(interval) + " years"; } interval = seconds / 2592000; if (interval > 1) { return Math.floor(interval) + " months"; } interval = seconds / 86400; if (interval > 1) { return Math.floor(interval) + " days"; } interval = seconds / 3600; if (interval > 1) { return Math.floor(interval) + " hours"; } interval = seconds / 60; if (interval > 1) { return Math.floor(interval) + " minutes"; } return Math.floor(seconds) + " seconds"; } var aDay = 24*60*60*1000; console.log(timeSince(new Date(Date.now()-aDay))); console.log(timeSince(new Date(Date.now()-aDay*2)));
我还没有检查(虽然这并不难),但我认为Stack Exchange站点使用jquery。Timeago插件来创建这些时间字符串。
这个插件使用起来很简单,而且很干净,还能自动更新。
下面是一个简单的例子(来自插件的主页):
First, load jQuery and the plugin: <script src="jquery.min.js" type="text/javascript"></script> <script src="jquery.timeago.js" type="text/javascript"></script> Now, let's attach it to your timestamps on DOM ready: jQuery(document).ready(function() { jQuery("abbr.timeago").timeago(); }); This will turn all abbr elements with a class of timeago and an ISO 8601 timestamp in the title: <abbr class="timeago" title="2008-07-17T09:24:17Z">July 17, 2008</abbr> into something like this: <abbr class="timeago" title="July 17, 2008">about a year ago</abbr> which yields: about a year ago. As time passes, the timestamps will automatically update.
您可能需要查看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"
更多信息请阅读文档。
将上面的函数更改为
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时间戳。
这将显示你过去和以前的时间格式,如“2天前”“从现在开始10分钟”,你可以传递给它一个日期对象,数字时间戳或日期字符串
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)));
从现在开始,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;
}
}
在这种情况下可能有点过头了,但如果有机会,moment.js真的很棒!
js是一个javascript datetime库,在这种情况下使用它,你需要做:
moment(yourdate).fromNow()
http://momentjs.com/docs/#/displaying/fromnow/
2018附录:Luxon是一个新的现代图书馆,可能值得一看!
2022年附录:Day.js是一个较新的库,比Luxon轻80%左右,具有类似的功能。
以下是对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)));
可读性强且跨浏览器兼容的代码:
@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'));
由@user1012181提供的ES6版本代码:
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编辑建议。(谢谢!)
我修改了Sky Sanders的版本。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();
}
}
我用js和python写了一个,在两个项目中使用,非常漂亮和简单:一个简单的库(少于2kb),用于*** time ago语句格式化日期。
简单,小巧,易于使用,并且经过良好测试。
NPM安装timeago.js 从timeago.js导入timeago;//或使用脚本标签 使用API格式。
示例:
var timeagoIns = timeago();
timeagoIns .format('2016-06-12');
你也可以实时渲染。
var timeagoIns = timeago();
timeagoIns.render(document.querySelectorAll('time'));
我一直在寻找这个问题的答案,并且几乎实现了其中一个解决方案,但一位同事提醒我检查react-intl库,因为我们已经在使用它了。
所以在解决方案中…在使用react-intl库的情况下,它们有一个<FormattedRelative>组件。
https://github.com/yahoo/react-intl/wiki/Components#formattedrelative
下面是我所做的(对象返回时间单位及其值):
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; }
function timeago(date) {
var seconds = Math.floor((new Date() - date) / 1000);
if(Math.round(seconds/(60*60*24*365.25)) >= 2) return Math.round(seconds/(60*60*24*365.25)) + " years ago";
else if(Math.round(seconds/(60*60*24*365.25)) >= 1) return "1 year ago";
else if(Math.round(seconds/(60*60*24*30.4)) >= 2) return Math.round(seconds/(60*60*24*30.4)) + " months ago";
else if(Math.round(seconds/(60*60*24*30.4)) >= 1) return "1 month ago";
else if(Math.round(seconds/(60*60*24*7)) >= 2) return Math.round(seconds/(60*60*24*7)) + " weeks ago";
else if(Math.round(seconds/(60*60*24*7)) >= 1) return "1 week ago";
else if(Math.round(seconds/(60*60*24)) >= 2) return Math.round(seconds/(60*60*24)) + " days ago";
else if(Math.round(seconds/(60*60*24)) >= 1) return "1 day ago";
else if(Math.round(seconds/(60*60)) >= 2) return Math.round(seconds/(60*60)) + " hours ago";
else if(Math.round(seconds/(60*60)) >= 1) return "1 hour ago";
else if(Math.round(seconds/60) >= 2) return Math.round(seconds/60) + " minutes ago";
else if(Math.round(seconds/60) >= 1) return "1 minute ago";
else if(seconds >= 2)return seconds + " seconds ago";
else return seconds + "1 second ago";
}
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`;
}
我的解决方案。
(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)')));
虽然这个问题是很久以前问过的,但写下这个答案希望它能帮助到一些人。
传递您想要开始计数的日期。使用momentjs的moment().fromNow():(在这里查看更多信息)
getRelativeTime(date) {
const d = new Date(date * 1000);
return moment(d).fromNow();
}
如果您想更改日期fromNow提供的信息,请编写自定义相对时间为时刻。
例如,在我自己的例子中,我想打印'one month ago'而不是'a month ago'(由moment(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中为项目编写代码的
简单易读版本:
const relativeTimePeriods = [
[31536000, 'year'],
[2419200, 'month'],
[604800, 'week'],
[86400, 'day'],
[3600, 'hour'],
[60, 'minute'],
[1, 'second']
];
function relativeTime(date, isUtc=true) {
if (!(date instanceof Date)) date = new Date(date * 1000);
const seconds = (new Date() - date) / 1000;
for (let [secondsPer, name] of relativeTimePeriods) {
if (seconds >= secondsPer) {
const amount = Math.floor(seconds / secondsPer);
return `${amount} ${name}${amount ? 's' : ''}s ago`;
}
}
return 'Just now';
}
也可以使用dayjs的relativeTime插件来解决这个问题。
import * as dayjs from 'dayjs';
import * as relativeTime from 'dayjs/plugin/relativeTime';
dayjs.extend(relativeTime);
dayjs(dayjs('1990')).fromNow(); // x years ago
我的尝试是基于其他的答案。
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;
}
function dateToHowManyAgo(stringDate){
var currDate = new Date();
var diffMs=currDate.getTime() - new Date(stringDate).getTime();
var sec=diffMs/1000;
if(sec<60)
return parseInt(sec)+' second'+(parseInt(sec)>1?'s':'')+' ago';
var min=sec/60;
if(min<60)
return parseInt(min)+' minute'+(parseInt(min)>1?'s':'')+' ago';
var h=min/60;
if(h<24)
return parseInt(h)+' hour'+(parseInt(h)>1?'s':'')+' ago';
var d=h/24;
if(d<30)
return parseInt(d)+' day'+(parseInt(d)>1?'s':'')+' ago';
var m=d/30;
if(m<12)
return parseInt(m)+' month'+(parseInt(m)>1?'s':'')+' ago';
var y=m/12;
return parseInt(y)+' year'+(parseInt(y)>1?'s':'')+' ago';
}
console.log(dateToHowManyAgo('2019-11-07 19:17:06'));
这应该正确地处理任何有效的时间戳,包括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
I achieve this by following method
timeAgo = (date) => {
var ms = (new Date()).getTime() - date.getTime();
var seconds = Math.floor(ms / 1000);
var minutes = Math.floor(seconds / 60);
var hours = Math.floor(minutes / 60);
var days = Math.floor(hours / 24);
var months = Math.floor(days / 30);
var years = Math.floor(months / 12);
if (ms === 0) {
return 'Just now';
} if (seconds < 60) {
return seconds + ' seconds Ago';
} if (minutes < 60) {
return minutes + ' minutes Ago';
} if (hours < 24) {
return hours + ' hours Ago';
} if (days < 30) {
return days + ' days Ago';
} if (months < 12) {
return months + ' months Ago';
} else {
return years + ' years Ago';
}
}
console.log(timeAgo(new Date()));
console.log(timeAgo(new Date('Jun 27 2020 10:12:19')));
console.log(timeAgo(new Date('Jun 27 2020 00:12:19')));
console.log(timeAgo(new Date('May 28 2020 13:12:19')));
console.log(timeAgo(new Date('May 28 2017 13:12:19')));
回答10年的老问题,帮助新人。
我们可以将这个包用于javascript时间之前
// 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"
这是一个简化版的@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(" ")
}
function calDateAgo(dString=null){
//var dString = "2021-04-1 12:00:00";
var d1 = new Date(dString);
var d2 = new Date();
var t2 = d2.getTime();
var t1 = d1.getTime();
var d1Y = d1.getFullYear();
var d2Y = d2.getFullYear();
var d1M = d1.getMonth();
var d2M = d2.getMonth();
var time_obj = {};
time_obj.year = d2.getFullYear()-d1.getFullYear();
time_obj.month = (d2M+12*d2Y)-(d1M+12*d1Y);
time_obj.week = parseInt((t2-t1)/(24*3600*1000*7));
time_obj.day = parseInt((t2-t1)/(24*3600*1000));
time_obj.hour = parseInt((t2-t1)/(3600*1000));
time_obj.minute = parseInt((t2-t1)/(60*1000));
time_obj.second = parseInt((t2-t1)/(1000));
for (const obj_key in time_obj) {
if(time_obj[obj_key] == 0){
delete time_obj[obj_key];
}
}
var ago_text = 'just now';
if(typeof Object.keys(time_obj)[0] != 'undefined'){
var time_key = Object.keys(time_obj)[0];
var time_val = time_obj[Object.keys(time_obj)[0]];
time_key += (time_val > 1) ? 's':'';
ago_text = time_val+' '+time_key+' ago';
}
return ago_text;
}
这是我的版本,它既适用于过去的日期,也适用于未来的日期。 它使用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() * @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 * @see https://stackoverflow.com/a/67338038/938822 */ 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); } } };
这是对国际的另一种看法。RelativeTimeFormat
支持过去日期和将来日期 同时接受字符串和日期 易于添加自定义范围(编辑范围) 可以很容易地翻译为Intl.RelativeTimeFormat('ua')
console.log(timeAgo('2021-08-09T15:29:01+0000')); function timeAgo(input) { const date = (input instanceof Date) ? input : new Date(input); const formatter = new Intl.RelativeTimeFormat('en'); const ranges = { years: 3600 * 24 * 365, months: 3600 * 24 * 30, weeks: 3600 * 24 * 7, days: 3600 * 24, hours: 3600, minutes: 60, seconds: 1 }; const secondsElapsed = (date.getTime() - Date.now()) / 1000; for (let key in ranges) { if (ranges[key] < Math.abs(secondsElapsed)) { const delta = secondsElapsed / ranges[key]; return formatter.format(Math.round(delta), key); } } }
https://jsfiddle.net/tv9701uf
function mdiv(dividend, divisor) {
return [ Math.floor(dividend/divisor), dividend % divisor ];
}
// pass in milliseconds, gained by Date1.getTime() - Date2.getTime()
// if max_units is two, the result will be, for example
// 2years 12months ago, or 2hours 38minutes ago
// return formated period
function readable_period(ms, max_units=2){
let [yy, yr] = mdiv(ms, 3.154e10);
let [mm, mr] = mdiv(yr, 2.628e9);
let [dd, dr] = mdiv(mr, 8.64e7);
let [hh, hr] = mdiv(dr, 3.6e6);
let [tt, ss] = mdiv(hr, 6e4);
var ymdht = ['year', 'month', 'day', 'hour', 'minute'];
let res = [];
[yy, mm, dd, hh, tt].forEach((tis, ii)=>{
if(res.length === max_units){return};
if(tis !== 0){
res.push(tis === 1 ? `${tis}${ymdht[ii]}` : `${tis}${ymdht[ii]}s`);
}
});
return res.length === 0 ? '' : res.join(' ') + ' ago';
}
const createdAt = moment(created_at).fromNow()
量身定制的解决方案
const duration = moment.duration(moment().diff(moment(created_at)))
const createdAt = duration.as('week') >= 1
? `${Math.floor(duration.as('week'))} week(s)`
: duration.as('day') >= 1
? `${Math.floor(duration.as('day'))} day(s)`
: duration.as('hour') >= 1
? `${Math.floor(duration.as('hour'))} hour(s)`
: `${Math.floor(duration.as('minute'))} minute(s)`
你可以使用Luxon:
DateTime.toRelative()
https://moment.github.io/luxon/api-docs/index.html#datetimetorelative
这里还有一些例子:
const DateTime = luxon.DateTime; // toRelative console.log(DateTime.now().minus({ seconds: 1 }).toRelative()) // 1 second ago console.log(DateTime.now().minus({ seconds: 10 }).toRelative()) // 10 seconds ago console.log(DateTime.now().minus({ days: 2 }).toRelative()) console.log(DateTime.now().minus({ years: 3 }).toRelative()) console.log(DateTime.now().plus({ years: 3 }).toRelative()) console.log(DateTime.now().plus({ days: 2 }).toRelative()) console.log(DateTime.now().plus({ seconds: 1 }).toRelative()) console.log(DateTime.now().plus({ seconds: 10 }).toRelative()) // toRelativeCalendar console.log(DateTime.now().minus({ seconds: 1 }).toRelativeCalendar()) // today console.log(DateTime.now().minus({ seconds: 10 }).toRelativeCalendar()) // today console.log(DateTime.now().minus({ days: 2 }).toRelativeCalendar()) console.log(DateTime.now().minus({ years: 3 }).toRelativeCalendar()) console.log(DateTime.now().plus({ years: 3 }).toRelativeCalendar()) console.log(DateTime.now().plus({ days: 2 }).toRelativeCalendar()) console.log(DateTime.now().plus({ seconds: 1 }).toRelativeCalendar()) console.log(DateTime.now().plus({ seconds: 10 }).toRelativeCalendar()) <script src="https://moment.github.io/luxon/global/luxon.min.js"></script>
我使用这个包:javascript-time-ago
设置TimeAgo 导入TimeAgo 从javascript-time-ago/locale/en.json导入en TimeAgo.addDefaultLocale (en) 写一个函数 // twitter-now是twitter风格。查看文档以获得更多选项 const clockToDateString = (timestamp) => timeAgo。format(new Date(timestamp.toNumber() * 1000), 'twitter-now') 在dom中使用它 < div > {clockToDateString (post.postTime)} < / div >
要使用这个,只需复制所有这些代码,并将其导入到你的组件或任何地方,并将你的ISOstring()日期放在:showTimeAgo("2022-06-20T13:42:29-05:00"),你将获得每个场景的自动时间更新。
旁注:我为这个https://www.npmjs.com/package/showtimeago做了一个npm包
export const showTimeAgo = () => {
const MONTH_NAMES = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
];
function getOrdinalNum() {
return (
n +
(n > 0
? ['th', 'st', 'nd', 'rd'][
(n > 3 && n < 21) || n % 10 > 3 ? 0 : n % 10
]
: '')
);
}
function getFormattedDate(
date,
preformattedDate = false,
hideYear = false
) {
const day = date.getDate();
const month = MONTH_NAMES[date.getMonth()];
const year = date.getFullYear();
let hours = date.getHours();
let minutes = date.getMinutes();
let ampm = hours >= 12 ? 'pm' : 'am';
switch(true){
case (hours > 12):
hours = hours - 12;
break;
case (hours === 0):
hours = 12;
break;
case(minutes < 10):
minutes = `0${minutes}`;
break;
case(preformattedDate):
// Today at 10:20am
// Yesterday at 10:20am
return `${preformattedDate} at ${hours}:${minutes} ${ampm}`;
case(hideYear):
// January 10th at 10:20pm
return `${month} ${getOrdinalNum(
day
)}, at ${hours}:${minutes} ${ampm}`;
default:
// January 10th 2022 at 10:20pm
return `${month} ${getOrdinalNum(
day
)}, ${year} at ${hours}:${minutes} ${ampm}`;
}
}
// --- Main function
function timeAgo(dateParam) {
if (!dateParam) {
return null;
}
const date =
typeof dateParam === 'object' ? dateParam : new Date(dateParam);
const DAY_IN_MS = 86400000; // 24 * 60 * 60 * 1000
const today = new Date();
const yesterday = new Date(today - DAY_IN_MS);
const seconds = Math.round((today - date) / 1000);
const minutes = Math.round(seconds / 60);
const hour = Math.round(seconds / 3600);
const day = Math.round(seconds / 86400);
const month = Math.round(seconds / 2629800);
const year = Math.floor(seconds / 31536000);
const isToday = today.toDateString() === date.toDateString();
const isYesterday =
yesterday.toDateString() === date.toDateString();
const isThisYear = today.getFullYear() === date.getFullYear();
switch(true){
case (seconds < 5):
return 'now';
case (seconds < 60):
return `${seconds} seconds ago`;
case (seconds < 90):
return 'about a minute ago';
case (minutes < 60):
return `${minutes} minutes ago`;
case (hour === 1 && hour < 2):
return `${hour} hour ago`; // 1 hour ago
case (hour > 1 && hour <= 12):
return `${hour} hours ago`; // 2 hours ago
case (isToday):
return getFormattedDate(date, 'Today'); // Today at 10:20am
case (isYesterday):
return getFormattedDate(date, 'Yesterday'); // Yesterday at 10:20am
case(day > 1 && day <= 30):
return `${day} days ago`; // 2 days ago
case (isThisYear):
return getFormattedDate(date, false, true); // January 10th at 10:20pm
case (day > 30 && month <= 1):
return `${hour} month ago`; // 1 month ago
case (month > 1 && month <= 12):
return `${month} months ago`; // 2 months ago
case (year === 1):
return `${year} year ago`; // 1 year ago
case (year > 1):
return `${year} years ago`; // 2 years ago
default:
return getFormattedDate(date); // January 10th 2022 at 10:20pm
}
}
return timeAgo(date);
};
console.log(showTimeAgo("2022-06-20T13:42:29-05:00"));-05:00"))
回复@Stas Parshin的答案,这是最好的答案,代码更少,但它在与typescript一起使用时有bug, Intl的.format函数需要2个输入
number, Units - i.e of type 'RelativeTimeFormatUnit' so if you pass a object key typescript will through error saying unit must be of type RelativeTimeFormatUnit and not of type string, so the work-around for this is to use the type to make another list of same type and rest you can have look at code... Happy coding. console.log(timeAgo('2021-08-09T15:29:01+0000')); function timeAgo(input) { const date = (input instanceof Date) ? input : new Date(input); const formatter = new Intl.RelativeTimeFormat('en'); const ranges = { years: 3600 * 24 * 365, months: 3600 * 24 * 30, weeks: 3600 * 24 * 7, days: 3600 * 24, hours: 3600, minutes: 60, seconds: 1 }; type RelativeTimeFormatUnit = | "year" | "years" | "quarter" | "quarters" | "month" | "months" | "week" | "weeks" | "day" | "days" | "hour" | "hours" | "minute" | "minutes" | "second" | "seconds" ; const units: RelativeTimeFormatUnit[] = ["years", "months", "weeks", "days", "hours", "minutes", "seconds"]; // order matters here. const secondsElapsed = (date.getTime() - Date.now()) / 1000; for (let key in ranges) { let i = 0; if (ranges[key] < Math.abs(secondsElapsed)) { const delta = secondsElapsed / ranges[key]; return formatter.format(Math.round(delta), units[i++]); } } }
这些答案大多不能解释复数(例如:复数)。当我们想要“1分钟前”时,用“1分钟前”)
const MINUTE = 60;
const HOUR = MINUTE * 60;
const DAY = HOUR * 24;
const WEEK = DAY * 7;
const MONTH = DAY * 30;
const YEAR = DAY * 365;
function getTimeAgo(date) {
const secondsAgo = Math.round((Date.now() - Number(date)) / 1000);
if (secondsAgo < MINUTE) {
return secondsAgo + ` second${secondsAgo !== 1 ? "s" : ""} ago`;
}
let divisor;
let unit = "";
if (secondsAgo < HOUR) {
[divisor, unit] = [MINUTE, "minute"];
} else if (secondsAgo < DAY) {
[divisor, unit] = [HOUR, "hour"];
} else if (secondsAgo < WEEK) {
[divisor, unit] = [DAY, "day"];
} else if (secondsAgo < MONTH) {
[divisor, unit] = [WEEK, "week"];
} else if (secondsAgo < YEAR) {
[divisor, unit] = [MONTH, "month"];
} else {
[divisor, unit] = [YEAR, "year"];
}
const count = Math.floor(secondsAgo / divisor);
return `${count} ${unit}${count > 1 ? "s" : ""} ago`;
}
然后你可以这样使用它:
const date = new Date();
console.log(getTimeAgo(date));
// 1 second ago
// 2 seconds ago
// 1 minute ago
// 2 minutes ago
// ...
如果你已经在使用date-fns,你可以使用内置的formatDistance(以前是distanceInWords):
const date1 = new Date(2014, 6, 2);
const date2 = new Date(2015, 0, 1);
const options = { addSuffix: true }
const result = formatDistance(date1, date2, options);
//=> '6 months ago'
以上答案适用于旧的java脚本。但它在新的EC6 JavaScript或TypeScript上运行得不太好。下面是一个非常简短和简单的函数,用于最新的JavaScript, TypeScript, AngularJs, ReactJs和NodeJs,根据给定的日期和时间返回时间。
public timeAgo(date) {
var seconds = Math.floor((new Date().getTime() - new Date(date).getTime()) / 1000);
var interval = seconds / 31536000;
if (interval > 1) return Math.floor(interval) + " years";
interval = seconds / 2592000;
if (interval > 1) return Math.floor(interval) + " months";
interval = seconds / 86400;
if (interval > 1) return Math.floor(interval) + " days";
interval = seconds / 3600;
if (interval > 1) return Math.floor(interval) + " hours";
interval = seconds / 60;
if (interval > 1) return Math.floor(interval) + " minutes";
return Math.floor(seconds) + " seconds";
}
console.log(timeAgo('2022-08-12 20:50:20'));
// 2 hours ago, as per the given date time string.
const timeHandler = (time: any) => {
var a = moment(); //now
var b = moment.utc(time);
const sec = a.diff(b, 'seconds');
const minuts = a.diff(b, 'minutes');
const hours = a.diff(b, 'hours');
const days = a.diff(b, 'days');
const weeks = a.diff(b, 'weeks');
return weeks == 0
? days == 0
? hours == 0
? minuts == 0
? sec >= 0 && `${sec}s ago`
: `${minuts}m ago`
: `${hours}h ago`
: `${days}d ago`
: `${weeks}w ago`;
};
console.log(timeHandler('2022-11-11T12:11:06.6103808'))
我使用了可能11的旧答案,并添加了Intl。用于翻译的RelativeTimeFormat。
https://stackoverflow.com/a/73331658/673809
function timeAgo (value) { const seconds = Math.floor((new Date().getTime() - new Date(value).getTime()) / 1000) let interval = seconds / 31536000 const rtf = new Intl.RelativeTimeFormat("en", { numeric: 'auto' }) if (interval > 1) { return rtf.format(-Math.floor(interval), 'year') } interval = seconds / 2592000 if (interval > 1) { return rtf.format(-Math.floor(interval), 'month') } interval = seconds / 86400 if (interval > 1) { return rtf.format(-Math.floor(interval), 'day') } interval = seconds / 3600 if (interval > 1) { return rtf.format(-Math.floor(interval), 'hour') } interval = seconds / 60 if (interval > 1) { return rtf.format(-Math.floor(interval), 'minute') } return rtf.format(-Math.floor(interval), 'second') } console.log(timeAgo('2022-08-12 20:50:20'))