-
-
Save MattCheetham/c717648e9604d19615d7ee89dbc695aa to your computer and use it in GitHub Desktop.
//: Playground - noun: a place where people can play | |
import UIKit | |
/// We're working with appointments. | |
/// So I get this string from the server and in some places I need to display it in the users local timezone and in other places I need to display it as the time and date that it was booked | |
var serverTimeString = "2017-03-21T19:00:00-07:00" | |
let localisedDateFormatter = DateFormatter() | |
localisedDateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ" | |
// Displays as March 22nd, 2am (GMT) - CORRECT | |
var date = localisedDateFormatter.date(from: serverTimeString) | |
// TO DO: Output date as March 21st, 7pm. | |
// ?? |
@tmdvs That seems to spit out nil for me. I wonder if doing this in playgrounds makes a difference...
IIRC, the dashes and colons in the dateFormat
need to be escaped.
localisedDateFormatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZZZZZ"
see listing 2 under "parsing date strings" on this page.
@jellybeansoup The parsing into the Date object works fine, adding those escapes gives the same result and continues to work.
The problem is I need to display it to the user as the -07:00 timezone but I can't see a way to create a TimeZone object with that data.
@MattCheetham I'm looking at regex-ing the timezone element out and setting it on the formatter
@tmdvs Yeah that's kind of where I'm thinking of going but it feels overkill. I felt like there must have been a simpler way but maybe not. Various examples online of people using substrings to split out the time zone.
That's not really how date formatting should work. I dunno the ins and outs of where the input date comes from but sounds like you want to discard the timezone completely and display it to the user as 2017-03-21T19:00:00
but nicely formatted?
Best way to do that would be to ignore the Z
component from the input string and then make sure the api date formatter and the ui date formatter have matching timezones but to do that you will need to update your input value (get them to change the API or manipulate the string)
Something like this:
/// We're working with appointments.
/// So I get this string from the server and in some places I need to display it in the users local timezone and in other places I need to display it as the time and date that it was booked
let serverTimeString = "2017-03-21T19:00:00-07:00"
// TODO: ensure the string is at least 19 chars before manipulating
let manipulatedString = serverTimeString.substring(to: serverTimeString.index(serverTimeString.startIndex, offsetBy: 19))
let timeZone = TimeZone(secondsFromGMT: 0)
// A formatter with a FIXED locale for formatting the input date (from the API?)
let apiFormatter = DateFormatter()
apiFormatter.locale = Locale(identifier: "en_US_POSIX")
apiFormatter.timeZone = timeZone
apiFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
// Ignores the concept of a time zone so formats as 19:00:00 GMT
let date = apiFormatter.date(from: manipulatedString)!
// A formatter for showing the date to the user
let uiFormatter = DateFormatter ()
uiFormatter.locale = Locale(identifier: "en_GB")
uiFormatter.timeZone = timeZone
uiFormatter.dateStyle = .medium
uiFormatter.timeStyle = .medium
let display = uiFormatter.string(from: date) // "21 Mar 2017, 19:00:00"
This works, I get Tuesday, 21 March 2017 at 19:00:00 GMT-07:00
do {
let serverTimeString = "2017-03-21T19:00:00-07:00"
let pattern = "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}([\\d:\\-].*)"
let rexp = try NSRegularExpression(pattern: pattern, options: .caseInsensitive)
let matches = rexp.matches(in: serverTimeString, options: [], range: NSMakeRange(0,25))
let timezone = (serverTimeString as NSString).substring(with: matches.last!.rangeAt(1)) as NSString
let tzParts = timezone.components(separatedBy: ":")
let hours = tzParts[0] as NSString
let minutes = tzParts[1] as NSString
let secondsSinceGMT = (hours.integerValue * 60 * 60) + (minutes.integerValue * 60)
print(secondsSinceGMT)
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssxxxxx"
formatter.timeZone = TimeZone(secondsFromGMT: secondsSinceGMT)
let date = formatter.date(from: serverTimeString)
let displayFormatter = DateFormatter()
displayFormatter.dateStyle = .full
displayFormatter.timeStyle = .full
displayFormatter.timeZone = TimeZone(secondsFromGMT: secondsSinceGMT)
print(displayFormatter.string(from: date!))
} catch {
// something borked
}
Could likely tidy it up. I've used regex and timezone calculations to try and catch any timezone not just -7 hours
Hmm does this work for you?