java 友好时间显示_仿微信的IM聊天时间显示格式(含iOS/Android/Web实现)[图文+源码]...
本文為原創分享,轉載請注明出處。
1、引言
即時通訊IM應用中的聊天消息時間顯示是個再常見不過的需求,現在都講究用戶體驗,所以時間顯示再也不能像傳統軟件一樣簡單粗地暴顯示成“年/月/日 時:分:秒”這樣。所以,市面上幾乎所有的IM都會對聊天消息的時間顯示格化做人性化處理,從而提升用戶體驗(使用感受會明顯友好)。
這兩天正在繼續開發RainbowChat-Web產品,所以正需要這樣的代碼。但經過在即時通訊網的論壇和技術交流群里詢問,以及網上的所謂仿微信例子,都不符合要求。這些例子要么簡陋粗暴(有邏輯bug硬傷)、要么并不完整(可能只是隨手寫的練手代碼,并不適合放到產品中),所以本著做技術精益求精的態度,沒有現成的輪子可用,那就只能造輪子了。
那么,按怎樣的顯示邏輯來實現呢?作為移動端IM的王者,微信無疑處處是標桿,所以本次的消息時間顯示格式,直接參照微信的實現邏輯準沒錯(隨大流雖然沒個性,但不至于非主流)。
* 提示:本文中的代碼實現,是從 RainbowChat 和 RainbowChat-Web 兩個IM產品中扒出來簡化后的結果,是基于完全相同的算法邏輯分別用OC、Java和JavaScript實現的。如您覺得有用,可以改改直接用于您的產品,如您有更好的建議請直接回復和評論。代碼僅供參考,不足之外,還請見諒!
學習交流:- 即時通訊/推送技術開發交流4群:101279154 [推薦]
- 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》
2、相關文章
3、看看微信中聊天消息的時間顯示規則
先來看看微信中聊天消息的時間顯示成什么樣:微信主頁“消息”界面
聊天界面(注意聊天界面中默認帶了“時:分”的顯示)
來自微信官方對聊天消息時間顯示的規則說明:
▲ 該規則的定義,主要是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 = {"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
// 取出當前是星期幾
String weedayDesc = weekday[gcSrc.get(GregorianCalendar.DAY_OF_WEEK)-1];
ret = weedayDesc+timeExtraStr;
}
// 否則直接顯示完整日期時間
else
ret = getTimeString(srcDate, "yyyy/M/d")+timeExtraStr;
}
}
}
else
ret = getTimeString(srcDate, "yyyy/M/d")+timeExtraStr;
}
catch(Exception e)
{
System.err.println("【DEBUG-getTimeStringAutoShort】計算出錯:"+e.getMessage()+" 【NO】");
}
returnret;
}
5.2 調用示例// 用于首頁“消息”界面時
getTimeStringAutoShort2(newDate(), false);
// 用于聊天內容界面時
getTimeStringAutoShort2(newDate(), true);
5.3 運行效果
▲ 上述代碼在RainbowChat Android版上的運行效果(首頁)
▲ 上述代碼在RainbowChat Android版上的運行效果(聊天界面)
6、iOS平臺上的代碼實現(Objective-C)
6.1 完整源碼
源文件TimeTool.h:#import
@interfaceTimeTool : NSObject
/**
* 仿照微信中的消息時間顯示邏輯,將時間戳(單位:毫秒)轉換為友好的顯示格式.
* 1)7天之內的日期顯示邏輯是:今天、昨天(-1d)、前天(-2d)、星期?(只顯示總計7天之內的星期數,即<=-4d);
* 2)7天之外(即>7天)的邏輯:直接顯示完整日期時間。
* @param dt 日期時間對象(本次被判斷對象)
* @param includeTime YES表示輸出的格式里一定會包含“時間:分鐘”,否則不包含(參考微信,不包含時分的情況,用于首頁“消息”中顯示時)
* @return 輸出格式形如:“剛剛”、“10:30”、“昨天 12:04”、“前天 20:51”、“星期二”、“2019/2/21 12:09”等形式
* @since 1.3
*/
+ (NSString*)getTimeStringAutoShort2:(NSDate*)dt mustIncludeTime:(BOOL)includeTime;
+ (NSString*)getTimeString:(NSDate*)dt format:(NSString*)fmt;
/**
* 獲得指定NSDate對象iOS時間戳(格式遵從ios的習慣,以秒為單位)。
*/
+ (NSTimeInterval) getIOSTimeStamp:(NSDate*)dat;
/**
* 獲得指定NSDate對象iOS時間戳的long形式(格式遵從ios的習慣,以秒為單位,形如:1485159493)。
*/
+ (long) getIOSTimeStamp_l:(NSDate*)dat;
@end
源文件TimeTool.m:#import "TimeTool.h"
@implementationTimeTool
// 仿照微信的邏輯,顯示一個人性化的時間字串
+ (NSString*)getTimeStringAutoShort2:(NSDate*)dt mustIncludeTime:(BOOL)includeTime{
NSString*ret = nil;
NSCalendar*calendar = [NSCalendarcurrentCalendar];
// 當前時間
NSDate*currentDate = [NSDatedate];
NSDateComponents*curComponents = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitWeekdayfromDate:currentDate];
NSIntegercurrentYear=[curComponents year];
NSIntegercurrentMonth=[curComponents month];
NSIntegercurrentDay=[curComponents day];
// 目標判斷時間
NSDateComponents*srcComponents = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitWeekdayfromDate:dt];
NSIntegersrcYear=[srcComponents year];
NSIntegersrcMonth=[srcComponents month];
NSIntegersrcDay=[srcComponents day];
// 要額外顯示的時間分鐘
NSString*timeExtraStr = (includeTime?[TimeTool getTimeString:dt format:@" HH:mm"]:@"");
// 當年
if(currentYear == srcYear) {
longcurrentTimestamp = [TimeTool getIOSTimeStamp_l:currentDate];
longsrcTimestamp = [TimeTool getIOSTimeStamp_l:dt];
// 相差時間(單位:秒)
longdelta = currentTimestamp - srcTimestamp;
// 當天(月份和日期一致才是)
if(currentMonth == srcMonth && currentDay == srcDay) {
// 時間相差60秒以內
if(delta < 60)
ret = @"剛剛";
// 否則當天其它時間段的,直接顯示“時:分”的形式
else
ret = [TimeTool getTimeString:dt format:@"HH:mm"];
}
// 當年 && 當天之外的時間(即昨天及以前的時間)
else{
// 昨天(以“現在”的時候為基準-1天)
NSDate*yesterdayDate = [NSDatedate];
yesterdayDate = [NSDatedateWithTimeInterval:-24*60*60 sinceDate:yesterdayDate];
NSDateComponents*yesterdayComponents = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDayfromDate:yesterdayDate];
NSIntegeryesterdayMonth=[yesterdayComponents month];
NSIntegeryesterdayDay=[yesterdayComponents day];
// 前天(以“現在”的時候為基準-2天)
NSDate*beforeYesterdayDate = [NSDatedate];
beforeYesterdayDate = [NSDatedateWithTimeInterval:-48*60*60 sinceDate:beforeYesterdayDate];
NSDateComponents*beforeYesterdayComponents = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDayfromDate:beforeYesterdayDate];
NSIntegerbeforeYesterdayMonth=[beforeYesterdayComponents month];
NSIntegerbeforeYesterdayDay=[beforeYesterdayComponents day];
// 用目標日期的“月”和“天”跟上方計算出來的“昨天”進行比較,是最為準確的(如果用時間戳差值
// 的形式,是不準確的,比如:現在時刻是2019年02月22日1:00、而srcDate是2019年02月21日23:00,
// 這兩者間只相差2小時,直接用“delta/3600” > 24小時來判斷是否昨天,就完全是扯蛋的邏輯了)
if(srcMonth == yesterdayMonth && srcDay == yesterdayDay)
ret = [NSStringstringWithFormat:@"昨天%@", timeExtraStr];// -1d
// “前天”判斷邏輯同上
elseif(srcMonth == beforeYesterdayMonth && srcDay == beforeYesterdayDay)
ret = [NSStringstringWithFormat:@"前天%@", timeExtraStr];// -2d
else{
// 跟當前時間相差的小時數
longdeltaHour = (delta/3600);
// 如果小于或等 7*24小時就顯示星期幾
if(deltaHour <= 7*24){
NSArray *weekdayAry = [NSArrayarrayWithObjects:@"星期日", @"星期一", @"星期二", @"星期三", @"星期四", @"星期五", @"星期六", nil];
// 取出的星期數:1表示星期天,2表示星期一,3表示星期二。。。。 6表示星期五,7表示星期六
NSIntegersrcWeekday=[srcComponents weekday];
// 取出當前是星期幾
NSString*weedayDesc = [weekdayAry objectAtIndex:(srcWeekday-1)];
ret = [NSStringstringWithFormat:@"%@%@", weedayDesc, timeExtraStr];
}
// 否則直接顯示完整日期時間
else
ret = [NSStringstringWithFormat:@"%@%@", [TimeTool getTimeString:dt format:@"yyyy/M/d"], timeExtraStr];
}
}
}
// 往年
else{
ret = [NSStringstringWithFormat:@"%@%@", [TimeTool getTimeString:dt format:@"yyyy/M/d"], timeExtraStr];
}
returnret;
}
+ (NSString*)getTimeString:(NSDate*)dt format:(NSString*)fmt{
NSDateFormatter* format = [[NSDateFormatteralloc] init];
[format setDateFormat:fmt];
return[format stringFromDate:(dt==nil?[TimeTool getIOSDefaultDate]:dt)];
}
+ (NSTimeInterval) getIOSTimeStamp:(NSDate*)dat{
NSTimeIntervala = [dat timeIntervalSince1970];
returna;
}
+ (long) getIOSTimeStamp_l:(NSDate*)dat{
return[[NSNumbernumberWithDouble:[TimeTool getIOSTimeStamp:dat]] longValue];
}
@end
6.2 調用示例// 用于首頁“消息”界面時
[TimeTool getTimeStringAutoShort2:[NSDatedate] mustIncludeTime:NO];
6.3 運行效果
▲ 上述代碼在RainbowChat iOS版上的運行效果(首頁)
7、Web網頁端的代碼實現(JavaScript)
7.1 完整源碼抱歉:因文章字數限制,JavaScript版源碼無非法貼上來,請從鏈接:http://www.52im.net/thread-2371-1-1.html,查看JavaScript版完整源碼!
7.2 調用示例// 用于首頁“消息”界面時
_getTimeStringAutoShort2(1550789954260, false);
// 用于聊天內容界面時
_getTimeStringAutoShort2(1550789954260, true);
7.3 運行效果
▲ 上述代碼在RainbowChat-Web產品上的運行效果
附錄:更多精品資源下載
總結
以上是生活随笔為你收集整理的java 友好时间显示_仿微信的IM聊天时间显示格式(含iOS/Android/Web实现)[图文+源码]...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python简单实用案例_Python
- 下一篇: python学习指令_由Python到深