mi è piaciuto l'API in soluzione di Leo e lo ha usato. Tuttavia mi sono imbattuto in problema quando l'ho eseguito (13 giugno 2015 9:33 AM PST). I sintomi erano:
Quando la data è nel futuro, funzione di xFromToday stavano tornando risultati per - (t-delta) (ad esempio, per 1 mese in futuro le funzioni XFromToday sarebbero tornati (0, -4, -29, -719, -43199) per x = (mese, settimana, giorni, ore, minuti). La stringa relative Date restituirà "1 settimane da oggi"
Quando la data è nel passato, i risultati sarebbero per -t, eccetto per la stringa di data relativa. Ad esempio, per un mese nel passato, I otterrebbe (1, 4, 31, 744, 44640). Data stringa è stata: "4 settimane e 744 ore"
non posso incollare l'uscita di test per ragioni di riservatezza, ma il codice con NSDate.test() viene incollato. Ha anche poche altre cose prese in prestito da un altro post (citato in codice) e alcune cose di formattazione che ho scritto.
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 _________________________")
}
}
Ecco la "correzione" che ho fatto. Ho aggiunto una funzione santizedDates() che restituisce "from" e "to" date e un moltiplicatore di segno (+ 1/-1). Un offset di 1 minuto viene aggiunto a intervalli di date se il confronto era in futuro. Funziona per il caso di test. Produce anche output leggibili e leggibili da relativeDateString (capitalizeFirst: Bool = false) come: "oggi, 1 ora 1 minuto in passato".Ho inviato una domanda per perché questo comportamento si verifica in primo luogo qui:
NSCalendar.components().minute returning inconsistent values
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 _________________________")
}
}
Look. Prima di tutto, non c'è NSDate in questa storia. Secondo, leggi la documentazione; NSDateComponents 'week' non è quello che pensi che sia, e in ogni caso è da tempo deprecato. – matt
Volevo solo dividere in componenti un intervallo di due NSDate. Il metodo 'calendar.components (unitFlags: NSCalendarUnit, fromDate: NSDate !, toDate: NSDate !, opzioni: NSCalendarOptions)' accetta come argomenti due ** NSDate **. Ho visto che 'week' è stato deprecato ecco perché ho chiesto qui un altro modo di contare le settimane – Giorgio