SwiftでTwitterとかにあるような「○○分前」といった表記を実現する

f:id:daihase:20190809100049p:plain

こんばんは、daihaseです。

タイトルにあるように「○○分前」「○○時間前」といったTwitterを始め、ユーザーの投稿一覧なんかを表示するアプリではおきまりの表記、こちらのSwiftでの実装方法を説明したいと思います。

まず日付となるとDateクラスですね。こちらを拡張したクラスを以下のように作ります。

import UIKit

extension Date {
    public var timeAgoSinceDate: String {
        let daysAgo = "日前"
        let hoursAgo = "時間前"
        let minutesAgo = "分前"
        let calendar = NSCalendar.current
        let unitFlags: Set<Calendar.Component> = [.minute, .hour, .day, .weekOfYear]
        let now = NSDate()
        let earliest = now.earlierDate(self)
        let latest = (earliest == now as Date) ? self : now as Date
        let components = calendar.dateComponents(unitFlags, from: earliest as Date, to: latest as Date)

        guard
            let week = components.weekOfYear,
            let day = components.day,
            let hour = components.hour,
            let minute = components.minute
            else { assertionFailure(); return "" }

        if week >= 2 {
            return self.stringFromUnixDate()
        } else if week >= 1 {
            return "7\(daysAgo)"
        } else if day >= 2 {
            return "\(day)" + daysAgo
        } else if day >= 1 {
            return "1\(daysAgo)"
        } else if hour >= 2 {
            return "\(hour)" + hoursAgo
        } else if hour >= 1 {
            return "1\(hoursAgo)"
        } else if minute >= 2 {
            return "\(minute)" + minutesAgo
        } else {
            return "1\(minutesAgo)"
        }
    }

    private func stringFromUnixDate() -> String {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "ja_JP")
        formatter.dateStyle = .medium
        formatter.timeZone = TimeZone(identifier: Locale.current.identifier)

        return formatter.string(from: self)
    }
}

 

1時間より前は○○分前、1日より前は○○時間前、といったように表示さえるためのDate拡張クラスですね。

では結果を見るためにViewController側を以下のように作ってみます。

import UIKit

class ViewController: UIViewController {
    var label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 50))

    override func viewDidLoad() {
        super.viewDidLoad()

        label.font = UIFont.systemFont(ofSize: 14)
        label.textColor = .black
        label.textAlignment = .center
        label.center = view.center

        view.addSubview(label)

        let date = Date()
        label.text = date.timeAgoSinceDate
    }
}

 

これを実行すると、常に最新の時刻にて結果が表示されます。

ではUnix時間を色々入れてみましょう。ViewControllerを以下のように変えて実行してみます。

import UIKit

class ViewController: UIViewController {
    var label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 50))

    override func viewDidLoad() {
        super.viewDidLoad()

        label.font = UIFont.systemFont(ofSize: 14)
        label.textColor = .black
        label.textAlignment = .center
        label.center = view.center

        view.addSubview(label)

        let dateUnix: TimeInterval = 1547091585
        let date = NSDate(timeIntervalSince1970: dateUnix) as Date

        label.text = date.timeAgoSinceDate
    }
}

 

このようにすれば簡単に「○○分前」といった表記を実現することが出来ます。例えばTwitterのようなアプリはユーザーの投稿データをDBに時刻と一緒に保存してますよね。その時刻を一覧に含めて返してもらい、アプリ側でそれを上記のように変換をかけて表示してやれば、同じようなことが実現出来るかと思います。

それでは良い開発ライフを〜