รับความแตกต่างระหว่างสอง NSDates ใน (เดือน / วัน / ชั่วโมง / นาที / วินาที)


206

ฉันพยายามรับความแตกต่างระหว่างวันที่ปัจจุบันNSDate()และวันที่จากการtime();โทรPHP ตัวอย่างเช่น: NSDate(timeIntervalSinceReferenceDate: 1417147270). ฉันจะไปเกี่ยวกับการรับความแตกต่างในเวลาระหว่างสองวันได้อย่างไร ฉันต้องการมีฟังก์ชั่นที่เปรียบเทียบวันที่สองวันif(seconds > 60)จากนั้นจะคืนค่านาทีจำนวนif(minutes > 60)ชั่วโมงif(hours > 24)คืนและจำนวนวันคืนเป็นต้น

ฉันจะไปเกี่ยวกับเรื่องนี้ได้อย่างไร

แก้ไข: คำตอบที่ยอมรับในปัจจุบันทำในสิ่งที่ฉันอยากจะทำ ฉันขอแนะนำให้ใช้งานง่ายสำหรับการรับช่วงเวลาระหว่างวันที่สองวันในรูปแบบที่time()ฟังก์ชันPHP ใช้ หากคุณไม่คุ้นเคยกับ PHP เป็นพิเศษนั่นคือเวลาในไม่กี่วินาทีตั้งแต่วันที่ 1 มกราคม 1970 นี่เป็นประโยชน์สำหรับแบ็กเอนด์ใน PHP หากบางทีคุณกำลังใช้แบ็กเอนด์อย่าง NodeJS คุณอาจต้องพิจารณาตัวเลือกอื่น ๆ ที่คุณจะพบด้านล่าง


2
ฉันรู้ว่านี่เป็นรุ่นเก่า แต่คุณต้องการทำอะไรกับความแตกต่าง NSDateComponentsFormatterตัวอย่างเช่นถ้าคุณกำลังมองหารูปแบบสตริงสำหรับผู้ใช้ที่คุณควรจะใช้ สามารถกำหนดค่าได้อย่างมากช่วยให้คุณได้รับผลลัพธ์ที่กระชับ (เช่น.maximumUnitCount = 1)
Ken Thomases

จริงๆคำถามที่คุณตั้งใจจะทำมีความสำคัญอย่างยิ่ง พิจารณาว่าเดือนนั้นสามารถน้อยได้เพียง 28 วันหรือมากถึง 31 วันบวกหนึ่งชั่วโมง
gnasher729

คำตอบ:


510

Xcode 8.3 • Swift 3.1 หรือใหม่กว่า

คุณสามารถใช้ปฏิทินเพื่อช่วยคุณสร้างส่วนขยายเพื่อทำการคำนวณวันที่ของคุณดังนี้:

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

การใช้ฟอร์แมตส่วนประกอบวันที่

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"

1
ใน Swift 2.0 มี.CalendarUnitSecondข้อผิดพลาด'NSCalendarUnit.Type' does not have a member named 'CalendarUnitSecond'คุณรู้วิธีแก้ไขไหม
Matte.Car

2
@ Matte.Car คุณต้องใช้สองและแทนตัวเลือก: ไม่มีคุณต้องใช้ตัวเลือก: [] คุณสามารถดูการแก้ไขของฉัน
Leo Dabus

1
ฉันเกลียดการซ้ำซ้อนในคำตอบนี้ฉันจะใช้วิธีการที่อิงกับNSCalendarUnitการนำไปใช้เป็นreturn Calendar.current().components(unit, from: date, to: self, options: [])?. valueForComponent(unit)(บน iOS> 8)
Sulthan

4
เนื่องจากคำตอบที่ใช้DateComponentsFormatterนั้นดีกว่าการทำในระยะยาวดังนั้นจึงควรอยู่ที่ด้านบนสุดของคำตอบ
rmaddy

1
คุณยอดเยี่ยมมาก! ส่วนขยายนี้ช่วยฉันได้มาก!
Marian Petrisor

45

หากมีคนต้องการที่จะแสดงหน่วยเวลาทั้งหมดเช่น "ชั่วโมงนาทีวินาที" ไม่เพียง "ชั่วโมง" สมมติว่าความแตกต่างของเวลาระหว่างสองวันคือ 1 ชั่วโมง 59 นาที 20 วินาที ฟังก์ชั่นนี้จะแสดง "1h 59m 20s"

นี่คือรหัส 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 ""
    }

}

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

}

3
นี่คือสิ่งที่ฉันต้องการ เรียบง่ายและทำงานให้เสร็จลุล่วง
เฉินหลี่หยง

14

คุณถาม:

ฉันต้องการมีฟังก์ชั่นที่เปรียบเทียบวันที่ทั้งสองและถ้า (วินาที> 60) แล้วมันจะคืนค่านาทีถ้า (นาที> 60) ส่งคืนชั่วโมงและถ้า (ชั่วโมง> 24) ส่งคืนวันและอื่น ๆ

ฉันสมมติว่าคุณกำลังพยายามสร้างการแสดงสตริงของเวลาที่ผ่านไประหว่างสองวัน แทนที่จะเขียนโค้ดของคุณเองเพื่อทำสิ่งนั้น Apple มีคลาสที่ออกแบบมาเพื่อทำอย่างนั้น กล่าวคือใช้DateComponentsFormatterตั้งค่าallowedUnitsเป็นสิ่งที่เหมาะสมกับแอปของคุณตั้งค่าunitsStyleเป็นสิ่งที่คุณต้องการ (เช่น.full) จากนั้นโทรstring(from:to:)แล้วโทร

เช่นใน 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)

นี่จะแปลสตริงที่เหมาะสมสำหรับอุปกรณ์ที่เป็นปัญหา

หรือใน 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)

dateComponentsหากคุณกำลังมองหาค่าตัวเลขที่เกิดขึ้นจริงเพียงแค่ใช้ เช่นใน Swift 3:

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

หรือใน Swift 2.3:

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

6

รวมส่วนขยาย + DateComponents รูปแบบจากคำตอบของ @ 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"

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

พยายามขี้เกียจโหลดตัวจัดรูปแบบวันที่และตัวเลือกที่ดียิ่งขึ้นก็คือการทำให้มันคงที่
thesummersign

4

ฉันเพิ่มเวอร์ชัน "ยาว" ลงใน asnwer ของ Leo Dabus ในกรณีที่คุณต้องการมีสตริงที่บอกว่าบางสิ่งเช่น "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 ""
    }

}

4

-> ใช้สิ่งนี้เพื่อค้นหาช่องว่างเวลาระหว่างวันที่สองวันใน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
    }
}

3

รหัสที่แก้ไขเล็กน้อยสำหรับ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!

3

Swift 5.1 • iOS 13

คุณสามารถใช้RelativeDateFormatterที่ Apple แนะนำใน iOS 13

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

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

print(relativeDate) // 4 hours ago

ดูวิธีการแสดงวันที่และเวลาที่ญาติใช้ RelativeDateTimeFormatter


1

หากจุดประสงค์ของคุณคือรับหมายเลขวันที่แน่นอนระหว่างวันที่สองวันคุณสามารถแก้ไขปัญหานี้ได้ดังนี้:

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

1

ด้วย Swift 3 ตามความต้องการของคุณคุณสามารถเลือกหนึ่งในสองวิธีต่อไปนี้เพื่อแก้ไขปัญหาของคุณ


1. แสดงความแตกต่างระหว่างวันที่สองวันกับผู้ใช้

คุณสามารถใช้ a DateComponentsFormatterเพื่อสร้างสตริงสำหรับอินเทอร์เฟซของแอปได้ DateComponentsFormatterมีmaximumUnitCountคุณสมบัติที่มีการประกาศดังต่อไปนี้:

var maximumUnitCount: Int { get set }

ใช้คุณสมบัตินี้เพื่อ จำกัด จำนวนหน่วยที่แสดงในสตริงผลลัพธ์ ตัวอย่างเช่นเมื่อตั้งค่าคุณสมบัตินี้เป็น 2 แทนที่จะเป็น“ 1h 10m, 30s” สตริงผลลัพธ์จะเป็น“ 1h 10m” ใช้คุณสมบัตินี้เมื่อคุณถูก จำกัด พื้นที่หรือต้องการปัดเศษค่าให้หน่วยใหญ่ที่ใกล้ที่สุด

ด้วยการตั้งmaximumUnitCountค่าเป็น1คุณรับประกันว่าจะแสดงความแตกต่างในหนึ่งเดียวDateComponentsFormatterหน่วยเดียว (ปี, เดือน, วัน, ชั่วโมงหรือนาที)

รหัสสนามเด็กเล่นด้านล่างแสดงวิธีการแสดงความแตกต่างระหว่างวันที่สองวัน:

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

โปรดทราบว่าDateComponentsFormatterปัดเศษผลลัพธ์ ดังนั้นความแตกต่างของ4 ชั่วโมงและ 30 นาทีจะแสดงเป็น5 ชั่วโมง

หากคุณต้องการทำซ้ำการดำเนินการนี้คุณสามารถ refactor รหัสของคุณ:

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. รับความแตกต่างระหว่างวันที่สองวันโดยไม่มีการจัดรูปแบบ

Calendarหากคุณไม่จำเป็นต้องแสดงผลที่มีการจัดรูปแบบที่แตกต่างกันระหว่างสองวันให้กับผู้ใช้ที่คุณสามารถใช้ CalendarมีวิธีการdateComponents(_:from:to:)ที่มีการประกาศดังต่อไปนี้:

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

ส่งคืนความแตกต่างระหว่างวันที่สองวัน

รหัสสนามเด็กเล่นด้านล่างที่ใช้dateComponents(_:from:to:)แสดงวิธีเรียกคืนความแตกต่างระหว่างวันที่สองวันโดยส่งคืนความแตกต่างในรูปแบบเดียวเท่านั้น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
    }
}

หากคุณต้องการทำซ้ำการดำเนินการนี้คุณสามารถ refactor รหัสของคุณ:

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
}

1

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

1

นอกเหนือจากคำตอบเล็ก ๆ ของ Leo Dabus เพื่อจัดทำพหูพจน์และสามารถอ่านได้ง่ายขึ้น

สวิฟท์ 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 ""
    }
}

0

นี่เป็นรุ่นที่สั้นกว่า: โดยทั่วไปฉันพยายามรับความแตกต่างระหว่างการประทับเวลากับ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))
}

0

นี่คือคำตอบของฉันสำหรับคำตอบ Swift 3 ด้านบน นี่เป็นปัจจุบัน ณ เดือนพฤศจิกายน 2559 การปล่อย Xcode เป็น 8.2 เบต้า (8C23) ใช้คำแนะนำทั้ง Sagar และ Emin ด้านบนและบางครั้งต้องปล่อยให้ Xcode เติมข้อความอัตโนมัติเพื่อแนะนำไวยากรณ์ ดูเหมือนว่าไวยากรณ์จะเปลี่ยนเป็นรุ่นเบต้านี้จริงๆ buyDateฉันได้รับจาก 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)")

ขออภัยที่ฉันดูนี้นี่คือทางออกของซาก้า ฉันทำซ้ำหลายครั้งและลองทำหลายสิ่งหลายอย่างที่ฉันคิดว่ามันเปลี่ยนไป วิธีการแก้ปัญหาของ Emin ไม่สามารถใช้งานกับ Swift 3 ล่าสุดได้
renaissanceMan

คุณไม่ควรใช้NSCalendarใน Swift 3 Calendarจริงๆ let calendar = Calendar.currentดังนั้นนี้จะง่ายไป และจากนั้นจะมีลักษณะ:components let components = calendar.dateComponents([.day], from: date1, to: date2)
Rob

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

0

นอกจากนี้ใน 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 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;
}

0

ใช้รหัสนี้:

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

ผลผลิตคือ: ผลลัพธ์: 10 ปี 1 เดือนและ 18 วัน


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

ใช้:

var durationString: String {
        return self.endTime.offset(from: self.startTime).dateComponentsToTimeString()
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.