Days between 2 NSDates in a calendar year swift - ios

I'm building a birthday reminder app. I want the user to be able to see how many days it is until somebody's next birthday.
Let's say I have an NSDate() = 2015-06-30 07:21:47 +0000
And the NSDate for the birthday = 1985-08-29 12:00:00 +0000
How would I get the number of days until the next birthday? I've used something like this which gives a negative number of days since the date's actual beginning (which are in the thousands with birthdates). Then with that I would add 365 to the numerical difference until it was positive but it still returns a wonky number. I'm assuming due to leap years or something.
Is there a method to this I can implement? Somehow equalize the year components so that it's always comparing from the next birthday and not the original birthdate?
Edit:
Here is the function I am using:
func daysBetween(date1: NSDate, date2: NSDate) -> Int {
var calendar: NSCalendar = NSCalendar.currentCalendar()
let date1 = calendar.startOfDayForDate(date1)
let date2 = calendar.startOfDayForDate(date2)
let flags = NSCalendarUnit.CalendarUnitDay
let components = calendar.components(flags, fromDate: date1, toDate: date2, options: nil)
return components.day
}
With the example dates I posted I would use it like this:
// sampleDate = 1985-08-29 12:00:00 +0000
daysBetween(sampleDate, date2: NSDate())
// --> 10897
Whether positive or negative, the number is in the thousands. I'm looking to equalize that into number of days to the next calendar birthday.

What you need is to compute the next occurrence of the (day and month
component of the) birthday after today:
let cal = NSCalendar.currentCalendar()
let today = cal.startOfDayForDate(NSDate())
let dayAndMonth = cal.components(.CalendarUnitDay | .CalendarUnitMonth,
fromDate: birthday)
let nextBirthDay = cal.nextDateAfterDate(today,
matchingComponents: dayAndMonth,
options: .MatchNextTimePreservingSmallerUnits)!
Remarks:
The purpose of the MatchNextTimePreservingSmallerUnits option is
that if the birthday is on February 29 (in the Gregorian calendar), its next occurrence will be
computed as March 1 if the year is not a leap year.
You might need to check first if the birthday is today, as it seems
that nextDateAfterDate() would return the next birthday in that case.
Then you can compute the difference in days as usual:
let diff = cal.components(.CalendarUnitDay,
fromDate: today,
toDate: nextBirthDay,
options: nil)
println(diff.day)
Update for Swift 2.2 (Xcode 7.3):
let cal = NSCalendar.currentCalendar()
let today = cal.startOfDayForDate(NSDate())
let dayAndMonth = cal.components([.Day, .Month],
fromDate: birthday)
let nextBirthDay = cal.nextDateAfterDate(today,
matchingComponents: dayAndMonth,
options: .MatchNextTimePreservingSmallerUnits)!
let diff = cal.components(.Day,
fromDate: today,
toDate: nextBirthDay,
options: [])
print(diff.day)
Update for Swift 3 (Xcode 8 GM):
let cal = Calendar.current
let today = cal.startOfDay(for: Date())
let dayAndMonth = cal.dateComponents([.day, .month], from: birthday)
let nextBirthDay = cal.nextDate(after: today, matching: dayAndMonth,
matchingPolicy: .nextTimePreservingSmallerComponents)!
let diff = cal.dateComponents([.day], from: today, to: nextBirthDay)
print(diff.day!)

Btw, in case anyone needs here is the #Aaron function in Swift 3:
func daysBetween(date1: Date, date2: Date) -> Int {
let calendar = Calendar.current
let date1 = calendar.startOfDay(for: date1)
let date2 = calendar.startOfDay(for: date2)
let components = calendar.dateComponents([Calendar.Component.day], from: date1, to: date2)
return components.day ?? 0
}

Related

How to get the number of days of current/last year

I want to find out the number of days from current and last year. I have managed to come up with this code which will give me a starting and ending date.
Then I use NSDateComponents to get the number of days for this current year. But what I get is 365, which means is the number of days from last year.
How can I corectly get the number of days for last and current year ?
func numOfDaysInYear() {
let calendar = NSCalendar.currentCalendar()
var interval = NSTimeInterval(0)
var startOfYear: NSDate?
var endOfYear: NSDate!
calendar.rangeOfUnit(.Year, startDate: &startOfYear, interval: &interval, forDate: NSDate())
endOfYear = startOfYear?.dateByAddingTimeInterval(interval - 1)
let comp = calendar.components(.Day, fromDate: startOfYear!, toDate: endOfYear, options: .MatchFirst)
print(comp.day)
}
endOfYear = startOfYear?.dateByAddingTimeInterval(interval - 1)
gives a date within the current year, and its difference to
startOfYear is 365 days, 23 hours and 59 seconds, and therefore the result is 365.
What you want is
let startOfNextYear = startOfYear!.dateByAddingTimeInterval(interval)
let comp = calendar.components(.Day, fromDate: startOfYear!, toDate: startOfNextYear, options: .MatchFirst)
print(comp.day)
which gives the correct output 366 for the leap year 2016.
To get results for the previous year, just replace the current data
NSDate() by a date "one year ago":
calendar.dateByAddingUnit(.Year, value: -1, toDate: NSDate(), options: [])
Alternative approach
let calendar = NSCalendar.currentCalendar()
let components = NSDateComponents()
components.day = 1
components.month = 1
let nextFirstJanuar = calendar.nextDateAfterDate(NSDate(), matchingComponents: components, options: .MatchNextTime)!
let thisFirstJanuar = calendar.nextDateAfterDate(nextFirstJanuar, matchingComponents: components, options: [.MatchNextTime, .SearchBackwards])!
let lastFirstJanuar = calendar.nextDateAfterDate(thisFirstJanuar, matchingComponents: components, options: [.MatchNextTime, .SearchBackwards])!
let daysInThisYear = calendar.components(.Day, fromDate: thisFirstJanuar, toDate: nextFirstJanuar, options: []).day
let daysInLastYear = calendar.components(.Day, fromDate: lastFirstJanuar, toDate: thisFirstJanuar, options: []).day

How to calculate the number of days in the current month/year

Is there any methods available for NSDate/NSCalendar to calculate the number of days in the current month and current year ?
The only thing I saw is to get the number of days from a given date or between two dates.
Is this the only way ?
Here is a method which works for both months and years:
let calendar = NSCalendar.currentCalendar()
let date = NSDate()
// Calculate start and end of the current year (or month with `.Month`):
var startOfInterval : NSDate?
var lengthOfInterval = NSTimeInterval()
calendar.rangeOfUnit(.Year, startDate: &startOfInterval, interval: &lengthOfInterval, forDate: date)
let endOfInterval = startOfInterval!.dateByAddingTimeInterval(lengthOfInterval)
// Compute difference in days:
let days = calendar.components(.Day, fromDate: startOfInterval!, toDate: endOfInterval, options: [])
print(days)
(You may want to add some error checking instead of forcibly unwrapping
optionals.)
Update for Swift 3:
let calendar = Calendar.current
let date = Date()
// Calculate start and end of the current year (or month with `.month`):
let interval = calendar.dateInterval(of: .year, for: date)!
// Compute difference in days:
let days = calendar.dateComponents([.day], from: interval.start, to: interval.end).day!
print(days)
let date = NSDate()
let cal = NSCalendar(calendarIdentifier:NSCalendarIdentifierGregorian)!
let days = cal.rangeOfUnit(.Day, inUnit: .Month, forDate: date)
print("\(days) in the month of \(date)")

Calculate duration between date ios in Years, months and date format

Im new at swift programming and i havent been able successfully find code to find difference between two dates in terms of years , months and days.
I tried the following code but it didnt work
let form = NSDateComponentsFormatter()
form.maximumUnitCount = 2
form.unitsStyle = .Full
let s = form.stringFromTimeInterval( date2.timeIntervalSinceReferenceDate - date1.timeIntervalSinceReferenceDate)
Input
Date1 = "12/March/2015"
Date2 = "1/June/2015"
Output : x years y months z days
Please advice
We can use this function in Swift 2.0
func yearsBetweenDate(startDate: NSDate, endDate: NSDate) -> Int
{
let calendar = NSCalendar.currentCalendar()
let components = calendar.components([.Year], fromDate: startDate, toDate: endDate, options: [])
return components.year
}
You can return anything like I returned year in this function. This will return number of years between the two dates.
You can just write months,days etc in order to find the difference between the two dates in months and days respectively.
Edit
Swift 3.0 and Above
func yearsBetweenDate(startDate: Date, endDate: Date) -> Int {
let calendar = Calendar.current
let components = calendar.dateComponents([.year], from: startDate, to: endDate)
return components.year!
}
If you need the difference (in years, months, days) numerically then
compute NSDateComponents as in Swift days between two NSDates or Rajan's answer.
If you need the difference as a (localized) string to present it to the user,
then use NSDateComponentsFormatter like this
let form = NSDateComponentsFormatter()
form.maximumUnitCount = 2
form.unitsStyle = .Full
form.allowedUnits = [.Year, .Month, .Day]
let s = form.stringFromDate(date1, toDate: date2)
As already mentioned in the comments, computing the difference
from the pure time interval between the dates cannot give correct
results because most information about the dates is lost.
Update for Swift 3:
let form = DateComponentsFormatter()
form.maximumUnitCount = 2
form.unitsStyle = .full
form.allowedUnits = [.year, .month, .day]
let s = form.string(from: date1, to: date2)
With Swift 5 and iOS 12, you can use one of the 3 solutions below in order to calculate the difference (in years, months, days) between two dates.
#1. Using Calendar's dateComponents(_:from:to:) method
Calendar has a method called dateComponents(_:from:to:). dateComponents(_:from:to:) has the following declaration:
func dateComponents(_ components: Set<Calendar.Component>, from start: DateComponents, to end: DateComponents) -> DateComponents
Returns the difference between two dates specified as DateComponents.
The Playground example below show how to use dateComponents(_:from:to:) in order to compute the difference between two dates:
import Foundation
let calendar = Calendar.current
let startComponents = DateComponents(year: 2010, month: 11, day: 22)
let endComponents = DateComponents(year: 2015, month: 5, day: 1)
let dateComponents = calendar.dateComponents([.year, .month, .day], from: startComponents, to: endComponents)
print(dateComponents) // prints: year: 4 month: 5 day: 9 isLeapMonth: false
#2. Using Calendar's dateComponents(_:from:to:) method
Calendar has a method called dateComponents(_:from:to:). dateComponents(_:from:to:) has the following declaration:
func dateComponents(_ components: Set<Calendar.Component>, from start: Date, to end: Date) -> DateComponents
Returns the difference between two dates.
The Playground example below show how to use dateComponents(_:from:to:) in order to compute the difference between two dates:
import Foundation
let calendar = Calendar.current
let startDate = calendar.date(from: DateComponents(year: 2010, month: 11, day: 22))!
let endDate = calendar.date(from: DateComponents(year: 2015, month: 5, day: 1))!
let dateComponents = calendar.dateComponents([.year, .month, .day], from: startDate, to: endDate)
print(dateComponents) // prints: year: 4 month: 5 day: 9 isLeapMonth: false
#3. Using DateComponentsFormatter's string(from:to:) method
DateComponentsFormatter has a method called string(from:to:). string(from:to:) has the following declaration:
func string(from startDate: Date, to endDate: Date) -> String?
Returns a formatted string based on the time difference between two dates.
The Playground example below show how to use string(from:to:) in order to compute the difference between two dates:
import Foundation
let calendar = Calendar.current
let startDate = calendar.date(from: DateComponents(year: 2010, month: 11, day: 22))!
let endDate = calendar.date(from: DateComponents(year: 2015, month: 5, day: 1))!
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
formatter.allowedUnits = [.year, .month, .day]
let string = formatter.string(from: startDate, to: endDate)!
print(string) // prints: 4 years, 5 months, 9 days
Try this one
func calculateDiffInTwoDate (date1: NSDate, date2: NSDate) -> NSInteger {
//var userAge : NSInteger = 0
let calendar : NSCalendar = NSCalendar.currentCalendar()
let unitFlags : NSCalendarUnit = [ .Year , .Month, .Day]
let dateComponentNow : NSDateComponents = calendar.components(unitFlags, fromDate: date2)
let dateComponentBirth : NSDateComponents = calendar.components(unitFlags, fromDate: date1)
if ( (dateComponentNow.month < dateComponentBirth.month) ||
((dateComponentNow.month == dateComponentBirth.month) && (dateComponentNow.day < dateComponentBirth.day))
)
{
return dateComponentNow.year - dateComponentBirth.year - 1
}
else {
return dateComponentNow.year - dateComponentBirth.year
}
}
By This you can get diff between two dates in Years
Why don't you use the inbuild method to find the difference between 2 dates in seconds, and then write a method to convert seconds in terms of years, months and days.
let diff = date1.timeIntervalSinceDate(date2)
//Assigning Dates
let StartDate = datePicker.date
let currentDate = Date()
//Finding Difference of Dates
let components = Set<Calendar.Component>([.day, .month, .year])
let differenceOfDate = Calendar.current.dateComponents(components, from:
StartDate, to: currentDate)
Print(differenceOfDate)

Swift Datepicker with minimum date

Goord Morning all together,
i have an app with ios 8 and swift.
in there is a UIViewcontroller within a UIDatepicker
I set a minimum date. for example the date of today: 2 | May | 2015
with this solution it should not be possible to set a date which is in the past
but if would like to set this date 15 | January | 2016
i set at first the day to 15
than the month to january but then the UIDatepicker goes back to the minimum date 2 May 2015
is it be possible, that wenn change the day to 15 and the month to january, that the year changes automaticly to 2016?
Let your minimumDate unset and try to configure it by code...
Try this:
#IBAction func changeValue(sender: UIDatePicker)
{
//Get time Now, and convert to a NSCalendar
//Specify the minimun date if you want.
let now = NSDate()
let nowCalendar = NSCalendar.currentCalendar()
let nowComponents = nowCalendar.components([.Day, .Month, .Year], fromDate: now)
//Compare if date is lesser than now and then create a new date
if nowCalendar.compareDate(sender.date, toDate: now, toUnitGranularity: [.Day, .Month, .Year]) == NSComparisonResult.OrderedAscending
{
let dateCalendar = NSCalendar.currentCalendar()
let dateComponents = dateCalendar.components([.Day, .Month, .Year], fromDate: sender.date)
dateComponents.year = nowComponents.year + 1
let newDate = dateCalendar.dateFromComponents(dateComponents)
sender.date = newDate!
}
}
///Swift4 Version - I think it may works with 3 too.
#IBAction func changeValue(sender: UIDatePicker)
{
//Get time Now, and convert to a NSCalendar
//Specify the minimun date if you want.
let now = Date()
let nowCalendar = Calendar.current
let nowComponents = nowCalendar.dateComponents([.day, .month, .year], from: now)
//Compare if date is lesser than now and then create a new date
if nowCalendar.compare(sender.date, to: now, toGranularity: Calendar.Component.day) == ComparisonResult.orderedAscending
{
var dateCalendar = Calendar.current
var dateComponents = dateCalendar.dateComponents([.day, .month, .year], from: sender.date)
guard let year = nowComponents.year else { return }
dateComponents.year = year + 1
let newDate = dateCalendar.date(from:dateComponents)
sender.date = newDate!
}
}
I published a complete example working in playground if you wish to play a little.
https://gist.github.com/dedeexe/4878f78d7e1d5fe8b372ef84de629b59
For swift 4:
I have like this.
1. My function:
func AddDaysToToday(days: Int) -> Date? {
var dateComponents = DateComponents()
dateComponents.day = days
return Func.GetCalendar(tz: .utc).date(byAdding: dateComponents, to: Date()) //you can return your own Date here.
}
In my VC:
let today = DateFunc.AddDaysToToday(days: 0)
datePicker.minimumDate = today

How to get the hour of the day with Swift?

How would I get the hour of the day in Swift.
I have tried NSCalendar and NSDateComponents, but I'm afraid I'm just starting with Swift.
Swift 5.0 / 4.0 / 3.0
let hour = Calendar.current.component(.hour, from: Date())
Or, if you're interested in 12 hour AM/PM date format, then use NSDateFormatter
let formatter = DateFormatter()
formatter.dateFormat = "hh a" // "a" prints "pm" or "am"
let hourString = formatter.string(from: Date()) // "12 AM"
If you want minutes, seconds and others, do as following
let date = Date() // save date, so all components use the same date
let calendar = Calendar.current // or e.g. Calendar(identifier: .persian)
let hour = calendar.component(.hour, from: date)
let minute = calendar.component(.minute, from: date)
let second = calendar.component(.second, from: date)
Check out available components on Apple docs:
.era, .year, .month, .day, .hour, .minute, .second,
.weekday, .weekdayOrdinal, .quarter, weekOfMonth, .weekOfYear,
.yearForWeekOfYear, .nanosecond, .calendar, .timezone
Swift 2.0
let hour = NSCalendar.currentCalendar().component(.Hour, fromDate: NSDate())
Swift 1.0
let hour = NSCalendar.currentCalendar().component(.CalendarUnitHour, fromDate: NSDate())
Swift 3:
let date = Date()// Aug 25, 2017, 11:55 AM
let calendar = Calendar.current
let hour = calendar.component(.hour, from: date) //11
let minute = calendar.component(.minute, from: date) //55
let sec = calendar.component(.second, from: date) //33
let weekDay = calendar.component(.weekday, from: date) //6 (Friday)
Get any of component available from the API below
public enum Component {
case era
case year
case month
case day
case hour
case minute
case second
case weekday
case weekdayOrdinal
case quarter
case weekOfMonth
case weekOfYear
case yearForWeekOfYear
case nanosecond
case calendar
case timeZone
}
Swift 2:
let currentHour = NSCalendar.currentCalendar().component(.Hour, fromDate: NSDate())
This could be enough :
let currentDate = NSDate() // You can input the custom as well
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitHour | .CalendarUnitMinute, fromDate: currentDate)
let currentHour = components.hour // You can play around with the ""components""
If you want the current hour in a String, this is as short and readable I could think of.
let formatter = NSDateFormatter()
formatter.dateFormat = "HH"
let timeString = formatter.stringFromDate(NSDate())
Finally I was able to find the easiest solution after struggling for a time
let dateComponents = NSCalendar.currentCalendar().components(NSCalendarUnit.HourCalendarUnit, fromDate: NSDate())
let nHourOfDay = dateComponents.hour
For Swift 2.0:
let hour = NSCalendar.currentCalendar().component(NSCalendarUnit.Hour, fromDate: NSDate())
Here is a reference example for how I do it (DateUtils.swift) -
Example Use:
let today = DateUtils.getToday();
let hr = DateUtils.getHours(today);
let min = DateUtils.getMinutes(today);
... (etc.) ...
DateUtils.swift:
//Field wrapper routines
class func getToday() -> Date { return Date(); }
class func getHours(_ date : Date) -> Int { return Calendar.current.component(.hour, from: date); }
class func getMinutes(_ date : Date) -> Int { return Calendar.current.component(.minute, from: date); }
... (continued for all fields, see file) ...
You can get the integer value of the current hour in one step like this:
let currentHour = NSCalendar.currentCalendar().components(.Hour, fromDate: NSDate()).hour

Resources