This is best done using an extension to the existing NSDate
class.
The following extension adds a new initializer which will create a date in the current locale using the date string in the format you specified.
extension NSDate
{
convenience
init(dateString:String) {
let dateStringFormatter = NSDateFormatter()
dateStringFormatter.dateFormat = "yyyy-MM-dd"
dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
let d = dateStringFormatter.dateFromString(dateString)!
self.init(timeInterval:0, sinceDate:d)
}
}
Now you can create an NSDate from Swift just by doing:
NSDate(dateString:"2014-06-06")
Please note that this implementation does not cache the NSDateFormatter, which you might want to do for performance reasons if you expect to be creating many NSDate
s in this way.
Please also note that this implementation will simply crash if you try to initialize an NSDate
by passing in a string that cannot be parsed correctly. This is because of the forced unwrap of the optional value returned by dateFromString
. If you wanted to return a nil
on bad parses, you would ideally use a failible initializer; but you cannot do that now (June 2015), because of a limitation in Swift 1.2, so then you're next best choice is to use a class factory method.
A more elaborate example, which addresses both issues, is here: https://gist.github.com/algal/09b08515460b7bd229fa .
extension Date {
init(_ dateString:String) {
let dateStringFormatter = DateFormatter()
dateStringFormatter.dateFormat = "yyyy-MM-dd"
dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale
let date = dateStringFormatter.date(from: dateString)!
self.init(timeInterval:0, since:date)
}
}
According to Apple documentation
Example :
var myObject = NSDate()
let futureDate = myObject.dateByAddingTimeInterval(10)
let timeSinceNow = myObject.timeIntervalSinceNow
According to Apple's Data Formatting Guide
Creating a date formatter is not a cheap operation. If you are likely to use a formatter frequently, it is typically more efficient to cache a single instance than to create and dispose of multiple instances. One approach is to use a static variable
And while I agree with @Leon that this should be failable initializer, when you enter seed data, we could have one that isn't failable (just like there is UIImage(imageLiteralResourceName:)
).
So here's my approach:
extension DateFormatter {
static let yyyyMMdd: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
formatter.calendar = Calendar(identifier: .iso8601)
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}()
}
extension Date {
init?(yyyyMMdd: String) {
guard let date = DateFormatter.yyyyMMdd.date(from: yyyyMMdd) else { return nil }
self.init(timeInterval: 0, since: date)
}
init(dateLiteralString yyyyMMdd: String) {
let date = DateFormatter.yyyyMMdd.date(from: yyyyMMdd)!
self.init(timeInterval: 0, since: date)
}
}
And now enjoy simply calling:
// For seed data
Date(dateLiteralString: "2020-03-30")
// When parsing data
guard let date = Date(yyyyMMdd: "2020-03-30") else { return nil }
In, Swift 3.0 you have set date object for this way.
extension Date
{
init(dateString:String) {
let dateStringFormatter = DateFormatter()
dateStringFormatter.dateFormat = "yyyy-MM-dd"
dateStringFormatter.locale = Locale(identifier: "en_US_POSIX")
let d = dateStringFormatter.date(from: dateString)!
self(timeInterval:0, since:d)
}
}
Here's how I did it in Swift 4.2:
extension Date {
/// Create a date from specified parameters
///
/// - Parameters:
/// - year: The desired year
/// - month: The desired month
/// - day: The desired day
/// - Returns: A `Date` object
static func from(year: Int, month: Int, day: Int) -> Date? {
let calendar = Calendar(identifier: .gregorian)
var dateComponents = DateComponents()
dateComponents.year = year
dateComponents.month = month
dateComponents.day = day
return calendar.date(from: dateComponents) ?? nil
}
}
Usage:
let marsOpportunityLaunchDate = Date.from(year: 2003, month: 07, day: 07)
According to @mythz answer, I decide to post updated version of his extension using swift3
syntax.
extension Date {
static func from(_ year: Int, _ month: Int, _ day: Int) -> Date?
{
let gregorianCalendar = Calendar(identifier: .gregorian)
let dateComponents = DateComponents(calendar: gregorianCalendar, year: year, month: month, day: day)
return gregorianCalendar.date(from: dateComponents)
}
}
I don't use parse
method, but if someone needs, I will update this post.
Personally I think it should be a failable initialiser:
extension Date {
init?(dateString: String) {
let dateStringFormatter = DateFormatter()
dateStringFormatter.dateFormat = "yyyy-MM-dd"
if let d = dateStringFormatter.date(from: dateString) {
self.init(timeInterval: 0, since: d)
} else {
return nil
}
}
}
Otherwise a string with an invalid format will raise an exception.
I often have a need to combine date values from one place with time values for another. I wrote a helper function to accomplish this.
let startDateTimeComponents = NSDateComponents()
startDateTimeComponents.year = NSCalendar.currentCalendar().components(NSCalendarUnit.Year, fromDate: date).year
startDateTimeComponents.month = NSCalendar.currentCalendar().components(NSCalendarUnit.Month, fromDate: date).month
startDateTimeComponents.day = NSCalendar.currentCalendar().components(NSCalendarUnit.Day, fromDate: date).day
startDateTimeComponents.hour = NSCalendar.currentCalendar().components(NSCalendarUnit.Hour, fromDate: time).hour
startDateTimeComponents.minute = NSCalendar.currentCalendar().components(NSCalendarUnit.Minute, fromDate: time).minute
let startDateCalendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)
combinedDateTime = startDateCalendar!.dateFromComponents(startDateTimeComponents)!
Swift doesn't have its own Date type, but you to use the existing Cocoa NSDate
type, e.g:
class Date {
class func from(year: Int, month: Int, day: Int) -> Date {
let gregorianCalendar = NSCalendar(calendarIdentifier: .gregorian)!
var dateComponents = DateComponents()
dateComponents.year = year
dateComponents.month = month
dateComponents.day = day
let date = gregorianCalendar.date(from: dateComponents)!
return date
}
class func parse(_ string: String, format: String = "yyyy-MM-dd") -> Date {
let dateFormatter = DateFormatter()
dateFormatter.timeZone = NSTimeZone.default
dateFormatter.dateFormat = format
let date = dateFormatter.date(from: string)!
return date
}
}
Which you can use like:
var date = Date.parse("2014-05-20")
var date = Date.from(year: 2014, month: 05, day: 20)
Source: Stackoverflow.com