skip to Main Content

I’m really struggling with dates and timezones.

My understanding is Date is independent of timezone and is just a point in time.

I’m writing a unit test and I want to create a Date object that would represent the time now if the user was in a different timezone than the default London zone I’m running the test from and then convert it to a different timezone.

I start off by creating a Date object using DateComponents with the projected time, in this example, I want Australia/Sydney time which is 11hrs ahead of GMT (my location).

Next, I want to derive a new Date that is adjusted back to GMT i.e. essentially subtracting 11hrs.

The derived date I want is 2022-12-07 13:30:00 +0000. I’m using dateComponents(in:from:) method on Calendar to specify the timezone, according to Apple’s documentation:

Returns all the date components of a date, as if in a given time zone (instead of the Calendar time zone).

I then set the timeZone component which should then adjust the time from Australia/Sydney to Europe/London but while it’s adjusting the time it’s not correctly adjusting the date component which should be shifted one day back.

Here is my code example:

let components = DateComponents(
    year: 2022,
    month: 12,
    day: 8,
    hour: 02,
    minute: 30,
    second: 0
)

let originalDate = Calendar.current.date(from: components)! 
// originalDate printed is 2022-12-08 02:30:00 +0000

var components = Calendar.current.dateComponents(in: TimeZone(identifier: "Australia/Sydney")!, from: originalDate)
components.timeZone = TimeZone(identifier: "Europe/London")!

let localTime = components.date! 
// localTime printed is 2022-12-08 13:30:00 +0000 but I expected 2022-12-07 13:30:00 +0000 as Sydney is +11hrs ahead of GMT+0.

3

Answers


  1. If your goal is to create a Date that is on 2022-12-08 at 02:30 local time in Sydney then the simplest way is:

    let components = DateComponents(
        timeZone: TimeZone(identifier: "Australia/Sydney")!,
        year: 2022,
        month: 12,
        day: 8,
        hour: 02,
        minute: 30,
        second: 0
    )
    
    let originalDate = Calendar.current.date(from: components)!
    

    That’s it. No other conversion is needed. originalDate will show as 2022-12-07 15:30:00 +0000.

    Login or Signup to reply.
  2. The reason you get the result you do is that DateComponents are just a set of components. You can create them from a Date and create a Date from them but they aren’t a Date.

    You are creating DateComponents from a Date using the Australia/Sydney so you get "13:30" in the hour and minute components and "Australia/Sydney" in the time zone component.

    Then you change the timezone component to "Europe/London". This doesn’t change any other component, so you now have a set of components that represent 13:30 in London.

    Another way of thinking about it, is if you set the hours component to 2 instead of changing the Timezone; You are just going to get 02:30 in Australia/Sydney. It isn’t going to change the time zone to UTC

    If you want to create a Date at a specific time in a particular Timezone, specify that Timezone in your original date components.

    Login or Signup to reply.
  3. let components = DateComponents(
        year: 2022,
        month: 12,
        day: 8,
        hour: 02,
        minute: 30,
        second: 0
    )
    
    let originalDate = Calendar.current.date(from: components)!
    // originalDate printed is 2022-12-08 02:30:00 +0000
    
    var components1 = Calendar.current.dateComponents(in: TimeZone(identifier: "Australia/Sydney")!, from: originalDate)
    let afterTimeZoneSetDate = Calendar.current.date(from: components1)!
    // this prints - "Dec 8, 2022 at 2:30 AM"
    
    components1.timeZone = TimeZone(identifier: "Europe/London")!
    
    let localTime = components1.date
    // localTime printed is 2022-12-08 13:30:00 and this is correct.
    

    If you look at the code above, because your original components does not include a timeZone, it does not alter the time after you set "Australia/Sydney", rather it assign a timeZone now. Beyond this since you are changing a timeZone, it will adapt the time accordingly.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search