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)
Related
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
}()
}
I have to show weekdays date in CollectionView start from Monday to Saturday. Until the end of the week, I have to show that weekdays date only. My task image Image. Please help/advise me how to do this task.
I am getting weekdays but its start from current day, But i need start date from monday,
func arrayOfDates() -> NSArray {
let numberOfDays: Int = 6
let formatter: DateFormatter = DateFormatter()
formatter.dateFormat = "dd"
let startDate = Date()
let calendar = Calendar.current
var offset = DateComponents()
var dates: [Any] = [formatter.string(from: startDate)]
for i in 1..<numberOfDays {
offset.day = i
let nextDay: Date? = calendar.date(byAdding: offset, to: startDate)
let nextDayString = formatter.string(from: nextDay!)
dates.append(nextDayString)
}
return dates as NSArray
}
Try this
func formattedDaysInThisWeekNet() -> [String]
{
// create calendar
let calendar = NSCalendar(identifier: NSCalendar.Identifier.gregorian)!
// today's date
let today = NSDate()
let weekday = calendar.component(.weekday, from: today as Date)
let beginningOfWeek : NSDate
if weekday != 2 { // if today is not Monday, get back
beginningOfWeek = calendar.nextDate(after: today as Date, matching: .weekday, value: 1, options: [.matchNextTime, .searchBackwards])! as NSDate
} else { // today is Monday
beginningOfWeek = calendar.startOfDay(for: today as Date) as NSDate
}
var formattedDays = [String]()
for i in 0..<7 {
let date = calendar.date(byAdding: .day, value: i, to: beginningOfWeek as Date, options: [])!
formattedDays.append(formatDate(date: date as NSDate))
let firstDate = calendar.date(byAdding: .day, value: 0, to: beginningOfWeek as Date, options: [])!
let lastDate = calendar.date(byAdding: .day, value: 6, to: beginningOfWeek as Date, options: [])!
let fullString = "\(formatDateFull(date: firstDate as NSDate)) - \(formatDateFull(date: lastDate as NSDate))" as String
fulldateLbl.text = "< \(fullString) >"
print(fullString)
}
return formattedDays
}
enum Days: Int {
case Sat = 0, Sun, Mon, Tue, Wed, Thu, Fri
static var all = [Mon, Tue, Wed, Thu, Fri, Sat]
}
func getWeekDays(date: Date) -> [Date] {
var weekDates = [Date]()
let cal = Calendar.current
var comps = cal.dateComponents([.weekOfYear, .yearForWeekOfYear], from: date)
let days = Days.all
for day in days {
comps.weekday = day.rawValue
weekDates.append(cal.date(from: comps)!)
}
return weekDates
}
print(getWeekDays(date: Date())) // print all dates from Monday to Saturday
Hi guys thank you for your response. I completed This task.
func arrayOfDates() -> NSArray {
var calendar = Calendar(identifier: Calendar.Identifier.gregorian)
let today = calendar.startOfDay(for: Date())
let dayOfWeek = calendar.component(.weekday, from: today) - calendar.firstWeekday
let weekdays = calendar.range(of: .weekday, in: .weekOfYear, for: today)!
let dayss = (weekdays.lowerBound ..< weekdays.upperBound)
.compactMap { calendar.date(byAdding: .day, value: $0 - dayOfWeek, to: today) }
//.filter { !calendar.isDateInWeekend($0) }
let formatter = DateFormatter()
formatter.dateFormat = "dd"
let strings = dayss.map { formatter.string(from: $0) }
self.dates = strings as NSArray
return dates as NSArray
}
But here I have one question, How to disable the previous dates. I need to select only current date and next dates.
I need to get the List of dates for the given date of the week.
As an example :
If user select the random date from picker Like 2017-6-7,
I needs to get and display the dates of the week.
[2017-6-4, 2017-6-5, 2017-6-6, 2017-6-7, 2017-6-8, 2017-6-9, 2017-6-10]
I couldn't find any solution on the internet.
Thank you
Try this:
let dateInWeek = Date()//7th June 2017
let calendar = Calendar.current
let dayOfWeek = calendar.component(.weekday, from: dateInWeek)
let weekdays = calendar.range(of: .weekday, in: .weekOfYear, for: dateInWeek)!
let days = (weekdays.lowerBound ..< weekdays.upperBound)
.compactMap { calendar.date(byAdding: .day, value: $0 - dayOfWeek, to: dateInWeek) }
print(days)
It will give you this:
4 June 2017(Sunday)
5 June 2017
6 June 2017
7 June 2017
8 June 2017
9 June 2017
10 June 2017(Saturday)
Start fromMonday
The above is default behavior for my calendar that's why it is starting from Sunday.
If you want start from Monday then do this change:
let dayOfWeek = calendar.component(.weekday, from: dateInWeek) - 1
It depends on which locale your calendar is in.
This is a starting point using the date math skills of Calendar
var calendar = Calendar.current
calendar.firstWeekday = 1 // adjust first weekday if necessary
var startOfWeek = Date()
var interval : TimeInterval = 0.0
_ = calendar.dateInterval(of:.weekOfYear, start: &startOfWeek, interval: &interval, for: Date())
for i in 0..<7 {
print(calendar.date(byAdding: .day, value: i, to: startOfWeek)!)
}
You can use this.
let today = Date()
let weekStartDate = today.getWeekStartDate(fromDate: today)
for i in 0..<5 {
let nextDate = weekStartDate?.getNextDay(value: i, currentDate:weekStartDate)
}
func getWeekStartDate(fromDate : Date?) -> Date? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
if let date = fromDate {
var calendar = Calendar(identifier: .gregorian)
calendar.firstWeekday = 3
var startDate : Date = Date()
var interval : TimeInterval = 0
if calendar.dateInterval(of: .weekOfYear, start: &startDate, interval: &interval, for: date) {
print("Start of week is \(startDate)")
// prints "Start of week is 2017-01-01 06:00:00 +0000"
return startDate
}
}
return nil
}
func getNextDay(value : Int, currentDate : Date?) -> Date? {
let dayComponenet = NSDateComponents()
dayComponenet.day = value
let theCalendar = NSCalendar.current
let nextDate = theCalendar.date(byAdding: dayComponenet as DateComponents, to: currentDate!)
return nextDate
}
Hope this will help!.
I'm trying to get Monday's date of the current week. This is treated as the first day of the week in my table view.
I also need to get Sunday's of the current week. This is treated as the last day of the week in my table view.
Current attempt:
let date = NSDate()
let calendar = NSCalendar.currentCalendar()
calendar.firstWeekday = 1
//attempt to changefirstday
let dateFormatter = NSDateFormatter()
let theDateFormat = NSDateFormatterStyle.ShortStyle
let theTimeFormat = NSDateFormatterStyle.ShortStyle
dateFormatter.dateStyle = theDateFormat
dateFormatter.timeStyle = theTimeFormat
let currentDateComponents = calendar.components([.YearForWeekOfYear, .WeekOfYear ], fromDate: date)
let startOfWeek = calendar.dateFromComponents(currentDateComponents)
print("startOfWeek is \(startOfWeek)")
let stringDate = dateFormatter.stringFromDate(startOfWeek!)
print("string date is \(stringDate)") //This is returning Sunday's date
I wrote Date extensions to get Date for certain weekday and here is how easy it is to use with Swift 5,
Date.today() // Oct 15, 2019 at 9:21 AM
Date.today().next(.monday) // Oct 21, 2019 at 9:21 AM
Date.today().next(.sunday) // Oct 20, 2019 at 9:21 AM
Date.today().previous(.sunday) // Oct 13, 2019 at 9:21 AM
Date.today().previous(.monday) // Oct 14, 2019 at 9:21 AM
Date.today().previous(.thursday) // Oct 10, 2019 at 9:21 AM
Date.today().next(.thursday) // Oct 17, 2019 at 9:21 AM
Date.today().previous(.thursday,
considerToday: true) // Oct 10, 2019 at 9:21 AM
Date.today().next(.monday)
.next(.sunday)
.next(.thursday) // Oct 31, 2019 at 9:21 AM
And here is Date extension for that,
extension Date {
static func today() -> Date {
return Date()
}
func next(_ weekday: Weekday, considerToday: Bool = false) -> Date {
return get(.next,
weekday,
considerToday: considerToday)
}
func previous(_ weekday: Weekday, considerToday: Bool = false) -> Date {
return get(.previous,
weekday,
considerToday: considerToday)
}
func get(_ direction: SearchDirection,
_ weekDay: Weekday,
considerToday consider: Bool = false) -> Date {
let dayName = weekDay.rawValue
let weekdaysName = getWeekDaysInEnglish().map { $0.lowercased() }
assert(weekdaysName.contains(dayName), "weekday symbol should be in form \(weekdaysName)")
let searchWeekdayIndex = weekdaysName.firstIndex(of: dayName)! + 1
let calendar = Calendar(identifier: .gregorian)
if consider && calendar.component(.weekday, from: self) == searchWeekdayIndex {
return self
}
var nextDateComponent = calendar.dateComponents([.hour, .minute, .second], from: self)
nextDateComponent.weekday = searchWeekdayIndex
let date = calendar.nextDate(after: self,
matching: nextDateComponent,
matchingPolicy: .nextTime,
direction: direction.calendarSearchDirection)
return date!
}
}
// MARK: Helper methods
extension Date {
func getWeekDaysInEnglish() -> [String] {
var calendar = Calendar(identifier: .gregorian)
calendar.locale = Locale(identifier: "en_US_POSIX")
return calendar.weekdaySymbols
}
enum Weekday: String {
case monday, tuesday, wednesday, thursday, friday, saturday, sunday
}
enum SearchDirection {
case next
case previous
var calendarSearchDirection: Calendar.SearchDirection {
switch self {
case .next:
return .forward
case .previous:
return .backward
}
}
}
}
You can use calendar ISO8601 where the first weekday is Monday:
Swift 5.2 or later
extension Calendar {
static let iso8601 = Calendar(identifier: .iso8601)
static let iso8601UTC: Calendar = {
var calendar = Calendar(identifier: .iso8601)
calendar.timeZone = TimeZone(identifier: "UTC")!
return calendar
}()
}
let monday =
Calendar.iso8601.dateComponents([.calendar, .yearForWeekOfYear, .weekOfYear], from: Date()).date! // "Nov 9, 2020 at 12:00 AM"
print(monday.description(with: .current)) // "Monday, November 9, 2020 at 12:00:00 AM Brasilia Standard Time\n"
let mondayUTC =
Calendar.iso8601UTC.dateComponents([.calendar, .yearForWeekOfYear, .weekOfYear], from: Date()).date! // "Nov 8, 2020 at 9:00 PM" TimeZone -03:00
print(mondayUTC) // "2020-11-09 00:00:00 +0000\n"
Implemented as a Date computer property extension:
extension Date {
var mondayOfTheSameWeek: Date {
Calendar.iso8601.dateComponents([.calendar, .yearForWeekOfYear, .weekOfYear], from: self).date!
}
var mondayOfTheSameWeekAtUTC: Date {
Calendar.iso8601UTC.dateComponents([.calendar, .yearForWeekOfYear, .weekOfYear], from: self).date!
}
}
let mondayOfTheSameWeek = Date().mondayOfTheSameWeek // "Nov 9, 2020 at 12:00 AM"
print(mondayOfTheSameWeek.description(with: .current)) // "Monday, November 9, 2020 at 12:00:00 AM Brasilia Standard Time\n"
let mondayOfTheSameWeekAtUTC = Date().mondayOfTheSameWeekAtUTC // "Nov 8, 2020 at 9:00 PM"
print(mondayOfTheSameWeekAtUTC) // "2020-11-09 00:00:00 +0000\n"
Here's a simplified version of Sandeep's answer.
Usage:
Date().next(.monday)
Date().next(.monday, considerToday: true)
Date().next(.monday, direction: .backward)
Extension:
public func next(_ weekday: Weekday,
direction: Calendar.SearchDirection = .forward,
considerToday: Bool = false) -> Date
{
let calendar = Calendar(identifier: .gregorian)
let components = DateComponents(weekday: weekday.rawValue)
if considerToday &&
calendar.component(.weekday, from: self) == weekday.rawValue
{
return self
}
return calendar.nextDate(after: self,
matching: components,
matchingPolicy: .nextTime,
direction: direction)!
}
public enum Weekday: Int {
case sunday = 1, monday, tuesday, wednesday, thursday, friday, saturday
}
Here is the extension I created, first it finds sunday and then it adds one day
extension Date {
var startOfWeek: Date? {
let gregorian = Calendar(identifier: .gregorian)
guard let sunday = gregorian.date(from: gregorian.dateComponents([.yearForWeekOfYear, .weekOfYear], from: self)) else { return nil }
return gregorian.date(byAdding: .day, value: 1, to: sunday)
}
}
Try to use:
calendar.firstWeekday = 2
Edit
To be more specific: NSCalendar.currentCalendar() returns user calendar. According to docs:
The returned calendar is formed from the settings for the current user’s chosen system locale overlaid with any custom settings the user has specified in System Preferences.
If you want always Monday as first day, I think you should use:
let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
calendar!.firstWeekday = 2
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!
Addition to #Saneep answer
If you would like to get exact dateTime as per given/current date (lets say you wanted to convert Monday's dateTime -> 23-05-2016 12:00:00 to 23-05-2016 05:35:17) then try this:
func convertDate(date: NSDate, toGivendate: NSDate) -> NSDate {
let calendar = NSCalendar.currentCalendar()
let comp = calendar.components([.Year, .Month, .Day, .Hour, .Minute, .Second], fromDate: toGivendate)
let hour = comp.hour
let minute = comp.minute
let second = comp.second
let dateComp = calendar.components([.Year, .Month, .Day], fromDate: date)
let year = dateComp.year
let month = dateComp.month
let day = dateComp.day
let components = NSDateComponents()
components.year = year
components.month = month
components.day = day
components.hour = hour
components.minute = minute
components.second = second
let newConvertedDate = calendar.dateFromComponents(components)
return newConvertedDate!
}
simple code (remember to take better care of the optionals):
let now = Date()
var calendar = Calendar(identifier: .gregorian)
let timeZone = TimeZone(identifier: "UTC")!
let desiredWeekDay = 2
let weekDay = calendar.component(.weekday, from: now)
var weekDayDate = calendar.date(bySetting: .weekday, value: desiredWeekDay, of: now)!
/// Swift will give back the closest day matching the value above so we need to manipulate it to be always included at cuurent week.
if weekDayDate > now, weekDay > desiredWeekDay {
weekDayDate = weekDayDate - 7*24*60*60
}
print(weekDayDate)
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)