How to sort an array dates in swift 4 - ios

I have an array of dates like this :-
var dateArray = ["2016-04-20", "2016-04-22", "2016-04-25", "2016-04-30"]
and I want to find out the difference of days between them. I do some research and i am able to do that with only two dates here is the approach i did in finding the difference between two date
let dateFormatter = DateFormatter()
let isoDate = "2016-04-20"
let calendar = NSCalendar.current
let currentDate = Date()
And in my viewDidLoad method I did this
override func viewDidLoad() {
super.viewDidLoad()
// let components = calendar.dateComponents([.day], from: )
dateFormatter.dateFormat = "yyyy-MM-dd"
dateFormatter.locale = Locale(identifier: "en_US_POSIX") //en_US_POSIX
let formatedStartDate = dateFormatter.date(from: isoDate)
let date = dateArray.compactMap { dateFormatter.date(from: $0) } // for date array
print(date)
let components = Set<Calendar.Component>([.day])
let differenceOfDate = Calendar.current.dateComponents(components, from: formatedStartDate!, to: currentDate )
print (differenceOfDate)
apiData()
}
As you can see in the code i created a constant let isoDate = "2016-04-20" and changed into formatedStartDate and find the difference between form this date to current date then it worked. But what if I have my own array of dates and how can i find the difference of my own array of dates and sort it into increasing or decreasing order. Please help?

Create the date formatter
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
dateFormatter.locale = Locale(identifier: "en_US_POSIX") //en_US_POSIX
Map the date string array to Date instances
let dateStringArray = ["2016-04-20", "2016-04-22", "2016-04-25", "2016-04-30"]
let dateArray = dateStringArray.map {dateFormatter.date(from: $0)!} // add .sorted() if the array is unordered.
In a loop get the differences between adjacent items
var differences = [Int]()
for i in 0..<dateArray.count - 1 {
let dayComponent = Calendar.current.dateComponents([.day], from: dateArray[i], to: dateArray[i+1])
differences.append(dayComponent.day!)
}
print(differences)

I'm not sure if you only want to compare the dates next to each other or compare each and every date. In the first case go with vadians solution. In the other case you can do something like this:
let dateStrings = ["2016-04-20", "2016-04-22", "2016-04-25", "2016-04-30"]
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
let dates = dateStrings.compactMap { dateFormatter.date(from: $0) }
let calendar = Calendar.current
var differences: [Int] = []
for i in 0..<dates.count {
for j in i + 1..<dates.count {
if let difference = calendar.dateComponents([.day], from: dates[i], to: dates[j]).day {
differences.append(difference)
}
}
}
let descendingDifferences = differences.sorted(by: >)
print(descendingDifferences) // results in [10, 8, 5, 5, 3, 2]

Related

Get month and date separately from date string

I have got a date in this format..
2019-12-16 18:30:00 +0000
This is the code I have for that..
var utcTime = "\(dic["dueDate"]!)"
self.dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
self.dateFormatter.locale = Locale(identifier: "en_US")
let date = self.dateFormatter.date(from:utcTime)!
print(date)
I wanted to extract month and date from this string. i.e. from the above date string, I want 'December' & '16' separately.
There are several ways to get the expected result, as an option you can use this code with Calendar:
let utcTime = "2020-01-17T22:01:00"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
dateFormatter.locale = Locale(identifier: "en_US")
if let date = dateFormatter.date(from:utcTime) {
let monthInt = Calendar.current.component(.month, from: date)
let dayInt = Calendar.current.component(.day, from: date)
let monthStr = Calendar.current.monthSymbols[monthInt-1]
print(monthStr, dayInt)
}
Welcome to stack overflow.
You can try this :
let calendar = Calendar.current
calendar.component(.year, from: date)
calendar.component(.month, from: date)
calendar.component(.day, from: date)
Hope it helps...
Welcome to stack overflow. Please try this.
func getMonthAndDate(dateString: String) ->(month:String , day:String) {
guard let date = Date.getMonthAndDate(from: dateString, with: "yyyy-MM-dd'T'HH:mm:ss") else {
return ("","")
}
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMMM"
let month = dateFormatter.string(from: date)
dateFormatter.dateFormat = "dd"
let day = dateFormatter.string(from: date)
return (month,day)
}
extension Date {
static func getMonthAndDate(from str: String, with formatter: String) -> Date? {
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone.current//(abbreviation: "GMT") //Set timezone that you want
dateFormatter.locale = NSLocale.current
dateFormatter.dateFormat = formatter //Specify your format that you want
return dateFormatter.date(from: str)
}
}
Swift 5
Here is the extension you need It returns tuple having Month and date as you wanted to have
extension Date {
func getMonthAndDate() ->(month:String , day:String) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMMM"
let month = dateFormatter.string(from: self)
dateFormatter.dateFormat = "dd"
let day = dateFormatter.string(from: self)
return (month,day)
}
}
I give you example of month u can get date and month value separately ,
visit link for your format http://userguide.icu-project.org/formatparse/datetime
extension Date {
var month: String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMMM"
return dateFormatter.string(from: self)
}
}
you can use it in this way:
let date = Date()
let monthString = date.month
try same thing for date, I hope it will work for you... :)
this is an example from your code. I have stored month and day in separate string to show you. You can change according to your requirements.
var utcTime = "2019-12-16 18:30:00 +0000"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss z"
dateFormatter.locale = Locale(identifier: "en_US")
let date = dateFormatter.date(from:utcTime)!
print(date) //2019-12-16 18:30:00 +0000
dateFormatter.dateFormat = "MMMM"
let strMonth = dateFormatter.string(from: date)
print(strMonth) //December
dateFormatter.dateFormat = "dd"
let strDay = dateFormatter.string(from: date)
print(strDay) //16
Also you can use Calendar object to get date, month (gives you in digit) and year.
var utcTime = "2019-12-16 18:30:00 +0000"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss z"
dateFormatter.locale = Locale(identifier: "en_US")
let date = dateFormatter.date(from:utcTime)!
let calendarDate = Calendar.current.dateComponents([.day, .year, .month], from: date)
let day = calendarDate.day
print(day) //16
let month = calendarDate.month
print(month) //12
let year = calendarDate.year
print(year) //2019
You can get the day, month and year as follows
let yourDate = Calendar.current.dateComponents([.day, .year, .month], from: Date())
if let day = yourDate.day, let month = yourDate.month, let year = yourDate.year {
let monthName = Calendar.current.monthSymbols[month - 1]
// your code here
}
extension String {
func getMonthDay() -> (Int,Int) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ssZ"
let date = dateFormatter.date(from: self) ?? Date()
let calendar = Calendar.current
let month = calendar.component(.month, from: date)
let day = calendar.component(.day, from: date)
return (month, day)
}
}

How to Calculate Days From Two Dates in Swift [same dates should count as "I" day ]

Hi I am Calculating days from two dates and I am taking same dates to apply leave and that difference should be "1" leave and my code is calculating as "0"
my code:
fromDateTextField.text = 29-06-2019
toDateTextField.text = 29-06-2019
let startDate = fromDateTxtField.text
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy"
let formatedStartDate = dateFormatter.date(from: startDate!)
let currentDate = toDateTxtField.text
dateFormatter.dateFormat = "dd-MM-yyyy"
let formatedEndDate = dateFormatter.date(from: currentDate!)
print(formatedEndDate)
print(formatedStartDate)
let components1 = Set<Calendar.Component>([.day])
let differenceOfDate = Calendar.current.dateComponents(components1, from: formatedStartDate!, to: formatedEndDate!)
print (differenceOfDate.day)
output I am getting is "0"

Create string array of dates from Dates range

I have Date() properties. startingAt and endingAt. And an array of Date(), which are alreadyRegistred. I have to create an array of strings with dates between startingAt and endingAt. StartingAt and endingAt are included and the last requirement is to exclude alreadyRegistred dates.
Do you have some elegant idea, how to do it? Thanks for help!
Edit: Maximum number of dates in final array will be about 7 days.
Dont forget that a Date is basically just a timestamp, and that you can have access to the addingTimeInterval(_:) method.
Knowing that, is very easy to do some calculation between two dates.
I do not have the whole knowledge about your required business logic, but here is a naive implementation that generates Dates between two dates. I'm sure you can run it in a playground and explore a little bit.
import UIKit
func intervalDates(from startingDate:Date, to endDate:Date, with interval:TimeInterval) -> [Date] {
guard interval > 0 else { return [] }
var dates:[Date] = []
var currentDate = startingDate
while currentDate <= endDate {
currentDate = currentDate.addingTimeInterval(interval)
dates.append(currentDate)
}
return dates
}
let startingDate = Date() // now
let endDate = Date(timeIntervalSinceNow: 3600 * 24 * 7) // one week from now
let intervalBetweenDates:TimeInterval = 3600 * 3// three hours
let dates:[Date] = intervalDates(from: startingDate, to: endDate, with: intervalBetweenDates)
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .long
dateFormatter.timeStyle = .long
let dateStrings = dates.map{dateFormatter.string(from: $0)}
print("NOW : \(startingDate)")
for (index, string) in dateStrings.enumerated() {
print("\(index) : \(string)")
}
print("END DATE : \(endDate)")
Try this and see:
// Start & End date string
let startingAt = "01/01/2018"
let endingAt = "08/03/2018"
// Sample date formatter
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy"
// start and end date object from string dates
var startDate = dateFormatter.date(from: startingAt) ?? Date()
let endDate = dateFormatter.date(from: endingAt) ?? Date()
// String date array, to be excluded
let alreadyRegistred = ["01/01/2018", "15/01/2018", "10/02/2018", "20/02/2018", "05/03/2018"]
// Actual operational logic
var dateRange: [String] = []
while startDate <= endDate {
let stringDate = dateFormatter.string(from: startDate)
startDate = Calendar.current.date(byAdding: .day, value: 1, to: startDate) ?? Date()
if (alreadyRegistred.contains(stringDate)) {
continue
} else {
dateRange.append(stringDate)
}
}
print("Resulting Array - \(dateRange)")
Here is result:
Resulting Array - ["02/01/2018", "03/01/2018", "04/01/2018", "05/01/2018", "06/01/2018", "07/01/2018", "08/01/2018", "09/01/2018", "10/01/2018", "11/01/2018", "12/01/2018", "13/01/2018", "14/01/2018", "16/01/2018", "17/01/2018", "18/01/2018", "19/01/2018", "20/01/2018", "21/01/2018", "22/01/2018", "23/01/2018", "24/01/2018", "25/01/2018", "26/01/2018", "27/01/2018", "28/01/2018", "29/01/2018", "30/01/2018", "31/01/2018", "01/02/2018", "02/02/2018", "03/02/2018", "04/02/2018", "05/02/2018", "06/02/2018", "07/02/2018", "08/02/2018", "09/02/2018", "11/02/2018", "12/02/2018", "13/02/2018", "14/02/2018", "15/02/2018", "16/02/2018", "17/02/2018", "18/02/2018", "19/02/2018", "21/02/2018", "22/02/2018", "23/02/2018", "24/02/2018", "25/02/2018", "26/02/2018", "27/02/2018", "28/02/2018", "01/03/2018", "02/03/2018", "03/03/2018", "04/03/2018", "06/03/2018", "07/03/2018", "08/03/2018"]
let startDate = Date()
let endDate = Date().addingTimeInterval(24*60*60*10) // i did this to get the end date for now
var stringdateArray = [String]()
if let days = getNumberofDays(date1: startDate, date2: endDate) {
for i in 0...days-1 {
let date = startDate.addingTimeInterval(Double(i)*24*3600)
let stringDate = getStringDate(fromDate: date, havingFormat: "yyyy-MM-dd")
if !(alreadyRegisteredArray.contains(stringDate)) { // checking if already registered
stringdateArray.append(stringDate)
}
}
}
and our helper method
let dateFormatter = DateFormatter()
func getStringDate(fromDate: Date,havingFormat: String) -> String {
dateFormatter.dateFormat = havingFormat
dateFormatter.amSymbol = "AM"
dateFormatter.pmSymbol = "PM"
let date = dateFormatter.string(from: fromDate)
return date
}
func getNumberofDays(date1: Date, date2: Date) -> Int? {
let calendar = NSCalendar.current
let date1 = calendar.startOfDay(for: date1)
let date2 = calendar.startOfDay(for: date2)
let components = calendar.dateComponents([.day], from: date1, to: date2)
return components.day
}

Display date in "st" , "nd", "rd" and "th" format

I have to display date in different format.
For eg.
21st July
I didn't find anything to convert my date in this format. If anyone knows please help me.
Swift
extension Date {
func dateFormatWithSuffix() -> String {
return "dd'\(self.daySuffix())' MMMM yyyy"
}
func daySuffix() -> String {
let calendar = Calendar.current
let components = (calendar as NSCalendar).components(.day, from: self)
let dayOfMonth = components.day
switch dayOfMonth {
case 1, 21, 31:
return "st"
case 2, 22:
return "nd"
case 3, 23:
return "rd"
default:
return "th"
}
}
}
Example
let date = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = date.dateFormatWithSuffix()
print(dateFormatter.string(from: date))
// Output for current date: 22nd May 2019
func setCurrentDate() {
let date = Date()
// Use this to add st, nd, th, to the day
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .ordinal
numberFormatter.locale = Locale.current
//Set other sections as preferred
let monthFormatter = DateFormatter()
monthFormatter.dateFormat = "MMM"
// Works well for adding suffix
let dayFormatter = DateFormatter()
dayFormatter.dateFormat = "dd"
let dayString = dayFormatter.string(from: date)
let monthString = monthFormatter.string(from: date)
// Add the suffix to the day
let dayNumber = NSNumber(value: Int(dayString)!)
let day = numberFormatter.string(from: dayNumber)!
yourDateLabel.text = "\(day) \(monthString)"
}
Label will currently be set to 25th May
You can use NSDateFormatter to display your NSDate. It has properties such as dateStyle, and timeStyle which can easily be altered to get your desired format. If you need more flexibility there's the dateFormat property as well.
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
formatter.stringFromDate(NSDate())

iOS Swift converting calendar component int month to medium style string month

I want to display calendar in this format
to the user. One option is to use "string range" to get the individual calendar components. The second one is to get it using NSCalendar which to me looks like the better one (is it?). So my code is as below. But there are two problems.
I am not getting the local time form "hour & minute components"
I am getting month in Int. I want it to be in String (month in mediumStyle)
Anyone know how to get what I need? Image attached is what exactly I want to achieve. There I am using three UILabel one for "date", second for "month, year" and third for "time".
Any help would be appreciated.
var inputDateString = "Jun/12/2015 02:05 Am +05:00"
override func viewDidLoad() {
super.viewDidLoad()
let newDate = dateformatterDateString(inputDateString)
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitHour | .CalendarUnitMinute | .CalendarUnitMonth | .CalendarUnitYear | .CalendarUnitDay, fromDate: newDate!)
let hour = components.hour
let minutes = components.minute
let month = components.month
let year = components.year
let day = components.day
println(newDate)
println(components)
println(day) // 12
println(month) // 6 -----> Want to have "Jun" here
println(year) // 2015
println(hour) // 2 ------> Want to have the hour in the inputString i.e. 02
println(minutes) // 35 ------> Want to have the minute in the inputString i.e. 05
}
func dateformatterDateString(dateString: String) -> NSDate? {
let dateFormatter: NSDateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MMM/dd/yyyy hh:mm a Z"
// dateFormatter.timeZone = NSTimeZone(abbreviation: "UTC")
dateFormatter.timeZone = NSTimeZone.localTimeZone()
return dateFormatter.dateFromString(dateString)
}
You can use DateFormatter as follow:
extension Formatter {
static let monthMedium: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "LLL"
return formatter
}()
static let hour12: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "h"
return formatter
}()
static let minute0x: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "mm"
return formatter
}()
static let amPM: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "a"
return formatter
}()
}
extension Date {
var monthMedium: String { return Formatter.monthMedium.string(from: self) }
var hour12: String { return Formatter.hour12.string(from: self) }
var minute0x: String { return Formatter.minute0x.string(from: self) }
var amPM: String { return Formatter.amPM.string(from: self) }
}
let date = Date()
let dateMonth = date.monthMedium // "May"
let dateHour = date.hour12 // "1"
let dateMinute = date.minute0x // "18"
let dateAmPm = date.amPM // "PM"
NSDateFormatter has monthSymbols, shortMonthSymbols and veryShortSymbols properties.
So try this:
let dateFormatter: NSDateFormatter = NSDateFormatter()
let months = dateFormatter.shortMonthSymbols
let monthSymbol = months[month-1] as! String // month - from your date components
println(monthSymbol)
I am adding three types. Have a look.
//Todays Date
let todayDate = NSDate()
let calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)!
let components = calendar.components(.CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay, fromDate: todayDate)
var (year, month, date) = (components.year, components.month, components.day)
println("YEAR: \(year) MONTH: \(month) DATE: \(date)")
//Making a X mas Yr
let morningOfChristmasComponents = NSDateComponents()
morningOfChristmasComponents.year = 2014
morningOfChristmasComponents.month = 12
morningOfChristmasComponents.day = 25
morningOfChristmasComponents.hour = 7
morningOfChristmasComponents.minute = 0
morningOfChristmasComponents.second = 0
let morningOfChristmas = NSCalendar.currentCalendar().dateFromComponents(morningOfChristmasComponents)!
let formatter = NSDateFormatter()
formatter.dateStyle = NSDateFormatterStyle.LongStyle
formatter.timeStyle = .MediumStyle
let dateString = formatter.stringFromDate(morningOfChristmas)
print("dateString : \(dateString)")
//Current month - complete name
let dateFormatter: NSDateFormatter = NSDateFormatter()
let months = dateFormatter.monthSymbols
let monthSymbol = months[month-1] as! String
println("monthSymbol : \(monthSymbol)")
Print Results:
YEAR: 2015 MONTH: 10 DATE: 9
dateString : December 25, 2014 at 7:00:00 AM
monthSymbol : October
Update Swift 5.x Solution:
Today is Monday, 20 April, 2020
let date = Date() // get a current date instance
let dateFormatter = DateFormatter() // get a date formatter instance
let calendar = dateFormatter.calendar // get a calendar instance
Now you can get every index value of year, month, week, day everything what you want as follows:
let year = calendar?.component(.year, from: date) // Result: 2020
let month = calendar?.component(.month, from: date) // Result: 4
let week = calendar?.component(.weekOfMonth, from: date) // Result: 4
let day = calendar?.component(.day, from: date) // Result: 20
let weekday = calendar?.component(.weekday, from: date) // Result: 2
let weekdayOrdinal = calendar?.component(.weekdayOrdinal, from: date) // Result: 3
let weekOfYear = calendar?.component(.weekOfYear, from: date) // Result: 17
You can get an array of all month names like:
let monthsWithFullName = dateFormatter.monthSymbols // Result: ["January”, "February”, "March”, "April”, "May”, "June”, "July”, "August”, "September”, "October”, "November”, "December”]
let monthsWithShortName = dateFormatter.shortMonthSymbols // Result: ["Jan”, "Feb”, "Mar”, "Apr”, "May”, "Jun”, "Jul”, "Aug”, "Sep”, "Oct”, "Nov”, "Dec”]
You can format current date as you wish like:
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let todayWithTime = dateFormatter.string(from: date) // Result: "2020-04-20 06:17:29"
dateFormatter.dateFormat = "yyyy-MM-dd"
let onlyTodayDate = dateFormatter.string(from: date) // Result: "2020-04-20"
I think this is the most simpler and updated answer.
Swift 4.x Solution:
//if currentMonth = 1
DateFormatter().monthSymbols[currentMonth - 1]
Answer:
January
let now = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "LLLL"
let nameOfMonth = dateFormatter.string(from: now)

Resources