前言
JDK中提供了好用的SimpleDateFormat工具來(lái)幫我們把格式化時(shí)間哺眯,并且制定了格式化的規(guī)范,只要我們按照規(guī)范傳入字符串扒俯,就能隨意定制我們想要的時(shí)間格式奶卓,例如:
- 傳入"yyyy.MM.dd G 'at' HH:mm:ss z"一疯,就能得到2001.07.04 AD at 12:08:56 PDT
- 傳入"EEE, MMM d, ''yy",就能得到Wed, Jul 4, '01
- 傳入"h:mm a"夺姑,就能得到12:08 PM
等等墩邀,具體用法 可以查閱官方文檔,用起來(lái)也非常方便盏浙。
但是近些年移動(dòng)互聯(lián)網(wǎng)發(fā)展迅速眉睹,用戶體驗(yàn)也被越來(lái)越多的重視起來(lái),對(duì)于時(shí)間的顯示也越來(lái)越人性化只盹。比如說聊天記錄的時(shí)間辣往,人們更愿意看到"兩分鐘前","一小時(shí)前"殖卑,"昨天"等樣式站削,而不是冷冰冰的幾月幾號(hào)幾點(diǎn)幾分。
當(dāng)產(chǎn)品給出了如上的需求時(shí)孵稽,很多開發(fā)者都是去判斷要顯示的時(shí)間與當(dāng)前時(shí)間的相對(duì)間隔许起,然后再查表得出需要顯示的時(shí)間。殊不知菩鲜,安卓已經(jīng)給我們提供好了相應(yīng)的工具园细,只需一個(gè)方法調(diào)用統(tǒng)統(tǒng)搞定。該工具就是今天的主角DateUtils接校,他位于android.text.format包下猛频。
作為系統(tǒng)提供的工具,當(dāng)然也會(huì)發(fā)揮本地化的優(yōu)勢(shì)蛛勉。格式化出來(lái)的時(shí)間也會(huì)跟隨系統(tǒng)系統(tǒng)自動(dòng)變化鹿寻,比如說如果系統(tǒng)默認(rèn)語(yǔ)言是中文,格式化出來(lái)的時(shí)間是"一分鐘前"诽凌,而如果系統(tǒng)語(yǔ)言是英語(yǔ)毡熏,格式化的時(shí)間就變成"one minute ago",省去了翻譯字符串的麻煩侣诵。
小試牛刀
按照上面描述的需求痢法,我們來(lái)看看用DateUtils如何實(shí)現(xiàn):
long currentTimeMillis = System.currentTimeMillis();
//兩分鐘前
Log.d(TAG, "getRelativeTimeSpanString " + DateUtils.getRelativeTimeSpanString(
currentTimeMillis - 2 * 60 * 1000));
//三個(gè)小時(shí)前
Log.d(TAG, "getRelativeTimeSpanString " + DateUtils.getRelativeTimeSpanString(
currentTimeMillis - 3 * 60 * 60 * 1000));
//一天前
Log.d(TAG, "getRelativeTimeSpanString " + DateUtils.getRelativeTimeSpanString(
currentTimeMillis - 28 * 60 * 60 * 1000));
打印出來(lái)的結(jié)果如下:
08-12 15:43:30.454 13935-13935/com.wangng.myapplication D/DateUtilsTAG: getRelativeTimeSpanString 2 分鐘前
08-12 15:43:30.454 13935-13935/com.wangng.myapplication D/DateUtilsTAG: getRelativeTimeSpanString 3 小時(shí)前
08-12 15:43:30.464 13935-13935/com.wangng.myapplication D/DateUtilsTAG: getRelativeTimeSpanString 昨天
getRelativeTimeSpanString有幾個(gè)重載方法:
public static CharSequence getRelativeTimeSpanString(long startTime)
public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution)
public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution, int flags)
我們來(lái)看看參數(shù)最多的最后一個(gè)方法,了解下這么多參數(shù)都有什么用杜顺。
- long time : 即你需要格式化的時(shí)間财搁;
- long now : 即你需要格式化的時(shí)間的相對(duì)時(shí)間,一般都是相對(duì)與當(dāng)前時(shí)間:System.currentTimeMillis()哑舒;
- long minResolution : 忽略的最小時(shí)間妇拯,有五個(gè)固定的常量取值,下面會(huì)開一個(gè)段落專門講解;
- int flags : 格式化的選項(xiàng)越锈,有幾個(gè)固定的取值仗嗦,也可以是這幾個(gè)固定取值的組合,下面會(huì)開一個(gè)段落專門講解甘凭。
其實(shí)看源碼就知道參數(shù)少的方法內(nèi)部最終都是調(diào)用的參數(shù)最多的方法稀拐。
public static CharSequence getRelativeTimeSpanString(long startTime) {
return getRelativeTimeSpanString(startTime, System.currentTimeMillis(), MINUTE_IN_MILLIS);
}
public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution) {
int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR | FORMAT_ABBREV_MONTH;
return getRelativeTimeSpanString(time, now, minResolution, flags);
}
第三個(gè)參數(shù)minResolution
那個(gè)方法的注釋已經(jīng)寫的很清楚
the minimum timespan to report. For example, a time3 seconds in the past will be reported as "0 minutes ago" if this is set to MINUTE_IN_MILLIS. Pass one of 0,MINUTE_IN_MILLIS, HOUR_IN_MILLIS, DAY_IN_MILLIS, WEEK_IN_MILLIS
大致意思就是:格式化的時(shí)候忽略的最小時(shí)間,比如說:如果該參數(shù)被設(shè)置成MINUTE_IN_MILLIS丹弱,小于一分鐘的時(shí)間就會(huì)被忽略德撬,傳入的時(shí)間剛好是3秒前,由于小于一分鐘就會(huì)被忽略而格式化成"0分鐘前";
該參數(shù)的取值有:
- 0 :即再小的時(shí)間間隔也不會(huì)被忽略躲胳;
- MINUTE_IN_MILLIS :其值為60X1000蜓洪,如果間隔小于一分鐘就會(huì)被忽略,最常用坯苹;
- HOUR_IN_MILLIS :其值為60X60X1000隆檀,如果時(shí)間間隔小于一個(gè)小時(shí)就會(huì)被忽略,詳見下面代碼打印結(jié)果粹湃;
- DAY_IN_MILLIS :其值為24X60X60X1000恐仑,如果時(shí)間間隔小于一天就會(huì)被忽略,詳見下面代碼打印結(jié)果为鳄;
-
WEEK_IN_MILLIS :其值為7X24X60X60X1000裳仆,如果時(shí)間間隔小于一個(gè)周就會(huì)被忽略枯饿,詳見下面代碼打印結(jié)果拙友;
為了更容易理解酬蹋,我們分別把函數(shù)的第三個(gè)參數(shù)設(shè)置成如上的幾個(gè)值挠阁,然后打印出來(lái)結(jié)果,一目了然:
DateUtils.getRelativeTimeSpanString(
currentTimeMillis - 2 * 60 * 1000,
currentTimeMillis,
DateUtils.MINUTE_IN_MILLIS,
DateUtils.FORMAT_SHOW_DATE)
DateUtils.getRelativeTimeSpanString(
currentTimeMillis - 3 * 60 * 60 * 1000,
currentTimeMillis,
DateUtils.DAY_IN_MILLIS,
DateUtils.FORMAT_SHOW_DATE)
DateUtils.getRelativeTimeSpanString(
currentTimeMillis - 28 * 60 * 60 * 1000,
currentTimeMillis,
DateUtils.DAY_IN_MILLIS,
DateUtils.FORMAT_SHOW_DATE)
DateUtils.getRelativeTimeSpanString(
currentTimeMillis - 180 * 60 * 60 * 1000,
currentTimeMillis,
DateUtils.DAY_IN_MILLIS,
DateUtils.FORMAT_SHOW_DATE)
為了直觀颜启,整理成表格如下:
時(shí)刻 | 時(shí)刻描述 | MINUTE | HOUR | DAY | WEEK |
---|---|---|---|---|---|
currentTimeMillis - 2 * 60 * 1000 | 兩分鐘前 | 2分鐘前 | 0小時(shí)前 | 今天 | 8月12日 |
currentTimeMillis - 3 * 60 * 60 * 1000 | 三小時(shí)前 | 3小時(shí)前 | 3小時(shí)前 | 今天 | 8月12日 |
currentTimeMillis - 28 * 60 * 60 * 1000 | 一天前 | 昨天 | 昨天 | 昨天 | 8月11日 |
currentTimeMillis - 180 * 60 * 60 * 1000 | 一周前 | 8月5日 | 8月5日 | 8月5日 | 8月5日 |
注1: 試驗(yàn)的當(dāng)前日期是8月12日
注2: 為了表格的簡(jiǎn)潔脏里,表格中的"MINUTE","HOUR","DAY","WEEK"均省略了后面的"IN_MILLIS"
注3 : markdown的表格真難用
如果看完上面的表格還有什么不清楚的踩麦,麻煩你去撞墻清醒一下腦袋壳猜。
第四個(gè)參數(shù)flags
我們知道,一個(gè)完整的時(shí)間包括年份滑凉,月份统扳,日期,星期畅姊,時(shí)咒钟,分,秒若未,當(dāng)然時(shí)分又有12小時(shí)制和24小時(shí)制朱嘴。flag的值就是限制顯示時(shí)間的哪些元素。
該參數(shù)可選的值包括:
- FORMAT_SHOW_TIME:單獨(dú)使用只顯示時(shí)和分,例如“下午12:16”萍嬉,或者“23:22”乌昔,具體是12小時(shí)制還是24小時(shí)制,取決于系統(tǒng)設(shè)置的樣式壤追,當(dāng)然也可以配合下面的FORMAT_12HOUR磕道,F(xiàn)ORMAT_24HOUR使用;
- FORMAT_SHOW_WEEKDAY:單獨(dú)使用只顯示星期幾行冰,例如“星期五”溺蕉;
- FORMAT_SHOW_YEAR:如果該值被設(shè)置了,則年份始終會(huì)顯示悼做,如果沒有設(shè)置疯特,年份只有在格式化的時(shí)間跟當(dāng)前時(shí)間不在同一年的時(shí)候顯示。例如現(xiàn)在是2017年8月12日肛走,而要格式化的時(shí)間是2017年7月22日漓雅,如果flag設(shè)置了FORMAT_SHOW_YEAR,則格式化出來(lái)的時(shí)間為“2017年7月12日”羹与,如果沒有設(shè)置FORMAT_SHOW_YEAR故硅,則格式化出來(lái)的時(shí)間為“7月12日”;
- FORMAT_SHOW_DATE:顯示月份和日期纵搁;
- FORMAT_NO_MONTH_DAY:顯示月份和日期當(dāng)中的月份吃衅,而不是日期,例如會(huì)顯示“八月”腾誉,而不是“8月18日”徘层;
- FORMAT_12HOUR:按照12小時(shí)制顯示,通常不要設(shè)置這個(gè)值利职,因?yàn)橄到y(tǒng)會(huì)自動(dòng)根據(jù)系統(tǒng)設(shè)置的顯示樣式來(lái)顯示趣效,如果FORMAT_12HOUR和FORMAT_24HOUR同時(shí)被設(shè)置,則按照FORMAT_24HOUR顯示猪贪;
- FORMAT_24HOUR:類似于FORMAT_12HOUR跷敬;
- FORMAT_CAP_AMPM:如果這個(gè)值和FORMAT_12HOUR同時(shí)被設(shè)置,則“AM”和“PM"會(huì)顯示成大寫热押;
- FORMAT_NO_NOON:正常情況下中午12點(diǎn)會(huì)被顯示成“noon”西傀,但是如果這個(gè)值和FORMAT_12HOUR同時(shí)被設(shè)置,則會(huì)顯示成“12pm”
- FORMAT_CAP_NOON:正常情況下中午12點(diǎn)會(huì)被顯示成“noon”桶癣,但是如果這個(gè)值被設(shè)置拥褂,則會(huì)顯示成“Noon”;
- FORMAT_NO_MIDNIGHT:類似于FORMAT_NO_NOON牙寞,正常情況下物業(yè)12點(diǎn)會(huì)被顯示成“midnight”饺鹃,如果設(shè)置了該值,則顯示成“12am”;
- FORMAT_CAP_MIDNIGHT:類似于FORMAT_CAP_NOON悔详,“midnight”大寫顯示成“Midnight”镊屎;
- FORMAT_ABBREV_TIME:如果該值和FORMAT_12HOUR同時(shí)被設(shè)置,且時(shí)間剛好是整點(diǎn)伟端,則分“00”就會(huì)被省略杯道,例如“3:00pm”將會(huì)簡(jiǎn)寫成“3pm”;
- FORMAT_ABBREV_WEEKDAY:星期幾會(huì)被簡(jiǎn)寫成三個(gè)字母的字符串责蝠,當(dāng)然這是在系統(tǒng)語(yǔ)言是英語(yǔ)的情況下党巾,例如“Sunday”會(huì)簡(jiǎn)寫成“Sun”;
- FORMAT_ABBREV_MONTH:類似于FORMAT_ABBREV_WEEKDAY霜医,簡(jiǎn)寫月份成三個(gè)字母的字符串齿拂;
- FORMAT_ABBREV_ALL:時(shí)間,星期肴敛,月份都會(huì)按照對(duì)應(yīng)的簡(jiǎn)寫規(guī)則簡(jiǎn)寫署海;
- FORMAT_NUMERIC_DATE:如果該值被設(shè)置,則直接格式化成“12/13”医男,而不是顯示月份的名稱砸狞,如“December 31”
參數(shù)的名字叫“flags”,是復(fù)數(shù)形式镀梭,所以意味著我們可以疊加這些flag使用刀森。舉個(gè)例子,大家就明白怎么用了:
DateUtils.formatDateTime(getActivity(),
System.currentTimeMillis(), DateUtils.FORMAT_SHOW_TIME
| DateUtils.FORMAT_SHOW_DATE
| DateUtils.FORMAT_ABBREV_ALL)
分析上面的代碼报账,flag用到了FORMAT_SHOW_TIME研底,F(xiàn)ORMAT_SHOW_DATE,根據(jù)我們上面的介紹透罢,可以推斷會(huì)顯示出時(shí)間和日期榜晦,又用到了FORMAT_ABBREV_ALL,所以月份和時(shí)間都會(huì)采用簡(jiǎn)寫形式羽圃,打印一下:8月12日 下午8點(diǎn)15乾胶,F(xiàn)ORMAT_ABBREV_ALL貌似沒起作用,但是如果把系統(tǒng)語(yǔ)言切換成英語(yǔ)朽寞,就能看到差別了:“Aug 12, 8:15 PM”胚吁。
DateUtils的其他方法
public boolean isToday(long when)
從方法名就能看出來(lái),判斷傳入時(shí)間是否跟今天是同一天愁憔,在發(fā)送某個(gè)頁(yè)面的UV統(tǒng)計(jì)的時(shí)候非常好用。
public static String formatDateRange(Context context, long startMillis,
long endMillis, int flags)
public static Formatter formatDateRange(Context context, Formatter formatter, long startMillis,
long endMillis, int flags)
public static Formatter formatDateRange(Context context, Formatter formatter,
long startMillis,long endMillis, int flags, String timeZone)
格式化一個(gè)時(shí)間區(qū)間孽拷,比如說電商的一個(gè)活動(dòng)的活動(dòng)時(shí)間就是由開始時(shí)間和結(jié)束時(shí)間組成吨掌,用上面的方法格式化就很方便。
小結(jié)
其實(shí)要是弄懂了flag的用法,就基本上已經(jīng)掌握了這個(gè)工具類了膜宋。