Using DateFormatter to parse this string into a Date? - ios

I'm hitting a webservice that is returning a string in the following format:
"yyyy-MM-dd'T'HH:mmZ"
It's very close to the standard UTC format, but just without the ss at the end. My issue is that my dateFormatter is always returning nil...and I have tried to make sure that locale and everything else is setup properly.
Here is an example of an actual string:
2019-12-26T00:00Z
Here is the code that creates the DF:
extension DateFormatter {
#objc static func defaultDateFormat(_ format: String) -> DateFormatter {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "US")
formatter.dateFormat = format
return formatter
}
func date(from string: String?) -> Date? {
if let string = string {
return self.date(from: string)
} else {
return nil
}
}
func string(fromOptional date: Date?) -> String? {
if let date = date {
return self.string(from: date)
} else {
return nil
}
}
func string(fromOptional date: Date?, defaultStr: String) -> String {
return self.string(fromOptional: date) ?? defaultStr
}
}
let df = DateFormatter.defaultDateFormat("yyyy-MM-dd'T'HH:mmZ")
let date: Date? = df.date(from: __dateString__) // always nil

A few observations:
You want to use a locale of en_US_POSIX, an invariant locale that always works for ISO 8601 / RFC 3339 date strings. See Technical Q&A 1480.
If you want to use this formatter to convert a date back to a string like 2019-12-26T00:00Z, you will want to:
Use X (or ZZZZZ or XXXXX) in your format string, not Z (see the “zone” section in the table at Date Format Patterns and you’ll see how these various time zone patterns, e.g. Z, ZZZZZ, and X, are interpreted); and
Set the timeZone of the formatter to use Zulu/GMT/UTC.
Thus:
#objc static func defaultDateFormat(_ format: String) -> DateFormatter {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = format
return formatter
}
And
let df = DateFormatter.defaultDateFormat("yyyy-MM-dd'T'HH:mmX")
let date = df.date(from: "2019-12-26T00:00Z")
Or
let string = df.string(from: Date())

Related

Date formatting in Swift that supports iOS 13+

I bet this is simple. I'm trying in Xcode playgrounds to play with getting a string date
let string = "2022-11-27 00:00:00 +0000"
and converting that into a Date object that's formatted like DD-MM-YYYY
func airdateFormat(_ key: String) -> Date? {
let expectedFormat = Date().formatted(.dateTime.day().month(.wide).year())
let date = try! Date(strategy: expectedFormat)
return date
}
I also tried
func airdateFormat(_ key: String) -> Date? {
guard let dateString = self[key] as? String else { return nil }
let dateFormatted = DateFormatter.dateFormat(fromTemplate: "MM-DD-YYYY", options: Int, locale: Locale?)
return dateFormatted().date(from: dateString)
}
}
I'm parsing this Date string from json hence the guard/else statement
You need to use a format that matches your input to parse the string to a Date
If you want to use the DateFormatter
let string = "2022-11-27 12:34:56 +0000"
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
let date = formatter.date(from: string)
and for recent OS versions you use a FormatStyle
let formatStyle = Date.FormatStyle()
.year(.defaultDigits)
.month(.twoDigits)
.day(.twoDigits)
.hour()
.minute()
.second()
.timeZone()
let date = try formatStyle.parse(string)

MST to IST wrong timezone conversion by abbreviation

In my code I am getting time and its format time zone like "IST", "MST" from a server and by using that I need to convert a given time to local device's time. For that I am using TimeZone(abbreviation:) method and its working fine with all formats except "MST" format. I am getting converted time one hour after.
In following code I am getting output as 04:30PM and 04:29PM which is one hour after the actual time. (here given time's format is "MST")
let startDateString = "04:00:00" // expected 3:30pm after convertine to IST
let endDateString = "03:59:59"
let timeZoneString = "MST"
func getTime() {
if let scheduleTimeZone = TimeZone(abbreviation: timeZoneString) {
let startScheduledTime = toScheduledTime(startDateString, using: scheduleTimeZone)
let endScheduledTime = toScheduledTime(endDateString, using: scheduleTimeZone)
print(startScheduledTime)
print(endScheduledTime)
}
}
/// Method to get local time for scheduled time
func toScheduledTime(_ time: String, using timeZone: TimeZone) -> String {
let today = "2022-05-09"
guard let dateTimeScheduleTZ = (today + " " + time).dateTime(createWithTZ: timeZone,
format: "yyyy-MM-dd HH:mm:ss") else {
return ""
}
return dateTimeScheduleTZ.dateTime(createLocal: "hh:mma")
}
extension String {
func dateTime(createWithTZ timeZone: TimeZone,
format: String) -> Date? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = format
dateFormatter.timeZone = timeZone
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
guard let date = dateFormatter.date(from: self) else {
return nil
}
return date
}
}
extension Date {
func dateTime(createLocal format: String) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = format
dateFormatter.timeZone = TimeZone.current
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
return dateFormatter.string(from: self)
}
}
getTime()

Convert String to Date with phones with differents date formats [duplicate]

This question already has an answer here:
DateFormatter doesn't return date for "HH:mm:ss"
(1 answer)
Closed 2 years ago.
I have some troubles parsing string date to Date format.
I recibe from one API the date string with this format 2020-08-27 12:39:32 (the date come in 24 hour format) and I have an extension of String to convert it to Date. So I do the convertion like this:
apiTime.toDate(format: "yyyy-MM-dd HH:mm:ss")
All works fine if the phone is configured with 24 hour. The problem came when the app runs in a AM/PM date format because the date return nil.
This is my extension to convert String to Date.
extension String {
func toDate(format: String) -> Date? {
let dateFormatter = DateFormatter()
dateFormatter.amSymbol = "AM"
dateFormatter.pmSymbol = "PM"
dateFormatter.dateFormat = format
return dateFormatter.date(from: self) //here return nil with AM/PM format
}
}
As suggested by #LeoDabus it's better not to create DateFormatter every time (this is very resource-consuming). You can extract it, eg. as a static property.
Here is a simple demo:
class Test {
static let dateFormatter: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
return dateFormatter
}()
func parseDateExample() {
let apiTime = "2020-08-27 12:39:32"
if let date = apiTime.toDate(formatter: Self.dateFormatter, format: "yyyy-MM-dd HH:mm:ss") {
print(date)
} else {
print("error")
}
}
}
You can reuse the formatter in your String extension instead of creating a new one every time you call toDate:
extension String {
func toDate(formatter: DateFormatter, format: String) -> Date? {
formatter.dateFormat = format
return formatter.date(from: self)
}
}

How to format date in Swift that similarly matches Json?

I am having trouble generating Date objects that match the json output. In http://chartapi.finance.yahoo.com/instrument/1.0/aapl/chartdata;type=quote;range=1y/json - the dates are in the following format "Date": 20151013. In order to get 2015-10-13, first I use Alamofire & SwiftJSON in my API call and JSON parsing. Here are some relevant lines from my code:
let dateInteger = subJson["Date"].int
if dateInteger != nil {
let editedDateInt = dateInteger!
let dateString = NSMutableString(string: "\(editedDateInt)")
dateString.insert("-", at: 4)
dateString.insert("-", at: 7)
chartpoint.date = Formatters.sharedInstance.dateFromString(key: dateString as String) }
// date extension
public class Formatters {
public static let sharedInstance = Formatters()
private let dateKeyFormatter = DateFormatter()
init() { dateKeyFormatter.dateFormat = "yyyy-MM-dd" }
public func dateFromString(key: String?) -> Date? {
guard let key = key else { return nil }
return dateKeyFormatter.date(from: key) }
Problem is the output came up Optional(2015-10-12 16:00:00 +0000). Not quite 2015-10-13 that I was expecting. How do I fix this? Is this related to user's Locale or TimeZone?
Check this out
Swift 3.0
let dateFromServer = "20151013"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyyMMdd"
dateFormatter.timeZone = TimeZone(abbreviation: "GMT")
let date = dateFormatter.date(from: dateFromServer)
dateFormatter.dateFormat = "yyyy-MM-dd"
let finalDate = dateFormatter.string(from: date!)
print(finalDate)
Output:
2015-10-13
As suggested by #rmaddy changed the format style form YYYY to yyyy.

Swift full date with milliseconds

Is any way to print full date with milliseconds?
For example, I'm doing this:
print("\(NSDate())")
But I'm just get this:
2016-05-09 22:07:19 +0000
How can I get the milliseconds too in the full date?
Updated for Swift 3
let d = Date()
let df = DateFormatter()
df.dateFormat = "y-MM-dd H:mm:ss.SSSS"
df.string(from: d) // -> "2016-11-17 17:51:15.1720"
When you have a Date d, you can get the formatted string using a NSDateFormatter. You can also use a formatter to turn a string date based on your format into a Date
See this chart for more on what dateFormat can do http://waracle.net/iphone-nsdateformatter-date-formatting-table/
Swift 5 to/from Timestamp String Extension
extension String {
static func timestamp() -> String {
let dateFMT = DateFormatter()
dateFMT.locale = Locale(identifier: "en_US_POSIX")
dateFMT.dateFormat = "yyyyMMdd'T'HHmmss.SSSS"
let now = Date()
return String(format: "%#", dateFMT.string(from: now))
}
func tad2Date() -> Date? {
let dateFMT = DateFormatter()
dateFMT.locale = Locale(identifier: "en_US_POSIX")
dateFMT.dateFormat = "yyyyMMdd'T'HHmmss.SSSS"
return dateFMT.date(from: self)
}
}

Resources