Date formatter crash in swift - 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.

Related

How can I show month and year in 12's timezone in swift?

func getMonYearDateFormat() -> String {
let dateFormatter = DateFormatter()//EEEE, d, MMM
dateFormatter.dateFormat = is24Hour() ? "yyyy-MM-dd' 'HH:mm:ss" : "yyyy-MM-dd' 'h:mm:ss a"
dateFormatter.timeZone = TimeZone.current
dateFormatter.locale = Locale.current
guard let oldDate = dateFormatter.date(from: self) else { return "" }
let convertDateFormatter = DateFormatter()
convertDateFormatter.dateFormat = "MMMM yyyy"
return convertDateFormatter.string(from: oldDate)
}
I show month and year as title in table view. I wrote this function to convert the date of the relevant card to month and year. If the device is in the 24-hour time zone, the function works properly. However, if the device is in the 12th time zone, it returns blank and I cannot see the month and year of the relevant card. I couldn't find the part that I wrote incorrectly in the function.
I've tested your code with 12 hour format and it works. The only thing I've. change is to use the 12 hour format without call is24Hour() because you did not provide that code. So I suspect the point of failure is the is24Hour() function.
As mentioned in the comments I would recommend you to investigate how you get this string and if possibly use the original Date object instead if it exists but below is a solution that I think handles the 12 vs 24h issue in an efficient way.
The logic is to first convert using 24h and if that returns nil then convert using the 12h format.
I have declared all formatters I use as static properties so they only get created one since creating a DateFormatter is expensive
extension String {
private static let formatter24: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd' 'HH:mm:ss"
return dateFormatter
}()
private static let formatter12: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd' 'h:mm:ss a"
return dateFormatter
}()
private static let formatterMonthYear: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMMM yyyy"
return dateFormatter
}()
func getMonYearDateFormat() -> String {
let date = Self.formatter24.date(from: self) ?? Self.formatter12.date(from: self)
guard let date else { return "" }
return Self.formatterMonthYear.string(from: date)
}
}

Swift - Convert a short format string of a date to long format using date formatter

I have a string that looks like this: "2021-08-05"
I would like to convert it into a date so that I can display it as "5th August 2021"
My code below just returns as nil and I don't understand why. Any help would be appreciated.
Code:
func stringToDate(dateString: String){
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd"
formatter.dateStyle = .long
let newDate = formatter.date(from: dateString)
print("formatter: \(newDate)")
}
I call the function as an action for a button (SwiftUI), so when the button is clicked the date should show.
Button("Go"){
stringToDate(dateString: "2021-08-05")
}
Removing the dateStyle line fixes it, and an actual date is printed.
Code:
func stringToDate(dateString: String){
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd"
let newDate = formatter.date(from: dateString)
print("formatter: \(newDate)")
}
// Prints: formatter: Optional(2021-08-04 23:00:00 +0000)
To do the whole conversion, the following function will work:
func convertDate(from original: String) -> String? {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd"
guard let date = formatter.date(from: original) else { return nil }
formatter.dateStyle = .long
let string = formatter.string(from: date)
return string
}
// Prints: Optional("August 5, 2021")
Of course, this may be printed slightly different due to my location & language
The following line of code can only be run after getting a Date otherwise you are 'overwriting' the dateFormat:
formatter.dateStyle = .long
You're overriding the .dateFotrmat setting with the .dateStyle setting.
If you want to do it this way, use the format string to convert the string to a date, then the style to output it.
func stringToDate(dateString: String){
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd"
let newDate = formatter.date(from: dateString)
formatter.dateStyle = .long
print("formatter: \(formatter.string(from: newDate!) )")
}
which give the output you wanted:
formatter: August 5, 2021

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
}

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

Swift D-Day UIPickerDate

I have a
#IBOutlet weak var EndDatePicker: UIDatePicker?
what I want to is, If a string called date is nil, set the datePicker to Today, the "D-Day":
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
if(task?.date != nil){
let date = dateFormatter.dateFromString(task!.date!)
EndDatePicker!.date = date!
}else{
//EndDatePicker!.date = D-Day?
}
Thank you for your help, I don't find on internet the way to do this on swift.
Regards.
try this :
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let dateString = dateFormatter.stringFromDate(NSDate())
let text = dateString
Since Swift 1.2 you can perform two optional binding checks in the same line.
The first check is if date is nil, the second if the dateformatter could create a valid date
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
if let dateString = task?.date, date = dateFormatter.dateFromString(dateString) {
EndDatePicker.date = date
}
else {
EndDatePicker.date = NSDate()
}