Search code examples
swiftdatensdateformatternscalendar

Working out the start and end of a day. Swift


I have a function to work out the start and end of a week which works as expected. I want to implement another function which works out the start and end of a single day. I have the code below however I get the following error:

Type of expression is ambiguous without more context.

public class Date {
    let dateFormatter = NSDateFormatter()
    let date = NSDate()
    let calendar = NSCalendar.currentCalendar()

    func calcStartAndEndDateForWeek(durationOccurance: Double) {
        print("Calculating start and end for week")
        let componentsWeek = calendar.components([.YearForWeekOfYear, .WeekOfYear], fromDate: date)
        let startOfWeek = calendar.dateFromComponents(componentsWeek)!

        print("start of Week = \(dateFormatter.stringFromDate(startOfWeek))")

        let componentsWeekEnds = NSDateComponents()
        componentsWeekEnds.weekOfYear = 1
        let endOfWeek = calendar.dateByAddingComponents(componentsWeekEnds, toDate: startOfWeek, options: [])!

        print("End of the week = \(dateFormatter.stringFromDate(endOfWeek))")
    }


    func calcStartAndEndDateForDay(durationOccurance: Double) {
        print("Calculating start and end for day")
        let componentsWeek = calendar.components([.Minutes, .Seconds], fromDate: date)
        let startOfDay = calendar.dateFromComponents(componentsWeek)!
        print("start day = \(dateFormatter.stringFromDate(startOfDay))")
    }

    init(){
        dateFormatter.dateFormat = "dd-MM-yyyy"
        }
   }

Solution

  • We can create a more generic function using the methods on NSCalendar:

    func rangeOfPeriod(period: NSCalendarUnit, date: NSDate) -> (NSDate, NSDate) {
        let calendar = NSCalendar.currentCalendar()    
        var startDate: NSDate? = nil
    
        // let's ask calendar for the start of the period
        calendar.rangeOfUnit(period, startDate: &startDate, interval: nil, forDate: date)
    
        // end of this period is the start of the next period
        let endDate = calendar.dateByAddingUnit(period, value: 1, toDate: startDate!, options: [])
    
        // you can subtract 1 second if you want to make "Feb 1 00:00:00" into "Jan 31 23:59:59"
        // let endDate2 = calendar.dateByAddingUnit(.Second, value: -1, toDate: endDate!, options: [])
    
        return (startDate!, endDate!)
    }
    

    Called as

     print("\(rangeOfPeriod(.WeekOfYear, date: NSDate()))")
     print("\(rangeOfPeriod(.Day, date: NSDate()))")
    

    Putting it into your code:

    public class Date {
        let dateFormatter = NSDateFormatter()
        let date = NSDate()
        let calendar = NSCalendar.currentCalendar()
    
        func rangeOfPeriod(period: NSCalendarUnit) -> (NSDate, NSDate) {
            var startDate: NSDate? = nil
    
            calendar.rangeOfUnit(period, startDate: &startDate, interval: nil, forDate: date)
    
            let endDate = calendar.dateByAddingUnit(period, value: 1, toDate: startDate!, options: [])
    
            return (startDate!, endDate!)
        }
    
        func calcStartAndEndDateForWeek() {
            let (startOfWeek, endOfWeek) = rangeOfPeriod(.WeekOfYear)
    
            print("Start of week = \(dateFormatter.stringFromDate(startOfWeek))")
            print("End of the week = \(dateFormatter.stringFromDate(endOfWeek))")
        }
    
    
        func calcStartAndEndDateForDay() {
            let (startOfDay, endOfDay) = rangeOfPeriod(.Day)
    
            print("Start of day = \(dateFormatter.stringFromDate(startOfDay))")
            print("End of the day = \(dateFormatter.stringFromDate(endOfDay))")
        }
    
        init() {
            dateFormatter.dateFormat = "dd-MM-yyyy"
        }
    }
    
    let myDate = Date()
    myDate.calcStartAndEndDateForWeek()
    myDate.calcStartAndEndDateForDay()