WeChat風IMチャットアプリのメッセージ時刻表示ロジックの実装

現代のインスタントメッセージング(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);

タグ: WeChat IM javascript UX チャットアプリ

5月14日 14:30 投稿