I have a String in this format: "2019-03-11T17:04:00+0100". I need to convert that string to the one that will be in this format: "03.11 17:04". I already tried some suggestions for instance this one.
As per my comment, this is a task for DateFormatter rather than RegeX. I threw this together in a playground quickly to demonstrate what I mean.
let inFormatter = DateFormatter()
inFormatter.locale = Locale(identifier: "en_US_POSIX")
inFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
let input = "2019-03-11T17:04:00+0100"
let dateFromInput = inFormatter.date(from: input)! // This should be unwrapped properly in your code.
let outFormatter = DateFormatter()
outFormatter.locale = Locale(identifier: "en_US_POSIX")
outFormatter.dateFormat = "MM. dd HH:mm"
let output = outFormatter.string(from: dateFromInput)
print(output) // Prints 03. 11 16:04.
The premise is that you provide a format for which to parse the input string against, this is transcoded to a Date object which you can then transcode to your desired output format with a second DateFormatter.
EDIT:
As pointed out by #user28434, the input you are passing in looks like CET (Central European Time); When I configure the output DateFormatter, I do not specify a time zone so it defaults to my local time zone, GMT (Greenwich Mean Time). This would obviously cause the output to be different based on the location of the user in the world, which should be expected/desired. But it's worth highlighting. You can use outFormatter.timeZone = TimeZone(identifier: "CET") to force a CET output.
You can use DateFormatter instead of regex,
first, convert the given string to a date with the string format,
then convert the resulted date to a string with the desired format.
func convertISO8601DateStringToDate(dateStr: String) -> Date? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
return dateFormatter.date(from: dateStr)
}
func convertDateToReadableOutput(date: Date) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM.dd HH:mm"
return dateFormatter.string(from: date)
}
you can use these two methods as below:
if let date = stringToDateConverter(dateStr: "2019-03-11T17:04:00+0100") {
print(dateToStringConverter(date: date))
}
Related
// 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
}
I'm trying to convert the date string "2020-05-07T22:59:51Z" to a Date object but have not had any success. This is how I've setup my DateFormatter yet I always receive nil:
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
formatter.timeZone = TimeZone(secondsFromGMT: 0)
In addition I have tried:
Making the formatter static
Changing the dateFormat string to "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ssZZZ", "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
Following the Apple documentation for Working With Fixed Format Date Representations (by first replacing the single occurrence of "Z" with "-00:00" to match RFC 3339 format, ex. "2020-05-07T22:59:51-00:00")
Digging into the Apple documentation archives and following the Parsing an RFC 3339 date-time example
Here is a snippet where I use the date formatter above to try and parse "2020-05-07T22:59:51Z". dateString is not nil and this is happening on the main thread as well:
if let dateString = readASN1DateString(ptr: &dateStartPtr, maxLength: length) {
receiptCreationDate = Receipt.RFC3339DateFormatter.date(from: dateString)
}
Any suggestions as to what I'm doing wrong?
EDIT
Thanks for the response and comments, funny enough when I put a raw string inside it works, but when I have a String variable with the EXACT same string it returns nil. Here are a couple images showing what I see when debugging:
Step over print(...), Step over self.receiptCreationDate = ...
Console log after print
self.receiptCreationDate = nil
value of dateString
One thing to note is that the String returned by readASN1DateString(...) is initialized using String(bytesNoCopy:, length:, encoding: .ascii, freeWhenDone: false)
I am using your code and getting the output
override func viewDidLoad() {
super.viewDidLoad()
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
// Do any additional setup after loading the view.
let isoDate = "2020-05-07T22:59:51Z"
if let date = formatter.date(from:isoDate) {
print(date)
}
This question already has answers here:
iOS Swift 3 : Convert "yyyy-MM-dd'T'HH:mm:ssZ" format string to date object
(3 answers)
Closed 2 years ago.
I need convert this string 2020-03-18T00:00:00 in date like this 2020.03.18 00:00
When i try to convert like this my app just crash.
public extension String {
var dateValue: Date {
let formatter = DateFormatter()
formatter.timeZone = .none
formatter.dateFormat = "yyyy-MM-dd HH:mm"
return formatter.date(from: self)!
}
}
Any ideas?
The issue is that this code is using a dateFormat string of yyyy-MM-dd HH:mm, but that’s not what the actual input string is. It is yyyy-MM-dd'T'HH:mm:ss. Thus the conversion to the Date object is failing, and the forced unwrapping will cause it to crash.
Instead, I would recommend one formatter to convert the ISO8601 format of 2020-03-18T00:00:00 into a Date object. And if you then want a string in the format of 2020.03.18 00:00, you would have a separate formatter for that.
In the absence of an explicit timezone in ISO8601 date strings, it’s assumed to be the local time zone. So do not specify the timeZone property at all. (The only time you’d generally specify it is if it was Zulu/GMT/UTC, i.e. TimeZone(secondsFromGMT: 0).)
E.g.
let iso8601Formatter = DateFormatter()
iso8601Formatter.locale = Locale(identifier: "en_US_POSIX")
iso8601Formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy.MM.dd HH:mm"
func convert(input: String) -> String? {
guard let date = iso8601Formatter.date(from: input) else { return nil }
return formatter.string(from: date)
}
let result = convert(input: "2020-03-18T00:00:00") // "2020.03.18 00:00"
Note, instantiation of formatters (and changing of dateFormat strings) is a notoriously computationally intensive process, which is why I made these formatters properties rather than local variables. Obviously name them whatever you want and put them wherever you want, but make sure you avoid repeatedly instantiating these formatters or changing of dateFormat strings.
Your date formatter needs to include the "T"
dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'"
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))
If I convert "2019-01-01T00:00:00+0000" to a date, I would like the date to be the date in the string - January 1, 2019. And if I calculate the number of seconds in the time portion, I would like the result to be zero.
The problem is, when I convert my string into a date, it is stored in the UTC timezone. My locale is set to "en_US_POSIX", and my time zone is set to current. My date formatter uses "yyyy-MM-dd'T'HH:mm:ssZ". I know that the final Z means UTC, but I can't seem to figure out the correct field symbol to get the results I want.
func convertToDate(_ dateString: String) -> Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.timeZone = .current
let date = dateFormatter.date(from: dateString)
else {
print("DATE ERROR:", dateString)
return Date()
}
return date
}
If you know for sure that the date strings you wish to parse will always end with a timezone in the form +XXXX then you can trim off that timezone from the string and then parse the remaining string as local time.
func convertToDate(_ dateString: String) -> Date? {
let minusTZ = String(dateString.dropLast(5)) // Assume the string ends with a +9999 timezone
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
let date = dateFormatter.date(from: minusTZ)
return date
}
This will give you a local date with the same date and time in the original string regardless of the timezone of the original string.