Parsing date string coming from Fitbit API - ios

For the life of me I cannot figure out how to convert date string coming back from the Fitbit API, to an NSDate/Date object on iOS.
The date string is in the following format:
2017-01-21T10:39:43.000
The API I am using is documented here: https://dev.fitbit.com/docs/devices/, and each device comes back with a "lastSyncTime" property in the JSON.
I've tried several different date formats that keep returning a nil value for the date.
let formatter = DateFormatter()
// formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
// formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
// formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"
// formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssz"
// formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSz"
formatter.dateFormat = "yyyy-MM-dd"
let date = formatter.date(from: lastSyncTime)
I've tried all these different date formats to no avail.
Any help would be greatly appreciated here. Thanks.

Use this formatter to parse it.
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
formatter.date(from: dateString)
I hope this helps

This works for me:
import Foundation
let date = "2017-01-21T10:39:43.000"
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
let formatDate = formatter.date(from: date)
print(formatDate!)
Output: 2017-01-21 16:39:43 +0000

Related

Wrong date in swift 5 after conversion [duplicate]

This question already has answers here:
How can I parse / create a date time stamp formatted with fractional seconds UTC timezone (ISO 8601, RFC 3339) in Swift?
(13 answers)
Closed 3 years ago.
I am converting current date into GMT/UTC date string. But every time it returns me with wrong date.
My todays date is 07 February 2020, 11:09:20 AM. You can refer below image.
Here is my code :
let apiFormatter = DateFormatter()
//apiFormatter.dateStyle = DateFormatter.Style.long
//apiFormatter.timeStyle = DateFormatter.Style.long
//apiFormatter.calendar = Calendar.current
apiFormatter.timeZone = TimeZone.init(identifier: "GMT") //TimeZone(abbreviation: "UTC") //TimeZone.current //
//apiFormatter.locale = Locale.current
//apiFormatter.dateFormat = "yyyy-MM-DD HH:mm:ss"
apiFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
//apiFormatter.dateFormat = "yyyy-MM-dd'T'hh:mm:ssZ"
let endDate = apiFormatter.string(from: Date())
print(endDate)
And what I am getting in return is also you can check in image - 2020-02-38T05:33:34.598Z. I have tried with all the format, but no any luck. Can anyone suggest where it is going wrong?
First of all, the format should be:
apiFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
The Z is not a literal letter, it's the description of the time zone. However, making it a literal won't probably make a problem.
The 38 for day from your output is obviously caused by the DD format you have commented out.
Nevertheless, you have to set the locale:
apiFormatter.locale = Locale(identifier: "en_US_POSIX")
Otherwise you will have problems with 12/24h switching.
let apiFormatter = DateFormatter()
apiFormatter.locale = Locale(identifier: "en_US_POSIX")
// remove this if you want to keep your current timezone (shouldn't really matter, the time is the same)
apiFormatter.timeZone = TimeZone(secondsFromGMT: 0)
apiFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
let endDate = apiFormatter.string(from: Date())
print(endDate) // 2020-02-07T08:25:23.470+0000
print(Date()) // 2020-02-07 08:25:23 +0000
Also note that you can use ISO8601DateFormatter instead of DateFormatter.
Try this and adjust according to what format you are getting from server -
private func getFormatedDateInString(_ dateString: String) -> String? {
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
dateFormatter.timeZone = TimeZone(identifier: "UTC")
if let date = dateFormatter.date(from: dateString) {
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
dateFormatter.timeZone = TimeZone.current
let timeStamp = dateFormatter.string(from: date)
return timeStamp
}
return nil
}

what is the format I should use for the ISO timestamp in my case

I have a ISO 8061 format timestamp string "2018-06-13T12:11:13+05:00", what is the correct way to create Date object out from the String?
I tried:
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
let myDate = formatter.date(from: "2018-06-13T12:11:13+05:00")
But it doesn't work correctly, myDate is one hour behind. What is the format string I should use for this kind of timestamp?
For ISO 8601 time zone format
use ZZZZZ in capital
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
EDIT
Check the following example
I have just changed +05:30 from 05:00
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
formatter.timeZone = TimeZone(identifier: "UTC")
let myDate = formatter.date(from: "2018-06-13T12:11:13+05:30")
formatter.dateFormat = "yyyy-MM-dd HH:mm"
formatter.timeZone = TimeZone.current
print(formatter.string(from: myDate!))
Output
2018-06-13 12:11

How to format a date using timezone in Swift?

I have checked other questions but none of them helped me much.
I have following string:
let dateString = "2018-04-29T21:00:00.000Z"
I have successfully converted it to date using the following:
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
let convertedDate = dateFormatter.date(from: dateString)
But now I only want the time "hh:mm a" using timezone such as "+8". I have tried following way but it's not working:
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(abbreviation: "UTC+8")
dateFormatter.dateFormat = "hh:mm a"
let requiredTime = dateFormatter.string(from: convertedDate!)
Can anyone help me to overcome this problem?
The format you want is hh:mm a Z, which will provide the +0800.
You want to create a TimeZone which +8 hours from GMT, normally I prefer to use the appropriate abrivations (ie AET), but I guess if you don't have that, you can create a TimeZone using secondsFromGMT, for example...
let tz = TimeZone(secondsFromGMT: 8 * 60 * 60)
let toFormatter = DateFormatter()
toFormatter.timeZone = tz
toFormatter.dateFormat = "hh:mm a Z"
let requiredTime = toFormatter.string(from: convertedDate!)
Which based on your example data, will produce a value of...
05:00 AM +0800

Date from String with .medium Format

I have a date on a UITextField represented by its .medium formatter style (e.g. Mar 14, 2017), that I want to turn back into date.
I know that if I have the correct format, I can do so, but since I didn't use a literal string as the format, I have a little trouble with the conversion.
I am trying:
let formatter = DateFormatter()
formatter.dateFormat =
//[NEED FORMAT STRING HERE]
calendarPicker.startDate = formatter.date(from: t3.text!)
But I have found no way to turn the .medium style into a string to reformat the string into a date.
Can somebody provide some help?
I've used this formatter with style in Swift 3.0 and it works perfectly fine.
let formatter = DateFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale!
//Specified date format
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
//Style can be medium, full and short as per the need.
formatter.dateStyle = .medium
let parsedDateString = formatter.date(from: stringDate)
Thank you.
Were you looking for dateStyle ?
let formatter = DateFormatter()
formatter.dateStyle = DateFormatter.Style.medium
calendarPicker.startDate = formatter.date(from: t3.text!)

Swift dateFormat for variable dateType strings

I am trying to parse some json which is the result of an oData connection and I am getting the following response from the server:
"Task_ID":24,"Equipment_ID":3,"Owner_ID":2,"Priority":5,"Date_Due":
"2015-04-08T19:37:56.913","Time_Complete":"2015-04-09T19:37:56","Task_Description"
I am actually interested at the two different date fields I am receiving:
"Date_Due":"2015-04-08T19:37:56.913"
and
"Time_Complete":"2015-04-09T19:37:56"
As we can see, one has the millisecond timestamp and the other one does not.
By looking at the DB, this happens because the millisecond is actually .000 in the database (MS SQL Server) and for whatever reason, the result I receive in my json has this part truncated.
I am not interested in the milliseconds but I would like to have a dateFormat function that can handle both scenarios.
Now I have an obvious answer which is (pre)parse every date field, remove the milliseconds if they are there and then use the following code to format them:
let SQLDateFormatter: NSDateFormatter = {
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
return formatter
}()
However I would like to know if we can build a formatter that can solve this issue without pre-parsing, something that would be able to take both:
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
and
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
and automatically do the formatting properly.
I have been checking for this issue but could not find anything out there, thanks in advance...
extension Formatter {
static let iso8601: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
return formatter
}()
static let iso8601withFractionalSeconds: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
return formatter
}()
}
extension String {
var date: Date? {
return Formatter.iso8601withFractionalSeconds.date(from: self) ??
Formatter.iso8601.date(from: self)
}
}
"2015-04-08T19:37:56.913".date // "Apr 8, 2015, 4:37 PM"
"2015-04-09T19:37:56".date // "Apr 9, 2015, 4:37 PM"
No, NSDateFormatter will return nil if the string is not in the exact dateFormat as specified.
What you can do instead of preprocessing the string, is just check if the string you got is with miliseconds or without.
The best way to do this is using Regex. The idea is to create the SQLDateFormatter like you normal, and then check if the string has miliseconds or not. If there are miliseconds included, just change the dateFormat - way better than parsing the string.
if let match = tes.rangeOfString("(\\d{4}-\\d\\d-\\d\\d[T](\\d\\d:){2}\\d\\d.\\d{3})", options: NSStringCompareOptions.RegularExpressionSearch)
{
SQLDateFormatter.format = "yyyy-MM-dd'T'HH:mm:ss.SSS"
}

Resources