Быстрое время назад от объекта NSDate

В ячейке я хочу отобразить время назад с NSDate на сервере Parse. Вот код, но он не работает. Ничего не меняется, и данные не анализируются.

    if let createdat = (object?["createdAt"] as? String){
            let pastDate = Date(timeIntervalSinceNow: TimeInterval(createdat)!)
            cell.TimeAgo.text = pastDate.timeAgoDisplay()
        }


       extension Date {
          func timeAgoDisplay() -> String {
        let secondsAgo = Int(Date().timeIntervalSince(self))

        let minute = 60
        let hour = 60 * minute
        let day = 24 * hour
        let week = 7 * day

        if secondsAgo < minute {
            return "\(secondsAgo) sec ago"
        } else if secondsAgo < hour {
            return "\(secondsAgo / minute) min ago"
        } else if secondsAgo < day {
            return "\(secondsAgo / hour) hrs ago"
        } else if secondsAgo < week {
            return "\(secondsAgo / day) days ago"
        }

        return "\(secondsAgo / week) weeks ago"
    }
}

9 ответов

Решение

Если вы просто хотите продлить время до даты, перейдите к нижней части ответа

Я покажу вам пример, чтобы получить секунды назад, а после я покажу ваше расширение обновлено.

Примечание: вы можете напрямую использовать дату из Pase, если хотите:

if let pastDate = (object?["createdAt"] as? Date){
        cell.TimeAgo.text = pastDate.timeAgoDisplay()
    }

Пример того, как получить секунды назад с Swift 3:

Во-первых: чтобы узнать количество секунд назад, нам нужно проверить, есть ли у нас одна минута или меньше, чтобы получить текущую дату минус одну минуту, вы можете написать:

let minuteAgo = calendar.date(byAdding: .minute, value: -1, to: Date())!

Второе: теперь сравните 2 даты! (В случае вашего продления мы заменяем yourDate на self) и получаем разницу между этими двумя датами.

if (minuteAgo < yourDate) {
    let diff = Calendar.current.dateComponents([.second], from: yourDate, to: Date()).second ?? 0
    print("\(diff) sec ago")
}

Вот и все, теперь вы можете распечатать время назад!

Итак, ваше расширение выглядит так: (Это простое расширение, чтобы узнать время назад)

extension Date {
    func timeAgoDisplay() -> String {

        let calendar = Calendar.current
        let minuteAgo = calendar.date(byAdding: .minute, value: -1, to: Date())!
        let hourAgo = calendar.date(byAdding: .hour, value: -1, to: Date())!
        let dayAgo = calendar.date(byAdding: .day, value: -1, to: Date())!
        let weekAgo = calendar.date(byAdding: .day, value: -7, to: Date())!

        if minuteAgo < self {
            let diff = Calendar.current.dateComponents([.second], from: self, to: Date()).second ?? 0
            return "\(diff) sec ago"
        } else if hourAgo < self {
            let diff = Calendar.current.dateComponents([.minute], from: self, to: Date()).minute ?? 0
            return "\(diff) min ago"
        } else if dayAgo < self {
            let diff = Calendar.current.dateComponents([.hour], from: self, to: Date()).hour ?? 0
            return "\(diff) hrs ago"
        } else if weekAgo < self {
            let diff = Calendar.current.dateComponents([.day], from: self, to: Date()).day ?? 0
            return "\(diff) days ago"
        }
        let diff = Calendar.current.dateComponents([.weekOfYear], from: self, to: Date()).weekOfYear ?? 0
        return "\(diff) weeks ago"
    }
}

Чтобы использовать это, это очень просто:

var now = Date()
now.timeAgoDisplay()

Swift 5.1 (iOS 13)

Начиная с iOS 13 вы можете использовать Apple RelativeDateFormatter. Преимущество в том, что результирующая строка локализована.

let date = Date().addingTimeInterval(-15000)

let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .full
let string = formatter.localizedString(for: date, relativeTo: Date())

print(string) // 4 hours ago

См., Например, это сообщение в блоге.

Вот решение в Swift 5:

extension Date {

func timeAgo() -> String {

    let secondsAgo = Int(Date().timeIntervalSince(self))

    let minute = 60
    let hour = 60 * minute
    let day = 24 * hour
    let week = 7 * day
    let month = 4 * week

    let quotient: Int
    let unit: String
    if secondsAgo < minute {
        quotient = secondsAgo
        unit = "second"
    } else if secondsAgo < hour {
        quotient = secondsAgo / minute
        unit = "min"
    } else if secondsAgo < day {
        quotient = secondsAgo / hour
        unit = "hour"
    } else if secondsAgo < week {
        quotient = secondsAgo / day
        unit = "day"
    } else if secondsAgo < month {
        quotient = secondsAgo / week
        unit = "week"
    } else {
        quotient = secondsAgo / month
        unit = "month"
    }
    return "\(quotient) \(unit)\(quotient == 1 ? "" : "s") ago"
}
}

Это немного сложно)

В основном вам нужно

  • интервал проверки
  • выбрать интересующие компоненты
  • проверьте, требуется ли частное и применимо ли оно для текущего языка

iOS предоставляет несколько способов сделать это

  1. DateComponentsFormatter

    +: нет работы с локализацией и прочим строковым делом

    -: не очень гибкий

    let formatter = DateComponentsFormatter()
    formatter.allowedUnits = [.hour, .minute, .second]
    formatter.unitsStyle = .brief
    formatter.zeroFormattingBehavior = .dropAll
    
    let result = formatter.string(from: Date().advanced(by: -300), to: Date())
    result
    

Результат:

"5 мин"

  1. RelativeDateTimeFormatter

    +: нет работы с локализацией и прочим строковым делом

    -: iOS13+

    let formatter = RelativeDateTimeFormatter()
    formatter.unitsStyle = .full
    return formatter.localizedString(for: self, relativeTo: Date())
    
  2. Пользовательский способ

    +: гибкий

    -: кодировать все

Образец:

import Foundation

public extension Date {

  struct DetailedDateSuffix {

    let year: String
    let month: String
    let week: String
    let day: String
    let hour: String
    let min: String
    let second: String

    let quotient: String
    let suffix: String

    public init(year: String,
                week: String,
                month: String,
                day: String,
                hour: String,
                min: String,
                second: String,
                quotient: String,
                suffix: String = String.empty) {
      self.year = year
      self.month = month
      self.week = week
      self.day = day
      self.hour = hour
      self.min = min
      self.second = second
      self.quotient = quotient
      self.suffix = suffix
    }
  }

  func toDetailedReadableFormat(_ suffix: DetailedDateSuffix) -> String {

    if #available(iOS 13.0, *) {
      let formatter = RelativeDateTimeFormatter()
      formatter.unitsStyle = .full
      return formatter.localizedString(for: self, relativeTo: Date())
    } else {
      let calendar = Calendar.current
      let ageComponents = calendar.dateComponents(
        [
          .year,
          .month,
          .weekOfYear,
          .day,
          .hour,
          .minute,
          .second
        ],
        from: self,
        to: Date())

      var description: String = String.empty

      if let years = ageComponents.year,
        let months = ageComponents.month,
        let weeks = ageComponents.weekOfYear,
        let days = ageComponents.day,
        let hours = ageComponents.hour,
        let min = ageComponents.minute,
        let sec = ageComponents.second {

        var requireQuotient = false

        if years > 0 {
          description = "\(years)" + suffix.year
          requireQuotient = years == 1
        } else if months > 0 {
          description = "\(months)" + suffix.month
          requireQuotient = months == 1
        } else if weeks > 0 {
          description = "\(weeks)" + suffix.week
          requireQuotient = weeks == 1
        } else if days > 0 {
          description = "\(days)" + suffix.day
          requireQuotient = days == 1
        } else if hours > 0 {
          description = "\(hours)" + suffix.hour
          requireQuotient = hours == 1
        } else if min > 0 {
          description = "\(min)" + suffix.min
          requireQuotient = min == 1
        } else if sec > 0 {
          description = "\(sec)" + suffix.second
          requireQuotient = sec == 1
        }

        description = requireQuotient ? "\(description)\(suffix.quotient)" : description
        description = "\(description)\(suffix.suffix)"
      }

      return description
    }
  }
}

Передать время в виде строки в формате, например, 2019-02-25 10:20:21 Передать формат даты в переменную dateFormat

let dateFormat = "yyyy-MM-dd HH:mm:ss"

    func timeInterval(timeAgo:String) -> String
        {
            let df = DateFormatter()

            df.dateFormat = dateFormat
            let dateWithTime = df.date(from: timeAgo)

            let interval = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: dateWithTime!, to: Date())

            if let year = interval.year, year > 0 {
                return year == 1 ? "\(year)" + " " + "year ago" : "\(year)" + " " + "years ago"
            } else if let month = interval.month, month > 0 {
                return month == 1 ? "\(month)" + " " + "month ago" : "\(month)" + " " + "months ago"
            } else if let day = interval.day, day > 0 {
                return day == 1 ? "\(day)" + " " + "day ago" : "\(day)" + " " + "days ago"
            }else if let hour = interval.hour, hour > 0 {
                return hour == 1 ? "\(hour)" + " " + "hour ago" : "\(hour)" + " " + "hours ago"
            }else if let minute = interval.minute, minute > 0 {
                return minute == 1 ? "\(minute)" + " " + "minute ago" : "\(minute)" + " " + "minutes ago"
            }else if let second = interval.second, second > 0 {
                return second == 1 ? "\(second)" + " " + "second ago" : "\(second)" + " " + "seconds ago"
            } else {
                return "a moment ago"

            }
        }
    let now = Date()
let pastDate = Date(timeIntervalSinceNow: -60 * 60 * 24)

enum DisplayTime {
    case short
    case long

    var seconds: String {
        switch self {
        case .short: return "s"
        case .long: return "seconds"
        }
    }

    var minutes: String {
        switch self {
        case .short: return "m"
        case .long: return "minutes"
        }
    }

    var hours: String {
        switch self {
        case .short: return "h"
        case .long: return "hours"
        }
    }

    var days: String {
        switch self {
        case .short: return "d"
        case .long: return "days"
        }
    }

    var weeks: String {
        switch self {
        case .short: return "w"
        case .long: return "weeks"
        }
    }
}

extension Date {

    func timeAgoDisplay(_ display: DisplayTime) -> String {

        let secondsAgo = Int(Date().timeIntervalSince(self))

        let minute = 60
        let hour = 60 * minute
        let day = 24 * hour
        let week = 7 * day

        switch secondsAgo {
        case let seconds where seconds < minute : return "\(secondsAgo) \(display.seconds) ago"
        case let seconds where seconds < hour: return "\(secondsAgo / minute) \(display.minutes) ago"
        case let seconds where seconds < day: return "\(secondsAgo / hour) \(display.hours) ago"
        case let seconds where seconds < week: return "\(secondsAgo / day) \(display.days) ago"
        default: "\(secondsAgo / week) \(display.weeks) ago"
        }
        return "\(secondsAgo / week) \(display.weeks) ago"
    }
}

pastDate.timeAgoDisplay(.short)

Наконец-то получил простое решение для меня в swift4.2

    let start = //Enter Start Date here....
    let end = Date()
    let formatter = DateComponentsFormatter()
    formatter.maximumUnitCount = 2
    formatter.unitsStyle = .full
    formatter.allowedUnits = [.year, .month, .day]
    let timeDifference = form.string(from: start, to: end)
    print(timeDifference)
    if timeDifference == "0 days"{
          print("Today")
    }
    else if  timeDifference == "1 days"{
           print("\(timeDifference!)day ago")
    }
    else{
           print("\(timeDifference!)days ago")
    }

Если у вас есть только временная метка 1970 года. Вы можете использовать эту функцию для возврата времени назад.

private func timestampToStringAgo(timestamp: Int64) -> String{
        let actualTime = Int64(Date().timeIntervalSince1970*1000)
        var lastSeenTime = actualTime - timestamp
        lastSeenTime /= 1000 //seconds
        var lastTimeString = ""
        if lastSeenTime < 60 {
            if lastSeenTime == 1 {
                lastTimeString = String(lastSeenTime) + " second ago"
            } else {
                lastTimeString = String(lastSeenTime) + " seconds ago"
            }
        } else {
            lastSeenTime /= 60
            if lastSeenTime < 60 {
                if lastSeenTime == 1 {
                    lastTimeString =  String(lastSeenTime) + " minute ago"
                } else {
                    lastTimeString =  String(lastSeenTime) + " minutes ago"
                }
                
            } else {
                lastSeenTime /= 60
                if lastSeenTime < 24 {
                    if lastSeenTime == 1 {
                        lastTimeString = String(lastSeenTime) + " hour ago"
                    } else {
                        lastTimeString = String(lastSeenTime) + " hours ago"
                    }
                } else {
                    lastSeenTime /= 24
                    if lastSeenTime == 1 {
                        lastTimeString = String(lastSeenTime) + " day ago"
                    } else {
                        lastTimeString = String(lastSeenTime) + " days ago"
                    }
                }
            }
        }
        return lastTimeString
    }

Как отобразить время назад с даты

Вы можете использоватьtimeIntervalSinceчтобы получить разницу между двумя датами в секундах. Затем сравните secondAgo с секундами, минутами, часами, днями, неделями, месяцами и годами, чтобы определить правильный суффикс строки.

Вы можете использовать эту функцию, чтобы вернуть отформатированное время назад, просто передав ей дату и предпочтение длинного (3 дня назад) или короткого (3 дня назад).

См. мое полное руководство здесь: Как отобразить время назад с даты

Полный код:

      func getTimeSince(date: Date, isShort: Bool = false) -> String {
    var formattedString = String()
    let now = Date()
    let secondsAgo = Int(now.timeIntervalSince(date))
    
    let twoSeconds = 2
    let minute = 60
    let twoMinutes = minute * 2
    let hour = 60 * minute
    let twoHours = hour * 2
    let day = 24 * hour
    let twoDays = day * 2
    let week = 7 * day
    let twoWeeks = week * 2
    let month = 4 * week
    let twoMonths = month * 2
    let year = 12 * month
    let twoYears = year * 2
    
    let secondString = isShort ? "s ago" : " second ago"
    let secondsString = isShort ? "s ago" : " seconds ago"
    let minuteString = isShort ? "m ago" : " minute ago"
    let minutesString = isShort ? "m ago" : " minutes ago"
    let hourString = isShort ? "h ago" : " hour ago"
    let hoursString = isShort ? "h ago" : " hours ago"
    let dayString = isShort ? "d ago" : " day ago"
    let daysString = isShort ? "d ago" : " days ago"
    let weekString = isShort ? "w ago" : " week ago"
    let weeksString = isShort ? "w ago" : " weeks ago"
    let monthString = isShort ? "mo ago" : " month ago"
    let monthsString = isShort ? "mo ago" : " months ago"
    let yearString = isShort ? "y ago" : " year ago"
    let yearsString = isShort ? "y ago" : " years ago"
    
    if secondsAgo < twoSeconds {
        formattedString = "\(secondsAgo)\(secondString)"
    } else if secondsAgo < minute {
        formattedString = "\(secondsAgo)\(secondsString)"
    } else if secondsAgo < twoMinutes {
        formattedString = "\(secondsAgo / minute)\(minuteString)"
    } else if secondsAgo < hour {
        formattedString = "\(secondsAgo / minute)\(minutesString)"
    } else if secondsAgo < twoHours {
        formattedString = "\(secondsAgo / hour)\(hourString)"
    } else if secondsAgo < day {
        formattedString = "\(secondsAgo / hour)\(hoursString)"
    } else if secondsAgo < twoDays {
        formattedString = "\(secondsAgo / day)\(dayString)"
    } else if secondsAgo < week {
        formattedString = "\(secondsAgo / day)\(daysString)"
    } else if secondsAgo < twoWeeks {
        formattedString = "\(secondsAgo / week)\(weekString)"
    } else if secondsAgo < month {
        formattedString = "\(secondsAgo / week)\(weeksString)"
    } else if secondsAgo < twoMonths {
        formattedString = "\(secondsAgo / month)\(monthString)"
    } else if secondsAgo < year {
        formattedString = "\(secondsAgo / month)\(monthsString)"
    } else if secondsAgo < twoYears {
        formattedString = "\(secondsAgo / year)\(yearString)"
    } else {
        formattedString = "\(secondsAgo / year)\(yearsString)"
    }
    return formattedString
}

Использование:

      let formattedTimeAgo = self.getTimeSince(date: date, isShort: false)
Другие вопросы по тегам