Swift: Create a Date() from a Google Drive API Timestamp - ios

I'm working with the Google Drive API in Swift, and one of the pieces of data I'm working with is a timestamp, formatted like this: 2021-04-18T22:50:33.235Z
I keep getting nil for my Date object, and I assume it has to do with my DateFormatter(), but I can't seem to figure out exactly what is wrong.
Here's my code that I tried:
var creationDateAsString = "2021-04-18T22:50:33.235Z"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
if let date = dateFormatter.date(from: creationDateAsString) {
//do what I need to do
}
Thanks for any help you can offer.

It's true that this code, for some reason, worked in the playground, but not in my actual Swift app. I was, however, able to solve the issue by defining the locale:
var creationDateAsString = "2021-04-18T22:50:33.235Z"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
if let date = dateFormatter.date(from: creationDateAsString) {
//do what I need to do
}

Related

Parsing date string coming from Fitbit API

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

How can I get current GMT 0 in Swift 3?

I'm looking for a way to display the current GMT-0 time.
So far, I've been doing it like:
let UTCDate = Date()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let defaultTimeZoneStr = formatter.string(from: UTCDate)
However it returns the current time of the phone.
How can I get the current GMT-0 time using Swift 3?
Before the last line of your code, insert this line:
formatter.timeZone = TimeZone(secondsFromGMT:0)
Or this line:
formatter.timeZone = TimeZone(identifier:"GMT")

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)

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"
}

How to constuct NSDate object from String with milliseconds

I need to construct NSDate object from String, so I wrote the following code:
func getNSDateObjectFromString(string: String) -> NSDate {
var formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
let date = formatter.dateFromString(string)
return date!
}
Unfortunately, the input string sometimes may contain milliseconds too. What can I do in this case? I don't find any way to read milliseconds (not in the day) according to the http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_Patterns
Thanks in advance.
As far as I know, the format doesn't support "optional" fields. So you have to try the formats one by one:
func getNSDateObjectFromString(string: String) -> NSDate {
var formatter = NSDateFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
var date = formatter.dateFromString(string)
if date == nil {
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.S"
date = formatter.dateFromString(string)
}
return date!
}
You can try something like:
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
A Swift 3 Solution
After a bit of trial and error with the date format this is what worked for me with Swift 3.
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
let date = formatter.date(from: "2017-03-11 13:16:31.177")!
debugPrint(dateFormatter.string(from: date))
and after a round trip results in the expected debug output of
"2017-03-11 13:16:31.177"
Note that using the format "yyyy-MM-dd'T'HH:mm:ss.SSS" resulted in formatter.date(from: returning a nil optional Date.
Are they important?
In DateFormatter you create your matching string in years, months, days, hours, mins, secs, but you don't need to. If your matching string does not contain any of them, formatter will just ignore them.

Resources