Swift ISO8601DateFormatter TimeZone - swift5

I receive a string timestamp from JSON formatted as follows: "2022-10-06T19:10:00.000Z"
I want to convert the string to my local timezone and possibly even reformat the whole thing to something more readable like "Oct 6 2022, 3:30:45 PM". I assume that I need to use both ISO8601DateFormatter() and DateFormatter() to make that happen?
When I run the code below I get "2022-10-07 02:10:00 +0000" which is tomorrow's date so obviously not my timezone.
How do I properly format this date/time stamp to my current timezone? Thanks!
let jsonDateString = "2022-10-06T19:10:00.000Z"
let dateFormatter = ISO8601DateFormatter()
dateFormatter.timeZone = TimeZone.current
dateFormatter.formatOptions = [.withYear, .withMonth, .withDay, .withTime, .withDashSeparatorInDate, .withColonSeparatorInTime]
let formattedDate = dateFormatter.date(from: jsonDateString)
print(formattedDate!)

Related

I want to format a date into a string, but its giving me nil, i want to use the date in a UITextField.text

// the creationdate is coming from an api call
var creationDate = "2020-11-04T16:46:59.439212Z"
let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .none
formatter.dateFormat = "dd-MM-yyyy"
var creationDateFormattedInToDate = formatter.date(from:
creationDate)
print("date \(creationDateFormattedInToDate)")
So i want that date in the format 04-11-2020 and pass in a UITextField.text
You will need two formatters, one to parse the input date to a Date object and one to convert the date object to a string of the right format.
The input date seems to be a variant of a internet date/time so we use a ISO8601DateFormatter
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
The second formatter is a basic DateFormatter with a custom format
let outputFormatter = DateFormatter()
outputFormatter.dateFormat = "dd-MM-yyyy"
And then we can use them like this
if let date = formatter.date(from: creationDate) {
someTextField.text = outputFormatter.string(from: date)
}
You will want to use one formatter for parsing the response from the server (which is in what’s called and “ISO 8601” or “RFC 3339” format), and another for preparing the string representation of the date in the UI.
Regarding the date formatter for parsing the server response:
Set the formatter’s locale to Locale(identifier: "en_US_POSIX").
The setting of the styles when parsing this date string are irrelevant if you’re going to set dateFormat.
When parsing the date from the string, set dateFormat to yyyy-MM-dd'T'HH:mm:ss.SSSSSSX.
If you ever plan on using this formatter for the reverse date-to-string conversion (for preparing date strings to be sent to the server) you might want to set the timeZone of the formatter to TimeZone(secondsFromGMT: 0).
Regarding the date formatter used to prepare the string representation of the date in your UI:
I would not advise ever using a fixed dd-MM-yyyy format in your UI. That might be natural for European users, but it may be unnatural to most US users, who generally expect to see month before the day.
I would suggest not using dateFormat for this second date formatter, but rather using a dateStyle (e.g. of .medium or .long). It results in a nice, localized, and natural reading date string.
If you insist in using dd and MM and yyyy in your UI, I’d localize it with setLocalizedDateFormatFromTemplate so that the day and the month appear in the logical order that this particular user would expect (month-followed-by-day for US users, day-followed-by-month for most other locales).
Thus:
let serverDateFormatter = DateFormatter()
serverDateFormatter.locale = Locale(identifier: "en_US_POSIX")
serverDateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
serverDateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSX"
let uiFormatter = DateFormatter()
uiFormatter.dateStyle = .medium // or uiFormatter.setLocalizedDateFormatFromTemplate("ddMMyyyy")
if let date = serverDateFormatter.date(from: creationDateString) {
let string = uiFormatter.string(from: date)
// use that `string` in your UI
}

ISO8601DateFormatter accepts wrong input

I want to parse a date of the format yyyyMM to a date (e.g. 202007 should convert to July 2020). This works fine using DateFormatter - also when sending wrongly formatted input to it:
let formatter = DateFormatter()
formatter.dateFormat = "yyyyMM"
let result = formatter.date(from: "***")// = nil
But after reading Apple's documentation for DateFormatter, I tried changing to ISO8601DateFormatter instead due to this phrase:
When working with date representations in ISO 8601 format, use
ISO8601DateFormatter instead.
However, I cannot make it work properly when sending invalid input to it:
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withMonth, .withYear]
let result = formatter.date(from: "***")//= 2000-01-01 00:00:00
Why does formatter.date return a date an not nil when sending a wrongly formatted string to it? Are there any way to make to above code return nil instead?

Swift: How to parse date & time string with timezone abbreviation?

I receive a date & time string from a server with an information about a timezone formatted in an unusual way:
2017-05-05T12:24:16.286462Z[UTC]
I would like to use DateFormatter to parse it, but I cannot figure out what date format should I use.
I tried parsing it with "yyyy-MM-dd'T'HH:mm:ss.SSSZ'['R']'" or something quite similar but with no luck.
Here is my code:
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en-US")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ'['R']'"
let date = dateFormatter.date(from: date)
What is the right date format for this string?
OK guys, I figured it out.
The right format is
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z['zzz']'"
zzz is for a timezone abbreviation, while Z[ and ] are treated as a plain text.
An alternative approach with ISO8601DateFormatter. The [UTC] portion is stripped with Regular Expression
let dateString = "2017-05-05T12:24:16.286462Z[UTC]"
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let date = formatter.date(from: dateString.replacingOccurrences(of: "\\[^\\[+\\]", with: "", options: .regularExpression))

UTC to local time - wrong result swift

I know there are a lot of threads, but I can't find a solution for my problem. Maybe I can't see the solution...
I receive a UTC Time: for example 12:50
I want convert this time to MEZ respectively to the time zone of the users device. For my example I expect 13:50, because atm is MEZ +1 to UTC.
This is my code
//transform date to string
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
let newDateAsString:String = dateFormatter.string(from: self)
//is 12:50 UTC
//transform date to MEZ respectively to the local device timezone
let dateFormatterToDate = DateFormatter()
dateFormatterToDate.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let timeZone = TimeZone.autoupdatingCurrent.identifier as String
dateFormatter.timeZone = TimeZone(identifier: timeZone)
//same result with: dateFormatter.timeZone = NSTimeZone.local
//result is 11:50 but i would expect 13:50
if let result = dateFormatterToDate.date(from: newDateAsString) {
return result
}
The result 11:50 is the time now in my current timezone. But I don't understand this. I give explicitly the date, which should convert. Somebody know where is my mistake?
The conversion that you are doing is the opposite of what you intend. The string newDateAsString, which gives the time as 12:50, does not specify a timezone, because your date format string does not include formatting for a timezone. When you set dateFormatterToDate's timezone to MEZ, and pass newDateAsString to dateFormatterToDate, you are saying: give me a Date object for 12:50 in MEZ.
By default Dates are displayed as UTC, so result is displayed as 11:50, because 12:50 in MEZ is 11:50 in UTC.
To format a date as a string in the local timezone you would use code like this:
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
dateFormatter.timeZone = NSTimeZone.local
let localTimeZoneDateString = dateFormatter.string(from: self)

Swift date formatting

I'm trying to pull a date string from a button and format is as a date to be store in CoreData.
Here is my code:
let dateStr = setDateBTN.titleLabel?.text
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MM-dd-YYYY"
let date:NSDate = dateFormatter.dateFromString(dateStr!)!
If I do a println on dateStr I get the following: 03-10-2015. Then if I immediately println on date I get: 2014-12-21 05:00:00 +0000.
Any ideas as to why the actual date is changing when I run it through the date formatter?
NSDateFormatter Class Reference : http://goo.gl/7fp9gl
Date Formatting Guide (Apple) : http://goo.gl/8zRTQl
A common mistake is to use YYYY. yyyy specifies the calendar year whereas YYYY specifies the year (of “Week of Year”), used in the ISO year-week calendar.
Your code should work, as you expect, like this :
let dateStr = setDateBTN.titleLabel?.text
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy"
let date:NSDate = dateFormatter.dateFromString(dateStr!)!