Compare Current Date to DatePicker Value in Swift - ios

In my app a user can select whether or not they are under 18 or over 18 years of age. The user enters their Date of Birth using a Date Picker. I need to make a function that will compare the current date in MM/DD/YYYY format to the DatePicker date to see if the user's entered age is over 18.
My current function for setting the DatePicker text to the associated textfield is:
func updatePicker() {
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MM/dd/yyyy"
dob.text = dateFormatter.stringFromDate(datePickerView.date)
}
When the user tries to go the next page, the form is validated which is when I need to compare the dates and display the alert if they're under 18.
Just not sure where to start with date string evaluation.

Use this function to compare date
func compareDate(date1: NSDate!, toDate date2: NSDate!, toUnitGranularity unit: NSCalendarUnit) -> NSComparisonResult
see this question

You can use NSCalendar components method and extract NSCalendarUnit.CalendarUnitYear difference from two dates:
extension NSDate {
var is18yearsOld:Bool {
return NSDate().yearsFrom(self) > 18
}
func yearsFrom(date:NSDate) -> Int { return NSCalendar.currentCalendar().components(NSCalendarUnit.CalendarUnitYear, fromDate: date, toDate: self, options: nil).year }
}
let dob1 = NSCalendar.currentCalendar().dateWithEra(1, year: 1970, month: 3, day: 27, hour: 7, minute: 19, second: 26, nanosecond: 0)!
let dob2 = NSCalendar.currentCalendar().dateWithEra(1, year: 2000, month: 3, day: 27, hour: 7, minute: 19, second: 26, nanosecond: 0)!
let is18years1 = dob1.is18yearsOld // true
let is18years2 = dob2.is18yearsOld // false

don't convert the date to text and later convert the text to the date again.
just keep the date from the datePicker around till you need it for the validation.
have a member variable var selectedDate : NSDate?
then later to check if older than 18 just do
if let userDate=self.selectedDate {
if(NSDate().timeIntervalSinceDate(userDate) >= (568024668 /*18 years in seconds*/) {
.... /*is 18*/
}
}

Firstly, you have to get parts of date as Int type using Calendar component methods:
// Current date
let currentDate = Date()
let calendar = Calendar.current
let currentYear = calendar.component(.year, from: currentDate) //year: Int
let currentMonth = calendar.component(.month, from: currentDate) //month: Int
let currentDay = calendar.component(.day, from: currentDate) //day: Int
// DatePicker's date
let yearFromDatePicker = calendar.component(.year, from: datePicker.date) //year: Int
let monthFromDatePicker = calendar.component(.month, from: datePicker.date) //month: Int
let dayFromDatePicker = calendar.component(.day, from: datePicker.date) //day: Int
and then you can compare parts of the date with each other based on your conditions.

Related

What is reliable way, to calculate day differences without taking time into consideration?

May I know, what is reliable way, to calculate day differences without taking time into consideration?
A similar question is asked before. However, the highest voted and accepted answer isn't entirely accurate - https://stackoverflow.com/a/28163560/72437
The code is broken, when dealing with Day light saving case. You can run the following code in Playground
Use startOfDay (Broken)
import UIKit
struct LocalDate: Equatable {
let year: Int
let month: Int
let day: Int
}
struct LocalTime: Equatable, Codable {
let hour: Int
let minute: Int
}
extension Date {
var startOfDay: Date {
return Calendar.current.startOfDay(for: self)
}
static func of(localDate: LocalDate, localTime: LocalTime) -> Date {
var dateComponents = DateComponents()
dateComponents.year = localDate.year
dateComponents.month = localDate.month
dateComponents.day = localDate.day
dateComponents.hour = localTime.hour
dateComponents.minute = localTime.minute
dateComponents.second = 0
return Calendar.current.date(from: dateComponents)!
}
func adding(_ component: Calendar.Component, _ value: Int) -> Date {
return Calendar.current.date(byAdding: component, value: value, to: self)!
}
}
// During 22 March 2021, Tehran will advance by 1 hour from 00:00 AM, to 01:00 AM.
let tehranTimeZone = TimeZone(identifier: "Asia/Tehran")!
let oldDefault = NSTimeZone.default
NSTimeZone.default = tehranTimeZone
defer {
NSTimeZone.default = oldDefault
}
// Just a random local time. We will use 'startOfDay' to perform local time resetting.
let localTime = LocalTime(hour: 2, minute: 59)
let localDate1 = LocalDate(year: 2021, month: 3, day: 22)
let localDate2 = LocalDate(year: 2021, month: 3, day: 23)
let date1 = Date.of(localDate: localDate1, localTime: localTime).startOfDay
let date2 = Date.of(localDate: localDate2, localTime: localTime).startOfDay
let components = Calendar.current.dateComponents([.day], from: date1, to: date2)
/*
date1 Monday, March 22, 2021 at 1:00:00 AM Iran Daylight Time
date2 Tuesday, March 23, 2021 at 12:00:00 AM Iran Daylight Time
diff in day is Optional(0)
*/
print("date1 \(date1.description(with: .current))")
print("date2 \(date2.description(with: .current))")
print("diff in day is \(components.day)")
The different of day should be 1, without taking time into consideration. However, due to day light saving, the computed hour difference is 23 hours instead of 24 hours.
We are then getting 0 day difference.
One of the workaround, is using 12:00 (noon) as local time, with an assumption there is no place in this world, where day light saving occurs during 12:00. I am not sure how solid is this assumption. Such assumption seems to be pretty fragile. What if one day government decides to admen day light saving to be at 12:00?
Use 12:00 (Seems to work. But, how solid it is?)
import UIKit
struct LocalDate: Equatable {
let year: Int
let month: Int
let day: Int
}
struct LocalTime: Equatable, Codable {
let hour: Int
let minute: Int
}
extension Date {
var startOfDay: Date {
return Calendar.current.startOfDay(for: self)
}
static func of(localDate: LocalDate, localTime: LocalTime) -> Date {
var dateComponents = DateComponents()
dateComponents.year = localDate.year
dateComponents.month = localDate.month
dateComponents.day = localDate.day
dateComponents.hour = localTime.hour
dateComponents.minute = localTime.minute
dateComponents.second = 0
return Calendar.current.date(from: dateComponents)!
}
func adding(_ component: Calendar.Component, _ value: Int) -> Date {
return Calendar.current.date(byAdding: component, value: value, to: self)!
}
}
// During 22 March 2021, Tehran will advance by 1 hour from 00:00 AM, to 01:00 AM.
let tehranTimeZone = TimeZone(identifier: "Asia/Tehran")!
let oldDefault = NSTimeZone.default
NSTimeZone.default = tehranTimeZone
defer {
NSTimeZone.default = oldDefault
}
// Use noon
let localTime = LocalTime(hour: 12, minute: 00)
let localDate1 = LocalDate(year: 2021, month: 3, day: 22)
let localDate2 = LocalDate(year: 2021, month: 3, day: 23)
let date1 = Date.of(localDate: localDate1, localTime: localTime)
let date2 = Date.of(localDate: localDate2, localTime: localTime)
let components = Calendar.current.dateComponents([.day], from: date1, to: date2)
/*
date1 Monday, March 22, 2021 at 12:00:00 PM Iran Daylight Time
date2 Tuesday, March 23, 2021 at 12:00:00 PM Iran Daylight Time
diff in day is Optional(1)
*/
print("date1 \(date1.description(with: .current))")
print("date2 \(date2.description(with: .current))")
print("diff in day is \(components.day)")
May I know, what is reliable way, to calculate day differences without taking time into consideration?
Date is a precise point in time, hence expressible as a TimeInterval (aka Double) from an exact moment in time (that'll be reference date aka January 1st 2001 00:00 GMT+0).
Thus that same point in time is differently calculated between TimeZones through Calendar: if the TimeZone has daylight savings, then the calendar take it into account.
Therefore when you operate through a Calendar adopting DateComponents you should keep that in mind.
Depending on what you are trying to do in your application it could be useful to just adopt a private Calendar instance set to adopt TimeZone(secondsFromGMT: 0)! for calculating dates as absolutes values.
As in:
extension Calendar {
static let appCal: Self = {
// I'm used to reason with Gregorian calendar
var cal = Calendar(identifier: .gregorian)
// I just need this calendar for executing absolute time calculations
cal.timeZone = TimeZone(secondsFromGMT: 0)!
return cal
}()
}

How do I improve the accuracy of number of weekdays in a month calculation?

I'm trying to work out how many days in a month there are for each day of the week. I've used this question / answer below as a basis for what I want to achieve and it's working for the most part.
how can we get the number of sundays on an given month ? ( swift )
Unfortunately it's also calculating the 1st day of the following month, if it's a weekday.
I'm not familiar enough with how the code is calculated to be able to understand whether there is anywhere I can add a -1 or something to the total days of the month.
If anyone could recommend a solution it would be most appreciated.
I've tried changing the "numberOfSundays += 1" to "numberOfSundays += 0" as I thought that might be causing the issue.
func getNumberOfDaysInMonth (month : Int, Year : Int, nameOfDay: String) -> Int? {
var dateComponents = DateComponents()
dateComponents.year = Year
dateComponents.month = month
let calendar = NSCalendar.current
let date = calendar.date(from: dateComponents)
guard let range = calendar.range(of: .day, in: .month, for: date!) else { return nil }
let numDays = range.endIndex
// New code starts here:
var numberOfSundays = 0
let dateFormatter = DateFormatter()
for day in 1...numDays {
dateComponents.day = day
guard let date = calendar.date(from: dateComponents) else { return nil }
dateFormatter.dateFormat = "EEEE"
let dayOfWeek = dateFormatter.string(from: date) // Get day of week
if dayOfWeek == nameOfDay { // Check if it's a Monday
numberOfSundays += 1
}
}
return numberOfSundays
}
getNumberOfDaysInMonth(month: 06, Year: 2019, nameOfDay: "Monday")
getNumberOfDaysInMonth(month: 06, Year: 2019, nameOfDay: "Tuesday")
getNumberOfDaysInMonth(month: 06, Year: 2019, nameOfDay: "Wednesday")
getNumberOfDaysInMonth(month: 06, Year: 2019, nameOfDay: "Thursday")
getNumberOfDaysInMonth(month: 06, Year: 2019, nameOfDay: "Friday")
Where I call the function "getNumberOfDaysInMonth(month: 06, Year: 2019, nameOfDay: "Monday")" it returns 5 as the number of days in the month of June 2019, in actual fact there are 4.
func getNumberOfDaysInMonth(month: Int , year: Int, nameOfDay: String) -> Int? {
var components = DateComponents()
components.year = year
components.month = month
let calendar = Calendar.current
guard let date = calendar.date(from: components),
let range = calendar.range(of: .day, in: .month, for: date) else { return nil }
return range
.map { DateComponents(year: year, month: month, day: $0) }
.map { calendar.date(from: $0) }
.compactMap { date -> String? in
guard let date = date else { return nil }
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEEE"
return dateFormatter.string(from: date)
}
.filter { $0 == nameOfDay }
.count
}
It's a bit hard to find in the documentation of Range, however, the documentation comment for .endIndex property is:
The collection's "past the end" position---that is, the position one greater than the last valid subscript argument.
Anyway, you should not be using indices the calculate the size.
Correctly, you should use:
let numDays = range.upperBound - range.lowerBound
or simply
let numDays = range.count
to correctly calculate the number of days.

How can I find the next weekend Swift

I have an app in which I want to show some data when it's Saturday or Sunday.
Actually I have a segmented control and if I press one of my option (which will be the weekend) I want to check If it is Saturday or Sunday but only the first weekend.
This is what I've done for my first option in segmented control to take the current date
dateevent is a variable that I take to check if is the currentDate
currentDate is declared to be the currentDate
if dateevent.earlierDate(self.currentDate).isEqualToDate(self.currentDate){
if NSCalendar.currentCalendar().isDate(dateevent, equalToDate: self.currentDate, toUnitGranularity: .Day){
//Do something
}
}
First find the number of days to add to NSDateComponents weekday property and then You can use dateByAddingComponents(_:toDate:options:).
let today = NSDate()
let calendar = NSCalendar.currentCalendar()
let todayWeekday = calendar.component(.Weekday, fromDate: today)
let addWeekdays = 7 - todayWeekday // 7: Saturday number
var components = NSDateComponents()
components.weekday = addWeekdays
let nextSaturday = calendar.dateByAddingComponents(components, toDate: today, options: .MatchFirst)
From the Apple docs:
If the date does fall within a weekend, you can use the
rangeOfWeekendStartDate:interval:containingDate: method to determine
the start date of that weekend period. Otherwise, you can use the
nextWeekendStartDate:interval:options:afterDate: method to determine
the start date of the next or previous weekend.
extension for getting day of the week
func dayOfTheWeek() -> String? {
let dateFormatter = NSDateFormatter()
dateFormatter.locale = NSLocale(localeIdentifier: "en_US")
dateFormatter.dateFormat = "EEEE"
return dateFormatter.stringFromDate(self)
}
then you can just count how many days do yo need to weekend and add it to NSDate
NSDate().dateByAddingTimeInterval(60 * 60 * 24 * daysFromTodayToWeekend)
Swift 4 Solution
I have figured out according to my requirement, where I have find out dates for following.
1. Today
2. Tomorrow
3. This Week
4. This Weekend
5. Next Week
6. Next Weekend
So, I have created Date Extension to get Dates of Current Week and Next Week.
CODE
extension Date {
func getWeekDates() -> (thisWeek:[Date],nextWeek:[Date]) {
var tuple: (thisWeek:[Date],nextWeek:[Date])
var arrThisWeek: [Date] = []
for i in 0..<7 {
arrThisWeek.append(Calendar.current.date(byAdding: .day, value: i, to: startOfWeek)!)
}
var arrNextWeek: [Date] = []
for i in 1...7 {
arrNextWeek.append(Calendar.current.date(byAdding: .day, value: i, to: arrThisWeek.last!)!)
}
tuple = (thisWeek: arrThisWeek,nextWeek: arrNextWeek)
return tuple
}
var tomorrow: Date {
return Calendar.current.date(byAdding: .day, value: 1, to: noon)!
}
var noon: Date {
return Calendar.current.date(bySettingHour: 12, minute: 0, second: 0, of: self)!
}
var startOfWeek: Date {
let gregorian = Calendar(identifier: .gregorian)
let sunday = gregorian.date(from: gregorian.dateComponents([.yearForWeekOfYear, .weekOfYear], from: self))
return gregorian.date(byAdding: .day, value: 1, to: sunday!)!
}
func toDate(format: String) -> String {
let formatter = DateFormatter()
formatter.dateFormat = format
return formatter.string(from: self)
}
}
USAGE:
let arrWeekDates = Date().getWeekDates() // Get dates of Current and Next week.
let dateFormat = "MMM dd" // Date format
let thisMon = arrWeekDates.thisWeek.first!.toDate(format: dateFormat)
let thisSat = arrWeekDates.thisWeek[arrWeekDates.thisWeek.count - 2].toDate(format: dateFormat)
let thisSun = arrWeekDates.thisWeek[arrWeekDates.thisWeek.count - 1].toDate(format: dateFormat)
let nextMon = arrWeekDates.nextWeek.first!.toDate(format: dateFormat)
let nextSat = arrWeekDates.nextWeek[arrWeekDates.nextWeek.count - 2].toDate(format: dateFormat)
let nextSun = arrWeekDates.nextWeek[arrWeekDates.nextWeek.count - 1].toDate(format: dateFormat)
print("Today: \(Date().toDate(format: dateFormat))") // Sep 26
print("Tomorrow: \(Date().tomorrow.toDate(format: dateFormat))") // Sep 27
print("This Week: \(thisMon) - \(thisSun)") // Sep 24 - Sep 30
print("This Weekend: \(thisSat) - \(thisSun)") // Sep 29 - Sep 30
print("Next Week: \(nextMon) - \(nextSun)") // Oct 01 - Oct 07
print("Next Weekend: \(nextSat) - \(nextSun)") // Oct 06 - Oct 07
You can modify Extension according to your need.
Thanks!
I use this implementation to get the next Saturday at specific time:
CODE (Swift 5):
func nextSaturday(atHour hour: Int, min: Int) -> Date {
let today = Date()
let daysToAdd = 7 - (Calendar.current.dateComponents([.weekday], from: today).weekday ?? 0 )
let nextSaturday = Calendar.current.date(byAdding: .day, value: daysToAdd, to: today)!
return Calendar.current.date(bySettingHour: hour, minute: min, second: 0, of: nextSaturday)!
}
How to use it:
nextSaturday(atHour: 10, min: 0)

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)

first and last day of the current month in swift

I'm trying to get the first and last day of the month in swift.
So far I have the following:
let dateFormatter = NSDateFormatter()
let date = NSDate()
dateFormatter.dateFormat = "yyyy-MM-dd"
let calendar = NSCalendar.currentCalendar()
let components = calendar.components([.Year, .Month, .Day, .Hour, .Minute, .Second], fromDate: date)
let month = components.month
let year = components.year
let startOfMonth = ("\(year)-\(month)-01")
But I'm not sure how to get the last date. Is there a built in method I'm missing? Obviously it has to take into account leap years etc.
Swift 3 and 4 drop-in extensions
This actually gets a lot easier with Swift 3+:
You can do it without guard (you could if you wanted to, but because DateComponents is a non-optional type now, it's no longer necessary).
Using iOS 8's startOfDayForDate (now startOfDay), you don't need to manually set the time to 12pm unless you're doing some really crazy calendar calculations across time zones.
It's worth mentioning that some of the other answers claim you can shortcut this by using Calendar.current.date(byAdding: .month, value: 0, to: Date())!, but where this fails, is that it doesn't actually zero out the day, or account for differences in timezones.
Here you go:
extension Date {
func startOfMonth() -> Date {
return Calendar.current.date(from: Calendar.current.dateComponents([.year, .month], from: Calendar.current.startOfDay(for: self)))!
}
func endOfMonth() -> Date {
return Calendar.current.date(byAdding: DateComponents(month: 1, day: -1), to: self.startOfMonth())!
}
}
print(Date().startOfMonth()) // "2018-02-01 08:00:00 +0000\n"
print(Date().endOfMonth()) // "2018-02-28 08:00:00 +0000\n"
You get the first day of the month simply with
let components = calendar.components([.Year, .Month], fromDate: date)
let startOfMonth = calendar.dateFromComponents(components)!
print(dateFormatter.stringFromDate(startOfMonth)) // 2015-11-01
To get the last day of the month, add one month and subtract one day:
let comps2 = NSDateComponents()
comps2.month = 1
comps2.day = -1
let endOfMonth = calendar.dateByAddingComponents(comps2, toDate: startOfMonth, options: [])!
print(dateFormatter.stringFromDate(endOfMonth)) // 2015-11-30
Alternatively, use the rangeOfUnit method which gives you
the start and the length of the month:
var startOfMonth : NSDate?
var lengthOfMonth : NSTimeInterval = 0
calendar.rangeOfUnit(.Month, startDate: &startOfMonth, interval: &lengthOfMonth, forDate: date)
For a date on the last day of month, add the length of the month minus one second:
let endOfMonth = startOfMonth!.dateByAddingTimeInterval(lengthOfMonth - 1)
Updated for Swift5:
extension Date {
var startOfDay: Date {
return Calendar.current.startOfDay(for: self)
}
var startOfMonth: Date {
let calendar = Calendar(identifier: .gregorian)
let components = calendar.dateComponents([.year, .month], from: self)
return calendar.date(from: components)!
}
var endOfDay: Date {
var components = DateComponents()
components.day = 1
components.second = -1
return Calendar.current.date(byAdding: components, to: startOfDay)!
}
var endOfMonth: Date {
var components = DateComponents()
components.month = 1
components.second = -1
return Calendar(identifier: .gregorian).date(byAdding: components, to: startOfMonth)!
}
func isMonday() -> Bool {
let calendar = Calendar(identifier: .gregorian)
let components = calendar.dateComponents([.weekday], from: self)
return components.weekday == 2
}
}
With Swift 3 & iOS 10 the easiest way I found to do this is Calendar's dateInterval(of:for:):
guard let interval = calendar.dateInterval(of: .month, for: Date()) else { return }
You can then use interval.start and interval.end to get the dates you need.
Swift 3
Many date example for :
Last 6 month,
last 3 month,
yesterday, last 7 day, last 30 day, previous month,
current month start & end, last month start & end date
let startDate = dateFormatter.string(from: Date().getThisMonthStart()!)
let endDate = dateFormatter.string(from: Date().getThisMonthEnd()!)
extension Date {
func getLast6Month() -> Date? {
return Calendar.current.date(byAdding: .month, value: -6, to: self)
}
func getLast3Month() -> Date? {
return Calendar.current.date(byAdding: .month, value: -3, to: self)
}
func getYesterday() -> Date? {
return Calendar.current.date(byAdding: .day, value: -1, to: self)
}
func getLast7Day() -> Date? {
return Calendar.current.date(byAdding: .day, value: -7, to: self)
}
func getLast30Day() -> Date? {
return Calendar.current.date(byAdding: .day, value: -30, to: self)
}
func getPreviousMonth() -> Date? {
return Calendar.current.date(byAdding: .month, value: -1, to: self)
}
// This Month Start
func getThisMonthStart() -> Date? {
let components = Calendar.current.dateComponents([.year, .month], from: self)
return Calendar.current.date(from: components)!
}
func getThisMonthEnd() -> Date? {
let components:NSDateComponents = Calendar.current.dateComponents([.year, .month], from: self) as NSDateComponents
components.month += 1
components.day = 1
components.day -= 1
return Calendar.current.date(from: components as DateComponents)!
}
//Last Month Start
func getLastMonthStart() -> Date? {
let components:NSDateComponents = Calendar.current.dateComponents([.year, .month], from: self) as NSDateComponents
components.month -= 1
return Calendar.current.date(from: components as DateComponents)!
}
//Last Month End
func getLastMonthEnd() -> Date? {
let components:NSDateComponents = Calendar.current.dateComponents([.year, .month], from: self) as NSDateComponents
components.day = 1
components.day -= 1
return Calendar.current.date(from: components as DateComponents)!
}
}
Swift 4
If you only need the ordinal day:
func lastDay(ofMonth m: Int, year y: Int) -> Int {
let cal = Calendar.current
var comps = DateComponents(calendar: cal, year: y, month: m)
comps.setValue(m + 1, for: .month)
comps.setValue(0, for: .day)
let date = cal.date(from: comps)!
return cal.component(.day, from: date)
}
lastDay(ofMonth: 2, year: 2018) // 28
lastDay(ofMonth: 2, year: 2020) // 29
This is the simplest way that I found (Swift 5+):
extension Date {
func getStart(of component: Calendar.Component, calendar: Calendar = Calendar.current) -> Date? {
return calendar.dateInterval(of: component, for: self)?.start
}
func getEnd(of component: Calendar.Component, calendar: Calendar = Calendar.current) -> Date? {
return calendar.dateInterval(of: component, for: self)?.end
}
}
Here is easiest solution:
extension Date {
func startOfMonth() -> Date {
let interval = Calendar.current.dateInterval(of: .month, for: self)
return (interval?.start.toLocalTime())! // Without toLocalTime it give last months last date
}
func endOfMonth() -> Date {
let interval = Calendar.current.dateInterval(of: .month, for: self)
return interval!.end
}
// Convert UTC (or GMT) to local time
func toLocalTime() -> Date {
let timezone = TimeZone.current
let seconds = TimeInterval(timezone.secondsFromGMT(for: self))
return Date(timeInterval: seconds, since: self)
}}
and then call these with your date instance:
print(Date().startOfMonth())
print(Date().endOfMonth())
2017...
First, get the month you need:
let cal = Calendar.current
let d = Calendar.current.date(byAdding: .month, value: 0, to: Date())!
// for "last month" just use -1, for "next month" just use 1, etc
To get the day-of-the-week for the first day of the month:
let c = cal.dateComponents([.year, .month], from: d)
let FDOM = cal.date(from: c)!
let dowFDOM = cal.component(.weekday, from: FDOM)
print("the day-of-week on the 1st is ... \(dowFDOM)")
// so, that's 1=Sunday, 2=Monday, etc.
To get the number of days in the month:
let r = cal.range(of: .day, in: .month, for: d)!
let kDays = r.count
print("the number of days is ... \(kDays)")
With Swift 3, you can choose one of the two following patters in order to retrieve the first and last days of a month.
#1. Using Calendar dateComponents(_:from:), date(from:) and date(byAdding:to:wrappingComponents:) methods
With this pattern, you first get the date of the first day of a month then add a month and remove a day from it in order to get the date of the last day of the month. The Playground code below shows how to set it:
import Foundation
// Set calendar and date
let calendar = Calendar.current
let date = calendar.date(byAdding: DateComponents(day: -10), to: Date())!
// Get first day of month
let firstDayComponents = calendar.dateComponents([.year, .month], from: date)
let firstDay = calendar.date(from: firstDayComponents)!
// Get last day of month
let lastDayComponents = DateComponents(month: 1, day: -1)
let lastDay = calendar.date(byAdding: lastDayComponents, to: firstDay)!
// Set date formatter
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_UK")
dateFormatter.dateStyle = .long
dateFormatter.timeStyle = .long
// Print results
print(dateFormatter.string(from: date)) // Prints: 22 March 2017 at 18:07:15 CET
print(dateFormatter.string(from: firstDay)) // Prints: 1 March 2017 at 00:00:00 CET
print(dateFormatter.string(from: lastDay)) // Prints: 31 March 2017 at 00:00:00 CEST
#2. Using Calendar range(of:in:for:), dateComponents(_:from:) and date(from:) and methods
With this pattern, you get a range of absolute day values in a month and then retrieve the dates of the first day and last day of the month from it. The Playground code below shows how to set it:
import Foundation
// Set calendar and date
let calendar = Calendar.current
let date = calendar.date(byAdding: DateComponents(day: -10), to: Date())!
// Get range of days in month
let range = calendar.range(of: .day, in: .month, for: date)! // Range(1..<32)
// Get first day of month
var firstDayComponents = calendar.dateComponents([.year, .month], from: date)
firstDayComponents.day = range.lowerBound
let firstDay = calendar.date(from: firstDayComponents)!
// Get last day of month
var lastDayComponents = calendar.dateComponents([.year, .month], from: date)
lastDayComponents.day = range.upperBound - 1
//lastDayComponents.day = range.count // also works
let lastDay = calendar.date(from: lastDayComponents)!
// Set date formatter
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_UK")
dateFormatter.dateStyle = .long
dateFormatter.timeStyle = .long
// Print results
print(dateFormatter.string(from: date)) // prints: 22 March 2017 at 18:07:15 CET
print(dateFormatter.string(from: firstDay)) // prints: 1 March 2017 at 00:00:00 CET
print(dateFormatter.string(from: lastDay)) // prints: 31 March 2017 at 00:00:00 CEST
In swift 3, if you put 0 to day component you can get the last day of the month. There's an example code:
public func isMoreDays(date: Date, asc: Bool)->Bool{
//components
var dayComponents = self.getDateComponents(date: date)
//asc is true if ascendant or false if descendant
dayComponents.day = asc ? 0 : 1
//plus 1 to month 'cos if you set up day to 0 you are going to the previous month
dayComponents.month = asc ? dayComponents.month! + 1 : dayComponents.month
//instantiate calendar and get the date
let calendar : Calendar = NSCalendar.current
let day = calendar.date(from: dayComponents)
//date comparison
if(day?.compare(date) == .orderedSame){
return false
}
return true
}
You can use the following extensions here :
let today = Date()
let startOfMonth = today.beginning(of: .month)
let endOfMonth = today.end(of: .month)

Resources