本文为原创分享,转载请注明出处。

1、引言

即时通讯IM应用中的聊天消息时间显示是个再常见不过的需求,现在都讲究用户体验,所以时间显示再也不能像传统软件一样简单粗地暴显示成“年/月/日 时:分:秒”这样。所以,市面上几乎所有的IM都会对聊天消息的时间显示格化做人性化处理,从而提升用户体验(使用感受会明显友好)。

这两天正在继续开发RainbowChat-Web产品,所以正需要这样的代码。但经过在即时通讯网的论坛和技术交流群里询问,以及网上的所谓仿微信例子,都不符合要求。这些例子要么简陋粗暴(有逻辑bug硬伤)、要么并不完整(可能只是随手写的练手代码,并不适合放到产品中),所以本着做技术精益求精的态度,没有现成的轮子可用,那就只能造轮子了。

那么,按怎样的显示逻辑来实现呢?作为移动端IM的王者,微信无疑处处是标杆,所以本次的消息时间显示格式,直接参照微信的实现逻辑准没错(随大流虽然没个性,但不至于非主流)。

* 提示:本文中的代码实现,是从 RainbowChat 和 RainbowChat-Web 两个IM产品中扒出来简化后的结果,是基于完全相同的算法逻辑分别用OC、Java和JavaScript实现的。如您觉得有用,可以改改直接用于您的产品,如您有更好的建议请直接回复和评论。代码仅供参考,不足之外,还请见谅!

(本文同步发布于:http://www.52im.net/thread-2371-1-1.html)

2、相关文章

《用于IM中图片压缩的Android工具类源码,效果可媲美微信 [附件下载]》

《高仿Android版手机QQ可拖拽未读数小气泡源码 [附件下载]》

《Android聊天界面源码:实现了聊天气泡、表情图标(可翻页) [附件下载]》

《高仿Android版手机QQ首页侧滑菜单源码 [附件下载]》

《分享java AMR音频文件合并源码,全网最全》

《Android版高仿微信聊天界面源码 [附件下载]》

《高仿手机QQ的Android版锁屏聊天消息提醒功能 [附件下载]》

《高仿iOS版手机QQ录音及振幅动画完整实现 [源码下载]》

《Android端社交应用中的评论和回复功能实战分享[图文+源码]》

《Android端IM应用中的@人功能实现:仿微博、QQ、微信,零入侵、高可扩展[图文+源码]》

3、看看微信中聊天消息的时间显示规则

先来看看微信中聊天消息的时间显示成什么样:

c07e0e897a2849e297cf5bf842d31dbd

微信主页“消息”界面

bfcf1bd3b96f480092dbeed4d3f6ed2c

聊天界面(注意聊天界面中默认带了“时:分”的显示)

来自微信官方对聊天消息时间显示的规则说明:

81d7f9b3316846a199c65f12d0db174c

▲ 该规则的定义,主要是2、3条(本图引用自微信官方FAQ文档)

4、总结一下微信中聊天消息的时间显示逻辑

参见第3节中的截图和微信官方的说明,我们可以总结出微信对于聊天消息时间显示的规则。

① 微信对于聊天消息时间显示的规则总结如下(首页“消息”界面):

1)当聊天消息时间为一周之内时:当天的消息显示为“小时:分钟”形式,然后是“昨天”、“前天”,然后就是“星期几”这个样子;

2)当聊天消息的时间大于一周时:直接显示“年/月/日”的时间格式。

② 微信对于聊天消息时间显示的规则总结如下(聊天内容界面):

1)当聊天消息时间为一周之内时:当天的消息显示为“小时:分钟”形式,然后是“昨天 时:分”、“前天 时:分”,然后就是“星期几 时:分”这个样子;

2)当聊天消息的时间大于一周时:直接显示“年/月/日 时:分”的完整时间格式。

注意:聊天内容界面里的时间格式,实际上是首页“消息”界面里的时间格式加上“时:分”后的结果,所以代码实现上这两套代码是可以重用的,无需两份代码。

好了,规则已经摸清,下面将直接上代码。

5、Android平台上的代码实现(标准Java)

5.1 完整源码

/**

* 返回指定pattern样的日期时间字符串。

*

* @param dt

* @param pattern

* @return 如果时间转换成功则返回结果,否则返回空字符串""

* @author 即时通讯网([url=http://www.52im.net]http://www.52im.net[/url])

*/

publicstaticString getTimeString(Date dt, String pattern)

{

try

{

SimpleDateFormat sdf = newSimpleDateFormat(pattern);//"yyyy-MM-dd HH:mm:ss"

sdf.setTimeZone(TimeZone.getDefault());

returnsdf.format(dt);

}

catch(Exception e)

{

return"";

}

}

/**

* 仿照微信中的消息时间显示逻辑,将时间戳(单位:毫秒)转换为友好的显示格式.

*

* 1)7天之内的日期显示逻辑是:今天、昨天(-1d)、前天(-2d)、星期?(只显示总计7天之内的星期数,即<=-4d);

* 2)7天之外(即>7天)的逻辑:直接显示完整日期时间。

*

* @param srcDate 要处理的源日期时间对象

* @param mustIncludeTime true表示输出的格式里一定会包含“时间:分钟”,否则不包含(参考微信,不包含时分的情况,用于首页“消息”中显示时)

* @return 输出格式形如:“10:30”、“昨天 12:04”、“前天 20:51”、“星期二”、“2019/2/21 12:09”等形式

* @author 即时通讯网([url=http://www.52im.net]http://www.52im.net[/url])

* @since 4.5

*/

publicstaticString getTimeStringAutoShort2(Date srcDate, booleanmustIncludeTime)

{

String ret = "";

try

{

GregorianCalendar gcCurrent = newGregorianCalendar();

gcCurrent.setTime(newDate());

intcurrentYear = gcCurrent.get(GregorianCalendar.YEAR);

intcurrentMonth = gcCurrent.get(GregorianCalendar.MONTH)+1;

intcurrentDay = gcCurrent.get(GregorianCalendar.DAY_OF_MONTH);

GregorianCalendar gcSrc = newGregorianCalendar();

gcSrc.setTime(srcDate);

intsrcYear = gcSrc.get(GregorianCalendar.YEAR);

intsrcMonth = gcSrc.get(GregorianCalendar.MONTH)+1;

intsrcDay = gcSrc.get(GregorianCalendar.DAY_OF_MONTH);

// 要额外显示的时间分钟

String timeExtraStr = (mustIncludeTime?" "+getTimeString(srcDate, "HH:mm"):"");

// 当年

if(currentYear == srcYear)

{

longcurrentTimestamp = gcCurrent.getTimeInMillis();

longsrcTimestamp = gcSrc.getTimeInMillis();

// 相差时间(单位:毫秒)

longdelta = (currentTimestamp - srcTimestamp);

// 当天(月份和日期一致才是)

if(currentMonth == srcMonth && currentDay == srcDay)

{

// 时间相差60秒以内

if(delta < 60* 1000)

ret = "刚刚";

// 否则当天其它时间段的,直接显示“时:分”的形式

else

ret = getTimeString(srcDate, "HH:mm");

}

// 当年 && 当天之外的时间(即昨天及以前的时间)

else

{

// 昨天(以“现在”的时候为基准-1天)

GregorianCalendar yesterdayDate = newGregorianCalendar();

yesterdayDate.add(GregorianCalendar.DAY_OF_MONTH, -1);

// 前天(以“现在”的时候为基准-2天)

GregorianCalendar beforeYesterdayDate = newGregorianCalendar();

beforeYesterdayDate.add(GregorianCalendar.DAY_OF_MONTH, -2);

// 用目标日期的“月”和“天”跟上方计算出来的“昨天”进行比较,是最为准确的(如果用时间戳差值

// 的形式,是不准确的,比如:现在时刻是2019年02月22日1:00、而srcDate是2019年02月21日23:00,

// 这两者间只相差2小时,直接用“delta/(3600 * 1000)” > 24小时来判断是否昨天,就完全是扯蛋的逻辑了)

if(srcMonth == (yesterdayDate.get(GregorianCalendar.MONTH)+1)

&& srcDay == yesterdayDate.get(GregorianCalendar.DAY_OF_MONTH))

{

ret = "昨天"+timeExtraStr;// -1d

}

// “前天”判断逻辑同上

elseif(srcMonth == (beforeYesterdayDate.get(GregorianCalendar.MONTH)+1)

&& srcDay == beforeYesterdayDate.get(GregorianCalendar.DAY_OF_MONTH))

{

ret = "前天"+timeExtraStr;// -2d

}

else

{

// 跟当前时间相差的小时数

longdeltaHour = (delta/(3600* 1000));

// 如果小于 7*24小时就显示星期几

if(deltaHour < 7*24)

{

String[] weekday = {"星期日

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐