6

I know how to get local date and time, but what I want to do is getting the date and time from different places. For example, I want to find out what the time and date is in New York. How can i solve this simple problem?

Here is my code for local date and time :

let date = NSDate()
let calendar = Calendar.current

let components = calendar.dateComponents([.hour, .minute, .month, .year, .day, .second, .weekOfMonth], from: date as Date)

let currentDate = calendar.date(from: components) 

I searched about it here, but i didn't find what i want and I'm still looking for the date libaries. If you know any source or sample to redirect me, I really appreciate that.

jorjj
  • 1,479
  • 4
  • 20
  • 36

3 Answers3

6

If you just want to format the date to a string, consider using a DateFormatter instead:

let date = Date()
let formatter = DateFormatter()
formatter.timeZone = TimeZone(identifier: "America/New_York")
formatter.dateStyle = .long
formatter.timeStyle = .long
formatter.string(from: date)

If you want to get the date components and process them, use the dateComponents(in:from:) method.

let components = Calendar.current.dateComponents(in: TimeZone(identifier: "America/New_York")!, from: date)
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • I used the `components` but i got my local date again. Should I define and initialize something more? – jorjj Nov 13 '17 at 19:57
  • @winnervswinner Did you create a new `Date` using `components`? That won't work because a `Date` does not contain any information about its time zone. It represents a point in time, regardless of where on earth you are. – Sweeper Nov 13 '17 at 19:59
  • So how can I add different date. that's what I'm struggling for. – jorjj Nov 13 '17 at 20:02
  • You can display (format) the date to the user using the first code snippet. Or if you want to do some calculations with the components, use the second code snippet. I don't know what your _ultimate_ goal is, because creating a `Date` that represents a point in time in a certain time zone makes no sense, since a `Date` does not represent a time zone. @winnervswinner – Sweeper Nov 13 '17 at 20:04
  • I guess you got me wrong. I wanna show people different time and dates from different cities instead of their local ones. This is what i am trying to make. – jorjj Nov 13 '17 at 20:08
  • 1
    @winnervswinner Okay, use the first code snippet then. – Sweeper Nov 13 '17 at 20:10
6

There are several different concepts involved here, and we need to understand (almost) all of them to get this right...

1) a Date (NSDate as was, in Swift) is an absolute point in time - it's slightly mis-named, because it has nothing to do with an actual date like 13th November 2017, because to get to that we need to define ...

2) a Calendar, because 13th November 2017 in the western Gregorian calendar could also be 23rd Safar 1439 in the Islamic calendar, or the 24th of Heshvan 5778 in the Hebrew calendar, or some other things in the many other calendars that iOS & MacOS support;

3) in turn Calendar changes not only what values are returned in the DateComponents that we have to use to unpack a Date + Calendar into days, months, years & eras (e.g. BC/AD), or even week number, etc..., but also some calendars might not have the same components as others;

4) time-of-day (as you know) depends on TimeZone, so the same absolute time can be one of many different times "o'clock" depending on where you are. It may also (as you can see in the example below) change the date as well as the "o'clock". This of course could be automatic (where you are) or set by the programmer;

5) further, we have DateFormatter (which is a convenience that wraps up DateComponents), because 13th November 2017 could be represented as 13/11/17 or 11/13/17 depending on whether you are British or American. We may also wish to choose whether we use text or numeric months, and, if displaying times, whether we want 12 hour or 24 hour format - all of these are covered by DateFormatter, but text representation may be "13e Novembre 2017" if you are French, which introduces the notion of

6) Locale, which can be set, like TimeZone, as being default (as chosen when you set up the device) or specified by the programmer.

The code you posted won't work, because all it does is takes a Date, transforms it through a Calendar to DateComponents (all good so far), but then recreates a Date from the components - all you will get is the original Date - the same absolute point in time.

What I believe from the question and your answers to questions in the comments is that you want a function that takes an absolute time (eg "now") aka a Date and displays it in a specific TimeZone. This works:

func timeComponents(date: Date, timeZone: TimeZone) -> DateComponents {
    var calendar = Calendar.current
    calendar.timeZone = timeZone
    return calendar.dateComponents([.hour, .minute, .month, .year, .day, .second, .weekOfMonth], from: date)
}

let absTime: Date = Date() // Now
let edinburgh = TimeZone(abbreviation: "GMT")!
let newYork = TimeZone(abbreviation: "EST")!
let ec = timeComponents(date: absTime, timeZone: edinburgh)
let nycc = timeComponents(date: absTime, timeZone: newYork)
print(ec)// year: 2017 month: 11 day: 14 hour: 0 minute: 44 second: 10 weekOfMonth: 3 isLeapMonth: false 
print(nycc) // year: 2017 month: 11 day: 13 hour: 19 minute: 44 second: 10 weekOfMonth: 3 isLeapMonth: false 

... which I think answers the minimum of your question, but to finesse it, we need to move from DateComponents to DateFormatter

func timeString(date: Date, timeZone: TimeZone, timeStyle: DateFormatter.Style) -> String {
    let dateFormatter = DateFormatter()
    dateFormatter.timeZone = timeZone
    dateFormatter.dateStyle = .none
    dateFormatter.timeStyle = timeStyle
    return dateFormatter.string(from: date)
}

let es = timeString(date: absTime, timeZone: edinburgh, timeStyle: .full)
let nycs = timeString(date: absTime, timeZone: newYork, timeStyle: .full)
print(es) // 12:44:10 AM Greenwich Mean Time
print(nycs) // 7:44:10 PM Eastern Standard Time

You can go on, and start to use Locale, if you want to internationalise your app, but I'l leave that as an exercise!

p.s. These are not all of the concepts - see here

p.p.s. See also this answer and this answer (neither duplicates)

Grimxn
  • 22,115
  • 10
  • 72
  • 85
2

If you don't know the time zone of the place you are searching for, you can use the CoreLocation's CLGeocoder and search on an address string. Then you can get the timezone for that place and translate that into the time you're looking for:

let geocoder = CLGeocoder()
geocoder.geocodeAddressString("New York, New York") { (placemarks, error) in
    guard error == nil else {
        print("Error")
        print(error!.localizedDescription)
        return
    }
    guard let placemarks = placemarks,
        let place = placemarks.first else {
        print("No results")
        return
    }

    if let timeZone = place.timeZone {
        print("TimeZone: \(timeZone.identifier)")
        // TimeZone: America/New_York

        //Ignore the time zone offset from this one, it will be the difference between the current time and the new york time
        let dateInNewYork = Date().addingTimeInterval(TimeInterval.init(timeZone.secondsFromGMT()))
        print(dateInNewYork)
        // 2017-11-13 15:03:05 +0000

        //Or
        let formatter = DateFormatter()
        formatter.timeZone = TimeZone(identifier: timeZone.identifier)
        formatter.dateStyle = .long
        formatter.timeStyle = .long
        let formattedDateInNewYork = formatter.string(from: Date())
        print(formattedDateInNewYork)
        // November 13, 2017 at 3:03:05 PM EST

        //Or
        let components = Calendar.current.dateComponents(in: TimeZone(identifier: timeZone.identifier)!, from: Date())
        print(components.date!)
        // 2017-11-13 20:03:05 +0000
    }

}
Zig
  • 2,603
  • 1
  • 14
  • 20
  • I don't need to get people's location, bec I just wanna show people specific places' dates and times. I tried your code with an exact adress anyway, but i didn't work. – jorjj Nov 13 '17 at 20:21
  • This is tested, working code. What didn't work about it? You can search for cities, it doesn't need to be specific addresses. – Zig Nov 13 '17 at 20:22
  • I typed New York, NY, United States and also tried yours, but it gave me my local dates. can you share your results with me? – jorjj Nov 13 '17 at 20:35
  • https://ibb.co/gy64Hb as you can see on the link, I'm getting the same datas. I didn't anything more. it's the same code and its result. – jorjj Nov 13 '17 at 20:49
  • What time zone are you in? – Zig Nov 13 '17 at 20:50
  • Europe GMT+03:00 – jorjj Nov 13 '17 at 20:52