在Swift中使用NSDate组件

我有一个date,我需要拆分一些组件。 例如

let components = NSCalendarUnit.CalendarUnitDay | NSCalendarUnit.CalendarUnitHour let date = calendar.components(components, fromDate: aDate, toDate: NSDate(), options: nil) var dateToPrint = "\(date.day) days \(date.hour) hours" 

dateToPrint将是从aDate到现在的天数和小时数。 但是,如果我想要数周而不是几天

 let components = NSCalendarUnit.CalendarUnitWeek | NSCalendarUnit.CalendarUnitHour let date = calendar.components(components, fromDate: aDate, toDate: NSDate(), options: nil) var dateToPrint = "\(date.week) weeks \(date.hour) hours" 

date.week不存在。 那我该如何解决呢?

Xcode 8.3.2•Swift 3.1

 extension Date { func xDays(_ x: Int) -> Date { return Calendar.current.date(byAdding: .day, value: x, to: self)! } func xWeeks(_ x: Int) -> Date { return Calendar.current.date(byAdding: .weekOfYear, value: x, to: self)! } var weeksHoursFromToday: DateComponents { return Calendar.current.dateComponents( [.weekOfYear, .hour], from: self, to: Date()) } var relativeDateString: String { var result = "" if let weeks = weeksHoursFromToday.weekOfYear, let hours = weeksHoursFromToday.hour, weeks > 0 { result += "\(weeks) week" if weeks > 1 { result += "s" } if hours > 0 { result += " and " } } if let hours = weeksHoursFromToday.hour, hours > 0 { result += "\(hours) hour" if hours > 1 { result += "s" } } return result } } 

 let today = Date() // "May 1, 2017, 9:29 PM" let yesterday = Date().xDays(-1) // "Apr 30, 2017, 9:29 PM" let twoWeeksAgo = Date().xWeeks(-2) // "Apr 17, 2017, 9:29 PM" let anotherDate = DateComponents(calendar: .current, year: 2013, month: 12, day: 4).date! // "Dec 4, 2013, 12:00 AM" let anotherDate2 = DateComponents(calendar: .current, year: 2012, month: 12, day: 3).date! // "Dec 3, 2012, 12:00 AM" yesterday.relativeDateString // "24 hours" twoWeeksAgo.relativeDateString // "2 weeks" anotherDate.relativeDateString // "177 weeks and 141 hours" anotherDate2.relativeDateString // "230 weeks and 21 hours" yesterday.relativeDateString // "24 hours" twoWeeksAgo.relativeDateString // "2 weeks" anotherDate.relativeDateString // "177 weeks and 141 hours" anotherDate2.relativeDateString // "230 weeks and 21 hours" 

我喜欢Leo解决scheme中的API并使用它。 然而,当我运行它时遇到了问题(2015年6月13日上午9:33)。 症状是:

  1. 当date在将来时,xFromToday函数返回 – (t-delta)的结果(例如对于未来1个月,XFromToday函数将返回(0,-4,-29,-719,-43199) x =(month,week,days,hrs,mins)。relativeDatesstring将返回“从今天起1周”

  2. date过去时,除了相对datestring之外,结果是-t。 例如,过去一个月,我会得到(1,4,31,744,44640)。 相对datestring是:“4周和744小时”

由于机密性,我无法粘贴testing输出,但是粘贴了NSDate.test()的代码。 它也有其他的东西借来的另一篇文章(引用代码)和一些格式化的东西,我写的。

 import Foundation // https://stackoverflow.com/questions/27339072/working-with-nsdate-components-in-swift // **** Use with caution may not do what you expect. See the stackoverflow post above. ******* public extension NSDate { func xDays(x:Int) -> NSDate { return NSCalendar.currentCalendar().dateByAddingUnit(.CalendarUnitDay, value: x, toDate: self, options: nil)! } func xWeeks(x:Int) -> NSDate { return NSCalendar.currentCalendar().dateByAddingUnit(.CalendarUnitWeekOfYear, value: x, toDate: self, options: nil)! } func xMonths(x:Int) -> NSDate { return NSCalendar.currentCalendar().dateByAddingUnit(.CalendarUnitMonth, value: x, toDate: self, options: nil)! } func xMins(x:Int) -> NSDate { return NSCalendar.currentCalendar().dateByAddingUnit(.CalendarUnitMinute, value: x, toDate: self, options: nil)! } func xHours(x:Int) -> NSDate { return NSCalendar.currentCalendar().dateByAddingUnit(.CalendarUnitHour, value: x, toDate: self, options: nil)! } var hoursFromToday: Int{ return NSCalendar.currentCalendar().components(.CalendarUnitHour, fromDate: self, toDate: NSDate(), options: nil).hour } var weeksFromToday: Int{ return NSCalendar.currentCalendar().components(.CalendarUnitWeekOfYear, fromDate: self, toDate: NSDate(), options: nil).weekOfYear } var daysFromToday: Int{ return NSCalendar.currentCalendar().components(.CalendarUnitDay, fromDate: self, toDate: NSDate(), options: nil).day } var monthsFromToday: Int{ return NSCalendar.currentCalendar().components(.CalendarUnitMonth, fromDate: self, toDate: NSDate(), options: nil).month } var minsFromToday: Int{ return NSCalendar.currentCalendar().components(.CalendarUnitMinute, fromDate: self, toDate: NSDate(), options: nil).minute } var relativeDateString: String { if weeksFromToday > 0 { return weeksFromToday > 1 ? "\(weeksFromToday) weeks and \(hoursFromToday) hours" : "\(weeksFromToday) week and \(hoursFromToday) hours" } if hoursFromToday > 0 { return hoursFromToday > 1 ? "\(hoursFromToday) hours" : "\(hoursFromToday) hour" } return "" } //Date Comparisions //https://stackoverflow.com/questions/26198526/nsdate-comparison-using-swift func isGreaterThanDate(dateToCompare : NSDate) -> Bool { //Declare Variables var isGreater = false //Compare Values if self.compare(dateToCompare) == NSComparisonResult.OrderedDescending { isGreater = true } //Return Result return isGreater } func isLessThanDate(dateToCompare : NSDate) -> Bool { //Declare Variables var isLess = false //Compare Values if self.compare(dateToCompare) == NSComparisonResult.OrderedAscending { isLess = true } //Return Result return isLess } // Date printing converstions var dayMonthYear: String { let dateMonthYearFormatter: NSDateFormatter = NSDateFormatter() let currentLocale: NSLocale = NSLocale.currentLocale() let dateMonthYearFormatString: NSString! = NSDateFormatter.dateFormatFromTemplate("EdMMMyyyy",options: 0, locale: currentLocale) dateMonthYearFormatter.dateFormat = dateMonthYearFormatString as! String return dateMonthYearFormatter.stringFromDate(self) } var timeDayMonthYear: String { let dateMonthYearFormatter: NSDateFormatter = NSDateFormatter() let currentLocale: NSLocale = NSLocale.currentLocale() let dateMonthYearFormatString: NSString! = NSDateFormatter.dateFormatFromTemplate("EdMMMyyyy' ' HH':'mm",options: 0, locale: currentLocale) dateMonthYearFormatter.dateFormat = dateMonthYearFormatString as! String return dateMonthYearFormatter.stringFromDate(self) } var hourMin: String { let hourMinFormatter = NSDateFormatter(); hourMinFormatter.dateFormat = "HH:mm" return hourMinFormatter.stringFromDate(self) } static func rfc3339DateFormatter() -> NSDateFormatter { let rfc3339DateFormatterRet = NSDateFormatter() let enUSPOSIXLocale: NSLocale = NSLocale(localeIdentifier: "en_US_POSIX") rfc3339DateFormatterRet.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'" rfc3339DateFormatterRet.locale = enUSPOSIXLocale rfc3339DateFormatterRet.timeZone = NSTimeZone(forSecondsFromGMT: 0) return rfc3339DateFormatterRet } var rfcString: String { return NSDate.rfc3339DateFormatter().stringFromDate(self) } func rfcDate(rfcString: String) -> NSDate { return NSDate.rfc3339DateFormatter().dateFromString(rfcString)! } func changeDate(toDate: NSDate) -> NSDate { let rfcToDate = toDate.rfcString let rfcSelf = self.rfcString let toDateArray : [String] = rfcToDate.componentsSeparatedByString("T") let selfArray : [String] = rfcSelf.componentsSeparatedByString("T") return rfcDate(toDateArray[0]+"T"+selfArray[1]) } static func test(months: Int = 0, weeks: Int = 0, days: Int = 0, hrs: Int = 0, mins: Int = 0) { NSLog("****************** Start Testing of NSDate **************************") NSLog("Inputs: months:\(months) weeks:\(weeks) days:\(days) hrs: \(hrs) mins: \(mins)") var today = NSDate() NSLog("Today is: \(today.timeDayMonthYear)") var monthsFromToday = today.xMonths(months) NSLog("** \(months) months from today: \(monthsFromToday.timeDayMonthYear)") NSLog("monthsFromToday returns: \(monthsFromToday.monthsFromToday)"); NSLog("weeksFromToday returns: \(monthsFromToday.weeksFromToday)"); NSLog("daysFromToday returns: \(monthsFromToday.daysFromToday)"); NSLog("hoursFromToday returns: \(monthsFromToday.hoursFromToday)"); NSLog("minsFromToday returns: \(monthsFromToday.minsFromToday)"); NSLog("relativeDateString returns: \(monthsFromToday.relativeDateString)") var weeksFromToday = today.xWeeks(weeks) NSLog("** \(weeks) weeks from today: \(weeksFromToday.timeDayMonthYear)") NSLog("weeksFromToday returns: \(weeksFromToday.weeksFromToday)"); NSLog("relativeDateString returns: \(weeksFromToday.relativeDateString)") var daysFromToday = today.xDays(days) NSLog("** \(days) days from today: \(daysFromToday.timeDayMonthYear)") NSLog("daysFromToday returns: \(daysFromToday.daysFromToday)"); NSLog("relativeDateString returns: \(daysFromToday.relativeDateString)") var hrsFromToday = today.xHours(hrs) NSLog("** \(hrs) hours from today: \(hrsFromToday.timeDayMonthYear)") NSLog("hoursFromToday returns: \(hrsFromToday.hoursFromToday)"); NSLog("relativeDateString returns: \(hrsFromToday.relativeDateString)") var minsFromToday = today.xMins(mins) NSLog("** \(mins) minutes from today: \(minsFromToday.timeDayMonthYear)") NSLog("minsFromToday returns: \(minsFromToday.minsFromToday)"); NSLog("relativeDateString returns: \(minsFromToday.relativeDateString)") NSLog("__________________ End Testing of NSDate _________________________") } } 

这是我做的“修复”。 我添加了一个santizedDates()函数,它返回“from”和“to”date以及一个符号乘数(+ 1 / -1)。 如果将来进行比较,则会在date范围内添加1分钟的偏移量。 它适用于testing用例。 还可以从relativeDateString(capitalizeFirst:Bool = false)生成正确的和人类可读的输出,例如:“今天,过去1小时1分钟”。 我已经发布了一个问题, 为什么这种行为发生在这里:

NSCalendar.components()。分钟返回不一致的值

 import Foundation // https://stackoverflow.com/questions/27339072/working-with-nsdate-components-in-swift public extension NSDate { func xDays(x:Int) -> NSDate { return NSCalendar.currentCalendar().dateByAddingUnit(.CalendarUnitDay, value: x, toDate: self, options: nil)! } func xWeeks(x:Int) -> NSDate { return NSCalendar.currentCalendar().dateByAddingUnit(.CalendarUnitWeekOfYear, value: x, toDate: self, options: nil)! } func xMonths(x:Int) -> NSDate { return NSCalendar.currentCalendar().dateByAddingUnit(.CalendarUnitMonth, value: x, toDate: self, options: nil)! } func xMins(x:Int) -> NSDate { return NSCalendar.currentCalendar().dateByAddingUnit(.CalendarUnitMinute, value: x, toDate: self, options: nil)! } func xHours(x:Int) -> NSDate { return NSCalendar.currentCalendar().dateByAddingUnit(.CalendarUnitHour, value: x, toDate: self, options: nil)! } var hoursFromToday: Int{ var fromDate: NSDate = self var toDate: NSDate = NSDate() var sign: Int = -1 (fromDate,toDate, sign) = self.sanitizedDates() return (sign * NSCalendar.currentCalendar().components(.CalendarUnitHour, fromDate: fromDate, toDate: toDate, options: nil).hour) } var weeksFromToday: Int{ var fromDate: NSDate = self var toDate: NSDate = NSDate() var sign: Int = -1 (fromDate,toDate,sign) = self.sanitizedDates() return (sign * NSCalendar.currentCalendar().components(.CalendarUnitWeekOfYear, fromDate: fromDate, toDate: toDate, options: nil).weekOfYear) } var daysFromToday: Int{ var fromDate: NSDate = self var toDate: NSDate = NSDate() var sign: Int = -1 (fromDate,toDate, sign) = self.sanitizedDates() return (sign * NSCalendar.currentCalendar().components(.CalendarUnitDay, fromDate: fromDate, toDate: toDate, options: nil).day) } var monthsFromToday: Int{ var fromDate: NSDate = self var toDate: NSDate = NSDate() var sign: Int = -1 (fromDate,toDate, sign) = self.sanitizedDates() return (sign * NSCalendar.currentCalendar().components(.CalendarUnitMonth, fromDate: fromDate, toDate: toDate, options: nil).month) } var minsFromToday: Int{ var fromDate: NSDate = self var toDate: NSDate = NSDate() var sign: Int = -1 var offset: Int = 0 (fromDate,toDate,sign) = self.sanitizedDates() return ( sign * NSCalendar.currentCalendar().components(.CalendarUnitMinute, fromDate: fromDate, toDate: toDate, options: nil).minute) } func relativeDateString(capitalizeFirst:Bool = false) -> String { let days: Int = daysFromToday let mins: Int = minsFromToday % 60 let tense: String = (minsFromToday > 0) ? " in the future" : " in the past" let hrs: Int = hoursFromToday % 24 var retString = (capitalizeFirst) ? "Now" : "now" if(minsFromToday != 0) { if(days == 0) { retString = (capitalizeFirst) ? "Today" : "today" retString = (mins != 0 || hrs != 0) ? retString+"," : retString } else { let absDays = abs(days) retString = "\(absDays)" retString += (absDays > 1) ? " days" : " day" } if(hrs != 0) { let absHrs = abs(hrs) retString += " \(absHrs)" retString += (absHrs > 1) ? " hours" : " hour" } if(mins != 0) { let absMins = abs(mins) retString += " \(absMins)" retString += (absMins > 1) ? " minutes" : " minute" } retString += tense } return retString } //Date Comparisons //https://stackoverflow.com/questions/26198526/nsdate-comparison-using-swift func isGreaterThanDate(dateToCompare : NSDate) -> Bool { //Declare Variables var isGreater = false //Compare Values if self.compare(dateToCompare) == NSComparisonResult.OrderedDescending { isGreater = true } //Return Result return isGreater } func isLessThanDate(dateToCompare : NSDate) -> Bool { //Declare Variables var isLess = false //Compare Values if self.compare(dateToCompare) == NSComparisonResult.OrderedAscending { isLess = true } //Return Result return isLess } // Date printing converstions var dayMonthYear: String { let dateMonthYearFormatter: NSDateFormatter = NSDateFormatter() let currentLocale: NSLocale = NSLocale.currentLocale() let dateMonthYearFormatString: NSString! = NSDateFormatter.dateFormatFromTemplate("EdMMMyyyy",options: 0, locale: currentLocale) dateMonthYearFormatter.dateFormat = dateMonthYearFormatString as! String return dateMonthYearFormatter.stringFromDate(self) } var timeDayMonthYear: String { let dateMonthYearFormatter: NSDateFormatter = NSDateFormatter() let currentLocale: NSLocale = NSLocale.currentLocale() let dateMonthYearFormatString: NSString! = NSDateFormatter.dateFormatFromTemplate("EdMMMyyyy' ' HH':'mm",options: 0, locale: currentLocale) dateMonthYearFormatter.dateFormat = dateMonthYearFormatString as! String return dateMonthYearFormatter.stringFromDate(self) } var hourMin: String { let hourMinFormatter = NSDateFormatter(); hourMinFormatter.dateFormat = "HH:mm" return hourMinFormatter.stringFromDate(self) } static func rfc3339DateFormatter() -> NSDateFormatter { let rfc3339DateFormatterRet = NSDateFormatter() let enUSPOSIXLocale: NSLocale = NSLocale(localeIdentifier: "en_US_POSIX") rfc3339DateFormatterRet.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'" rfc3339DateFormatterRet.locale = enUSPOSIXLocale rfc3339DateFormatterRet.timeZone = NSTimeZone(forSecondsFromGMT: 0) return rfc3339DateFormatterRet } var rfcString: String { return NSDate.rfc3339DateFormatter().stringFromDate(self) } func rfcDate(rfcString: String) -> NSDate { return NSDate.rfc3339DateFormatter().dateFromString(rfcString)! } func changeDate(toDate: NSDate) -> NSDate { let rfcToDate = toDate.rfcString let rfcSelf = self.rfcString let toDateArray : [String] = rfcToDate.componentsSeparatedByString("T") let selfArray : [String] = rfcSelf.componentsSeparatedByString("T") return rfcDate(toDateArray[0]+"T"+selfArray[1]) } private func sanitizedDates() -> (fromDate: NSDate, toDate: NSDate, sign: Int ) { var toDate: NSDate = self var fromDate: NSDate = NSDate() var sign: Int = 1 // For toDates in the past, results are reasonable, except for sign. //In future dates, we to flip dates to make them past dates and add 1 minute for unknown reason. if(toDate.isGreaterThanDate(fromDate)) { // NSLog("****** Flipping dates ********") toDate = fromDate.xMins(-1) // In this case, the results are consistently shorter by a minute fromDate = self sign = -1 } return (fromDate,toDate,sign) } static func test(months: Int = 0, weeks: Int = 0, days: Int = 0, hrs: Int = 0, mins: Int = 0) { NSLog("****************** Start Testing of NSDate **************************") NSLog("Inputs: months:\(months) weeks:\(weeks) days:\(days) hrs: \(hrs) mins: \(mins)") var today = NSDate() NSLog("Today is: \(today.timeDayMonthYear)") var monthsFromToday = today.xMonths(months) NSLog("** \(months) months from today: \(monthsFromToday.timeDayMonthYear)") NSLog("monthsFromToday returns: \(monthsFromToday.monthsFromToday)"); NSLog("weeksFromToday returns: \(monthsFromToday.weeksFromToday)"); NSLog("daysFromToday returns: \(monthsFromToday.daysFromToday)"); NSLog("hoursFromToday returns: \(monthsFromToday.hoursFromToday)"); NSLog("minsFromToday returns: \(monthsFromToday.minsFromToday)"); NSLog("relativeDateString returns: \(monthsFromToday.relativeDateString())") var weeksFromToday = today.xWeeks(weeks) NSLog("** \(weeks) weeks from today: \(weeksFromToday.timeDayMonthYear)") NSLog("weeksFromToday returns: \(weeksFromToday.weeksFromToday)"); NSLog("relativeDateString returns: \(weeksFromToday.relativeDateString(capitalizeFirst:true))") NSLog("minsFromToday returns: \(weeksFromToday.minsFromToday)"); NSLog("monthsFromToday returns: \(weeksFromToday.monthsFromToday)"); NSLog("weeksFromToday returns: \(weeksFromToday.weeksFromToday)"); NSLog("daysFromToday returns: \(weeksFromToday.daysFromToday)"); NSLog("hoursFromToday returns: \(weeksFromToday.hoursFromToday)"); NSLog("minsFromToday returns: \(weeksFromToday.minsFromToday)"); var daysFromToday = today.xDays(days) NSLog("** \(days) days from today: \(daysFromToday.timeDayMonthYear)") NSLog("daysFromToday returns: \(daysFromToday.daysFromToday)"); NSLog("relativeDateString returns: \(daysFromToday.relativeDateString())") NSLog("minsFromToday returns: \(daysFromToday.minsFromToday)"); NSLog("monthsFromToday returns: \(daysFromToday.monthsFromToday)"); NSLog("weeksFromToday returns: \(daysFromToday.weeksFromToday)"); NSLog("daysFromToday returns: \(daysFromToday.daysFromToday)"); NSLog("hoursFromToday returns: \(daysFromToday.hoursFromToday)"); NSLog("minsFromToday returns: \(daysFromToday.minsFromToday)"); var hrsFromToday = today.xHours(hrs) NSLog("** \(hrs) hours from today: \(hrsFromToday.timeDayMonthYear)") NSLog("hoursFromToday returns: \(hrsFromToday.hoursFromToday)"); NSLog("minsFromToday returns: \(hrsFromToday.minsFromToday)"); NSLog("monthsFromToday returns: \(hrsFromToday.monthsFromToday)"); NSLog("weeksFromToday returns: \(hrsFromToday.weeksFromToday)"); NSLog("daysFromToday returns: \(hrsFromToday.daysFromToday)"); NSLog("hoursFromToday returns: \(hrsFromToday.hoursFromToday)"); NSLog("minsFromToday returns: \(hrsFromToday.minsFromToday)"); NSLog("relativeDateString returns: \(hrsFromToday.relativeDateString(capitalizeFirst:true))") var minsFromToday = today.xMins(mins) NSLog("** \(mins) minutes from today: \(minsFromToday.timeDayMonthYear)") NSLog("minsFromToday returns: \(minsFromToday.minsFromToday)"); NSLog("monthsFromToday returns: \(minsFromToday.monthsFromToday)"); NSLog("weeksFromToday returns: \(minsFromToday.weeksFromToday)"); NSLog("daysFromToday returns: \(minsFromToday.daysFromToday)"); NSLog("hoursFromToday returns: \(minsFromToday.hoursFromToday)"); NSLog("minsFromToday returns: \(minsFromToday.minsFromToday)"); NSLog("relativeDateString returns: \(minsFromToday.relativeDateString())") NSLog("__________________ End Testing of NSDate _________________________") } } 

你将需要制作另一个名为“calendar”(NSCalendar对象)的variables,并使用init“currentCalendar”方法。 定义日历对象之后,调用日历rangeOfUnit下的方法:NSWeekCalendarUnit inUnit:NSMonthCalendarUnit forDate:date 。 然后使一个名为amountOfWeeks的NSInteger等于上述函数返回的范围。 函数返回的范围的长度将是该月的周数。

不知道你想要什么,但有weekdayweekdayOrdinalweekOfMonthweekOfYear 。 ( week已被弃用)