Comparing NSDates without time component - ios

In a swift playground, I have been using
NSDate.date()
But, this always appears with the time element appended. For my app I need to ignore the time element. Is this possible in Swift? How can it be done? Even if I could set the time element to be the same time on every date that would work too.
Also, I am trying to compare two dates and at the moment I am using the following code:
var earlierDate:NSDate = firstDate.earlierDate(secondDate)
Is this the only way or can I do this in a way that ignores the time element? For instance I don't want a result if they are the same day, but different times.

Use this Calendar function to compare dates in iOS 8.0+
func compare(_ date1: Date, to date2: Date, toGranularity component: Calendar.Component) -> ComparisonResult
passing .day as the unit
Use this function as follows:
let now = Date()
// "Sep 23, 2015, 10:26 AM"
let olderDate = Date(timeIntervalSinceNow: -10000)
// "Sep 23, 2015, 7:40 AM"
var order = Calendar.current.compare(now, to: olderDate, toGranularity: .hour)
switch order {
case .orderedDescending:
print("DESCENDING")
case .orderedAscending:
print("ASCENDING")
case .orderedSame:
print("SAME")
}
// Compare to hour: DESCENDING
var order = Calendar.current.compare(now, to: olderDate, toGranularity: .day)
switch order {
case .orderedDescending:
print("DESCENDING")
case .orderedAscending:
print("ASCENDING")
case .orderedSame:
print("SAME")
}
// Compare to day: SAME

Xcode 11.2.1, Swift 5 & Above
Checks whether the date has same day component.
Calendar.current.isDate(date1, equalTo: date2, toGranularity: .day)
Adjust toGranularity as your need.

There are several useful methods in NSCalendar in iOS 8.0+:
startOfDayForDate, isDateInToday, isDateInYesterday, isDateInTomorrow
And even to compare days:
func isDate(date1: NSDate!, inSameDayAsDate date2: NSDate!) -> Bool
To ignore the time element you can use this:
var toDay = Calendar.current.startOfDay(for: Date())
But, if you have to support also iOS 7, you can always write an extension
extension NSCalendar {
func myStartOfDayForDate(date: NSDate!) -> NSDate!
{
let systemVersion:NSString = UIDevice.currentDevice().systemVersion
if systemVersion.floatValue >= 8.0 {
return self.startOfDayForDate(date)
} else {
return self.dateFromComponents(self.components(.CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay, fromDate: date))
}
}
}

In Swift 4:
func compareDate(date1:Date, date2:Date) -> Bool {
let order = NSCalendar.current.compare(date1, to: date2, toGranularity: .day)
switch order {
case .orderedSame:
return true
default:
return false
}
}

I wrote the following method to compare two dates by borrowing from Ashley Mills solution. It compares two dates and returns true if the two dates are the same (stripped of time).
func compareDate(date1:NSDate, date2:NSDate) -> Bool {
let order = NSCalendar.currentCalendar().compareDate(date1, toDate: date2,
toUnitGranularity: .Day)
switch order {
case .OrderedSame:
return true
default:
return false
}
}
And it is called like this:
if compareDate(today, date2: anotherDate) {
// The two dates are on the same day.
}

Two Dates comparisions in swift.
// Date comparision to compare current date and end date.
var dateComparisionResult:NSComparisonResult = currentDate.compare(endDate)
if dateComparisionResult == NSComparisonResult.OrderedAscending
{
// Current date is smaller than end date.
}
else if dateComparisionResult == NSComparisonResult.OrderedDescending
{
// Current date is greater than end date.
}
else if dateComparisionResult == NSComparisonResult.OrderedSame
{
// Current date and end date are same.
}

I wrote a Swift 4 extension for comparing two dates:
import Foundation
extension Date {
func isSameDate(_ comparisonDate: Date) -> Bool {
let order = Calendar.current.compare(self, to: comparisonDate, toGranularity: .day)
return order == .orderedSame
}
func isBeforeDate(_ comparisonDate: Date) -> Bool {
let order = Calendar.current.compare(self, to: comparisonDate, toGranularity: .day)
return order == .orderedAscending
}
func isAfterDate(_ comparisonDate: Date) -> Bool {
let order = Calendar.current.compare(self, to: comparisonDate, toGranularity: .day)
return order == .orderedDescending
}
}
Usage:
startDate.isSameDateAs(endDate) // returns a true or false

For iOS7 support
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let date1String = dateFormatter.stringFromDate(date1)
let date2String = dateFormatter.stringFromDate(date2)
if date1String == date2String {
println("Equal date")
}

You can compare two dates using it's description.
let date1 = NSDate()
let date2 = NSDate(timeIntervalSinceNow: 120)
if date1.description == date2.description {
print(true)
} else {
print(false) // false (I have added 2 seconds between them)
}
If you want set the time element of your dates to a different time you can do as follow:
extension NSDate {
struct Calendar {
static let gregorian = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
}
var day: Int { return Calendar.gregorian.component(.Day, fromDate: self) }
var month: Int { return Calendar.gregorian.component(.Month, fromDate: self) }
var year: Int { return Calendar.gregorian.component(.Year, fromDate: self) }
var noon: NSDate {
return Calendar.gregorian.dateWithEra(1, year: year, month: month, day: day, hour: 12, minute: 0, second: 0, nanosecond: 0)!
}
}
let date1 = NSDate()
let date2 = NSDate(timeIntervalSinceNow: 120)
print(date1.noon == date2.noon) // true
or you can also do it using NSDateFormatter:
extension NSDate {
struct Date {
static let formatterYYYYMMDD: NSDateFormatter = {
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyyMMdd"
return formatter
}()
}
var yearMonthDay: String {
return Date.formatterYYYYMMDD.stringFromDate(self)
}
func isSameDayAs(date:NSDate) -> Bool {
return yearMonthDay == date.yearMonthDay
}
}
let date1 = NSDate()
let date2 = NSDate(timeIntervalSinceNow: 120)
print(date1.yearMonthDay == date2.yearMonthDay) // true
print(date1.isSameDayAs(date2)) // true
Another option (iOS8+) is to use calendar method isDate(inSameDayAsDate:):
extension NSDate {
struct Calendar {
static let gregorian = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
}
func isInSameDayAs(date date: NSDate) -> Bool {
return Calendar.gregorian.isDate(self, inSameDayAsDate: date)
}
}
let date1 = NSDate()
let date2 = NSDate(timeIntervalSinceNow: 120)
if date1.isInSameDayAs(date: date2 ){
print(true) // true
} else {
print(false)
}

Swift 3
let order = NSCalendar.current.compare(date1, to: date2, toGranularity: .day)
if order == .orderedAscending {
// date 1 is older
}
else if order == .orderedDescending {
// date 1 is newer
}
else if order == .orderedSame {
// same day/hour depending on granularity parameter
}

For Swift3
var order = NSCalendar.current.compare(firstDate, to: secondDate, toGranularity: .hour)
if order == .orderedSame {
//Both the dates are same.
//Your Logic.
}

Swift:
extension NSDate {
/**
Compares current date with the given one down to the seconds.
If date==nil, then always return false
:param: date date to compare or nil
:returns: true if the dates has equal years, months, days, hours, minutes and seconds.
*/
func sameDate(date: NSDate?) -> Bool {
if let d = date {
let calendar = NSCalendar.currentCalendar()
if NSComparisonResult.OrderedSame == calendar.compareDate(self, toDate: d, toUnitGranularity: NSCalendarUnit.SecondCalendarUnit) {
return true
}
}
return false
}
}

When you NSDate.date() in the playground, you see the default description printed. Use NSDateFormatter to print a localized description of the date object, possibly with only the date portion.
To zero out specific portions of a date (for the sake of comparison), use NSDateComponents in conjunction with NSCalendar.

In my experience, most people's problems with using NSDate comes from the incorrect assumption that an NSDate can be used to represent a date in the 'normal' sense (i.e. a 24 period starting at midnight in the local timezone). In normal (everyday / non-programming) usage, 1st January 2014 in London is the same date as 1st January in Beijing or New York even though they cover different periods in real time. To take this to the extreme, the time on Christmas Island is UTC+14 while the time on Midway Island is UTC-11. So 1st January 2014 on these two island are the same date even though one doesn't even start until the other has been completed for an hour.
If that is the kind of date you are recording (and if you are not recording the time component, it probably is), then do not use NSDate (which stores only seconds past 2001-01-01 00:00 UTC, nothing else) but store the year month and day as integers - perhaps by creating your own CivilDate class that wraps these values - and use that instead.
Only dip into NSDate to compare dates and then make sure to explicitly declare the time zone as "UTC" on both NSDates for comparison purposes.

Swift 4
func compareDate(date1:Date, date2:Date) -> Bool {
let order = Calendar.current.compare(date1, to: date2,toGranularity: .day)
switch order {
case .orderedSame:
return true
default:
return false
}
}

If you need to compare just if date is in the same day as other date use this:
Calendar.current.isDate(date1, inSameDayAs: date2)

To answer your question:
Is this possible in Swift?
Yes, it is possible
Ahh, you also want to now HOW
let cal = NSCalendar.currentCalendar()
cal.rangeOfUnit(.DayCalendarUnit, startDate: &d1, interval: nil, forDate: d1) // d1 NSDate?
cal.rangeOfUnit(.DayCalendarUnit, startDate: &d2, interval: nil, forDate: d2) // d2 NSDate?
Now d1 and d2 will contain the dates at beginning of their days.
compare with d1!.compare(d2!)
To display them without time portion, us NSDateFormatter.

Related

Check if date is in coming month

I'm setting a date to a certain birthdayTextField like so
#objc func birthdayDatePickerValueChanged(sender: UIDatePicker) {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .none
birthdayTextField.text = formatter.string(from: sender.date)
}
Now this textfield value is stored in coredata in a string attribute. There can be many such birthday dates stored in coredata. Now when I fetch these dates from the database, I want to show in a tableview only those dates which come in the following month.
How can it be achieved...?
This is a solution using the powerful date math abilities of Calendar together with DateComponents in a Date extension.
It calculates the first day of next month with nextDate(after:matching:matchingPolicy:) looking for day == 1
It compares the given date with the first date of next month to the month granularity with compare(:to:toGranularity:).
extension Date {
func isDateInNextMonth() -> Bool {
let calendar = Calendar.current
let nextMonth = calendar.nextDate(after: Date(), matching: DateComponents(day:1), matchingPolicy: .nextTime)!
return calendar.compare(self, to: nextMonth, toGranularity: .month) == .orderedSame
}
}
Use it simply in your method
sender.date.isDateInNextMonth()
Or – more versatile – according to the other isDateIn... methods as extension of Calendar
extension Calendar {
func isDateInNextMonth(_ date : Date) -> Bool {
let nextMonth = self.nextDate(after: Date(), matching: DateComponents(day:1), matchingPolicy: .nextTime)!
return self.compare(date, to: nextMonth, toGranularity: .month) == .orderedSame
}
}
and use it
Calendar.current.isDateInNextMonth(sender.date)
Edit:
If you want to check if the date is in the next 30 days it's still easier
extension Calendar {
func isDateInNextThirtyDays(_ date : Date) -> Bool {
return self.dateComponents([.month], from: Date(), to:date).month! < 1
}
}

Swift - check if a timestamp is yesterday, today, tomorrow, or X days ago

I'm trying to work out how to decide if a given timestamp occurs today, or +1 / -1 days. Essentially, I'd like to do something like this (Pseudocode)
IF days_from_today(timestamp) == -1 RETURN 'Yesterday'
ELSE IF days_from_today(timestamp) == 0 RETURN 'Today'
ELSE IF days_from_today(timestamp) == 1 RETURN 'Tomorrow'
ELSE IF days_from_today(timestamp) < 1 RETURN days_from_today(timestamp) + ' days ago'
ELSE RETURN 'In ' + days_from_today(timestamp) + ' ago'
Crucially though, it needs to be in Swift and I'm struggling with the NSDate / NSCalendar objects. I started with working out the time difference like this:
let calendar = NSCalendar.currentCalendar()
let date = NSDate(timeIntervalSince1970: Double(timestamp))
let timeDifference = calendar.components([.Second,.Minute,.Day,.Hour],
fromDate: date, toDate: NSDate(), options: NSCalendarOptions())
However comparing in this way isn't easy, because the .Day is different depending on the time of day and the timestamp. In PHP I'd just use mktime to create a new date, based on the start of the day (i.e. mktime(0,0,0)), but I'm not sure of the easiest way to do that in Swift.
Does anybody have a good idea on how to approach this? Perhaps an extension to NSDate or something similar would be best?
Swift 3/4/5:
Calendar.current.isDateInToday(yourDate)
Calendar.current.isDateInYesterday(yourDate)
Calendar.current.isDateInTomorrow(yourDate)
Additionally:
Calendar.current.isDateInWeekend(yourDate)
Note that for some countries weekend may be different than Saturday-Sunday, it depends on the calendar.
You can also use autoupdatingCurrent instead of current calendar, which will track user updates. You use it the same way:
Calendar.autoupdatingCurrent.isDateInToday(yourDate)
Calendar is a type alias for the NSCalendar.
Calendar has methods for all three cases
func isDateInYesterday(_ date: Date) -> Bool
func isDateInToday(_ date: Date) -> Bool
func isDateInTomorrow(_ date: Date) -> Bool
To calculate the days earlier than yesterday use
func dateComponents(_ components: Set<Calendar.Component>,
from start: Date,
to end: Date) -> DateComponents
pass [.day] to components and get the day property from the result.
This is a function which considers also is in for earlier and later dates by stripping the time part (Swift 3+).
func dayDifference(from interval : TimeInterval) -> String
{
let calendar = Calendar.current
let date = Date(timeIntervalSince1970: interval)
if calendar.isDateInYesterday(date) { return "Yesterday" }
else if calendar.isDateInToday(date) { return "Today" }
else if calendar.isDateInTomorrow(date) { return "Tomorrow" }
else {
let startOfNow = calendar.startOfDay(for: Date())
let startOfTimeStamp = calendar.startOfDay(for: date)
let components = calendar.dateComponents([.day], from: startOfNow, to: startOfTimeStamp)
let day = components.day!
if day < 1 { return "\(-day) days ago" }
else { return "In \(day) days" }
}
}
Alternatively you could use DateFormatter for Yesterday, Today and Tomorrow to get localized strings for free
func dayDifference(from interval : TimeInterval) -> String
{
let calendar = Calendar.current
let date = Date(timeIntervalSince1970: interval)
let startOfNow = calendar.startOfDay(for: Date())
let startOfTimeStamp = calendar.startOfDay(for: date)
let components = calendar.dateComponents([.day], from: startOfNow, to: startOfTimeStamp)
let day = components.day!
if abs(day) < 2 {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .none
formatter.doesRelativeDateFormatting = true
return formatter.string(from: date)
} else if day > 1 {
return "In \(day) days"
} else {
return "\(-day) days ago"
}
}
Update:
In macOS 10.15 / iOS 13 RelativeDateTimeFormatter was introduced to return (localized) strings relative to a specific date.
Swift 4 update:
let calendar = Calendar.current
let date = Date()
calendar.isDateInYesterday(date)
calendar.isDateInToday(date)
calendar.isDateInTomorrow(date)
NSCalender has new methods that you can use directly.
NSCalendar.currentCalendar().isDateInTomorrow(NSDate())//Replace NSDate() with your date
NSCalendar.currentCalendar().isDateInYesterday()
NSCalendar.currentCalendar().isDateInTomorrow()
Hope this helps
On Swift 5 and iOS 13 use the RelativeDateTimeFormatter,
let formatter = RelativeDateTimeFormatter()
formatter.dateTimeStyle = .named
formatter.localizedString(from: DateComponents(day: -1)) // "yesterday"
formatter.localizedString(from: DateComponents(day: 1)) // "Tomorrow"
formatter.localizedString(from: DateComponents(hour: 2)) // "in 2 hours"
formatter.localizedString(from: DateComponents(minute: 45)) // "in 45 minutes"
1)According to your example you want to receive labels "Yesterday", "Today" and etc. iOS can do this by default:
https://developer.apple.com/documentation/foundation/nsdateformatter/1415848-doesrelativedateformatting?language=objc
2)If you want to compute your custom label when iOS don't add these labels by itself then alternatively you can use 2 DateFormatter objects with both doesRelativeDateFormatting == true and doesRelativeDateFormatting == false and compare if their result date strings are the same or different

Swift 3 - Comparing Date objects

I'm updating my app to Swift 3.0 syntax (I know it's still in beta but I want to be prepared as soon as it released).
Until the previous Beta of Xcode (Beta 5) I was able to compare two Date objects using the operands <, > and ==. But in the latest beta (Beta 6) this isn't working any more. Here are some screenshots:
As you can see in both screenshots, these are two Date objects. But I get the following error:
What am I doing wrong? The functions are still declared in the Date class:
static func >(Date, Date)
Returns true if the left hand Date is later in time than the right hand Date.
Is this just a Beta bug or am I doing something wrong?
I have tried this snippet (in Xcode 8 Beta 6), and it is working fine.
let date1 = Date()
let date2 = Date().addingTimeInterval(100)
if date1 == date2 { ... }
else if date1 > date2 { ... }
else if date1 < date2 { ... }
Date is Comparable & Equatable (as of Swift 3)
This answer complements #Ankit Thakur's answer.
Since Swift 3 the Date struct (based on the underlying NSDate class) adopts the Comparable and Equatable protocols.
Comparable requires that Date implement the operators: <, <=, >, >=.
Equatable requires that Date implement the == operator.
Equatable allows Date to use the default implementation of the != operator (which is the inverse of the Equatable == operator implementation).
The following sample code exercises these comparison operators and confirms which comparisons are true with print statements.
Comparison function
import Foundation
func describeComparison(date1: Date, date2: Date) -> String {
var descriptionArray: [String] = []
if date1 < date2 {
descriptionArray.append("date1 < date2")
}
if date1 <= date2 {
descriptionArray.append("date1 <= date2")
}
if date1 > date2 {
descriptionArray.append("date1 > date2")
}
if date1 >= date2 {
descriptionArray.append("date1 >= date2")
}
if date1 == date2 {
descriptionArray.append("date1 == date2")
}
if date1 != date2 {
descriptionArray.append("date1 != date2")
}
return descriptionArray.joined(separator: ", ")
}
Sample Use
let now = Date()
describeComparison(date1: now, date2: now.addingTimeInterval(1))
// date1 < date2, date1 <= date2, date1 != date2
describeComparison(date1: now, date2: now.addingTimeInterval(-1))
// date1 > date2, date1 >= date2, date1 != date2
describeComparison(date1: now, date2: now)
// date1 <= date2, date1 >= date2, date1 == date2
from Swift 3 and above, Date is Comparable so we can directly compare dates like
let date1 = Date()
let date2 = Date().addingTimeInterval(50)
let isGreater = date1 > date2
print(isGreater)
let isSmaller = date1 < date2
print(isSmaller)
let isEqual = date1 == date2
print(isEqual)
Alternatively We can create extension on Date
extension Date {
func isEqualTo(_ date: Date) -> Bool {
return self == date
}
func isGreaterThan(_ date: Date) -> Bool {
return self > date
}
func isSmallerThan(_ date: Date) -> Bool {
return self < date
}
}
Use: let isEqual = date1.isEqualTo(date2)
Don't use comparators <, >, ==, !=.
Use compare(_ other: Date) function.
Usage
// Get current date
let dateA = Date()
// Get a later date (after a couple of milliseconds)
let dateB = Date()
// Compare them using switch
switch dateA.compare(dateB) {
case .orderedAscending : print("Date A is earlier than date B")
case .orderedDescending : print("Date A is later than date B")
case .orderedSame : print("The two dates are the same")
}
// Compare them using if
if dateA.compare(dateB) == .orderedAscending {
datePickerTo.date = datePicker.date
}
For me the problem was that I had my own extension to Date class that was defining all the compare operators. Now (since swift 3) that Date is comparable, these extensions are not needed. So I commented them out and it worked.
SWIFT 3: Don't know if this is what you're looking for. But I compare a string to a current timestamp to see if my string is older that now.
func checkTimeStamp(date: String!) -> Bool {
let dateFormatter: DateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
dateFormatter.locale = Locale(identifier:"en_US_POSIX")
let datecomponents = dateFormatter.date(from: date)
let now = Date()
if (datecomponents! >= now) {
return true
} else {
return false
}
}
To use it:
if (checkTimeStamp(date:"2016-11-21 12:00:00") == false) {
// Do something
}
If you want to ignore seconds for example
you can use
func isDate(Date, equalTo: Date, toUnitGranularity: NSCalendar.Unit) -> Bool
Example compare if it's the same day:
Calendar.current.isDate(date1, equalTo: date2, toGranularity: .day)
To compare date only with year - month - day and without time for me worked like this:
let order = Calendar.current.compare(self.startDate, to: compareDate!, toGranularity: .day)
switch order {
case .orderedAscending:
print("\(gpsDate) is after \(self.startDate)")
case .orderedDescending:
print("\(gpsDate) is before \(self.startDate)")
default:
print("\(gpsDate) is the same as \(self.startDate)")
}
As of the time of this writing, Swift natively supports comparing Dates with all comparison operators (i.e. <, <=, ==, >=, and >). You can also compare optional Dates but are limited to <, ==, and >. If you need to compare two optional dates using <= or >=, i.e.
let date1: Date? = ...
let date2: Date? = ...
if date1 >= date2 { ... }
You can overload the <= and >=operators to support optionals:
func <= <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
return lhs == rhs || lhs < rhs
}
func >= <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
return lhs == rhs || lhs > rhs
}
extension Date {
func isBetween(_ date1: Date, and date2: Date) -> Bool {
return (min(date1, date2) ... max(date1, date2)).contains(self)
}
}
let resultArray = dateArray.filter { $0.dateObj!.isBetween(startDate, and: endDate) }
Another way to do it:
switch date1.compare(date2) {
case .orderedAscending:
break
case .orderedDescending:
break;
case .orderedSame:
break
}
var strDateValidate = ""
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let firstDate = dateFormatter.date(from:lblStartTime.text!)
let secondDate = dateFormatter.date(from:lblEndTime.text!)
if firstDate?.compare(secondDate!) == .orderedSame || firstDate?.compare(secondDate!) == .orderedAscending {
print("Both dates are same or first is less than scecond")
strDateValidate = "yes"
}
else
{
//second date is bigger than first
strDateValidate = "no"
}
if strDateValidate == "no"
{
alertView(message: "Start date and end date for a booking must be equal or Start date must be smaller than the end date", controller: self)
}
Swift 5:
1) If you use Date type:
let firstDate = Date()
let secondDate = Date()
print(firstDate > secondDate)
print(firstDate < secondDate)
print(firstDate == secondDate)
2) If you use String type:
let firstStringDate = "2019-05-22T09:56:00.1111111"
let secondStringDate = "2019-05-22T09:56:00.2222222"
print(firstStringDate > secondStringDate) // false
print(firstStringDate < secondStringDate) // true
print(firstStringDate == secondStringDate) // false
I'm not sure or the second option works at 100%. But how much would I not change the values of firstStringDate and secondStringDate the result was correct.
in Swift 3,4 you should use "Compare".
for example:
DateArray.sort { (($0)?.compare($1))! == .orderedDescending }

How to Add events to FSCalendar Swift?

I am using FSCalendar to add calendar UI in my project . But I am unable to find any solution to add events to the calendar. So any ideas on how to add events to FSCalendar or any third party calendar framework?
To Set Events Base On Dates..
Instance of DateFormatter And Variables:
var datesWithEvent = ["2015-10-03", "2015-10-06", "2015-10-12", "2015-10-25"]
var datesWithMultipleEvents = ["2015-10-08", "2015-10-16", "2015-10-20", "2015-10-28"]
fileprivate lazy var dateFormatter2: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
next is... DataSource Function:
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
let dateString = self.dateFormatter2.string(from: date)
if self.datesWithEvent.contains(dateString) {
return 1
}
if self.datesWithMultipleEvents.contains(dateString) {
return 3
}
return 0
}
I Hope This Help You, This Code is Base On FsCalendar Sample Project.
I have an array that contains events's dates and the number of event on this date what I did is:
1- Comparing dates(comparing dates without time using compareDate(data.eventDate!, toDate: date, toUnitGranularity: .Day)) from my array with date(in the function)
2- If they're equal I'll add date to an array(datesWithEvent) without time so I can compare it later without problems
3- return true when it finds the right dates
var datesWithEvent:[NSDate] = []
func calendar(calendar: FSCalendar, hasEventForDate date: NSDate) -> Bool {
for data in eventsArray{
let order = NSCalendar.currentCalendar().compareDate(data.eventDate!, toDate: date, toUnitGranularity: .Day)
if order == NSComparisonResult.OrderedSame{
let unitFlags: NSCalendarUnit = [ .Day, .Month, .Year]
let calendar2: NSCalendar = NSCalendar.currentCalendar()
let components: NSDateComponents = calendar2.components(unitFlags, fromDate: data.eventDate!)
datesWithEvent.append(calendar2.dateFromComponents(components)!)
}
}
return datesWithEvent.contains(date)
}
And to precise the number of event on this date (different number of dots) I've added this code
func calendar(calendar: FSCalendar, numberOfEventsForDate date: NSDate) -> Int {
for data in eventsArray{
let order = NSCalendar.currentCalendar().compareDate(data.eventDate!, toDate: date, toUnitGranularity: .Day)
if order == NSComparisonResult.OrderedSame{
return data.numberOfEvent!
}
}
return 0
}
Try this code,in Objective-C
- (NSInteger)calendar:(FSCalendar *)calendar numberOfEventsForDate:(NSDate*)date
{
NSString *dateString = [calendar stringFromDate:date format:#"yyyy-MM-dd"];
if ([_datesWithEvent containsObject:dateString]){
return 1;
}
else{
NSLog(#"........Events List........");
}
return 0;
}
try these code it will help you
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
let dateString = self.dateFormatter.string(from: date)
print(dateString)
// datesForEvents : array of dates
if self.datesForEvents.contains(dateString) {
return 1
}
return 0

Check if date is before current date (Swift)

I would like to check if a NSDate is before (in the past) by comparing it to the current date. How would I do this?
Thanks
I find the earlierDate method.
if date1.earlierDate(date2).isEqualToDate(date1) {
print("date1 is earlier than date2")
}
You also have the laterDate method.
Swift 3 to swift 5:
if date1 < date2 {
print("date1 is earlier than date2")
}
There is a simple way to do that. (Swift 3 is even more simple, check at end of answer)
Swift code:
if myDate.timeIntervalSinceNow.isSignMinus {
//myDate is earlier than Now (date and time)
} else {
//myDate is equal or after than Now (date and time)
}
If you need compare date without time ("MM/dd/yyyy").
Swift code:
//Ref date
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MM/dd/yyyy"
let someDate = dateFormatter.dateFromString("03/10/2015")
//Get calendar
let calendar = NSCalendar.currentCalendar()
//Get just MM/dd/yyyy from current date
let flags = NSCalendarUnit.CalendarUnitDay | NSCalendarUnit.CalendarUnitMonth | NSCalendarUnit.CalendarUnitYear
let components = calendar.components(flags, fromDate: NSDate())
//Convert to NSDate
let today = calendar.dateFromComponents(components)
if someDate!.timeIntervalSinceDate(today!).isSignMinus {
//someDate is berofe than today
} else {
//someDate is equal or after than today
}
Apple docs link here.
Edit 1: Important
From Swift 3 migration notes:
The migrator is conservative but there are some uses of NSDate that have better representations in Swift 3:
(x as NSDate).earlierDate(y) can be changed to x < y ? x : y
(x as NSDate).laterDate(y) can be changed to x < y ? y : x
So, in Swift 3 you be able to use comparison operators.
If you need to compare one date with now without creation of new Date object you can simply use this in Swift 3:
if (futureDate.timeIntervalSinceNow.sign == .plus) {
// date is in future
}
and
if (dateInPast.timeIntervalSinceNow.sign == .minus) {
// date is in past
}
You don't need to extend NSDate here, just use "compare" as illustrated in the docs.
For example, in Swift:
if currentDate.compare(myDate) == NSComparisonResult.OrderedDescending {
println("myDate is earlier than currentDate")
}
You can extend NSDate to conform to the Equatable and Comparable protocols. These are comparison protocols in Swift and allow the familiar comparison operators (==, <, > etc.) to work with dates. Put the following in a suitably named file, e.g. NSDate+Comparison.swift in your project:
extension NSDate: Equatable {}
extension NSDate: Comparable {}
public func ==(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.timeIntervalSince1970 == rhs.timeIntervalSince1970
}
public func <(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.timeIntervalSince1970 < rhs.timeIntervalSince1970
}
Now you can check if one date is before another with standard comparison operators.
let date1 = NSDate(timeIntervalSince1970: 30)
let date2 = NSDate()
if date1 < date2 {
print("ok")
}
For information on extensions in Swift see here. For information on the Equatable and Comparable protocols see here and here, respectively.
Note: In this instance we're not creating custom operators, merely extending an existing type to support existing operators.
Here is an extension in Swift to check if the date is past date.
extension Date {
var isPastDate: Bool {
return self < Date()
}
}
Usage:
let someDate = Date().addingTimeInterval(1)
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
print(date.isPastDate)
}
In Swift5
let nextDay = Calendar.current.date(byAdding: .day, value: -1, to: Date())
let toDay = Date()
print(toDay)
print(nextDay!)
if nextDay! < toDay {
print("date1 is earlier than date2")
}
let nextDay = Calendar.current.date(byAdding: .month, value: 1, to: Date())
let toDay = Date()
print(toDay)
print(nextDay!)
if nextDay! >= toDay {
print("date2 is earlier than date1")
}
In Swift 4 you can use this code
if endDate.timeIntervalSince(startDate).sign == FloatingPointSign.minus {
// endDate is in past
}
we can use < for checking date:
if myDate < Date() {
}
Since Swift 3, Dates are comparable so
if date1 < date2 { // do something }
They're also comparable so you can compare with == if you want.
Upgrading Vagner's answer to Swift 5:
import Foundation
//Ref date
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/dd/yyyy"
//Get calendar
let calendar = NSCalendar.current
//Get just MM/dd/yyyy from current date
let flags: Set<Calendar.Component> = [Calendar.Component.day, Calendar.Component.month, Calendar.Component.year]
let components = calendar.dateComponents(flags, from: Date())
//Convert to NSDate
if let today = calendar.date(from: components), let someDate = dateFormatter.date(from: "03/10/2015"), someDate.timeIntervalSince(today).sign == .minus {
//someDate is berofe than today
} else {
//someDate is equal or after than today
}
Made a quick Swift 2.3 function out of this
// if you omit last parameter you comare with today
// use "11/20/2016" for 20 nov 2016
func dateIsBefore(customDate:String, referenceDate:String="today") -> Bool {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MM/dd/yyyy"
let myDate = dateFormatter.dateFromString(customDate)
let refDate = referenceDate == "today"
? NSDate()
: dateFormatter.dateFromString(referenceDate)
if NSDate().compare(myDate!) == NSComparisonResult.OrderedDescending {
return false
} else {
return true
}
}
Use it like this to see if your date is before today's date
if dateIsBefore("12/25/2016") {
print("Not Yet Christmas 2016 :(")
} else {
print("Christmas Or Later!")
}
Or with a custom reference date
if dateIsBefore("12/25/2016", referenceDate:"12/31/2016") {
print("Christmas comes before new years!")
} else {
print("Something is really wrong with the world...")
}

Resources