disabling past days in fscalendar

2019-08-27 04:31发布

问题:

I'm using fscalender and am disabling user's selected days like this:

        func getUserSelectedDates(_ arrWeekDay: [Int], calender calenderVW: FSCalendar?) -> NSMutableArray {
    let arrUnAvailibilityDates = NSMutableArray()
    let currentDate: Date? = calenderVW?.currentPage
    //get calender
    let gregorianCalendar = Calendar.init(identifier: .gregorian)
    // Start out by getting just the year, month and day components of the current date.
    var components: DateComponents? = nil
    if let aDate = currentDate {
        components = gregorianCalendar.dateComponents([.year, .month, .day, .weekday], from: aDate)
        print(aDate)

    }
    // Change the Day component to 1 (for the first day of the month), and zero out the time components.
    components?.day = 1
    components?.hour = 0
    components?.minute = 0
    components?.second = 0
    //get first day of current month
    var firstDateOfCurMonth: Date? = nil
    if let aComponents = components {
        firstDateOfCurMonth = gregorianCalendar.date(from: aComponents)
    }
    //create new component to get weekday of first date
    var newcomponents: DateComponents? = nil
    if let aMonth = firstDateOfCurMonth {
        newcomponents = gregorianCalendar.dateComponents([.year, .month, .day, .weekday], from: aMonth)
    }
    let firstDateWeekDay: Int? = newcomponents?.weekday
    //get last month date
    let curMonth: Int? = newcomponents?.month
    newcomponents?.month = (curMonth ?? 0) + 1
    var templastDateOfCurMonth: Date? = nil
    if let aNewcomponents = newcomponents {
        templastDateOfCurMonth = gregorianCalendar.date(from: aNewcomponents)?.addingTimeInterval(-1)
    }
    // One second before the start of next month
    var lastcomponents: DateComponents? = nil
    if let aMonth = templastDateOfCurMonth {
        lastcomponents = gregorianCalendar.dateComponents([.year, .month, .day, .weekday], from: aMonth)
    }
    lastcomponents?.hour = 0
    lastcomponents?.minute = 0
    lastcomponents?.second = 0
    var lastDateOfCurMonth: Date? = nil
    if let aLastcomponents = lastcomponents {
        lastDateOfCurMonth = gregorianCalendar.date(from: aLastcomponents)
    }
    var dayDifference = DateComponents()
    dayDifference.calendar = gregorianCalendar

    if arrWeekDay.count == 0 {

    } else if arrWeekDay.count == 1 {
        let wantedWeekDay = Int(arrWeekDay[0])
        var firstWeekDateOfCurMonth: Date? = nil
        if wantedWeekDay == firstDateWeekDay {
            firstWeekDateOfCurMonth = firstDateOfCurMonth
        } else {
            var day: Int = wantedWeekDay - firstDateWeekDay!
            if day < 0 {
                day += 7
            }
            day += 1
            components?.day = day
            firstWeekDateOfCurMonth = gregorianCalendar.date(from: components!)
        }
        var weekOffset: Int = 0
        var nextDate: Date? = firstWeekDateOfCurMonth
        repeat {
            let strDT: String = getSmallFormatedDate(convertCalendarDate(toNormalDate: nextDate))!
            arrUnAvailibilityDates.add(strDT)
            weekOffset += 1
            dayDifference.weekOfYear = weekOffset
            var date: Date? = nil
            if let aMonth = firstWeekDateOfCurMonth {
                date = gregorianCalendar.date(byAdding: dayDifference, to: aMonth)
            }
            nextDate = date
        } while nextDate?.compare(lastDateOfCurMonth!) == .orderedAscending || nextDate?.compare(lastDateOfCurMonth!) == .orderedSame
    }
    else {
        for i in 0..<arrWeekDay.count {
            let wantedWeekDay = Int(arrWeekDay[i])
            var firstWeekDateOfCurMonth: Date? = nil
            if wantedWeekDay == firstDateWeekDay {
                firstWeekDateOfCurMonth = firstDateOfCurMonth
            } else {
                var day: Int = wantedWeekDay - firstDateWeekDay!
                if day < 0 {
                    day += 7
                }
                day += 1
                components?.day = day
                firstWeekDateOfCurMonth = gregorianCalendar.date(from: components!)
            }


            var weekOffset: Int = 0
            var nextDate: Date? = firstWeekDateOfCurMonth
            repeat {
                let strDT = getSmallFormatedDate(convertCalendarDate(toNormalDate: nextDate))
                arrUnAvailibilityDates.add(strDT!)
                weekOffset += 1
                dayDifference.weekOfYear = weekOffset
                var date: Date? = nil
                if let aMonth = firstWeekDateOfCurMonth {
                    date = gregorianCalendar.date(byAdding: dayDifference, to: aMonth)
                }
                nextDate = date
            } while nextDate?.compare(lastDateOfCurMonth!) == .orderedAscending || nextDate?.compare(lastDateOfCurMonth!) == .orderedSame
        }
    }
    return arrUnAvailibilityDates
}


func getSmallFormatedDate(_ localDate: Date?) -> String? {
    let dateFormatter = DateFormatter()
    let timeZone = NSTimeZone(name: "UTC")
    if let aZone = timeZone {
        dateFormatter.timeZone = aZone as TimeZone
    }
    dateFormatter.dateFormat = "yyyy-MM-dd"
    var dateString: String? = nil
    if let aDate = localDate {
        dateString = dateFormatter.string(from: aDate)
    }
    return dateString
}

func convertCalendarDate(toNormalDate selectedDate: Date?) -> Date? {
    let sourceTimeZone = NSTimeZone(abbreviation: "UTC")
    let destinationTimeZone = NSTimeZone.system as NSTimeZone
    var sourceGMTOffset: Int? = nil
    if let aDate = selectedDate {
        sourceGMTOffset = sourceTimeZone?.secondsFromGMT(for: aDate)
    }
    var destinationGMTOffset: Int? = nil
    if let aDate = selectedDate {
        destinationGMTOffset = destinationTimeZone.secondsFromGMT(for: aDate)
    }
    let interval1 = TimeInterval((destinationGMTOffset ?? 0) - (sourceGMTOffset ?? 0))
    var localDate: Date? = nil
    if let aDate = selectedDate {
        localDate = Date(timeInterval: interval1, since: aDate)
    }
    return localDate
}
   extension CalenderViewController: FSCalendarDelegate, FSCalendarDataSource, FSCalendarDelegateAppearance {
func calendar(_ calendar: FSCalendar, boundingRectWillChange bounds: CGRect, animated: Bool) {
    self.view.layoutIfNeeded()
}

func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
    self.date = dateFormatter2.string(from: date)
}

func calendarCurrentPageDidChange(_ calendar: FSCalendar) {
    arrDates = self.getUserSelectedDates(days, calender: self.calendar)
    calendar.reloadData()
}

func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, titleDefaultColorFor date: Date) -> UIColor? {
    if arrDates.contains(dateFormatter2.string(from: date)) {
        return UIColor.darkGray
    } else {
        return UIColor.lightGray
    }
}

func calendar(_ calendar: FSCalendar, shouldSelect date: Date, at monthPosition: FSCalendarMonthPosition) -> Bool {

    if arrDates.contains(dateFormatter2.string(from: date))) {
        return true
    }
    else {
        return false
    }
}

}

which is working perfectly .. now am trying to disable past days in fscalender .. i have tried this:

 func calendar(_ calendar: FSCalendar, shouldSelect date: Date, at monthPosition: FSCalendarMonthPosition) -> Bool {

    if arrDates.contains(dateFormatter2.string(from: date)) && (date > calendar.currentPage) {
        return true
    }
    else {
        return false
    }
}

but it didn't work for me...

also i noticed that the current date is wrong! i keep getting

2018-04-30 21:00:00 +0000

while today's date is 2018-05-12

how to solve this and disable past days?

回答1:

You just need to compare selected date with current date. If it's Ascending than return false otherwise return true in shouldSelect method like below.

Try only 1 solution.

1. SOLUTION (It display previous month while you swipe to see previous month, This solution consider current date as past date because there's time difference)

func calendar(_ calendar: FSCalendar, shouldSelect date: Date, at monthPosition: FSCalendarMonthPosition) -> Bool {
    if date .compare(Date()) == .orderedAscending {
        return false
    }
    else {
        return true
    }
}

2. SOLUTION (This will not display Past Months, In This solution you can also select current date)

func minimumDate(for calendar: FSCalendar) -> Date {
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
    let myString = formatter.string(from: Date())
    let yourDate = formatter.date(from: myString)
    formatter.dateFormat = "yyyy-MM-dd"
    let strCurrentDate = formatter.string(from: yourDate!)
    return self.dateFormatter2.date(from: strCurrentDate)!
}