如何格式化自xxx以来的时间,例如类似于Stack Exchange站点的“4分钟前”

问题是如何将JavaScript Date格式化为一个string,说明时间已经过去了,就像您看到堆栈溢出时所显示的时间一样。

例如

  • 1分钟前
  • 1小时前
  • 1天前
  • 1个月前
  • 1年以前
 function timeSince(date) { var seconds = Math.floor((new Date() - date) / 1000); var interval = Math.floor(seconds / 31536000); if (interval > 1) { return interval + " years"; } interval = Math.floor(seconds / 2592000); if (interval > 1) { return interval + " months"; } interval = Math.floor(seconds / 86400); if (interval > 1) { return interval + " days"; } interval = Math.floor(seconds / 3600); if (interval > 1) { return interval + " hours"; } interval = Math.floor(seconds / 60); if (interval > 1) { return 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))); 

在这种情况下可能是一个矫枉过正的情况,但如果机会显示moment.js是真棒!

Moment.js是一个JavaScript的date时间库,使用它的这种情况下,你会做:

 moment(yourdate).fromNow() 

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

我没有检查(虽然这不会很难),但我认为Stack Exchange站点使用jquery.timeago插件来创build这些时间string


使用插件相当简单,而且它是干净的,并自动更新。

下面是一个快速示例(来自插件的主页):

首先,加载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 class="timeago" title="2008-07-17T09:24:17Z">July 17, 2008</abbr> timeago一个timeago和ISO 8601时间戳的所有abbr元素转换为像这样: <abbr class="timeago" title="July 17, 2008">about a year ago</abbr>产量:大约一年前。 随着时间的推移,时间戳会自动更新。

这将显示过去和过去的时间格式,比如“2天前”,从现在开始10分钟“,您可以传递Date对象,数字时间戳或datestring

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

这里是对Sky Sander的解决scheme进行细微的修改,允许date以stringformsinput,并能显示“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))); 

你可能想看看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

 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小时之间)。 现在还假设inputdate是Unix时间戳。

很多可读和跨浏览器兼容的代码:

由@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')); 

从现在起,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; } } 

由@ user1012181提供的代码的ES6版本

 // Epochs const epochs = [ ['year', 31536000], ['month', 2592000], ['day', 86400], ['hour', 3600], ['minute', 60], ['second', 1] ]; // Get duration const getDuration = (timeAgoInSeconds) => { for (let [name, seconds] of epochs) { const interval = Math.floor(timeAgoInSeconds / seconds); if (interval >= 1) { return { interval: interval, epoch: name }; } } }; // Calculate 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的build议。 (谢谢 !)

我修改了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语句格式化date。

简单,小巧,易于使用,并经过良好的testing。

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

您也可能对这种function的国际版本感兴趣,可以在这里find:

https://github.com/halt-hammerzeit/javascript-time-ago

并支持任何语言环境。

我正在寻找答案,几乎实现了其中的一个解决scheme,但是一位同事提醒我检查react-intl库,因为我们已经在使用它了。

所以join解决scheme…在使用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: 0 } ]; 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`; }