iosswiftnsdatenscalendar

first and last day of the current month in swift


I'm trying to get the first and last day of the month in swift.

So far I have the following:

let dateFormatter = NSDateFormatter()
let date = NSDate()
dateFormatter.dateFormat = "yyyy-MM-dd"
let calendar = NSCalendar.currentCalendar()
let components = calendar.components([.Year, .Month, .Day, .Hour, .Minute, .Second], fromDate: date)

let month = components.month
let year = components.year

let startOfMonth = ("\(year)-\(month)-01")

But I'm not sure how to get the last date. Is there a built in method I'm missing? Obviously it has to take into account leap years etc.


Solution

  • You get the first day of the month simply with

    let components = calendar.components([.Year, .Month], fromDate: date)
    let startOfMonth = calendar.dateFromComponents(components)!
    print(dateFormatter.stringFromDate(startOfMonth)) // 2015-11-01
    

    To get the last day of the month, add one month and subtract one day:

    let comps2 = NSDateComponents()
    comps2.month = 1
    comps2.day = -1
    let endOfMonth = calendar.dateByAddingComponents(comps2, toDate: startOfMonth, options: [])!
    print(dateFormatter.stringFromDate(endOfMonth)) // 2015-11-30
    

    Alternatively, use the rangeOfUnit method which gives you the start and the length of the month:

    var startOfMonth : NSDate?
    var lengthOfMonth : NSTimeInterval = 0
    calendar.rangeOfUnit(.Month, startDate: &startOfMonth, interval: &lengthOfMonth, forDate: date)
    

    For a date on the last day of month, add the length of the month minus one second:

    let endOfMonth = startOfMonth!.dateByAddingTimeInterval(lengthOfMonth - 1)
    

    Updated for Swift5:

    extension Date {
        var startOfDay: Date {
            return Calendar.current.startOfDay(for: self)
        }
    
        var startOfMonth: Date {
    
            let calendar = Calendar(identifier: .gregorian)
            let components = calendar.dateComponents([.year, .month], from: self)
    
            return  calendar.date(from: components)!
        }
    
        var endOfDay: Date {
            var components = DateComponents()
            components.day = 1
            components.second = -1
            return Calendar.current.date(byAdding: components, to: startOfDay)!
        }
    
        var endOfMonth: Date {
            var components = DateComponents()
            components.month = 1
            components.second = -1
            return Calendar(identifier: .gregorian).date(byAdding: components, to: startOfMonth)!
        }
    
        func isMonday() -> Bool {
            let calendar = Calendar(identifier: .gregorian)
            let components = calendar.dateComponents([.weekday], from: self)
            return components.weekday == 2
        }
    }