16

I have a bunch of different show times in a database and want to display the correct time based on the users time zone by creating an offset.

I'm getting the users time zone offset from GMT and converting that to hours first.

NSTimeZone.localTimeZone().secondsFromGMT / 60 / 60

Then I need to find a way to add the hours to the date object.. that is where I/m struggling.

let formatter = NSDateFormatter()
    formatter.dateFormat = "HH:mm"

    let date = formatter.dateFromString(timeAsString)
    println("date: \(date!)")

Then I'm creating a string from the date to use in a label, to have it easy to read with the AM / PM.

    formatter.dateFormat = "H:mm"
    formatter.timeStyle = .ShortStyle
    let formattedDateString = formatter.stringFromDate(date!)
    println("formattedDateString: \(formattedDateString)")

I just can't seem to find out how to add/subtract hours. I've split the string up but it sometimes goes negative and won't work. Maybe I'm going about this wrong.

Thanks for any help.

Keith

Keith
  • 1,969
  • 4
  • 17
  • 27

3 Answers3

20

If you want to convert a show time which is stored as a string in GMT, and you want to show it in the user's local time zone, you should not be manually adjusting the NSDate/Date objects. You should be simply using the appropriate time zones with the formatter. For example, in Swift 3:

let gmtTimeString = "5:00 PM"

let formatter = DateFormatter()
formatter.dateFormat = "h:mm a"
formatter.timeZone = TimeZone(secondsFromGMT: 0)            // original string in GMT
guard let date = formatter.date(from: gmtTimeString) else {
    print("can't convert time string")
    return
}

formatter.timeZone = TimeZone.current                       // go back to user's timezone
let localTimeString = formatter.string(from: date)

Or in Swift 2:

let formatter = NSDateFormatter()
formatter.dateFormat = "h:mm a"
formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)  // original string in GMT
let date = formatter.dateFromString(gmtTimeString)

formatter.timeZone = NSTimeZone.localTimeZone()        // go back to user's timezone
let localTimeString = formatter.stringFromDate(date!)
Rob
  • 415,655
  • 72
  • 787
  • 1,044
6

I would use the dateByAddingTimeInterval function to add and subtract hours. Add a to the dateFormat string to print am or pm.

var showTimeStr = "00:00 PM" //show time in GMT as String
let formatter = NSDateFormatter()
formatter.dateFormat = "hh:mm a"
let showTime = formatter.dateFromString(showTimeStr)
showTime.dateByAddingTimeInterval(3600) //Add number of hours in seconds, subtract to take away time
showTimeStr = formatter.stringFromDate(showTime)
Blake Morgan
  • 767
  • 1
  • 7
  • 25
  • 1
    Thanks for replying. What you put is pretty much working, I had to just add the optionals. Now i'm trying to put the offset where you have the 3600 let offsetTime = NSTimeZone.localTimeZone().secondsFromGMT but I'm getting "Int is not convertible to NSTimeInterval" is there a way to cast that? – Keith Dec 23 '14 at 02:01
  • Thanks. Please upvote and select as right answer if it worked. To cast: `let offsetTime = Int(NSTimeZone.localTimeZome().secondsFromGMT)`. Doing that will work, but realize it will truncate the interval (i.e. 83.96748 becomes 83, not 84). If you want to round then cast, then the answer to this post: http://stackoverflow.com/questions/11121459/how-to-convert-nstimeinterval-to-int will help you. – Blake Morgan Dec 23 '14 at 02:17
  • Actually it only subtracts it 7 minutes and that link doesn't really work in swift unless I"m doing it wrong. – Keith Dec 23 '14 at 02:55
  • I was wrong. I misread you're error message. This would be the correct code: `let offsetTime = NSTimeZone.localTimeZone().secondsFromGMT showTime!.dateByAddingTimeInterval(NSTimeInterval(offsetTime))`. You need to cast `offsetTime` as an NSTimeInterval. – Blake Morgan Dec 23 '14 at 20:16
1

Here is my final code, combined with b.Morgans answer. I believe it's all working now.

let offsetTime = NSTimeInterval(NSTimeZone.localTimeZone().secondsFromGMT)

var showTimeStr = "05:00 PM" //show time in GMT as String
let formatter = NSDateFormatter()
formatter.dateFormat = "h:mm a"
let showTime = formatter.dateFromString(showTimeStr)
let finalTime = showTime?.dateByAddingTimeInterval(offsetTime) //Add number of hours in seconds, subtract to take away time
showTimeStr = formatter.stringFromDate(finalTime!)
Keith
  • 1,969
  • 4
  • 17
  • 27
  • 1
    You often get to the right result this way, but it belies a fundamental misunderstanding of `NSDate` objects. For example, with this code, the `showTime` variable is not 5pm GMT, but rather 5pm in your local time zone (for me in NY, 5pm is 10pm GMT). Sure, in `finalTime`, you reverse this mistake, replacing the 10pm GMT with 5pm GMT, and when you then use formatter to display this as a string again, you get the 5pm GMT correctly shown in your local time zone (i.e. noon here in NY). That's unnecessarily confusing (and if you start using full date strings, you'll sometimes be off by 24 hours). – Rob Dec 23 '14 at 03:39
  • Thanks a ton Rob, that makes sense and I want to do it the correct way and avoid confusion. – Keith Dec 23 '14 at 03:49
  • Yeah, actually I am using the date too. I basically have a separate field in the database for time and separate date field ie 2014-01-01. But maybe I should use both at the same time and I'm setting up the database content however I need so I can adjust the formatting before as well. So yeah basically whatever works best and in the end I need the date as one label and time as another in the app. Thanks. – Keith Dec 23 '14 at 04:03
  • Yeah, I should have given more thought into that, originally I was thinking only US time. I guess that would be a totally different question now with date involved. – Keith Dec 23 '14 at 04:17
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/67508/discussion-between-rob-and-user3712837). – Rob Dec 23 '14 at 04:17