Swift string date to date - swift

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"))")
}

Related

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())

format string date using DateFormatter

I'm making a function to format string date (like "2018-05-01 18:23:31") to string type of Japanese date format, which is "2018年5月1日". I made a function but when I run it throws me an error saying
Fatal error: Unexpectedly found nil while unwrapping an Optional value
when I print my input string date, it has a value, but while it's converting, I start getting an error. Can anyone tell me why I'm getting nill in this function?
func setTemplate (strDate: String) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "ydMMM", options: 0, locale: Locale(identifier: "ja_JP"))
print(strDate) // getting this value => "2018-05-01 18:23:31"
let date = dateFormatter.date(from: strDate)! // getting an error in here
let result = dateFormatter.string(from: date)
return result
}
I guess I'm trying to get rid of time in the string and it somehow throws me an error, but not sure...
You need to first parse your string then you can get a localized string from the resulting date:
let strDate = "2018-05-01 18:23:31"
func setTemplate (strDate: String) -> String? {
let dateFormatter = DateFormatter()
dateFormatter.locale = .init(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
guard let date = dateFormatter.date(from: strDate) else { return nil }
let locale = Locale(identifier: "ja_JP")
dateFormatter.locale = locale
dateFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "ydMMM", options: 0, locale: locale)
return dateFormatter.string(from: date)
}
setTemplate(strDate: strDate) // "2018年5月1日"

Parsing a Swift String to Date, then Components

I have a date "2017-12-31" as a String.
What I want to get finally is only the month: "12" as a String.
So I thought that I can change it to Date using a date formatter
let formatter = DateFormatter()
formatter.dateFormat = "MM"
What do I do next?
let dateString = "2017-12-31"
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: Calendar.Identifier.iso8601) formatter.timeZone = TimeZone(identifier: TimeZone.autoupdatingCurrent.identifier)
formatter.dateFormat = "yyyy-MM-dd"
let localDate = formatter.date(from: dateString)
formatter.dateFormat = "MM"
let strMonth = formatter.string(from: localDate!)
print("Month is:",strMonth)
Another way
let dateString = "2017-12-31"
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
let localDate = formatter.date(from: dateString)
let month = String(NSCalendar.current.component(.month, from: localDate!))
print(month)
First you have to use the DateFormatter to create a temporary Date object from your source String object. Then you have to use it to create your final String from the temporary Date object.
let dateString = "2017-12-31"
let dateFormatter = DateFormatter()
// set the dateFormatter's dateFormat to the dateString's format
dateFormatter.dateFormat = "yyyy-MM-dd"
// create date object
guard let tempDate = dateFormatter.date(from: dateString) else {
fatalError("wrong dateFormat")
}
// set the dateFormatter's dateFormat to the output format you wish to receive
dateFormatter.dateFormat = "LL" // LL is the stand-alone month
let month = dateFormatter.string(from: tempDate)
Use below function for getting month from string file of date
func getMonthFromDateString(strDate: String) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
let date = formatter.date(from: strDate) // Convert String File To Date
formatter.dateFormat = "MM"
let strMM = formatter.string(from: date!) // Convert date to string
return strMM
}

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.

Change date format in Swift

I have a date format in String value of "2015-08-27" which is "YYYY-MM-DD". I need to convert this to Date format and change the format to "DD-MMM-YYYY". And change it back to String format again to display. So the end result would be "27-AUG-2015".
I have been searching for codes, but couldn't find one.
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "YYYY-MM-DD"
let date = dateFormatter.dateFromString("2015-08-27")
dateFormatter.dateFormat = "DD-MMM-YYYY"
let goodDate = dateFormatter.stringFromDate(date!)
Its not tested but I hope it will work.
You can create a class helper like DateHelper and class func:
class func convertDateString(dateString : String!, fromFormat sourceFormat : String!, toFormat desFormat : String!) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = sourceFormat
let date = dateFormatter.date(from: dateString)
dateFormatter.dateFormat = desFormat
return dateFormatter.string(from: date!)
}
And use it:(note format you give on question wrong so it will wrong convert): begin format is YYYY-MM-dd and you want convert to dd-MMM-YYYY)
print(DateHelper.convertDateString("2015-08-27", fromFormat: "YYYY-MM-dd", toFormat: "dd-MMM-YYYY"))
Hope this help.
Just used the function in your code(swift 4.2).
public func convertDateFormatter(date: String) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"//this your string date format
dateFormatter.timeZone = NSTimeZone(name: "UTC") as TimeZone!
dateFormatter.locale = Locale(identifier: "your_loc_id")
let convertedDate = dateFormatter.date(from: date)
guard dateFormatter.date(from: date) != nil else {
assert(false, "no date from string")
return ""
}
dateFormatter.dateFormat = "HH:mm a"///this is what you want to convert format
dateFormatter.timeZone = NSTimeZone(name: "UTC") as TimeZone!
let timeStamp = dateFormatter.string(from: convertedDate!)
print(timeStamp)
return timeStamp
}
Thanks