Schnell - Überprüfen Sie, ob ein Zeitstempel gestern, heute, morgen oder vor X Tagen liegt

70

Ich versuche herauszufinden, wie ich entscheiden kann, ob ein bestimmter Zeitstempel heute oder +1 / -1 Tage auftritt. Im Wesentlichen möchte ich so etwas machen (Pseudocode)

IF days_from_today(timestamp) == -1 RETURN 'Yesterday'
ELSE IF days_from_today(timestamp) == 0 RETURN 'Today'
ELSE IF days_from_today(timestamp) == 1 RETURN 'Tomorrow'
ELSE IF days_from_today(timestamp) < 1 RETURN days_from_today(timestamp) + ' days ago'
ELSE RETURN 'In ' + days_from_today(timestamp) + ' ago'

Entscheidend ist jedoch, dass es in Swift sein muss und ich Probleme mit den NSDate / NSCalendar-Objekten habe. Ich begann damit, den Zeitunterschied wie folgt zu berechnen:

let calendar = NSCalendar.currentCalendar()
let date = NSDate(timeIntervalSince1970: Double(timestamp))
let timeDifference = calendar.components([.Second,.Minute,.Day,.Hour],
    fromDate: date, toDate: NSDate(), options: NSCalendarOptions())

Ein Vergleich auf diese Weise ist jedoch nicht einfach, da er .Dayje nach Tageszeit und Zeitstempel unterschiedlich ist. In PHP würde ich nur mktime verwenden, um ein neues Datum zu erstellen, basierend auf dem Beginn des Tages (dh mktime(0,0,0)), aber ich bin mir nicht sicher, wie ich das in Swift am einfachsten machen kann.

Hat jemand eine gute Idee, wie man das angeht? Vielleicht wäre eine Erweiterung auf NSDate oder ähnliches am besten?

Ben
quelle

Antworten:

129

Calendar hat Methoden für alle drei Fälle

func isDateInYesterday(_ date: Date) -> Bool
func isDateInToday(_ date: Date) -> Bool
func isDateInTomorrow(_ date: Date) -> Bool

Um die Tage früher als gestern zu berechnen, verwenden Sie

func dateComponents(_ components: Set<Calendar.Component>, 
                      from start: Date, 
                          to end: Date) -> DateComponents

Übergeben Sie [.day]an componentsund erhalten Sie die dayEigenschaft aus dem Ergebnis.


Dies ist eine Funktion, die auch is infrühere und spätere Daten berücksichtigt, indem der Zeitteil entfernt wird (Swift 3+).

func dayDifference(from interval : TimeInterval) -> String
{
    let calendar = Calendar.current
    let date = Date(timeIntervalSince1970: interval)
    if calendar.isDateInYesterday(date) { return "Yesterday" }
    else if calendar.isDateInToday(date) { return "Today" }
    else if calendar.isDateInTomorrow(date) { return "Tomorrow" }
    else {
        let startOfNow = calendar.startOfDay(for: Date())
        let startOfTimeStamp = calendar.startOfDay(for: date)
        let components = calendar.dateComponents([.day], from: startOfNow, to: startOfTimeStamp)
        let day = components.day!
        if day < 1 { return "\(-day) days ago" }
        else { return "In \(day) days" }
    }
}

Alternativ können Sie DateFormatterfür Gestern , Heute und Morgen kostenlos lokalisierte Zeichenfolgen abrufen

func dayDifference(from interval : TimeInterval) -> String
{
    let calendar = Calendar.current
    let date = Date(timeIntervalSince1970: interval)
    let startOfNow = calendar.startOfDay(for: Date())
    let startOfTimeStamp = calendar.startOfDay(for: date)
    let components = calendar.dateComponents([.day], from: startOfNow, to: startOfTimeStamp)
    let day = components.day!
    if abs(day) < 2 {
        let formatter = DateFormatter()
        formatter.dateStyle = .short
        formatter.timeStyle = .none
        formatter.doesRelativeDateFormatting = true
        return formatter.string(from: date)
    } else if day > 1 {
        return "In \(day) days"
    } else {
        return "\(-day) days ago"
    }
}

Aktualisieren:

In macOS 10.15 / iOS 13 RelativeDateTimeFormatterwurde eingeführt, um (lokalisierte) Zeichenfolgen relativ zu einem bestimmten Datum zurückzugeben.

vadian
quelle
Vielen Dank! Das Oberteil sieht perfekt aus. Mit dem unteren Teil könnte es hier 10 Uhr sein, aber der Zeitstempel könnte morgen 9 Uhr sein, was ein anderes Ergebnis ergeben würde, als wenn es morgen 11 Uhr wäre. Oder habe ich falsch verstanden, wie das funktioniert?
Ben
Tolles Zeug, nochmals vielen Dank. Die einzige Änderung, die ich vorgenommen habe, war die Zeile vor Tagen, indem ich eine hinzufügte abs, um die Negation zu entfernen, dhreturn "\(abs(day)) days ago"
Ben
Könnten Sie mir bei dieser Frage helfen: - stackoverflow.com/questions/48320572/… @vadian
Dilip Tiwari
Ihre "beste" Antwort erfordert manuelle Berechnungen und Überprüfungen für jeden Fall, während einige Arbeiten standardmäßig von iOS ausgeführt werden könnten
Vyachaslav Gerchicov
@VyachaslavGerchicov Welche Arbeit ? Bitte erläutern Sie.
Vadian
148

Swift 3/4/5:

Calendar.current.isDateInToday(yourDate)
Calendar.current.isDateInYesterday(yourDate)
Calendar.current.isDateInTomorrow(yourDate)

Zusätzlich:

Calendar.current.isDateInWeekend(yourDate)

Beachten Sie, dass das Wochenende in einigen Ländern vom Samstag bis Sonntag abweichen kann. Dies hängt vom Kalender ab.

Sie können auch autoupdatingCurrentanstelle des currentKalenders verwenden, um Benutzeraktualisierungen zu verfolgen. Sie verwenden es auf die gleiche Weise:

Calendar.autoupdatingCurrent.isDateInToday(yourDate)

Calendarist ein Typalias für die NSCalendar.

KlimczakM
quelle
1
Omg ja! Genau das, was ich brauchte.
Khoury
18

Swift 4 Update:

    let calendar = Calendar.current
    let date = Date()

    calendar.isDateInYesterday(date)
    calendar.isDateInToday(date)
    calendar.isDateInTomorrow(date)
Edward
quelle
Was Date()bringt es , das aktuelle Datum ( ) zu nehmen und zu überprüfen, ob es gestern oder morgen ist? Es sieht so aus, als wollten Sie etwas in einem kopierten Code ändern ...
KlimczakM
7

NSCalender verfügt über neue Methoden, die Sie direkt verwenden können.

NSCalendar.currentCalendar().isDateInTomorrow(NSDate())//Replace NSDate() with your date
NSCalendar.currentCalendar().isDateInYesterday()
NSCalendar.currentCalendar().isDateInTomorrow()

Hoffe das hilft

Nishith Singh
quelle
4

Verwenden Sie unter Swift 5 und iOS 13 den RelativeDateTimeFormatter.

let formatter = RelativeDateTimeFormatter()
formatter.dateTimeStyle = .named 

formatter.localizedString(from: DateComponents(day: -1)) // "yesterday"
formatter.localizedString(from: DateComponents(day: 1)) // "Tomorrow"
formatter.localizedString(from: DateComponents(hour: 2)) // "in 2 hours"
formatter.localizedString(from: DateComponents(minute: 45)) // "in 45 minutes"
Rustylepord
quelle
2

1) Gemäß Ihrem Beispiel möchten Sie die Bezeichnungen "Gestern", "Heute" usw. erhalten. IOS kann dies standardmäßig tun:

https://developer.apple.com/documentation/foundation/nsdateformatter/1415848-doesrelativedateformatting?language=objc

2) Wenn Sie Ihr benutzerdefiniertes Etikett berechnen wollen , wenn iOS diese Etiketten selbst nicht hinzufügen dann alternativ können Sie 2 verwenden DateFormatterObjekte mit beiden doesRelativeDateFormatting == trueund doesRelativeDateFormatting == falsevergleichen , wenn ihr Ergebnis Datum Strings gleich oder verschieden sind

Vyachaslav Gerchicov
quelle