NSDateComponentsFormatter's stringFromDate(_, toDate:) returns nil

丶灬走出姿态 提交于 2019-12-06 03:05:29

问题


Question

Why is string nil?

let formatter = NSDateComponentsFormatter()
let referenceDate = NSDate(timeIntervalSinceReferenceDate: 0)
let intervalDate = NSDate(timeInterval: 3628810, sinceDate: referenceDate)
let string = formatter.stringFromDate(referenceDate, toDate: intervalDate)

I'm expecting a string like "6w 10s" to be returned.

(6 weeks is 3,628,800 seconds.)


Attempted Troubleshooting

To troubleshoot, I tried setting allowedUnits:

formatter.allowedUnits = .YearCalendarUnit | .MonthCalendarUnit | .WeekCalendarUnit | .DayCalendarUnit | .HourCalendarUnit | .MinuteCalendarUnit | .SecondCalendarUnit

Which results in this error:

"NSInvalidArgumentException", "Specifying positional units with gaps is ambiguous, and therefore unsupported"

I don't know what a "positional unit" is (outside of football), and I don't think I'm specifying any gaps.


Notes

I'm not using stringFromTimeInterval() because that will return different results depending on the system's current date. (i.e., February only has 28/29 days in a month.) I want to calculate the time interval from the NSDate reference date.

I'm using Xcode 6.1.1 (6A2008a). Here's a Playground screenshot if that helps:


回答1:


From the headerdoc:

/* Bitmask of units to include. Set to 0 to get the default behavior.
   Note that, especially if the maximum number of units is low, unit
   collapsing is on, or zero dropping is on, not all allowed units may
   actually be used for a given NSDateComponents. Default value is the
   components of the passed-in NSDateComponents object, or years | 
   months | weeks | days | hours | minutes | seconds if passed an
   NSTimeInterval or pair of NSDates.

   Allowed units are:

    NSCalendarUnitYear
    NSCalendarUnitMonth
    NSCalendarUnitWeekOfMonth (used to mean "quantity of weeks")
    NSCalendarUnitDay
    NSCalendarUnitHour
    NSCalendarUnitMinute
    NSCalendarUnitSecond

   Specifying any other NSCalendarUnits will result in an exception.
 */
var allowedUnits: NSCalendarUnit

So:

let formatter = NSDateComponentsFormatter()
formatter.calendar = NSCalendar.currentCalendar()
formatter.allowedUnits = nil
formatter.allowedUnits |= .CalendarUnitYear
formatter.allowedUnits |= .CalendarUnitMonth
formatter.allowedUnits |= .CalendarUnitWeekOfMonth
formatter.allowedUnits |= .CalendarUnitDay
formatter.allowedUnits |= .CalendarUnitHour
formatter.allowedUnits |= .CalendarUnitMinute
formatter.allowedUnits |= .CalendarUnitSecond

let referenceDate = NSDate(timeIntervalSinceReferenceDate: 0)
let intervalDate = NSDate(timeInterval: 214458810, sinceDate: referenceDate)
let string = formatter.stringFromDate(referenceDate, toDate: intervalDate)
// -> "6y 9m 2w 4d 3:53:30"

When we omit one of them in the middle:

formatter.allowedUnits = nil
formatter.allowedUnits |= .CalendarUnitYear
formatter.allowedUnits |= .CalendarUnitMonth
formatter.allowedUnits |= .CalendarUnitWeekOfMonth
formatter.allowedUnits |= .CalendarUnitDay
// formatter.allowedUnits |= .CalendarUnitHour
formatter.allowedUnits |= .CalendarUnitMinute
formatter.allowedUnits |= .CalendarUnitSecond

'Specifying positional units with gaps is ambiguous, and therefore unsupported' error :) That is the "gap" means, I think.




回答2:


This works for me to get rid of the "gaps":

formatter.allowedUnits = .DayCalendarUnit | .HourCalendarUnit | .MinuteCalendarUnit | .SecondCalendarUnit



回答3:


Swift 3.0 version for Solving this.

 let dateFormatted = DateComponentsFormatter()

 dateFormatted.allowedUnits = [NSCalendar.Unit.year, NSCalendar.Unit.month, NSCalendar.Unit.weekOfMonth ,NSCalendar.Unit.day, NSCalendar.Unit.hour, NSCalendar.Unit.minute, NSCalendar.Unit.second]

 let autoFormattedDifference = dateFormatted.string(from: currentDate, to: dateFromTimestamp)

 print("The difference between dates is: \(autoFormattedDifference!)")

Now here the difference is giving all the value of allowUnits from ascending or descending order.




回答4:


Not specifying a unit style will throw this error in Swift 4. The fix:

let componentsFormatter = DateComponentsFormatter()
componentsFormatter.unitsStyle = .full // or .spellOut, .short, .brief, .abbreviated, .positional


来源:https://stackoverflow.com/questions/28633850/nsdatecomponentsformatters-stringfromdate-todate-returns-nil

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!