Formatting JSON date to Swift date doesn't work - ios

I'm trying to format this date: 2018-01-10T11:57:21.153 to Swift Date object like this:
let dateSentString = jsonDict["date"] as! String
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
let date = dateFormatter.date(from: dateSentString)!
For some reason, the app crashes on the last line.
What am I doing wrong? Thanks!

change the milli seconds format use 'SSS' specifier (with number of S's equal to number of digits of milliseconds ). for more information you get here
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
from
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
Full code
let dateSentString = "2018-01-10T11:57:21.153"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
let date = dateFormatter.date(from: dateSentString)!
print(date)

You have to first set formatter for date you are getting from JSON and then another formatter for the date you want.
First convert string fro JSON to a date variable by setting same format coming in JSON object .
Then you have to re-format that date variable into format you want.
I can write code if you want but it is better to try yourself.
Happy Coding

Related

How to get only time from date in swift

This question is not asked for the first time, but no solution works for me. I am getting time in String from Api response in the following format "14:45".
I want to compare this time with the current time, for this purpose I need to convert this string in Time formate(swift sports)
I always get nil after conversion
I have tried multiple ways but none of them worked for me and one is given for reference, I don't know what am I missing here
Thanks for any response
func stringToTime(str:String) -> Date{ // 14:45 passed here in str
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "hh:mm a"
print(str)
//here time string prints
let date = dateFormatter.date(from: (str))
print(date)
//date is nil here, should be 02:45 pm
return date!
}
If the time you get from the API is in 24h format you can do a string comparison
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm"
let currentTime = formatter.string(from: Date())
let compare = currentTime.compare("14:45")
You might need to set the time zone for the DateFormatter to make sure it uses the same as the API
It seems like you want to transform a time string in one format to another format. Your method signature should look like this:
func changeFormat(str:String) -> String {
Note that you should not output a Date here, because Dates don't have formats. They will always be printed in the same way. What you need to do in this method is 2 things:
parse str to a Date using a DateFormatter, specifying the format HH:mm. You seem to assume that DateFormatter can automatically work this format out. It can't :(
format the Date object you just got using a DateFormatter, specifying the format hh:mm a. This produces a string, not a date.
(You could also consider having the method return a Date (then it would be called parseTime), and do the second step just before you show the date to the screen.)
func changeFormat(str:String) -> String {
let dateFormatter = DateFormatter()
// step 1
dateFormatter.dateFormat = "HH:mm" // input format
let date = dateFormatter.date(from: str)!
// step 2
dateFormatter.dateFormat = "hh:mm a" // output format
let string = dateFormatter.string(from: date)
return string
}

cast "1900-01-01T00:00:00" string value to date

I've watching trough stack overflow to find the answer and I can't find it I want to cast this string value "1900-01-01T00:00:00" to Date format, I was trying with some formats like those:
"yyyy-MM-dd HH:mm:ss"
"EEE, dd MMM yyyy hh:mm:ss +zzzz"
"YYYY-MM-dd HH:mm:ss.A"
"yyyy-MM-dd HH:mm:ss.S"
but anyone of those its working.
and I want the date format like this
"dd-mm-yyyy"
Hope you can help me!
Thanks.
It is a two step process, first converting 1900-01-01T00:00:00 (known as a RFC 3999 or ISO 8601 date, referred to the specifications that define this format) into a Date object, and then converting that Date object back to a string in the form of 01-01-1900:
To convert your string in the form of 1900-01-01T00:00:00 into a Date object, you can use ISO8601DateFormatter:
let formatter = ISO8601DateFormatter()
formatter.formatOptions.remove(.withTimeZone)
let date = formatter.date(from: string)!
That is equivalent to the following DateFormat, in which one has to manually set the locale to en_US_POSIX (because RFC 3999/ISO 8601 dates use a Gregorian calendar, regardless of what the device's default calendar type) and sets the timeZone to GMT/Zulu, because usually RFC 3999/ISO 8601 dates are representing GMT unless specified otherwise:
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
let date = formatter.date(from: string)!
For more information about the importance of timezones and locales in parsing RFC 3999 and ISO 8601 dates, see Apple's Technical Q&A 1480.
Then, to convert that Date object to a string into 01-01-1900 (day, month, and year), you'd use a format string of dd-MM-yyyy (note the uppercase MM for "month", to distinguish it from mm for "minute"):
let formatter2 = DateFormatter()
formatter2.dateFormat = "dd-MM-yyyy"
let string = formatter2.string(from: date)
Two observations regarding the dateFormat string:
If this string is for displaying to the user, you might use use dateStyle rather than dateFormat, e.g.:
formatter2.dateStyle = .short
While this will generate a slightly different format, e.g. dd/MM/yy, the virtue of this approach is that the string will be localized (e.g. UK users will see MM/dd/yyyy, their preferred way of seeing short dates).
It just depends upon the purpose of your dd-MM-yyyy format. If it's for internal purposes, go ahead and use dateFormat. But if it's for showing dates in your UI, use dateStyle instead, and enjoy the localization that DateFormatter does automatically for you. For more information, see "Working With User-Visible Representations of Dates and Times" section of the DateFormatter reference.
Note that in the absence of a timeZone specified for this second formatter, it assumes that while the ISO 8601 date was in GMT, that you want to see the date in your local timezone. For example, (1900-01-01T00:00:00 GMT was Dec 31, 1899 at 4pm in California). If you want to see the date string of the original ISO 8601 object, not corrected for timezones, you'd just set the timeZone of this second formatter to be GMT as well, e.g.
formatter2.timeZone = TimeZone(secondsFromGMT: 0)
As others have pointed out, you want to avoid unnecessarily re-instantiating DateFormatter objects. So you might put these formatters in properties that are instantiated only once, or use an extension:
extension DateFormatter {
static let customInputFormatter: ISO8601DateFormatter = {
let formatter = ISO8601DateFormatter()
formatter.formatOptions.remove(.withTimeZone)
return formatter
}()
static let customOutputFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "dd-MM-yyyy"
formatter.timeZone = TimeZone(secondsFromGMT: 0) // if you want date in your local timezone, remove this line
return formatter
}()
}
And then:
let input = "1900-01-01T00:00:00"
let date = DateFormatter.customInputFormatter.date(from: input)!
let output = DateFormatter.customOutputFormatter.string(from: date)
print(output)
This is how I do custom date formatters:
extension DateFormatter {
static let inDateFormatter: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
return dateFormatter
}()
static let outDateFormatter: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-mm-yyyy"
return dateFormatter
}()
}
And then use it like:
if let date = DateFormatter.inDateFormatter.date(from: "1900-01-01T00:00:00") {
let newDateString = DateFormatter.outDateFormatter.string(from: date);
print(newDateString) //prints 01-00-1900
}
This avoids any potential performance issues and is clear at the point of use, while still being concise.
Use this extension I created, where you can pass the format as a parameter.
extension String
{
func toDate( dateFormat format : String) -> Date
{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = format
if let date = dateFormatter.date(from: self)
{
return date
}
print("Invalid arguments ! Returning Current Date . ")
return Date()
}
}
"1900-01-01T00:00:00".toDate(dateFormat: "yyyy-MM-dd'T'HH:mm:ss") //Plyground call test

Why does this date formatting not work?

I am puzzled. I read the international spec for formats...yet it seems to return a nil in playgrounds and in code.
let dateString = "022018"
let formatter = NSDateFormatter()
formatter.setLocalizedDateFormatFromTemplate("MMyyyy")
let date = formatter.dateFromString(dateString)
I can't change the stringDate to be 02/2018...I have to maintain that format..what is the right mask then to get some output?
The problem is the call to formatter.setLocalizedDateFormatFromTemplate. I don't think this means what you think it does. You are turning a string to a date, not a date to a string. Just set the formatter's dateFormat. This works fine (Swift 3, hope you don't mind):
let dateString = "022018"
let formatter = DateFormatter()
formatter.dateFormat = "MMyyyy"
let date = formatter.date(from:dateString)

What should be the format of a string to convert into NSDate?

I'm getting following two types of strings from server:
2016-07-28T12:25:31.922247
2016-07-28T13:39:13
I want to convert them into NSDate. I'm using following snippet to convert but it's failing:
let dateFormatter = NSDateFormatter()
dateFormatter.timeZone = NSTimeZone(name: "UTC")
dateFormatter.dateFormat = "yyyy-MM-ddTHH:mm:ss"
I'm not getting the desired output.
If you doesn't care the fraction of second then you can remove it like this.
var strDate = "2016-07-28T12:25:31.922247"
if strDate.rangeOfString(".") != nil{
let arr = strDate.characters.split{$0 == " "}.map(String.init)
strDate = arr[0]
}
//Now you can convert this string to date using same date format
let formatter= NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let date = formatter.dateFromString(strDate)
You can get the exact format from this Link
For the second string use this
yyyy-MM-dd'T'HH:mm:ss
You need to quote the "T" (or any alpha characters that should be present in literal form), try:
let dateFormatter = NSDateFormatter()
dateFormatter.timeZone = NSTimeZone(name: "UTC")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
Note that this will only parse your second string. To parse your first string you'll need to use:
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.S"
if you care about the fractional seconds. Since NSDateFormatter is a literal parser it doesn't allow you to easily parse either format, if you have to parse both you'll just need to pass it to one, if that fails pass to the other.
Your date format works in 2016-07-28T13:39:13 but add 'T'
Example: yyyy-MM-dd'T'HH:mm:ss.
But for the 2016-07-28T12:25:31.922247 you need clarifies that this means 922247
the truth had never seen anything like it, but I would try with yyyy-MM-ddTHH:mm:ssZ

Why my date parser doesn't work in Swift?

I have a json that contains date field:
"created_at":"2016-03-06T16:39:29.786Z"
in my app I'm doing like this:
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-ddThh:mm:ss.SSSZ"
let created_at = json["created_at"].string
let crd = dateFormatter.dateFromString(created_at!)
print(crd) //prints nil
Why am I getting nil there?
You need to quote literal text and you are using the wrong format specifier for the hour.
The T must be quoted.
hh is for 12-hour format but you have 24-hour format which is HH.
So you want:
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"

Resources