Uzyskiwanie różnicy między dwoma datami NSD w (miesiące / dni / godziny / minuty / sekundy)

206

Próbuję uzyskać różnicę między aktualną datą, jak NSDate()i datę z PHP time();zaproszenia na przykład: NSDate(timeIntervalSinceReferenceDate: 1417147270). Jak mogę uzyskać różnicę czasu między dwiema datami. Chciałbym mieć funkcję, która porównuje dwie daty, a if(seconds > 60)następnie zwraca minuty, if(minutes > 60)godziny if(hours > 24)zwrotu i dni powrotu itd.

Jak mam to zrobić?

EDYCJA: Akceptowana obecnie odpowiedź zrobiła dokładnie to, co chciałem zrobić. Polecam to dla łatwego użycia, aby uzyskać czas między dwiema datami w formie, której time()używa funkcja PHP . Jeśli nie jesteś szczególnie zaznajomiony z PHP, jest to czas w sekundach od 1 stycznia 1970 roku. Jest to korzystne dla backendu w PHP. Jeśli używasz backendu, takiego jak NodeJS, możesz rozważyć inne opcje, które znajdziesz poniżej.

uhfocuz
źródło
2
Zdaję sobie sprawę, że to trochę stare, ale co zamierzasz zrobić z tą różnicą? Na przykład, jeśli chcesz sformatować ciąg dla użytkownika, powinieneś użyć NSDateComponentsFormatter. Jest bardzo konfigurowalny, co pozwala uzyskać odpowiednio zwięzłe wyniki (np .maximumUnitCount = 1.).
Ken Thomases
Naprawdę, pytanie, co zamierzasz zrobić, jest absolutnie niezbędne. Weź pod uwagę, że miesiąc może trwać zaledwie 28 dni lub nawet 31 dni plus jedna godzina.
gnasher729,

Odpowiedzi:

510

Xcode 8.3 • Swift 3.1 lub nowszy

Możesz użyć Kalendarza, aby pomóc Ci utworzyć rozszerzenie, aby wykonać obliczenia daty w następujący sposób:

extension Date {
    /// Returns the amount of years from another date
    func years(from date: Date) -> Int {
        return Calendar.current.dateComponents([.year], from: date, to: self).year ?? 0
    }
    /// Returns the amount of months from another date
    func months(from date: Date) -> Int {
        return Calendar.current.dateComponents([.month], from: date, to: self).month ?? 0
    }
    /// Returns the amount of weeks from another date
    func weeks(from date: Date) -> Int {
        return Calendar.current.dateComponents([.weekOfMonth], from: date, to: self).weekOfMonth ?? 0
    }
    /// Returns the amount of days from another date
    func days(from date: Date) -> Int {
        return Calendar.current.dateComponents([.day], from: date, to: self).day ?? 0
    }
    /// Returns the amount of hours from another date
    func hours(from date: Date) -> Int {
        return Calendar.current.dateComponents([.hour], from: date, to: self).hour ?? 0
    }
    /// Returns the amount of minutes from another date
    func minutes(from date: Date) -> Int {
        return Calendar.current.dateComponents([.minute], from: date, to: self).minute ?? 0
    }
    /// Returns the amount of seconds from another date
    func seconds(from date: Date) -> Int {
        return Calendar.current.dateComponents([.second], from: date, to: self).second ?? 0
    }
    /// Returns the a custom time interval description from another date
    func offset(from date: Date) -> String {
        if years(from: date)   > 0 { return "\(years(from: date))y"   }
        if months(from: date)  > 0 { return "\(months(from: date))M"  }
        if weeks(from: date)   > 0 { return "\(weeks(from: date))w"   }
        if days(from: date)    > 0 { return "\(days(from: date))d"    }
        if hours(from: date)   > 0 { return "\(hours(from: date))h"   }
        if minutes(from: date) > 0 { return "\(minutes(from: date))m" }
        if seconds(from: date) > 0 { return "\(seconds(from: date))s" }
        return ""
    }
}

Korzystanie z formatera składników daty

let dateComponentsFormatter = DateComponentsFormatter()
dateComponentsFormatter.allowedUnits = [.year,.month,.weekOfMonth,.day,.hour,.minute,.second]
dateComponentsFormatter.maximumUnitCount = 1
dateComponentsFormatter.unitsStyle = .full
dateComponentsFormatter.string(from: Date(), to: Date(timeIntervalSinceNow: 4000000))  // "1 month"

let date1 = DateComponents(calendar: .current, year: 2014, month: 11, day: 28, hour: 5, minute: 9).date!
let date2 = DateComponents(calendar: .current, year: 2015, month: 8, day: 28, hour: 5, minute: 9).date!

let years = date2.years(from: date1)     // 0
let months = date2.months(from: date1)   // 9
let weeks = date2.weeks(from: date1)     // 39
let days = date2.days(from: date1)       // 273
let hours = date2.hours(from: date1)     // 6,553
let minutes = date2.minutes(from: date1) // 393,180
let seconds = date2.seconds(from: date1) // 23,590,800

let timeOffset = date2.offset(from: date1) // "9M"

let date3 = DateComponents(calendar: .current, year: 2014, month: 11, day: 28, hour: 5, minute: 9).date!
let date4 = DateComponents(calendar: .current, year: 2015, month: 11, day: 28, hour: 5, minute: 9).date!

let timeOffset2 = date4.offset(from: date3) // "1y"

let date5 = DateComponents(calendar: .current, year: 2017, month: 4, day: 28).date!
let now = Date()
let timeOffset3 = now.offset(from: date5) // "1w"
Leo Dabus
źródło
1
W Swift 2.0 .CalendarUnitSeconddaje błąd 'NSCalendarUnit.Type' does not have a member named 'CalendarUnitSecond', czy wiesz jak go rozwiązać?
Matte.Car
2
@ Matte.Car musisz użyć. Drugie i zamiast opcji: zero musisz użyć opcji: []. Możesz rzucić okiem na moją edycję.
Leo Dabus
1
Nienawidzę duplikatów w tej odpowiedzi, użyłbym metody opartej na NSCalendarUnit, zaimplementowanej jako return Calendar.current().components(unit, from: date, to: self, options: [])?. valueForComponent(unit)(w iOS> 8).
Sulthan,
4
Ponieważ użycie odpowiedzi DateComponentsFormatterjest O wiele lepsze niż robienie tego na dłuższą metę, to naprawdę powinno być na górze odpowiedzi.
rmaddy
1
Jesteś absolutnie niesamowity! To rozszerzenie bardzo mi pomogło!
Marian Petrisor
45

Jeśli ktoś musi wyświetlić wszystkie jednostki czasu, np. „Godziny minuty sekundy”, a nie tylko „godziny”. Powiedzmy, że różnica czasu między dwiema datami wynosi 1 godzinę 59 minut 20 sekund. Ta funkcja wyświetli „1h 59m 20s”.

Oto mój kod Objective-C:

extension NSDate {

    func offsetFrom(date: NSDate) -> String {

        let dayHourMinuteSecond: NSCalendarUnit = [.Day, .Hour, .Minute, .Second]
        let difference = NSCalendar.currentCalendar().components(dayHourMinuteSecond, fromDate: date, toDate: self, options: [])

        let seconds = "\(difference.second)s"
        let minutes = "\(difference.minute)m" + " " + seconds
        let hours = "\(difference.hour)h" + " " + minutes
        let days = "\(difference.day)d" + " " + hours

        if difference.day    > 0 { return days }
        if difference.hour   > 0 { return hours }
        if difference.minute > 0 { return minutes }
        if difference.second > 0 { return seconds }
        return ""
    }

}

W Swift 3+:

extension Date {

    func offsetFrom(date: Date) -> String {

        let dayHourMinuteSecond: Set<Calendar.Component> = [.day, .hour, .minute, .second]
        let difference = NSCalendar.current.dateComponents(dayHourMinuteSecond, from: date, to: self)

        let seconds = "\(difference.second ?? 0)s"
        let minutes = "\(difference.minute ?? 0)m" + " " + seconds
        let hours = "\(difference.hour ?? 0)h" + " " + minutes
        let days = "\(difference.day ?? 0)d" + " " + hours

        if let day = difference.day, day          > 0 { return days }
        if let hour = difference.hour, hour       > 0 { return hours }
        if let minute = difference.minute, minute > 0 { return minutes }
        if let second = difference.second, second > 0 { return seconds }
        return ""
    }

}
Adam Studenic
źródło
3
właśnie tego potrzebuję. proste i wykonuje pracę.
Chen Li Yong,
14

Ty pytasz:

Chciałbym mieć funkcję, która porównuje dwie daty i jeśli (sekundy> 60) zwraca minuty, jeśli (minuty> 60) zwraca godziny i jeśli (godziny> 24) zwraca dni i tak dalej.

Zakładam, że próbujesz zbudować ciąg reprezentujący upływ czasu między dwiema datami. Zamiast pisać własny kod, Apple ma już klasę zaprojektowaną właśnie do tego. Mianowicie, użyj DateComponentsFormatter, ustaw allowedUnitsna dowolne wartości, które mają sens dla twojej aplikacji, ustaw unitsStylena cokolwiek chcesz (np. .full), A następnie zadzwoń string(from:to:).

Np. W Swift 3:

let previousDate = ...
let now = Date()

let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
formatter.allowedUnits = [.month, .day, .hour, .minute, .second]
formatter.maximumUnitCount = 2   // often, you don't care about seconds if the elapsed time is in months, so you'll set max unit to whatever is appropriate in your case

let string = formatter.string(from: previousDate, to: now)

Spowoduje to również zlokalizowanie ciągu odpowiedniego dla danego urządzenia.

Lub w Swift 2.3:

let previousDate = ...
let now = NSDate()

let formatter = NSDateComponentsFormatter()
formatter.unitsStyle = .Full
formatter.allowedUnits = [.Month, .Day, .Hour, .Minute, .Second]
formatter.maximumUnitCount = 2

let string = formatter.stringFromDate(previousDate, toDate: now)

Jeśli szukasz rzeczywistych wartości liczbowych, po prostu użyj dateComponents. Np. W Swift 3:

let components = Calendar.current.dateComponents([.month, .day, .hour, .minute, .second], from: previousDate, to: now)

Lub w Swift 2.3:

let components = NSCalendar.currentCalendar().components([.Month, .Day, .Hour, .Minute, .Second], fromDate: previousDate, toDate: now, options: [])
Obrabować
źródło
6

połączone rozszerzenie + DateComponentsFormatter z odpowiedzi @ leo-dabus

Xcode 8.3 • Swift 3.1

extension DateComponentsFormatter {
    func difference(from fromDate: Date, to toDate: Date) -> String? {
        self.allowedUnits = [.year,.month,.weekOfMonth,.day]
        self.maximumUnitCount = 1
        self.unitsStyle = .full
        return self.string(from: fromDate, to: toDate)
    }
}

let dateComponentsFormatter = DateComponentsFormatter()
dateComponentsFormatter.difference(from: Date(), to: Date(timeIntervalSinceNow: 4000000)) // "1 month"
Adam Smaka
źródło
4
   func dateDiff(dateStr:String) -> String {
            var f:NSDateFormatter = NSDateFormatter()
            f.timeZone = NSTimeZone.localTimeZone()
            f.dateFormat = "yyyy-M-dd'T'HH:mm:ss.SSSZZZ"

            var now = f.stringFromDate(NSDate())
            var startDate = f.dateFromString(dateStr)
            var endDate = f.dateFromString(now)
            var calendar: NSCalendar = NSCalendar.currentCalendar()

            let calendarUnits = NSCalendarUnit.CalendarUnitWeekOfMonth | NSCalendarUnit.CalendarUnitDay | NSCalendarUnit.CalendarUnitHour | NSCalendarUnit.CalendarUnitMinute | NSCalendarUnit.CalendarUnitSecond
            let dateComponents = calendar.components(calendarUnits, fromDate: startDate!, toDate: endDate!, options: nil)

            let weeks = abs(dateComponents.weekOfMonth)
            let days = abs(dateComponents.day)
            let hours = abs(dateComponents.hour)
            let min = abs(dateComponents.minute)
            let sec = abs(dateComponents.second)

            var timeAgo = ""

            if (sec > 0){
                if (sec > 1) {
                    timeAgo = "\(sec) Seconds Ago"
                } else {
                    timeAgo = "\(sec) Second Ago"
                }
            }

            if (min > 0){
                if (min > 1) {
                    timeAgo = "\(min) Minutes Ago"
                } else {
                    timeAgo = "\(min) Minute Ago"
                }
            }

            if(hours > 0){
                if (hours > 1) {
                    timeAgo = "\(hours) Hours Ago"
                } else {
                    timeAgo = "\(hours) Hour Ago"
                }
            }

            if (days > 0) {
                if (days > 1) {
                    timeAgo = "\(days) Days Ago"
                } else {
                    timeAgo = "\(days) Day Ago"
                }
            }

            if(weeks > 0){
                if (weeks > 1) {
                    timeAgo = "\(weeks) Weeks Ago"
                } else {
                    timeAgo = "\(weeks) Week Ago"
                }
            }

            print("timeAgo is===> \(timeAgo)")
            return timeAgo;
        }
jose920405
źródło
spróbuj leniwie załadować formatyzator daty, a jeszcze lepszym rozwiązaniem byłoby ustawienie go na statyczny
thesummersign
4

Dodałem „długą” wersję do odpowiedzi Leo Dabusa na wypadek, gdybyś chciał napisać coś w stylu „2 tygodnie temu” zamiast po prostu „2w” ...

extension Date {
    /// Returns the amount of years from another date
    func years(from date: Date) -> Int {
        return Calendar.current.dateComponents([.year], from: date, to: self).year ?? 0
    }
    /// Returns the amount of months from another date
    func months(from date: Date) -> Int {
        return Calendar.current.dateComponents([.month], from: date, to: self).month ?? 0
    }
    /// Returns the amount of weeks from another date
    func weeks(from date: Date) -> Int {
        return Calendar.current.dateComponents([.weekOfYear], from: date, to: self).weekOfYear ?? 0
    }
    /// Returns the amount of days from another date
    func days(from date: Date) -> Int {
        return Calendar.current.dateComponents([.day], from: date, to: self).day ?? 0
    }
    /// Returns the amount of hours from another date
    func hours(from date: Date) -> Int {
        return Calendar.current.dateComponents([.hour], from: date, to: self).hour ?? 0
    }
    /// Returns the amount of minutes from another date
    func minutes(from date: Date) -> Int {
        return Calendar.current.dateComponents([.minute], from: date, to: self).minute ?? 0
    }
    /// Returns the amount of seconds from another date
    func seconds(from date: Date) -> Int {
        return Calendar.current.dateComponents([.second], from: date, to: self).second ?? 0
    }
    /// Returns the a custom time interval description from another date
    func offset(from date: Date) -> String {
        if years(from: date)   > 0 { return "\(years(from: date))y"   }
        if months(from: date)  > 0 { return "\(months(from: date))M"  }
        if weeks(from: date)   > 0 { return "\(weeks(from: date))w"   }
        if days(from: date)    > 0 { return "\(days(from: date))d"    }
        if hours(from: date)   > 0 { return "\(hours(from: date))h"   }
        if minutes(from: date) > 0 { return "\(minutes(from: date))m" }
        if seconds(from: date) > 0 { return "\(seconds(from: date))s" }
        return ""
    }

    func offsetLong(from date: Date) -> String {
        if years(from: date)   > 0 { return years(from: date) > 1 ? "\(years(from: date)) years ago" : "\(years(from: date)) year ago" }
        if months(from: date)  > 0 { return months(from: date) > 1 ? "\(months(from: date)) months ago" : "\(months(from: date)) month ago" }
        if weeks(from: date)   > 0 { return weeks(from: date) > 1 ? "\(weeks(from: date)) weeks ago" : "\(weeks(from: date)) week ago"   }
        if days(from: date)    > 0 { return days(from: date) > 1 ? "\(days(from: date)) days ago" : "\(days(from: date)) day ago" }
        if hours(from: date)   > 0 { return hours(from: date) > 1 ? "\(hours(from: date)) hours ago" : "\(hours(from: date)) hour ago"   }
        if minutes(from: date) > 0 { return minutes(from: date) > 1 ? "\(minutes(from: date)) minutes ago" : "\(minutes(from: date)) minute ago" }
        if seconds(from: date) > 0 { return seconds(from: date) > 1 ? "\(seconds(from: date)) seconds ago" : "\(seconds(from: date)) second ago" }
        return ""
    }

}
zumzum
źródło
4

-> Użyj tego, aby znaleźć odstęp czasu między dwiema datami w Swift (z dwoma ciągami).

func timeGapBetweenDates(previousDate : String,currentDate : String)
{
    let dateString1 = previousDate
    let dateString2 = currentDate

    let Dateformatter = DateFormatter()
    Dateformatter.dateFormat = "yyyy-MM-dd HH:mm:ss"


    let date1 = Dateformatter.date(from: dateString1)
    let date2 = Dateformatter.date(from: dateString2)


    let distanceBetweenDates: TimeInterval? = date2?.timeIntervalSince(date1!)
    let secondsInAnHour: Double = 3600
    let minsInAnHour: Double = 60
    let secondsInDays: Double = 86400
    let secondsInWeek: Double = 604800
    let secondsInMonths : Double = 2592000
    let secondsInYears : Double = 31104000

    let minBetweenDates = Int((distanceBetweenDates! / minsInAnHour))
    let hoursBetweenDates = Int((distanceBetweenDates! / secondsInAnHour))
    let daysBetweenDates = Int((distanceBetweenDates! / secondsInDays))
    let weekBetweenDates = Int((distanceBetweenDates! / secondsInWeek))
    let monthsbetweenDates = Int((distanceBetweenDates! / secondsInMonths))
    let yearbetweenDates = Int((distanceBetweenDates! / secondsInYears))
    let secbetweenDates = Int(distanceBetweenDates!)




    if yearbetweenDates > 0
    {
        print(yearbetweenDates,"years")//0 years
    }
    else if monthsbetweenDates > 0
    {
        print(monthsbetweenDates,"months")//0 months
    }
    else if weekBetweenDates > 0
    {
        print(weekBetweenDates,"weeks")//0 weeks
    }
    else if daysBetweenDates > 0
    {
        print(daysBetweenDates,"days")//5 days
    }
    else if hoursBetweenDates > 0
    {
        print(hoursBetweenDates,"hours")//120 hours
    }
    else if minBetweenDates > 0
    {
        print(minBetweenDates,"minutes")//7200 minutes
    }
    else if secbetweenDates > 0
    {
        print(secbetweenDates,"seconds")//seconds
    }
}
Ayush jain
źródło
3

Nieznacznie zmodyfikowany kod dla Swift 3.0

let calendar = NSCalendar.current as NSCalendar

// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDay(for: startDateTime)
let date2 = calendar.startOfDay(for: endDateTime)

let flags = NSCalendar.Unit.day
let components = calendar.components(flags, from: date1, to: date2, options: [])

return components.day!
Sagar Desai
źródło
1

Jeśli Twoim celem jest uzyskanie dokładnej liczby dni między dwiema datami, możesz obejść ten problem w następujący sposób:

// Assuming that firstDate and secondDate are defined
// ...

var calendar: NSCalendar = NSCalendar.currentCalendar()

// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDayForDate(firstDate)
let date2 = calendar.startOfDayForDate(secondDate)

let flags = NSCalendarUnit.DayCalendarUnit
let components = calendar.components(flags, fromDate: date1, toDate: date2, options: nil)

components.day  // This will return the number of day(s) between dates
Emin Bugra Saral
źródło
1

W Swift 3, w zależności od potrzeb, możesz wybrać jeden z dwóch poniższych sposobów rozwiązania problemu.


1. Wyświetl różnicę między dwiema datami dla użytkownika

Możesz użyć a, DateComponentsFormatteraby utworzyć ciągi interfejsu aplikacji. DateComponentsFormatterma maximumUnitCountwłaściwość z następującą deklaracją:

var maximumUnitCount: Int { get set }

Użyj tej właściwości, aby ograniczyć liczbę jednostek wyświetlanych w wynikowym ciągu. Na przykład, jeśli ta właściwość jest ustawiona na 2, zamiast „1h 10m, 30s”, wynikowy ciąg miałby wartość „1h 10m”. Tej właściwości należy użyć, gdy jest ograniczona przestrzeń lub chcesz zaokrąglić wartości do najbliższej dużej jednostki.

Ustawiając maximumUnitCountwartość na 1, masz gwarancję wyświetlenia różnicy tylko w jednej DateComponentsFormatterjednostce (lata, miesiące, dni, godziny lub minuty).

Poniższy kod placu zabaw pokazuje, jak wyświetlić różnicę między dwiema datami:

import Foundation

let oldDate = Date(timeIntervalSinceReferenceDate: -16200)
let newDate = Date(timeIntervalSinceReferenceDate: 0)

let dateComponentsFormatter = DateComponentsFormatter()
dateComponentsFormatter.allowedUnits = [NSCalendar.Unit.year, .month, .day, .hour, .minute]
dateComponentsFormatter.maximumUnitCount = 1
dateComponentsFormatter.unitsStyle = DateComponentsFormatter.UnitsStyle.full
let timeDifference = dateComponentsFormatter.string(from: oldDate, to: newDate)

print(String(reflecting: timeDifference)) // prints Optional("5 hours")

Zauważ, że DateComponentsFormatterzaokrągla wynik. Dlatego różnica 4 godzin i 30 minut zostanie wyświetlona jako 5 godzin .

Jeśli musisz powtórzyć tę operację, możesz zmienić kod:

import Foundation

struct Formatters {

    static let dateComponentsFormatter: DateComponentsFormatter = {
        let dateComponentsFormatter = DateComponentsFormatter()
        dateComponentsFormatter.allowedUnits = [NSCalendar.Unit.year, .month, .day, .hour, .minute]
        dateComponentsFormatter.maximumUnitCount = 1
        dateComponentsFormatter.unitsStyle = DateComponentsFormatter.UnitsStyle.full
        return dateComponentsFormatter
    }()

}

extension Date {
    
    func offset(from: Date) -> String? {
        return Formatters.dateComponentsFormatter.string(from: oldDate, to: self)
    }
    
}

let oldDate = Date(timeIntervalSinceReferenceDate: -16200)
let newDate = Date(timeIntervalSinceReferenceDate: 0)

let timeDifference = newDate.offset(from: oldDate)
print(String(reflecting: timeDifference)) // prints Optional("5 hours")

2. Uzyskaj różnicę między dwiema datami bez formatowania

Jeśli nie musisz wyświetlać z formatowaniem różnicy między dwiema datami dla użytkownika, możesz użyć Calendar. Calendarma metodę, dateComponents(_:from:to:)która ma następującą deklarację:

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

Zwraca różnicę między dwiema datami.

Poniższy kod placu zabaw, który używa, dateComponents(_:from:to:)pokazuje, jak odzyskać różnicę między dwiema datami, zwracając różnicę tylko w jednym typie Calendar.Component(lata, miesiące, dni, godziny lub minuty).

import Foundation

let oldDate = Date(timeIntervalSinceReferenceDate: -16200)
let newDate = Date(timeIntervalSinceReferenceDate: 0)

let descendingOrderedComponents = [Calendar.Component.year, .month, .day, .hour, .minute]
let dateComponents = Calendar.current.dateComponents(Set(descendingOrderedComponents), from: oldDate, to: newDate)
let arrayOfTuples = descendingOrderedComponents.map { ($0, dateComponents.value(for: $0)) }

for (component, value) in arrayOfTuples {
    if let value = value, value > 0 {
        print(component, value) // prints hour 4
        break
    }
}

Jeśli musisz powtórzyć tę operację, możesz zmienić kod:

import Foundation

extension Date {
    
    func offset(from: Date) -> (Calendar.Component, Int)? {
        let descendingOrderedComponents = [Calendar.Component.year, .month, .day, .hour, .minute]
        let dateComponents = Calendar.current.dateComponents(Set(descendingOrderedComponents), from: from, to: self)
        let arrayOfTuples = descendingOrderedComponents.map { ($0, dateComponents.value(for: $0)) }
        
        for (component, value) in arrayOfTuples {
            if let value = value, value > 0 {
                return (component, value)
            }
        }
        
        return nil
    }

}

let oldDate = Date(timeIntervalSinceReferenceDate: -16200)
let newDate = Date(timeIntervalSinceReferenceDate: 0)

if let (component, value) = newDate.offset(from: oldDate) {
    print(component, value) // prints hour 4
}
Imanou Petit
źródło
1

W Swift 2.2

    /// Returns the amount of years from another date
func years(fromdate: NSDate) -> Int {
    return NSCalendar.currentCalendar().components([.Year], fromDate: fromdate, toDate: NSDate(), options: []).year ?? 0
}
/// Returns the amount of months from another date
func months(fromdate: NSDate) -> Int {
    return NSCalendar.currentCalendar().components([.Month], fromDate: fromdate, toDate: NSDate(), options: []).month ?? 0
}
/// Returns the amount of weeks from another date
func weeks(fromdate: NSDate) -> Int {
    return NSCalendar.currentCalendar().components([.WeekOfYear], fromDate: fromdate, toDate: NSDate(), options: []).weekOfYear ?? 0
}
/// Returns the amount of days from another date
func days(fromdate: NSDate) -> Int {
    return NSCalendar.currentCalendar().components([.Day], fromDate: fromdate, toDate: NSDate(), options: []).day ?? 0
}
/// Returns the amount of hours from another date
func hours(fromdate: NSDate) -> Int {
    return NSCalendar.currentCalendar().components([.Hour], fromDate: fromdate, toDate: NSDate(), options: []).hour ?? 0
}
/// Returns the amount of minutes from another date
func minutes(fromdate: NSDate) -> Int {
    return NSCalendar.currentCalendar().components([.Minute], fromDate: fromdate, toDate: NSDate(), options: []).minute ?? 0
}
/// Returns the amount of seconds from another date
func seconds(fromdate: NSDate) -> Int {
    return NSCalendar.currentCalendar().components(.Second, fromDate: fromdate, toDate: NSDate(), options: []).second ?? 0
}
Mohsin Qureshi
źródło
1

Mały dodatek do odpowiedzi Leo Dabusa, aby zapewnić liczbę mnogą i być bardziej czytelnym dla człowieka.

Szybki 3

extension Date {
    /// Returns the amount of years from another date
    func years(from date: Date) -> Int {
        return Calendar.current.dateComponents([.year], from: date, to: self).year ?? 0
    }
    /// Returns the amount of months from another date
    func months(from date: Date) -> Int {
        return Calendar.current.dateComponents([.month], from: date, to: self).month ?? 0
    }
    /// Returns the amount of weeks from another date
    func weeks(from date: Date) -> Int {
        return Calendar.current.dateComponents([.weekOfMonth], from: date, to: self).weekOfMonth ?? 0
    }
    /// Returns the amount of days from another date
    func days(from date: Date) -> Int {
        return Calendar.current.dateComponents([.day], from: date, to: self).day ?? 0
    }
    /// Returns the amount of hours from another date
    func hours(from date: Date) -> Int {
        return Calendar.current.dateComponents([.hour], from: date, to: self).hour ?? 0
    }
    /// Returns the amount of minutes from another date
    func minutes(from date: Date) -> Int {
        return Calendar.current.dateComponents([.minute], from: date, to: self).minute ?? 0
    }
    /// Returns the amount of seconds from another date
    func seconds(from date: Date) -> Int {
        return Calendar.current.dateComponents([.second], from: date, to: self).second ?? 0
    }
    /// Returns the a custom time interval description from another date
    func offset(from date: Date) -> String {
        if years(from: date)   == 1 { return "\(years(from: date)) year"   } else if years(from: date)   > 1 { return "\(years(from: date)) years"   }
        if months(from: date)  == 1 { return "\(months(from: date)) month"  } else if months(from: date)  > 1 { return "\(months(from: date)) month"  }
        if weeks(from: date)   == 1 { return "\(weeks(from: date)) week"   } else if weeks(from: date)   > 1 { return "\(weeks(from: date)) weeks"   }
        if days(from: date)    == 1 { return "\(days(from: date)) day"    } else if days(from: date)    > 1 { return "\(days(from: date)) days"    }
        if hours(from: date)   == 1 { return "\(hours(from: date)) hour"   } else if hours(from: date)   > 1 { return "\(hours(from: date)) hours"   }
        if minutes(from: date) == 1 { return "\(minutes(from: date)) minute" } else if minutes(from: date) > 1 { return "\(minutes(from: date)) minutes" }
        return ""
    }
}
brycejl
źródło
0

To jest krótsza wersja: Zasadniczo próbuję uzyskać różnicę między datownikiem postu a Date()teraz.

// MARK: - UPDATE Time Stamp
static func updateTimeStampPost(postTimeStamp: Date?, _ completion: (_ finalString: String?) -> Void) {
    // date in the current state
    let date = Date()
    let dateComponentFormatter = DateComponentsFormatter()

    // change the styling date, wether second minute or hour
    dateComponentFormatter.unitsStyle = .abbreviated
    dateComponentFormatter.allowedUnits = [.second, .minute, .hour, .day, .weekOfMonth]
    dateComponentFormatter.maximumUnitCount = 1

    // return the date new format as a string in the completion
    completion(dateComponentFormatter.string(from: postTimeStamp!, to: date))
}
Buka Cakrawala
źródło
0

Oto moja odpowiedź na powyższe odpowiedzi Swift 3. To jest aktualne na listopad 2016, wydanie Xcode było 8.2 Beta (8C23). Użyłem niektórych z powyższych sugestii Sagar i Emin i czasami musiał pozwolić Xcode na autouzupełnianie, aby zasugerować składnię. Wyglądało na to, że składnia została naprawdę zmieniona na tę wersję beta. buyDateDostałem od DatePicker:

let calendar = NSCalendar.current as NSCalendar
let currentDate = Date()
let date1 = calendar.startOfDay(for: buyDate!)
let date2 = calendar.startOfDay(for: currentDate)      
let flags = NSCalendar.Unit.day
let components = calendar.components(flags, from: date1, to: date2)
NSLog(" day= \(components.day)")
człowiek renesansu
źródło
Przepraszam, teraz, kiedy na to patrzę, oto rozwiązanie Sagara. Zrobiłem tyle iteracji i próbowałem wielu rzeczy, które, jak sądzę, zmieniły się. Rozwiązanie Emin nie działa w najnowszym Swift 3.
renaissanceMan
Tak naprawdę nie powinieneś używać NSCalendarw Swift 3. Użyj Calendar. To jest uproszczone do let calendar = Calendar.current. I wtedy componentsbędzie wyglądać następująco: let components = calendar.dateComponents([.day], from: date1, to: date2).
Rob
0

W przypadku XCode w wersji 8.3.3 i Swift 3.0:

    let dateFormatter = DateFormatter()
    dateFormatter.dateStyle = .medium
    dateFormatter.timeStyle = .short

    var beginDate = "2017-08-24 12:00:00"
    var endDate = "2017-09-07 12:00:00"


    let startDateTime = dateFormatter.date(from: beginDate) //according to date format your date string
    print(startDateTime ?? "") //Convert String to Date

    let endDateTime = dateFormatter.date(from: endDate) //according to date format your date string
    print(endDateTime ?? "") //Convert String to Date

    let dateComponentsFormatter = DateComponentsFormatter()
    dateComponentsFormatter.allowedUnits = [NSCalendar.Unit.minute,NSCalendar.Unit.hour,NSCalendar.Unit.day]


   let interval = endDateTime!.timeIntervalSince(startDateTime!)
   var diff = dateComponentsFormatter.string(from: interval)!

   print(diff)

   var day_i  = 0
   var hour_i = 0
   var min_i = 0


     if (diff.contains("d"))
       {
              let day = diff.substring(to: (diff.range(of: "d")?.lowerBound)!)

               day_i  = Int(day)!
               print ("day --> \(day_i)")

               diff = diff.substring(from:(diff.range(of : " ")?.upperBound )!)
               print(diff)
       }


       let hour = diff.substring(to: (diff.range(of : ":")?.lowerBound )!)
       hour_i  = Int(hour)!
       print ("hour --> \(hour_i)")

       let min = diff.substring(from: (diff.range(of : ":")?.upperBound )!)
       min_i  = Int(min)!
       print ("min --> \(min_i)")
Muge Cevik
źródło
0

Niektóre dodatki w odpowiedzi na pytanie jose920405 w celu zapewnienia zgodności z Swift 3.0 i nowszymi wersjami

func getDateTimeDiff(dateStr:String) -> String {

    let formatter : DateFormatter = DateFormatter()
    formatter.timeZone = NSTimeZone.local
    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

    let now = formatter.string(from: NSDate() as Date)
    let startDate = formatter.date(from: dateStr)
    let endDate = formatter.date(from: now)

    // *** create calendar object ***
    var calendar = NSCalendar.current

    // *** Get components using current Local & Timezone ***
    print(calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: startDate!))

    // *** define calendar components to use as well Timezone to UTC ***
    let unitFlags = Set<Calendar.Component>([.year, .month, .day, .hour, .minute, .second])
    calendar.timeZone = TimeZone(identifier: "UTC")!
    let dateComponents = calendar.dateComponents(unitFlags, from: startDate!, to: endDate!)

    // *** Get Individual components from date ***
    let years = dateComponents.year!
    let months = dateComponents.month!
    let days = dateComponents.day!
    let hours = dateComponents.hour!
    let minutes = dateComponents.minute!
    let seconds = dateComponents.second!

    var timeAgo = ""

    if (seconds > 0){
        if seconds < 2 {
            timeAgo = "Second Ago"
        }
        else{
            timeAgo = "\(seconds) Second Ago"
        }
    }

    if (minutes > 0){
        if minutes < 2 {
            timeAgo = "Minute Ago"
        }
        else{
            timeAgo = "\(minutes) Minutes Ago"
        }
    }

    if(hours > 0){
        if minutes < 2 {
            timeAgo = "Hour Ago"
        }
        else{
            timeAgo = "\(hours) Hours Ago"
        }
    }

    if (days > 0) {
        if minutes < 2 {
            timeAgo = "Day Ago"
        }
        else{
            timeAgo = "\(days) Days Ago"
        }
    }

    if(months > 0){
        if minutes < 2 {
            timeAgo = "Month Ago"
        }
        else{
            timeAgo = "\(months) Months Ago"
        }
    }

    if(years > 0){
        if minutes < 2 {
            timeAgo = "Year Ago"
        }
        else{
            timeAgo = "\(years) Years Ago"
        }
    }

    DLog("timeAgo is ===> \(timeAgo)")
    return timeAgo;
}
Ajit Satarkar
źródło
0

Użyj tego kodu:

let registrationDateString = "2008-10-06 00:00:00"
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd hh:mm:ss"
    if let registrationDate = dateFormatter.date(from: registrationDateString) {
        let currentDate = Date()
        let dateDifference = Calendar.current.dateComponents([.day, .month, .year],
                                                               from: registrationDate,
                                                               to: currentDate)
        print("--------------------- Result: \(dateDifference.year ?? 0) years \(dateDifference.month ?? 0) months and \(dateDifference.day ?? 0) days")
    } else {
        print("--------------------- No result")
    }

Wyjście to: Wynik: 10 lat 1 miesiąc i 18 dni

nitin.agam
źródło
0
import Foundation

extension DateComponents {

    func dateComponentsToTimeString() -> String {

        var hour = "\(self.hour!)"
        var minute = "\(self.minute!)"
        var second = "\(self.second!)"

        if self.hour! < 10 { hour = "0" + hour }
        if self.minute! < 10 { minute = "0" + minute }
        if self.second! < 10 { second = "0" + second }

        let str = "\(hour):\(minute):\(second)"
        return str
    }

}

extension Date {

    func offset(from date: Date)-> DateComponents {
        let components = Set<Calendar.Component>([.second, .minute, .hour, .day, .month, .year])
        let differenceOfDate = Calendar.current.dateComponents(components, from: date, to: self)
        return differenceOfDate
    }
}

Posługiwać się:

var durationString: String {
        return self.endTime.offset(from: self.startTime).dateComponentsToTimeString()
    }
Mohammad Razipour
źródło