7 Replies
      Latest reply on Jun 13, 2015 3:51 AM by DressTheMonkey
      therealcanadian Level 1 Level 1 (0 points)

        Here's a code snippet that compiles and works as expected, but I get a warning for depricated use of the unit .NSYearCalendarUnit.  

         

        This is within XCode 7 (Swift 2.0)

         

        Playground execution failed: /var/folders/37/2hl0kpw50lv18q1d48gbbb5r0000gn/T/./lldb/16158/playground8.swift:52:20: warning: 'NSYearCalendarUnit' was deprecated in iOS 8.0: Use NSCalendarUnitYear instead

         

        var TermEndDate = NSDate()
        
        if (TermYears>0) {
            TermEndDate = userCalendar.dateByAddingUnit(
            NSCalendarUnit.NSYearCalendarUnit,
            value: TermYears,
            toDate: TermStartDate,
            options: .WrapComponents )!
        }
        
        if (leaseMonths>0) {
            TermEndDate = userCalendar.dateByAddingUnit(
            NSCalendarUnit.NSMonthCalendarUnit,
            value: TermMonths,
            toDate: TermEndDate,
            options: .WrapComponents )!
        }
        
        
        

        If I switch to the recommended syntax, it errors out. 

        /var/folders/37/2hl0kpw50lv18q1d48gbbb5r0000gn/T/./lldb/16158/playground8.swift:60:5: error: 'NSCalendarUnit.Type' does not have a member named 'NSCalendarUnitMonth'

        NSCalendarUnit.NSCalendarUnitMonth,

        ^ ~~~~~~~~~~~~~~~~~~~

         

        I've dug through the documentation and can't find what I'm doing wrong.

         

        Thoughts?

         

        Thanks!!!

        • Re: Questions about NSCalendar
          therealcanadian Level 1 Level 1 (0 points)

          Also.... I found a very informative website that has a ton of examples specifically on how to work with dates within Swift.

           

          Here's a code snippet that he uses as an example, but does not compile for me, and I have no idea why I get the "error: could not find member 'CalendarUnitDay'".  Was this syntax changed with Swift 2.0?

           

          Every example I could find uses this syntax, but for me... no luck.

           

          // Playground - noun: a place where people can play
          
          import UIKit
          
          let userCalendar = NSCalendar.currentCalendar()
          
          // Let's create some dates to work with
          // ====================================
          
          // It's 3:45:30 a.m., New Year's Day. Time to go home.
          let goHomeYoureDrunkTimeComponents = NSDateComponents()
          goHomeYoureDrunkTimeComponents.year = 2015
          goHomeYoureDrunkTimeComponents.month = 1
          goHomeYoureDrunkTimeComponents.day = 1
          goHomeYoureDrunkTimeComponents.hour = 3
          goHomeYoureDrunkTimeComponents.minute = 45
          goHomeYoureDrunkTimeComponents.second = 30
          let goHomeYoureDrunkTime = userCalendar.dateFromComponents(goHomeYoureDrunkTimeComponents)!
          
          // Let's create an NSDate representing Bad Poetry Day (August 18)
          // at 4:20:10 p.m.
          let badPoetryDayComponents = NSDateComponents()
          badPoetryDayComponents.year = 2015
          badPoetryDayComponents.month = 8
          badPoetryDayComponents.day = 18
          badPoetryDayComponents.hour = 16
          badPoetryDayComponents.minute = 20
          badPoetryDayComponents.second = 10
          let badPoetryDay = userCalendar.dateFromComponents(badPoetryDayComponents)!
          
          // How many days, hours, minutes, and seconds between
          // goHomeYoureDrunkTime and badPoetryDay?
          let dayHourMinuteSecond: NSCalendarUnit =
              .CalendarUnitDay    |  //                <<-- Error listed below
              .CalendarUnitHour   |
              .CalendarUnitMinute |
              .CalendarUnitSecond
          
          let difference = NSCalendar.currentCalendar().components(
              dayHourMinuteSecond,
              fromDate: goHomeYoureDrunkTime,
              toDate: badPoetryDay,
              options: nil)
          
          difference.day     // 229
          difference.hour    // 12
          difference.minute  // 34
          difference.second  // 40
          
          

           

          I get the following errors in XCode...

           

          Playground execution failed: /var/folders/37/2hl0kpw50lv18q1d48gbbb5r0000gn/T/./lldb/16158/playground35.swift:37:6: error: could not find member 'CalendarUnitDay'

          .CalendarUnitDay |

          ~^~~~~~~~~~~~~~~

          /var/folders/37/2hl0kpw50lv18q1d48gbbb5r0000gn/T/./lldb/16158/playground35.swift:42:47: error: cannot invoke 'components' with an argument list of type '(NSCalendarUnit, fromDate: NSDate, toDate: NSDate, options: nil)'

          let difference = NSCalendar.currentCalendar().components(

          ^

           

          Thoughts?

           

          Thanks!!


          • Re: Questions about NSCalendar
            LCS Level 4 Level 4 (605 points)

            They renamed some enums / options to be more consistent.

             

            In Swift, it would now be NSCalendarUnit.Year  (type NSCalendarUnit, case .Year). If you double command-click on NSCalendarUnit (or NSYearCalendarUnit) in Xcode in your playground, it will pull up the Swift version of the header.

             

            And as far as the example code goes, OptionSets are handled differently now in Swift 2.0 and use set syntax instead of bitwise operators to join and test them.

            See the Xcode 7 beta release notes or https://forums.developer.apple.com/thread/3623 for more info on that.

              • Re: Questions about NSCalendar
                therealcanadian Level 1 Level 1 (0 points)

                Ok.. that finally clicked.  Thanks!!!

                 

                For those following along, the proper code that doesn't flag a warning is:

                 

                if (leaseTermYears>0) {
                    leaseTermEnd = userCalendar.dateByAddingUnit(
                    NSCalendarUnit.Year,
                    value: leaseTermYears,
                    toDate: startLease,
                    options: .WrapComponents )!
                }
                

                 

                I'm still attempting to fix the second example, but I think I understand the change now.  I'll post the solution when I get it working for everyone else who may be interested as well.

                  • Re: Questions about NSCalendar
                    therealcanadian Level 1 Level 1 (0 points)

                    I'm getting a bit futher.

                     

                    let dayHourMinuteSecond = NSDateComponentsFormatter()
                        dayHourMinuteSecond.allowedUnits = [.Day, .Hour, .Minute, .Second]
                    
                    

                     

                    Now conforms to the new way Swift 2.0 wants things formatted.

                     

                    I'm trying to figure out the calculated calendar time difference between two dates.  Pretty simple.  I think the function is the following: (using the autofill template),

                     

                    let userCalendar = NSCalendar.currentCalendar()
                    let difference = userCalendar.components(
                        <#T##unitFlags: NSCalendarUnit##NSCalendarUnit#>,
                        fromDate: <#T##NSDate#>,
                        toDate: <#T##NSDate#>,
                        options: <#T##NSCalendarOptions#>)
                    
                    


                    So my code with my variables would read (with the components used from the formatter above (which the compiler is happy with)


                    let difference = userCalendar.components(
                        dayHourMinuteSecond,
                        fromDate: goHomeYoureDrunkTime,
                        toDate: badPoetryDay,
                        options: NSCalendarOptions)
                    
                    


                    But I can't find any value that satisfies the Options for this. 


                    In my other code, WrapComponents was the only value that worked, even though I really did want it to carry forward and overflow months into years.


                    It's a UInt Struct (I've listed the header file below).  nil doesn't work, 0 doesn't work, UInt 0 doesn't work, _ doesn't work. None of the values in the struct (WrapComponents, MatchStrictly, etc) work...

                     

                    Thoughts?

                     

                    struct NSCalendarOptions : OptionSetType {
                        init(rawValue: UInt)
                    
                        static var WrapComponents: NSCalendarOptions { get } /
                    
                        @available(iOS 7.0, *)
                        static var MatchStrictly: NSCalendarOptions { get }
                        @available(iOS 7.0, *)
                        static var SearchBackwards: NSCalendarOptions { get }
                    
                        @available(iOS 7.0, *)
                        static var MatchPreviousTimePreservingSmallerUnits: NSCalendarOptions { get }
                        @available(iOS 7.0, *)
                        static var MatchNextTimePreservingSmallerUnits: NSCalendarOptions { get }
                        @available(iOS 7.0, *)
                        static var MatchNextTime: NSCalendarOptions { get }
                    
                        @available(iOS 7.0, *)
                        static var MatchFirst: NSCalendarOptions { get }
                        @available(iOS 7.0, *)
                        static var MatchLast: NSCalendarOptions { get }
                    }
                    
                    
                      • Re: Questions about NSCalendar
                        LCS Level 4 Level 4 (605 points)

                        You'll need to pass the formatter's unit OptionSet as the first parameter, and then need to make an OptionSet using the same syntax for the NSCalendarOptions.

                         

                        You can pass an empty set [ ] for no options, or [.WrapComponents, .MatchFirst] etc...

                         

                        let difference = NSCalendar.currentCalendar().components(
                            dayHourMinuteSecond.allowedUnits,
                            fromDate: goHomeYoureDrunkTime,
                            toDate: badPoetryDay,
                            options: [])
                        
                          • Re: Questions about NSCalendar
                            therealcanadian Level 1 Level 1 (0 points)

                            LCS,

                             

                            Many Many thanks for your help!  This now works as expected:

                             

                            For those following along and someone else can hopefully learn from the thrashing I did to get this to work...

                             

                            let userCalendar = NSCalendar.currentCalendar()
                            
                            let difference = userCalendar.components(
                                [NSCalendarUnit.Day, NSCalendarUnit.Hour, NSCalendarUnit.Minute, NSCalendarUnit.Second],
                                fromDate: goHomeYoureDrunkTime,
                                toDate: badPoetryDay,
                                options: [] )
                            
                            
                            

                             

                            To pass in the units as with a constant representing the array, I had to use:

                             

                            let dayHourMinuteSecond =    NSCalendarUnit([ .Day, .Hour, .Minute, .Second] )
                            
                            
                            

                             

                            Please note, I was wrong above, using a NSDateComponentsFormatter array was not acceptable for this call.

                             

                            let dayHourMinuteSecond = NSDateComponentsFormatter()
                                dayHourMinuteSecond.allowedUnits = [.Day, .Hour, .Minute, .Second]  // DOES NOT WORK FOR NSCalendar.currentCalendar.components
                            
                            
                            

                             

                            This also worked for the Options, to pass them in as a constant array:

                             

                            let calendarOptions = NSCalendarOptions ([.WrapComponents])
                            let calendarOptions2 = NSCalendarOptions ([ ])
                            
                            

                             

                            This also helped me get rid of my ugly work around to having to use the .WrapComponents to get it to compile.

                             

                            I can now pass in the months at 38 and it will calculate the length of the term, with it all just adding up as I had hoped.

                             

                            let termMonths = 38;
                            let CalendarUnitsMonthOnly =    NSCalendarUnit( [.Month] )
                            
                            let calendarOptions = NSCalendarOptions ([.WrapComponents])
                            let calendarOptions2 = NSCalendarOptions ([ ])
                            
                            TermEnd = userCalendar.dateByAddingUnit(
                                    CalendarUnitsMonthOnly,
                                    value: termMonths,
                                    toDate: startDate,
                                    options: calendarOptions2)!
                            
                            print(TermEnd)
                            
                            
                            

                             

                            I still don't fully understand why userCalendar.dateByAddingUnit returns an Optional, so I had to use the ! operator to unwrap it, (I think?) whereas the userCalendar.componets didn't.

                             

                            Thoughts?

                             

                            It's working now, and I have a much better grasp of how to call everything in Swift / Swift 2.0

                             

                            Thanks VERY much LCS.

                              • Re: Questions about NSCalendar
                                DressTheMonkey Level 1 Level 1 (15 points)

                                wrt returning nil.  I think dateByAddingUnit works by calling dateByAddingComponents, and that returns nil because (quoting from the docs):

                                 

                                Returns nil if date falls outside the defined range of the receiver or if the computation cannot be performed.

                                 

                                This would be much easier to figure out if only Apple would document these "new" NSCalendar methods which have been around now for a couple years.