Working out the start and end of a day. Swift

蓝咒 提交于 2019-12-08 06:04:01

问题


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"
        }
   }

回答1:


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()



回答2:


I was implementing something similar and went the following route:

extension Date {
    static var startOfToday: Date? {
        let date = Date()
        guard !date.isStartOfDay else { return date }
        return date
            .zero(out: .second)?
            .zero(out: .minute)?
            .zero(out: .hour)?
            .addingTimeInterval(-24 * 60 * 60)
    }

    private func zero(out: Calendar.Component) -> Date? {
        return Calendar.current
            .date(bySetting: out, value: 0, of: self)
    }

    private var isStartOfDay: Bool {
        let cal = Calendar.current
        let hours = cal.component(.hour, from: self)
        let minutes = cal.component(.minute, from: self)
        let seconds = cal.component(.second, from: self)
        return hours == 0 && minutes == 0 && seconds == 0
    }
}

Setting a component to zero will increment the next bigger component. So just setting the hour to zero will push the date to the next day at 00:00, unless of course the hour is already at zero. So to make it work for any date we have to zero out the seconds, minutes and hours (in that order). And to make sure we don't end up at the beginning of yesterday we first check if all values aren't already at zero.

I realize this is kinda hacky and probably not the best way to go about this, but it seems to work well enough for my use-case at least.

Getting the end of the day can be built on top of this by just adding another day.



来源:https://stackoverflow.com/questions/35943023/working-out-the-start-and-end-of-a-day-swift

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