Search code examples
swifttimercountdown

How to have reoccurring countdown each year to a date in Swift


I am trying to incorporate a countdown to a holiday within my app in Swift and having trouble with the timer going into negative numbers once the date has passed. The countdown should reset after the date passing. What am I doing wrong?

var holidayDate: Date {
    let currentYear = Date()
    let userCalendar = Calendar.current
    var components = DateComponents()
    components.year = userCalendar.component(.year, from: currentYear)
    components.day = 02
    components.month = 11
    
    return userCalendar.date(from: components)!
}

var today: Date {
    let now = Date()
    let userCalendar = Calendar.current
    var components = DateComponents()
    components.year = userCalendar.component(.year, from: now)
    components.day = userCalendar.component(.day, from: now)
    components.month = userCalendar.component(.month, from: now)
    
    return userCalendar.date(from: components)!
}

func daysBetweenDates(startDate: Date, endDate: Date) -> Int {
    let calendar = Calendar.current
    let components = calendar.dateComponents([.day], from: startDate, to: endDate)
    return components.day!
}

Solution

  • You can simply use calendar nextDate method to get the next date matching components and pass the month and day components to it:

    func daysUntilNextDate(matching components: DateComponents) -> Int {
        let date = Date()
        guard let calendar = components.calendar,
              let nextDate = calendar.nextDate(after: date, matching: components, matchingPolicy: .strict) else { return .zero }
        return calendar.dateComponents([.day], from: date, to: nextDate).day!
    }
    

    let holiday: DateComponents = .init(calendar: .current, month: 11, day: 2)
    let christmas: DateComponents = .init(calendar: .current, month: 12, day: 25)
    

    daysUntilNextDate(matching: holiday)   // 363
    daysUntilNextDate(matching: christmas) // 51