現代のインスタントメッセージング(IM)アプリにおいて、チャットメッセージの時刻表示はユーザー体験(UX)において重要な要素となっている。従来の「年/月/日 時:分:秒」という単調な表示形式から、より直感的で理解しやすい形式へと進化している。
WeChatの時刻表示ルール
WeChatでは、メッセージの時刻表示において以下のルールを採用している:
チャット一覧画面(ホーム画面):
- 当日のメッセージ:「時:分」形式
- 昨日:「昨日」
- 一昨日:「一昨日」
- 1週間以内:「曜日」形式
- 1週間以上前:「年/月/日」形式
チャット詳細画面:
- 当日のメッセージ:「時:分」形式
- 昨日以降:各表示に「時:分」を付加
両画面の表示ロジックは、時刻情報の付加有無のみが異なるため、共通の処理関数として実装可能である。
JavaScriptによる実装
/**
* 日付フォーマット処理
* @param {Date} targetDate - 対象日付
* @param {string} pattern - フォーマットパターン
* @returns {string} フォーマット済み文字列
*/
function formatDateTime(targetDate, pattern) {
const dateElements = {
'M+': targetDate.getMonth() + 1,
'd+': targetDate.getDate(),
'H+': targetDate.getHours(),
'm+': targetDate.getMinutes(),
's+': targetDate.getSeconds(),
'S': targetDate.getMilliseconds()
};
// 年の置換処理
if (/(y+)/.test(pattern)) {
const yearMatch = RegExp.$1;
pattern = pattern.replace(yearMatch,
(targetDate.getFullYear() + '').substring(4 - yearMatch.length));
}
// 各要素の置換処理
for (const key in dateElements) {
const regex = new RegExp('(' + key + ')');
if (regex.test(pattern)) {
const matchStr = RegExp.$1;
const elementValue = dateElements[key];
pattern = pattern.replace(matchStr,
matchStr.length === 1 ? elementValue : ('00' + elementValue).slice(-2));
}
}
return pattern;
}
/**
* チャット時刻表示変換処理
* @param {number} timestamp - ミリ秒単位のタイムスタンプ
* @param {boolean} showTime - 時刻表示フラグ
* @returns {string} 変換済み時刻文字列
*/
function formatChatTime(timestamp, showTime = false) {
const now = new Date();
const targetDate = new Date(timestamp);
// 各日付要素の取得
const nowInfo = {
year: now.getFullYear(),
month: now.getMonth(),
day: now.getDate()
};
const targetInfo = {
year: targetDate.getFullYear(),
month: targetDate.getMonth(),
day: targetDate.getDate()
};
// 時刻サフィックスの生成
const timeSuffix = showTime ? ' ' + formatDateTime(targetDate, 'HH:mm') : '';
// 差分時間の計算
const diffMs = now.getTime() - timestamp;
const diffMinutes = Math.floor(diffMs / (60 * 1000));
// 当日の判定
const isToday = nowInfo.year === targetInfo.year &&
nowInfo.month === targetInfo.month &&
nowInfo.day === targetInfo.day;
if (isToday) {
if (diffMinutes < 1) {
return 'たった今';
}
return formatDateTime(targetDate, 'HH:mm');
}
// 昨日の判定
const yesterday = new Date(now);
yesterday.setDate(yesterday.getDate() - 1);
if (targetInfo.year === yesterday.getFullYear() &&
targetInfo.month === yesterday.getMonth() &&
targetInfo.day === yesterday.getDate()) {
return '昨日' + timeSuffix;
}
// 一昨日の判定
const dayBefore = new Date(now);
dayBefore.setDate(dayBefore.getDate() - 2);
if (targetInfo.year === dayBefore.getFullYear() &&
targetInfo.month === dayBefore.getMonth() &&
targetInfo.day === dayBefore.getDate()) {
return '一昨日' + timeSuffix;
}
// 1週間以内の判定
const diffDays = Math.floor(diffMs / (24 * 60 * 60 * 1000));
if (diffDays < 7) {
const weekDays = ['日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'];
return weekDays[targetDate.getDay()] + timeSuffix;
}
// それ以外(完全な日付形式)
const fullFormat = targetInfo.year === nowInfo.year ? 'M/d' : 'yyyy/M/d';
return formatDateTime(targetDate, fullFormat) + timeSuffix;
}
使用例
// チャット一覧画面用(時刻なし)
const displayTime1 = formatChatTime(messageTimestamp, false);
// チャット詳細画面用(時刻あり)
const displayTime2 = formatChatTime(messageTimestamp, true);