Swift 4 Date is nil after formatting - swift

I have a date like so:
2014-10-28T00:00:00
and when I try to format it, it returns nil, this is what I tried:
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
let closingDate = formatter.date(from: item["closingDate"] as! String)
Why is it returning nil? and How can I fix it?

Drop the millisecond and the timezone from your format:
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"

Related

Creating Date object from timestamp in Swift [duplicate]

I get a crash when running and it points at the dateFormmater.timezone.
The error in the console is:
Could not cast value of type 'Swift.Optional' (0x1192bf4a8) to 'NSTimeZone' (0x1192c0270).
the value of rowEvents.date is "1480134638.0"
Im trying to pull out a Unix timestamp from Firebase saved as a string. Convert it to Date and again save it as a string so I can post it on a cell label.
I got this code from StackOverflow. I plugged in my data and everything is all good until I run it. I guess everything is not all good...
if let lastUpdated : String = rowEvents.date {
let epocTime = TimeInterval(lastUpdated)! / 1000 // convert it from milliseconds dividing it by 1000
let unixTimestamp = NSDate(timeIntervalSince1970: epocTime) //convert unix timestamp to Date
let dateFormatter = DateFormatter()
dateFormatter.timeZone = NSTimeZone() as TimeZone!
dateFormatter.locale = NSLocale.current // NSLocale(localeIdentifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
dateFormatter.date(from: String(describing: unixTimestamp))
let updatedTimeStamp = unixTimestamp
let cellDate = DateFormatter.localizedString(from: updatedTimeStamp as Date, dateStyle: DateFormatter.Style.full, timeStyle: DateFormatter.Style.medium)
cell.subtitleLabel.text = cellDate
}
The result came from this code here:
let myTimeStamp = self.datePicker?.date.timeIntervalSince1970
let calendarDate = String(describing: myTimeStamp! /** 1000*/)
You can convert unixTimestamp to date using Date(timeIntervalSince1970:).
let unixTimestamp = 1480134638.0
let date = Date(timeIntervalSince1970: unixTimestamp)
If you want to display date in string with specific formate than you can use DateFormatter like this way.
let date = Date(timeIntervalSince1970: unixtimeInterval)
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(abbreviation: "GMT") //Set timezone that you want
dateFormatter.locale = NSLocale.current
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm" //Specify your format that you want
let strDate = dateFormatter.string(from: date)
The problem is the line dateFormatter.timeZone = NSTimeZone() as TimeZone!.
Simply use TimeZone instead of NSTimeZone like
dateFormatter.timeZone = TimeZone.current and your code will work.
You might also remove your / 1000 because 1480134638.0 looks more like seconds than milliseconds (since 1970).
Swift 4.1. I created a function. Just pass you timeStamp in function param and function will return data in string data type. You can add more properties to DateFormatter object.
func getDateFromTimeStamp(timeStamp : Double) -> String {
let date = NSDate(timeIntervalSince1970: timeStamp / 1000)
let dayTimePeriodFormatter = DateFormatter()
dayTimePeriodFormatter.dateFormat = "dd MMM YY, hh:mm a"
// UnComment below to get only time
// dayTimePeriodFormatter.dateFormat = "hh:mm a"
let dateString = dayTimePeriodFormatter.string(from: date as Date)
return dateString
}
Using playground all I did was this.
let epochTime = 1547855446
let newTime = Date(timeIntervalSince1970: TimeInterval(epochTime))
print(newTime)
Returns this - 2019-01-18 23:50:46 +0000
extension Double{
func convertDate(formate: String) -> String {
let date = (timeIntervalSince1970: self)
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone.current
dateFormatter.locale = NSLocale(localeIdentifier: "(your localization language)" ) as Locale //localization language
dateFormatter.dateFormat = formate //Specify your format that you want let
strDate = dateFormatter.string(from: date)
return strDate
}
}
//usage
let timeStamp:Double = Double(1595407043)
print(timeStamp.convertDate(formate: "EEEE dd/MM/YYY"))
This solution is valid for swift 3 -> 4.2 :
you can add an extension on the Double that returns the date formatted:
extension Double {
// returns the date formatted.
var dateFormatted : String? {
let date = Date(timeIntervalSince1970: self)
let dateFormatter = DateFormatter()
dateFormatter.timeStyle = DateFormatter.Style.none //Set time style
dateFormatter.dateStyle = DateFormatter.Style.short //Set date style
return dateFormatter.string(from: date)
}
// returns the date formatted according to the format string provided.
func dateFormatted(withFormat format : String) -> String{
let date = Date(timeIntervalSince1970: self)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = format
return dateFormatter.string(from: date)
}
}
example on the above :
let timeStamp = 82749029.0
print(timeStamp. dateFormatted)
//output
//12/11/1994
let timeStamp = 82749029.0
print(timeStamp. dateFormatted(withFormat : "MM-dd-yyyy HH:mm"))
//output
//12-11-1994 13:04

How to get system time in formatted style swift?

I have such time which I have to send to the server:
2019-03-06T14:49:55+01:00
I thought that I can do it in such way:
NSDate(timeIntervalSince1970: TimeInterval(NSDate().timeIntervalSince1970))
but I got such time:
2021-01-24 15:42:31 +0000
I thought that I have to user decoding pattern, so used such way:
let dateFormatterGet = DateFormatter()
dateFormatterGet.dateFormat = "yyyy-MM-dd HH:mm:ss+z"
let dateFormatterPrint = DateFormatter()
dateFormatterPrint.dateFormat = "MMM dd,yyyy"
let time = NSDate(timeIntervalSince1970: TimeInterval(NSDate().timeIntervalSince1970))
if let date = dateFormatterGet.date(from: time.description) {
print(dateFormatterPrint.string(from: date))
} else {
print("There was an error decoding the string")
}
but its output was:
There was an error decoding the string
what means that I can't decode this time in such way. What I did wrong?
You are creating a string from a date from a time interval from a date, three of the conversions are waste.
The conversion failed because time.description doesn't match the format yyyy-MM-dd HH:mm:ss+z
To get an ISO8601 string with time zone the date format is yyyy-MM-dd'T'HH:mm:ssZ and you have to specify a fixed locale
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
let isoString = formatter.string(from: Date())
There is a shorter way as suggested by Rob in the comments
let formatter = ISO8601DateFormatter()
formatter.timeZone = .current
let isoString = formatter.string(from: Date())

Swift string date to date

I read a date from UserDefaults.standard as string in the following format:
"2020-11-06T05:20:20+0100"
I try to convert this string to a date using the following code
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "de_DE")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
let dateString: String! = UserDefaults.standard.string(forKey: "timeShared")
let date = dateFormatter.date(from: dateString)
However, the result is always nil. Using let date = dateFormatter.date(from: dateString)! explicitly causes a fatal error.
Any ideas what to do?
Changing the former code to
dateFormatter.dateFormat = "\"yyyy-MM-dd'T'HH:mm:ssZ\""
returns a neatly formatted date subsequently. The error was that the date read from UserDefaults included "".
May be UserDefaults.standard.string(forKey: "timeShared") have no value or the value is not in string format and you are doing force unwrapping in let dateString: String! = UserDefaults.standard.string(forKey: "timeShared") here that making the fatal error.
Better add a conditional if, then use the dateString.
Refer the below code.
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "de_DE")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
if let dateString: String = UserDefaults.standard.string(forKey: "timeShared") {
let date = dateFormatter.date(from: dateString)
print(date)
} else {
print("Data in UserDefaults: \(UserDefaults.standard.string(forKey: "timeShared"))")
}

How to compare two different date formats in swift

I have two different date formats from the API for the same object one is "yyyy-MM-dd" and other one is "dd-MM-YYYY" how to differentiate, that object contains specific format.
Use this may be worked for you.
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd" // YOUR DATE FORMATE
if let date = formatter.date(from: dateString) {
// IT CONTAIN YOUR DATE FORMATE
}
Try this,
let datestring = "2019-06-13" // try 13-06-2019 as well
let dateformatter = DateFormatter()
dateformatter.dateFormat = "yyyy-MM-dd"
var date = dateformatter.date(from: datestring)
if date == nil {
dateformatter.dateFormat = "dd-MM-yyyy"
date = dateformatter.date(from: datestring)
}
print(date!)
there should be many other ways to this and hope this will help to you.
You don't need to worry about whatever the format is, You just need to populate it into Date Object by using date formatter. After that you can use that Date Object where ever you want to use. Like
let datestring = "2019-06-13"
let dateformatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
var date1 = formatter.date(from: dateString)
and for other type of date
let dateString = "13-06-2019"
let dateformatter = DateFormatter()
formatter.dateFormat = "dd-MM-yyyy"
var date2 = formatter.date(from: dateString)
Now you got 2 date objects date1 & date2, use these in your code without bothering about their previous formats.

Date formatter crash in swift

Please help me to modify this part of code,
if let dateVaule = UserDefaults().value(forKey: SplashSeenDate){
let dateStr = dateVaule as! String
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
dateFormatter.timeZone = TimeZone.ReferenceType.local
let date = dateFormatter.date(from:dateStr)
if Global.sharedInstance.Splashs != nil && Global.sharedInstance.Splashs?.count != 0{
for (i,splash) in (Global.sharedInstance.Splashs?.enumerated().reversed())!{
if !checkTimeStamp(date: splash.create_timestamp,StoredDate: date!){
Global.sharedInstance.Splashs?.remove(at: i)
}
}
print(Global.sharedInstance.Splashs?.count ?? "-1")
}
}
Honestly speaking, i am very confuse with the date formatter.
when this project launch, it occured crash at
if !checkTimeStamp(date: splash.create_timestamp,StoredDate: date!){
However, I could not replicate this crash... **Only a few user with iOS10 occured this crash.**Please kindly advise, Thanks a lot!
func checkTimeStamp(date: String!,StoredDate: Date) -> 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)
if (datecomponents! >= StoredDate) {
return true
} else {
return false
}
}
You are converting String to Date in two different ways:
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
dateFormatter.timeZone = TimeZone.ReferenceType.local //###Why don't you use `TimeZone.current`?
let date = dateFormatter.date(from:dateStr)
And in checkTimeStamp(date: String!,StoredDate: Date) -> 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)
In your case, lacking this line is critical for your first conversion:
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
You can find many articles discussing about DateFormatter (or NSDateFormatter in old articles) returning nil.
When you use DateFormatter with fixed format like "yyyy-MM-dd HH:mm:ss", you must set locale to Locale(identifier: "en_US_POSIX").
Maybe you'd better define one conversion method (or computed property) to convert String to Date which fits for your app's requirements, and use it everywhere you need String to Date conversion:
extension String {
var toAppDate: Date? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
dateFormatter.timeZone = TimeZone.current
dateFormatter.locale = Locale(identifier: "en_US_POSIX") //### <- Do not miss.
return dateFormatter.date(from: self)
}
}
Generally, your code uses too much forced-unwrapping or forced-casting. You can re-write it without using any forced-something:
if
let dateStr = UserDefaults().string(forKey: SplashSeenDate),
let date = dateStr.toAppDate,
let splashes = Global.sharedInstance.Splashs, !splashes.isEmpty
{
//### In most cases, `filter` is faster than repeated `remove`.
Global.sharedInstance.Splashs = splashes.filter {
checkTimeStamp(date: $0.create_timestamp, storedDate: date)
}
print(Global.sharedInstance.Splashs?.count ?? "-1")
}
(Assuming create_timestamp is not Optional, and renamed parameter label StoredDate: to storedDate:.)
Seems like splash.create_timestamp is getting nil and when you are passing in this function checkTimeStamp. It is getting crash. You can prevent the crash by changing date parameter inside checkTimeStamp function as optional and use guard statement before passing inside the function.