简体   繁体   English

获取 Swift 中两个日期(月/日/小时/分钟/秒)之间的差异

[英]Getting the difference between two Dates (months/days/hours/minutes/seconds) in Swift

I am trying to get the difference between the current date as NSDate() and a date from a PHP time();我正在尝试获取当前日期作为NSDate()和来自 PHP time(); call for example: NSDate(timeIntervalSinceReferenceDate: 1417147270) .例如调用: NSDate(timeIntervalSinceReferenceDate: 1417147270) How do I go about getting the difference in time between the two dates.我 go 如何获得两个日期之间的时间差。 I'd like to have a function that compares the two dates and if(seconds > 60) then it returns minutes, if(minutes > 60) return hours and if(hours > 24) return days and so on.我想要一个 function 来比较两个日期, if(seconds > 60)然后返回分钟, if(minutes > 60)返回小时数, if(hours > 24)返回天数等等。

How should I go about this?我应该怎么go一下这个?

EDIT: The current accepted answer has done exactly what I've wanted to do.编辑:当前接受的答案正是我想做的。 I recommend it for easy usage for getting the time between two dates in the form that that PHP time() function uses.我推荐它以便于使用 PHP time() function 使用的形式获取两个日期之间的时间。 If you aren't particularly familiar with PHP, that's the time in seconds from January 1st, 1970. This is beneficial for a backend in PHP. If perhaps you're using a backend like NodeJS you might want to consider some of the other options you'll find below.如果您不是特别熟悉 PHP,那是从 1970 年 1 月 1 日开始的以秒为单位的时间。这对于 PHP 中的后端是有益的。如果您可能正在使用像 NodeJS 这样的后端,您可能需要考虑其他一些选项你会在下面找到。

Xcode 8.3 • Swift 3.1 or later Xcode 8.3 • Swift 3.1 或更高版本

You can use Calendar to help you create an extension to do your date calculations as follow:您可以使用 Calendar 来帮助您创建一个扩展来进行日期计算,如下所示:

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 ""
    }
}

Using Date Components Formatter使用日期组件格式化程序

let dateComponentsFormatter = DateComponentsFormatter()
dateComponentsFormatter.allowedUnits = [.second, .minute, .hour, .day, .weekOfMonth, .month, .year]
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"

If someone needs to display all time units eg "hours minutes seconds" not just "hours".如果有人需要显示所有时间单位,例如“小时分秒”而不仅仅是“小时”。 Let's say the time difference between two dates is 1hour 59minutes 20seconds.假设两个日期之间的时差是 1 小时 59 分 20 秒。 This function will display "1h 59m 20s".此功能将显示“1h 59m 20s”。

Here is my Objective-C code:这是我的 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 ""
    }

}

In Swift 3+:在 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 ""
    }

}

You ask:你问:

I'd like to have a function that compares the two dates and if(seconds > 60) then it returns minutes, if(minutes > 60) return hours and if(hours > 24) return days and so on.我想要一个函数来比较两个日期和 if(seconds > 60) 然后它返回分钟, if(minutes > 60) return hours 和 if(hours > 24) return days 等等。

I'm assuming that you're trying to build a string representation of the elapsed time between two dates.我假设您正在尝试构建两个日期之间经过时间的字符串表示形式。 Rather than writing your own code to do that, Apple already has a class designed to do precisely that.与其编写自己的代码来做到这一点,Apple 已经有一个专为做到这一点而设计的类。 Namely, use DateComponentsFormatter , set allowedUnits to whatever values make sense to your app, set unitsStyle to whatever you want (eg .full ), and then call string(from:to:) .即,使用DateComponentsFormatter ,将allowedUnits设置为对您的应用程序有意义的任何值,将unitsStyle设置为您想要的任何值(例如.full ),然后调用string(from:to:)

Eg in Swift 3:例如在 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)

This also will localize the string appropriate for the device in question.这也将本地化适合相关设备的字符串。

Or, in Swift 2.3:或者,在 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)

If you're looking for the actual numeric values, just use dateComponents .如果您正在寻找实际的数值,只需使用dateComponents Eg in Swift 3:例如在 Swift 3 中:

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

Or, in Swift 2.3:或者,在 Swift 2.3 中:

let components = NSCalendar.currentCalendar().components([.Month, .Day, .Hour, .Minute, .Second], fromDate: previousDate, toDate: now, options: [])

Swift 5.1 • iOS 13斯威夫特 5.1 • iOS 13

You can use RelativeDateFormatter that has been introduced by Apple in iOS 13.您可以使用 Apple 在 iOS 13 中引入的RelativeDateFormatter

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

let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .full
let relativeDate = formatter.localizedString(for: exampleDate, relativeTo: Date())

print(relativeDate) // 4 hours ago

See How to show a relative date and time using RelativeDateTimeFormatter .请参阅如何使用 RelativeDateTimeFormatter 显示相对日期和时间

combined Extension + DateComponentsFormatter from the answer of @leo-dabus来自@leo-dabus 的答案的组合扩展 + DateComponentsFormatter

Xcode 8.3 • Swift 3.1 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"

--> Use this to find time gap between two dates in Swift (With two Strings). --> 使用它来查找Swift 中两个日期之间的时间间隔(使用两个字符串)。

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
    }
}
   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;
        }

Slightly modified code for Swift 3.0Swift 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!

I added a "long" version to Leo Dabus's asnwer in case you want to have a string that says something like "2 weeks ago" instead of just "2w"...我在 Leo Dabus 的 asnwer 中添加了一个“长”版本,以防您想要一个字符串,上面写着“2周前”而不是“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 ""
    }

}

If your purpose is to get the exact day number between two dates, you can work around this issue like this:如果您的目的是获取两个日期之间的确切天数,您可以像这样解决这个问题:

// 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

With Swift 3, according to your needs, you may choose one of the two following ways to solve your problem.使用 Swift 3,您可以根据需要,选择以下两种方式之一来解决您的问题。


1. Display the difference between two dates to the user 1. 向用户显示两个日期之间的差异

You can use a DateComponentsFormatter to create strings for your app's interface.您可以使用DateComponentsFormatter为您的应用程序界面创建字符串。 DateComponentsFormatter has a maximumUnitCount property with the following declaration: DateComponentsFormatter有一个带有以下声明的maximumUnitCount属性:

var maximumUnitCount: Int { get set }

Use this property to limit the number of units displayed in the resulting string.使用此属性来限制结果字符串中显示的单位数。 For example, with this property set to 2, instead of “1h 10m, 30s”, the resulting string would be “1h 10m”.例如,将此属性设置为 2,而不是“1h 10m, 30s”,结果字符串将为“1h 10m”。 Use this property when you are constrained for space or want to round up values to the nearest large unit.当您受空间限制或想要将值向上舍入到最接近的大单位时使用此属性。

By setting maximumUnitCount 's value to 1 , you are guaranteed to display the difference in only one DateComponentsFormatter 's unit (years, months, days, hours or minutes).通过将maximumUnitCount的值设置为1 ,您可以保证仅以一个DateComponentsFormatter的单位(年、月、日、小时或分钟)显示差异。

The Playground code below shows how to display the difference between two dates:下面的 Playground 代码显示了如何显示两个日期之间的差异:

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")

Note that DateComponentsFormatter rounds up the result.请注意DateComponentsFormatter对结果进行四舍五入。 Therefore, a difference of 4 hours and 30 minutes will be displayed as 5 hours .因此, 4 小时 30 分钟的差异将显示为5 hours

If you need to repeat this operation, you can refactor your code:如果你需要重复这个操作,你可以重构你的代码:

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. Get the difference between two dates without formatting 2.不格式化获取两个日期的差值

If you don't need to display with formatting the difference between two dates to the user, you can useCalendar .如果您不需要向用户显示两个日期之间的差异的格式,则可以使用Calendar Calendar has a method dateComponents(_:from:to:) that has the following declaration: Calendar有一个dateComponents(_:from:to:) ,它具有以下声明:

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

Returns the difference between two dates.返回两个日期之间的差值。

The Playground code below that uses dateComponents(_:from:to:) shows how to retrieve the difference between two dates by returning the difference in only one type of Calendar.Component (years, months, days, hours or minutes).下面使用dateComponents(_:from:to:)的 Playground 代码显示了如何通过仅返回一种Calendar.Component类型(年、月、日、小时或分钟)的差异来检索两个日期之间的差异。

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
    }
}

If you need to repeat this operation, you can refactor your code:如果你需要重复这个操作,你可以重构你的代码:

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
}

In Swift 2.2在 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
}

A small addition to Leo Dabus' answer to provide the plural versions and be more human readable. Leo Dabus 的答案的一个小补充,以提供复数版本并更具人类可读性。

Swift 3斯威夫特 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 ""
    }
}

Swift 5 Swift 5

func dateDiff(dateStr:String) -> String {
    let f:DateFormatter = DateFormatter()
    f.timeZone = NSTimeZone.local
      f.dateFormat = "yyyy-M-dd'T'HH:mm:ss.SSSZZZ"
      
    let now = f.string(from: NSDate() as Date)
    let startDate = f.date(from: dateStr)
    let endDate = f.date(from: now)
    var _: NSCalendar = NSCalendar.current as NSCalendar
      
    
    let dateComponents = Calendar.current.dateComponents([ .weekOfMonth, .day , .hour , .minute , .second], from: startDate!, to: endDate!)
      
      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;
  }

Here is my answer for the Swift 3 answers above.这是我对上述 Swift 3 个答案的回答。 This is current as of Nov 2016, Xcode release was 8.2 Beta (8C23).这是截至 2016 年 11 月的最新版本,Xcode 版本为 8.2 Beta (8C23)。 Used some of both Sagar and Emin suggestions above and sometimes had to let Xcode autocomplete to suggest the syntax.使用了上面 Sagar 和 Emin 的一些建议,有时不得不让 Xcode 自动完成来建议语法。 It seemed like the syntax really changed to this beta version.看起来这个测试版的语法真的发生了变化。 buyDate I got from a DatePicker:我从 DatePicker 得到的buyDate

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)")

This is the shorter version: Basically I try to get the difference between the post timestamp with the Date() now.这是较短的版本:基本上我现在尝试获取发布时间戳与Date()之间的差异。

// 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))
}

For XCode Version 8.3.3 & Swift 3.0:对于 XCode 版本 8.3.3 和 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)")

Some addition in jose920405 answer to make it compatible with Swift 3.0 and above jose920405 答案中的一些补充使其与Swift 3.0及更高版本兼容

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 hours < 2 {
            timeAgo = "Hour Ago"
        }
        else{
            timeAgo = "\(hours) Hours Ago"
        }
    }
    
    if (days > 0) {
        if days < 2 {
            timeAgo = "Day Ago"
        }
        else{
            timeAgo = "\(days) Days Ago"
        }
    }
    
    if(months > 0){
        if months < 2 {
            timeAgo = "Month Ago"
        }
        else{
            timeAgo = "\(months) Months Ago"
        }
    }
    
    if(years > 0){
        if years < 2 {
            timeAgo = "Year Ago"
        }
        else{
            timeAgo = "\(years) Years Ago"
        }
    }
    
    DLog("timeAgo is ===> \(timeAgo)")
    return timeAgo;
}

Use this code:使用此代码:

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")
    }

Output is: Result: 10 years 1 months and 18 days输出为: 结果:10 年 1 个月零 18 天

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
    }
}

Use:用:

var durationString: String {
        return self.endTime.offset(from: self.startTime).dateComponentsToTimeString()
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM