Spyke
Spyke

Reputation: 21

How to calculate days, hours, minutes from now to certain date in swift

Calculate the number of days, hours, minutes and seconds to another date in swift.

I have already tried using swifts datecomponents to and from function but it is returning the incorrect amount of days for me.

@objc func createCountdown(){
    let date = Date()
    let calendar = Calendar.current

    let components = calendar.dateComponents([.day, .hour, .minute, .second], from: date)

    let currentDate = calendar.date(from: components)

    let userCalendar = Calendar.current

    var birthdayDate = DateComponents()
    //Get user's birthday
    birthdayDate.month = 4
    birthdayDate.day = 16
    birthdayDate.hour = 0
    birthdayDate.minute = 0


    let birthday = userCalendar.date(from: birthdayDate as DateComponents)


    let BirthdayDifference = calendar.dateComponents([.day, .hour, .minute, .second], from: currentDate!, to: birthday!)

    let daysLeft = BirthdayDifference.day
    let hoursLeft = BirthdayDifference.hour
    let minutesLeft = BirthdayDifference.minute
    let secondsLeft = BirthdayDifference.second

    daysLabel.text = String(daysLeft!)
    hoursLabel.text = String(hoursLeft!)
    minutesLabel.text = String(minutesLeft!)
    secondsLabel.text = String(secondsLeft!)
}

The test date in the code is the birthday values. I'm simply trying to make a day, hour, minute, and second countdown to the specified birthday from the current date.

The output for this is 74 days, but obviously it is more than 74 days from today, 12/31/2018 to april 16th, 4/16/2019. That is around 105 days, not 74. Any advice is greatly appreciated.

Thank you.

Upvotes: 2

Views: 2806

Answers (1)

Leo Dabus
Leo Dabus

Reputation: 236315

You need to find out when is the next birth date based on the day and month of birthday. You can use Calendar's method nextDate(after: Date, matching: DateComponents)

func nextDate(after date: Date, matching components: DateComponents, matchingPolicy: Calendar.MatchingPolicy, repeatedTimePolicy: Calendar.RepeatedTimePolicy = default, direction: Calendar.SearchDirection = default) -> Date?

let birthDateCoponents = DateComponents(month: 4, day: 16)
let nextBirthDate = Calendar.current.nextDate(after: Date(), matching: birthDateCoponents, matchingPolicy: .nextTime)!

let difference = Calendar.current.dateComponents([.day, .hour, .minute, .second], from: Date(), to: nextBirthDate)

difference.day     // 105
difference.hour    // 2
difference.minute  // 5
difference.second  // 30

When displaying it to the user you can use DateComponentsFormatter with the appropriate unitsStyle. You can see below how it would look like when using .full style and limiting the units to .day, .hour, .minute, .second:

let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.day, .hour, .minute, .second]

formatter.unitsStyle = .full
formatter.string(from: Date(), to: nextBirthDate)  // "105 days, 1 hour, 44 minutes, 36 seconds"

Upvotes: 4

Related Questions