I'm trying to calculate the number of weeks and days that a pet is alive. I'm using SwiftDate for that. So I let the user select a birthdate and compare it to the current date.
I don't want to compare the time... so both the birthdate and current date should have the same time.
My code is:
let greg = Calendar(identifier: .gregorian)
var date1 = birthday // from datepicker
var date2 = Date()
var components1 = greg.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date1)
var components2 = greg.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date2)
components1.hour = 15
components1.minute = 0
components1.second = 0
components2.hour = 15
components2.minute = 0
components2.second = 0
date1 = greg.date(from: components1)!
date2 = greg.date(from: components2)!
let daysAlive = (date2 - date1).in(.day)
let weeksAlive = Int(weeksAlive! / 7)
let restDays = daysAlive! - (weeksAlive * 7)
let aLive = "Age: \(weeksAlive) wk, \(restDays) d (\(daysAlive!) d)"
Output is "Age: 28 wk, 3 d (199 d)"
The code works... but how can I refactor it? And is there an easier way to set the 'same time' for two given dates?
If you don't care about the time difference, why not just leave the time out completely? It would give you the same output, and would just save you from putting in default time values and then ignoring them for the rest of your function:
let greg = Calendar(identifier: .gregorian)
var date1 = birthday // from datepicker
var date2 = Date()
var components1 = greg.dateComponents([.year, .month, .day], from: date1)
var components2 = greg.dateComponents([.year, .month, .day], from: date2)
date1 = greg.date(from: components1)!
date2 = greg.date(from: components2)!
let daysAlive = (date2 - date1).in(.day)
let weeksAlive = Int(weeksAlive! / 7)
let restDays = daysAlive! - (weeksAlive * 7)
let aLive = "Age: \(weeksAlive) wk, \(restDays) d (\(daysAlive!) d)"
To ignore the time just omit the components for .hour
, .minute
and .second
let components1 = greg.dateComponents([.year, .month, .day], from: date1)
let components2 = greg.dateComponents([.year, .month, .day], from: date2)
date1 = greg.date(from: components1)!
date2 = greg.date(from: components2)!
This is a simpler solution without any third party library. It calculates the difference once for weekOfMonth
and day
and once for day
with the Calendar
method dateComponents(:from:to:
. Extra math is not needed.
let greg = Calendar(identifier: .gregorian)
var date1 = greg.date(from: DateComponents(year: 2017, month: 6, day: 25))!
var date2 = Date()
var components1 = greg.dateComponents([.year, .month, .day], from: date1)
var components2 = greg.dateComponents([.year, .month, .day], from: date2)
let weeksAndDays = greg.dateComponents([.weekOfMonth, .day], from: components1, to: components2)
let justDays = greg.dateComponents([.day], from: components1, to: components2)
let aLive = "Age: \(weeksAndDays.weekOfMonth!) wk, \(weeksAndDays.day!) d (\(justDays.day!) d)"
// "Age: 28 wk, 3 d (199 d)"
As others have pointed out, you can just grab .year
, .month
, .day
from your calendar. You might also see if DateComponentsFormatter
can achieve what you want:
let formatter: DateComponentsFormatter = {
let _formatter = DateComponentsFormatter()
_formatter.allowedUnits = [.day, .weekOfMonth]
_formatter.unitsStyle = .full
return _formatter
}()
@IBAction func didValueChange(_ picker: UIDatePicker) {
let calendar = Calendar.current
let birthDate = calendar.date(from: calendar.dateComponents([.year, .month, .day], from: picker.date))!
let now = calendar.date(from: calendar.dateComponents([.year, .month, .day], from: Date()))!
label.text = formatter.string(from: birthDate, to: now)
}
While the DateComponentsFormatter
is a little constrained regarding the results, it is localized, resulting in the following in US locale:
28 weeks, 3 days
But if your app is configured to support other locales, for example German, it results in:
28 Wochen und 3 Tage
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.