Swift converting Eureka date into String for firebase storing - swift

I am attempting to collect the date value from a Eureka DateTimeRow to then store it into Firebase but to store it I would need it to be in a string format. I have attempted this conversion but I receive the error 'Could not cast value of type 'Foundation.Date' (0x108af27e8) to 'Swift.String' (0x1086e99f8).'
I would like to know if there is something I am missing from my conversion method.
DateTimeRow:
<<< DateTimeRow("startDate"){
$0.title = "Start Date"
$0.value = NSDate() as Date
$0.cellUpdate { (cell, row) in
cell.datePicker.minimumDate = Date()
}
$0.onChange { row in
start = row.value!
}
}
Code getting the values of the Erueka form and converting:
let valuesDictionary = form.values()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
let formattedDate = formatter.date(from: valuesDictionary["startDate"] as! String)
Thank you all feedback welcomed.

As you want to convert from a Date (Eureka) to a String (Firebase), you should use the string(from:) method of the DateFormatter, whereas you are attempting to use the date(from:) method.
// Date to String
func string(from date: Date) -> String
// String to Date
func date(from string: String) -> Date?

Related

Swift DateFormatter - Parse from UTC String

I'm using a String extension to parse utc string to Date. But the parsed date is wrong. Not sure what i'm missing.
extension String {
var parseUTCDateTime:Date? {
let parser = DateFormatter()
parser.dateFormat = "MM/dd/yyyy HH:mm:ss a"
if let result = parser.date(from: self) {
return result
}
return nil
}
When I do "3/7/2022 7:40:17 AM".parseUTCDateTime, the result returned 2022-03-06 19:10:17 UTC.
Ideally the result should be 2022-03-06 07:10:17 UTC as the string contains AM in it.
Format strings have type-safe interpolation now, so you don't need to worry about the hh vs HH anymore that tripped you up.
try Date(utc: "3/7/2022 7:40:17 AM")
extension Date {
init(utc string: ParseStrategy.ParseInput) throws {
try self.init(
string,
strategy: ParseStrategy(
format: """
\(month: .defaultDigits)\
/\(day: .defaultDigits)\
/\(year: .defaultDigits)
\(hour: .defaultDigits(clock: .twelveHour, hourCycle: .oneBased))\
:\(minute: .defaultDigits)\
:\(second: .defaultDigits)
\(dayPeriod: .standard(.narrow))
""",
timeZone: .init(abbreviation: "UTC")!,
isLenient: false
)
)
}
}

Swift Why isn't my date object that's (Equatable) equal after converting it to a string and back?

I'm writing a unit test to check that my conversion from a date to string and back is successful.
I convert it to a string via:
func convertDateToString(date: Date) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
return dateFormatter.string(from: date)
}
and convert it back via:
func convertStringToDate(string: String) -> Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
return dateFormatter.date(from: string)!
}
If you try to use the Equatable protocol on the pre-conversion date and post-conversion date it says they are not the same. However, if you convert both pre and post dates to strings and compare them, they are Equatable. This is what it says when I run XCAssertEqual on pre and post dates:
XCTAssertEqual failed: ("2020-01-22 19:35:40 +0000") is not equal to ("2020-01-22 19:35:40 +0000")
Which looks pretty identical to me. I even tried converting the pre-conversion date to a string and back to check if the dates were equal and they still weren't
The problem there is that Date is stored as a FloatingPoint value (timeIntervalSinceReferenceDate). There is fractional seconds being discarded there when converting your Date to String and back to Date. Take a look at post.

Swift and iso8601 try parse "HH:mm:ss"

We used Decodable, and have a time: Date field, but from server came only time with "HH:mm:ss" format. Another date parsers with DateInRegion.
But this field crash app
I try do smth in decoder, but cant see any properties (.count)
and I dont now what need do
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .custom({ decoder -> Date in
do {
let value = try decoder.singleValueContainer()
let string = try value.decode(String.self)
if string.conut == 8 {
if let date = DateInRegion(
string: string,
format: .iso8601(options: .withTime),
fromRegion: Region.Local()
) {
return date.absoluteDate
} else {
throw DecodingError.nil
}
} else if let date = DateInRegion(
string: string,
format: .iso8601(options: .withInternetDateTime),
fromRegion: Region.Local()
) {
return date.absoluteDate
} else {
throw DecodingError.nil
}
} catch let error {
Not sure what you are trying to achieve, but it seems you want to handle multiple date format in a single JSON decoder.
Given the response struct is Decodable:
struct Response: Decodable {
var time: Date
var time2: Date
}
You can configure your decoder to handle all the date format you want:
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in
// Extract string date from the container
let container = try decoder.singleValueContainer()
let stringDate = try container.decode(String.self)
// Trying to parse the "HH:mm:ss" format
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH:mm:ss"
if let date = dateFormatter.date(from: stringDate) {
return date // successfully parsed "HH:mm:ss" format
}
// Trying to parse the iso8601 format
if let date = ISO8601DateFormatter().date(from: stringDate) {
return date // successfully parsed iso8601 format.
}
// Unknown date format, throw an error.
let context = DecodingError.Context(codingPath: [], debugDescription: "Unable to parse a date from '\(stringDate)'")
throw DecodingError.dataCorrupted(context)
})
Note: This is an example code and it's not very optimized (DateFormatter init each time you want to parse a date, using the brute force parsing to determine whether the date is in "HH:mm:ss" format or not, ...).
I think, the best way to optimize this, is to use multiple decoders, each configured for a specific date format, and use the right one when needed. For example, if you are trying to parse a JSON from an API, you should be able to determine whether you need to parse an iso8601 format or something else, and use the right decoder accordingly.
Here is an example of the decoder working in a playground:
let json = """
{"time": "11:05:45", "time2": "2018-09-28T16:02:55+00:00"}
"""
let response = try! decoder.decode(Response.self, from: json.data(using: .utf8)!)
response.time // Jan 1, 2000 at 11:05 AM
response.time2 // Sep 28, 2018 at 6:02 PM

Swift: how to convert from a string (like 5/3/17, 10:16 AM) to Date object [duplicate]

This question already has answers here:
Convert date string swift
(3 answers)
Closed 5 years ago.
So I took a current date and did stored theDate.description (which is something like 5/3/17, 10:16 AM) into my firebase database. When retrieving the data from my database, I want to be able to sort by that date, so I want to convert it back to a Date object. How do you do that?
I looked at some previous posts but they were all either old (with NSDate) or just didn't work. Thanks!
for (key, value) in dictionary {
print("\n\nKEY AND VALUE")
print(key)
print(value)
print("\n\n")
var date1: Date = Date()
var dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy"
date1 = dateFormatter.date(from: value)!
let temp = historyListItem(keyEntered: key, dateEntered: date1)
self.historyKeysAndDateArray.append(temp)
print(value)
}
^It gives me the error: fatal error: unexpectedly found nil while unwrapping an Optional value at this line: date1 = dateFormatter.date(from: value)!
value is a string in this format: 5/2/17, 3:15 PM
There are a few issues here. The main one being the wrong date format for the string. Here's the proper code with some other cleanup:
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "M/d/yy, h:mm a"
for (key, value) in dictionary {
print("\n\nKEY AND VALUE")
print(key)
print(value)
print("\n\n")
if let date1 = dateFormatter.date(from: value) {
let temp = historyListItem(keyEntered: key, dateEntered: date1)
self.historyKeysAndDateArray.append(temp)
print(value)
}
}
Don't force-unwrap optionals. Your app will crash.
Also, create the formatter before the loop. It will be much more efficient.
The date/time you are trying to format is: 5/2/17, 3:15 PM
Yet your dateFormatter is: dateFormatter.dateFormat = "dd/MM/yyyy"
The dateFormat much match exactly to convert that string to a date type.
Where is the time and am/pm

How to handle two possible date formats?

My app calls a web api that sometimes returns json dates in this format:
"2017-01-18T10:49:00Z"
and sometimes in this format:
"2017-02-14T19:53:38.1173228Z"
I can use the following dateformat to convert the 2nd one to a Date object:
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
But of course it doesn't work for the 1st one.
I've tried utilities like https://github.com/melvitax/DateHelper to see if it will work, but I haven't found a way to convert a json date (in any format) into a Date object.
Any recommendations?
Try both formats:
let parser1 = DateFormatter()
parser1.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
let parser2 = DateFormatter()
parser2.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
func parse(_ dateString: String) -> Date? {
let parsers = [parser1, parser2]
for parser in parsers {
if let result = parser.date(from: dateString) {
return result
}
}
return nil
}
print(parse("2017-01-18T10:49:00Z"))
print(parse("2017-02-14T19:53:38.1173228Z"))
Also note that the Z in the format is not a literal value.