仿微信的IM聊天时间显示格式

前言

即时通讯(IM)应用中,对于聊天消息时间的呈现已经成为一项非常普遍的需求。在当前注重用户体验的时代,我们不再局限于传统软件中简单粗暴地采用“年/月/日 时:分:秒”的时间格式。相反,几乎所有的IM应用都在处理聊天消息时间显示时,采取了更为人性化的设计,从而提升用户体验,使其更加友好。

这种人性化处理包括更加直观和易读的时间格式,例如:

刚刚:表示消息是在几秒钟之前发送的。
今天:表示消息是在当天发送的。
昨天:表示消息是在昨天发送的。
日期:表示消息是在前天或更早之前发送的,这时候可能会显示具体的日期,而不仅仅是时分秒。
通过这样的设计,用户能够更轻松地理解消息的时间,使整体交互更为自然流畅。这种友好的时间显示方式已经成为IM应用中提升用户满意度的一项有效手段。

微信显示规则
微信聊天消息时间显示说明
1、当天的消息,以每5分钟为一个跨度的显示时间;
2、消息超过1天、小于1周,显示星期+收发消息的时间;
3、消息大于1周,显示手机收发时间的日期。

以上内容来自微信官方FAQ文档

分析下微信中聊天消息的时间显示逻辑

  1. 微信对于聊天消息时间显示的规则总结如下(首页“消息”界面):
  • 当聊天消息时间为一周之内时:当天的消息显示为“小时:分钟”形式,然后是“昨天”、“前天”,然后就是“星期几”这个样子。
  • 当聊天消息的时间大于一周时:直接显示“年/月/日”的时间格式。
  1. 微信对于聊天消息时间显示的规则总结如下(聊天内容界面):
  • 当聊天消息时间为一周之内时:当天的消息显示为“小时:分钟”形式,然后是“昨天 时:分”、“前天 时:分”,然后就是“星期几 时:分”这个样子。
  • 当聊天消息的时间大于一周时:直接显示“年/月/日 时:分”的完整时间格式。

注意:聊天内容界面中的时间格式实际上是首页“消息”界面中时间格式与“时:分”相结合的结果。因此,从代码实现的角度来看,这两种时间格式的处理可以共用一套代码,无需重复编写两份代码。

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

Web网页端的代码实现(JavaScript)

完整源码:

/**
 * 对Date的扩展,将 Date 转化为指定格式的String。
 *
 *  月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
 *  年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)。
 *
 *  【示例】:
 *  common.formatDate(new Date(), 'yyyy-MM-dd hh:mm:ss.S') ==> 2006-07-02 08:09:04.423
 *  common.formatDate(new Date(), 'yyyy-M-d h:m:s.S')      ==> 2006-7-2 8:9:4.18
 *  common.formatDate(new Date(), 'hh:mm:ss.S')            ==> 08:09:04.423
 *  
 */
let _formatDate = function (date, fmt) {
    let o = {
        "M+": date.getMonth() + 1, //月份
        "d+": date.getDate(), //日
        "h+": date.getHours(), //小时
        "m+": date.getMinutes(), //分
        "s+": date.getSeconds(), //秒
        "q+": Math.floor((date.getMonth() + 3) / 3), //季度
        "S": date.getMilliseconds() //毫秒
    };
    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (let k in o)
        if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
    return fmt;
};

/**
 * 仿照微信中的消息时间显示逻辑,将时间戳(单位:毫秒)转换为友好的显示格式.
 *
 * 1)7天之内的日期显示逻辑是:今天、昨天(-1d)、前天(-2d)、星期?(只显示总计7天之内的星期数,即<=-4d);
 * 2)7天之外(即>7天)的逻辑:直接显示完整日期时间。
 *
 * @param  {[long]} timestamp 时间戳(单位:毫秒),形如:1550789954260
 * @param {boolean} mustIncludeTime true表示输出的格式里一定会包含“时间:分钟”
 * ,否则不包含(参考微信,不包含时分的情况,用于首页“消息”中显示时)
 *
 * @return {string} 输出格式形如:“刚刚”、“10:30”、“昨天 12:04”、“前天 20:51”、“星期二”、“2019/2/21 12:09”等形式
 */
export function _getTimeStringAutoShort(timestamp, mustIncludeTime) {

    // 当前时间
    let currentDate = new Date();
    // 目标判断时间
    let srcDate = new Date(parseInt(timestamp));

    let currentYear = currentDate.getFullYear();
    let currentMonth = (currentDate.getMonth() + 1);
    let currentDateD = currentDate.getDate();

    let srcYear = srcDate.getFullYear();
    let srcMonth = (srcDate.getMonth() + 1);
    let srcDateD = srcDate.getDate();

    let ret = "";

    // 要额外显示的时间分钟
    let timeExtraStr = (mustIncludeTime ? " " + _formatDate(srcDate, "hh:mm") : "");

    // 当年
    if (currentYear == srcYear) {
        let currentTimestamp = currentDate.getTime();
        let srcTimestamp = timestamp;
        // 相差时间(单位:毫秒)
        let deltaTime = (currentTimestamp - srcTimestamp);

        // 当天(月份和日期一致才是)
        if (currentMonth == srcMonth && currentDateD == srcDateD) {
            // 时间相差60秒以内
            if (deltaTime < 60 * 1000)
                ret = "刚刚";
            // 否则当天其它时间段的,直接显示“时:分”的形式
            else
                ret = _formatDate(srcDate, "hh:mm");
        }
        // 当年 && 当天之外的时间(即昨天及以前的时间)
        else {
            // 昨天(以“现在”的时候为基准-1天)
            let yesterdayDate = new Date();
            yesterdayDate.setDate(yesterdayDate.getDate() - 1);

            // 前天(以“现在”的时候为基准-2天)
            let beforeYesterdayDate = new Date();
            beforeYesterdayDate.setDate(beforeYesterdayDate.getDate() - 2);

            // 用目标日期的“月”和“天”跟上方计算出来的“昨天”进行比较,是最为准确的(如果用时间戳差值
            // 的形式,是不准确的,比如:现在时刻是2019年02月22日1:00、而srcDate是2019年02月21日23:00,
            // 这两者间只相差2小时,直接用“deltaTime/(3600 * 1000)” > 24小时来判断是否昨天,就完全是扯蛋的逻辑了)
            if (srcMonth == (yesterdayDate.getMonth() + 1) && srcDateD == yesterdayDate.getDate())
                ret = "昨天" + timeExtraStr; // -1d
            // “前天”判断逻辑同上
            else if (srcMonth == (beforeYesterdayDate.getMonth() + 1) && srcDateD == beforeYesterdayDate.getDate())
                ret = "前天" + timeExtraStr; // -2d
            else {
                // 跟当前时间相差的小时数
                let deltaHour = (deltaTime / (3600 * 1000));

                // 如果小于或等 7*24小时就显示星期几
                if (deltaHour <= 7 * 24) {
                    let weekday = new Array(7);
                    weekday[0] = "周日";
                    weekday[1] = "周一";
                    weekday[2] = "周二";
                    weekday[3] = "周三";
                    weekday[4] = "周四";
                    weekday[5] = "周五";
                    weekday[6] = "周六";

                    // 取出当前是星期几
                    let weedayDesc = weekday[srcDate.getDay()];
                    ret = weedayDesc + timeExtraStr;
                }
                // 否则直接显示完整日期时间
                else
                    ret = _formatDate(srcDate, "yyyy/M/d") + timeExtraStr;
            }
        }
    }
    // 往年
    else {
        ret = _formatDate(srcDate, "yyyy/M/d") + timeExtraStr;
    }

    return ret;
};

调用实示例

_getTimeStringAutoShort(time, true);

原文地址

仿微信的IM聊天时间显示格式

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值