HDaniel999
HDaniel999

Reputation: 27

Swift CountDown Days Until from Date Picker

I have been struggling making a countdown in Swift where it shows only the days left until some date where the input is the DatePicker... I have creo experience with Swift so, I have been struggling for a while. I tried some similar answers here but didn't work, I watched a tutorial but is a normal countdown with months, days, minutes and seconds, this is the code.

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var timeLabel: UILabel!

let formatter = DateFormatter()
let userCleander = Calendar.current;
let requestedComponent : Set<Calendar.Component> = [
    Calendar.Component.month,
    Calendar.Component.day
]

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(timePrinter), userInfo: nil, repeats: true)

    timer.fire()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func timeCalculator(dateFormat: String, endTime: String, startTime: Date = Date()) -> DateComponents {
    formatter.dateFormat = dateFormat
    let _startTime = startTime
    let _endTime = formatter.date(from: endTime)

    let timeDifference = userCleander.dateComponents(requestedComponent, from: _startTime, to: _endTime!)
    return timeDifference
}

func timePrinter() -> Void {
    let time = timeCalculator(dateFormat: "MM/dd/yyyy a", endTime: "12/25/2018 a")
    timeLabel.text = "\(time.month!) Months \(time.day!) Days"
}

}

Upvotes: 0

Views: 1030

Answers (1)

Duncan C
Duncan C

Reputation: 131408

Several things: Don't use strings to compare dates. Use Date objects and Calendar operations. (More on that in a second.)

Don't run a timer once a second. Save the current date to user defaults. When your app is launched, compare the saved date to the current date and see if the day has changed.

When running, listen for UIApplicationSignificantTimeChange notifications, and when you get one, check to see if the date has changed.

As for comparing the current date to the user-selected date, you've got the right idea using dateComponents(_:from:to:), but you should pass in components of just [.day].

EDIT:

Code like this would do the trick:

override func viewDidLoad() {
    super.viewDidLoad()
    //Set up the date picker to pick dates, not dates & times
    datePicker.datePickerMode =  .date
    
    //Force the date picker to use midnight today as it's base date and
    //to pick a date at least 1 day in the future
    guard let today = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: Date()),
        let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: today)
        else {
            return
    }
    datePicker.minimumDate = tomorrow
    datePicker.date = tomorrow
}

@IBAction func datePickerChanged(_ sender: UIDatePicker) {
    let future = datePicker.date
    //Use midnight today as the starting date
    guard let today = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: Date()) else { return }
    
    //Calculate the number of days between today and the user's chosen day.
    let difference = Calendar.current.dateComponents([.day], from: today, to: future)
    guard let days = difference.day else { return }
    let ess = days > 1 ? "s" : ""
    infoLabel.text = "That date is \(days) day\(ess) away."
}

Upvotes: 1

Related Questions