0

When I convert any sort of timestamp to a date, whether it be UTC or with another offset, it converts it to my local time. How can I stop it from doing that?

As an example, the following code prints out 2022-05-24 09:40:11 +0000 but it should show up as 2022-05-24 01:40:11 +0000. I do not want the equivalent time in my own time zone that it is returning

let dateStr = "2022-05-024T01:40:11.126-08:00"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
let parsedDate = dateFormatter.date(from: dateStr)
print(parsedDate)
Matt
  • 1,087
  • 1
  • 12
  • 28
  • 1
    `Date` is just a container for the amount of time which has passed since some anchor point (ie milliseconds since the Unix Epoch), it doesn't "convert" the value, what it does do is, when you "print" make use of the platforms locale to present a "human readable" presentation of the time it represents – MadProgrammer May 24 '22 at 23:21
  • `parsedDate` will contain the correctly converted date, you just testing it wrong with `print`. Instead do this: `print(parsedDate?.timeIntervalSince1970)` and see that this is the right date (for example via this site: https://www.epochconverter.com/). Also `2022-05-024` is not a valid date. – timbre timbre May 24 '22 at 23:28
  • You date is being correctly parsed but there are other issues with your implementation – Leo Dabus May 24 '22 at 23:34
  • to check if your date was parsed correctly you need also to use your date formatter to convert the date back to string `print(dateFormatter.string(from: parsedDate))` – Leo Dabus May 24 '22 at 23:40
  • Btw you should use `let dateFormatter = ISO8601DateFormatter()` and insert `withFractionalSeconds` to its formatOptions `dateFormatter.formatOptions.insert(.withFractionalSeconds)` or check this post how to properly deal with iso8601 date format [How can I parse / create a date time stamp formatted with fractional seconds UTC timezone (ISO 8601, RFC 3339) in Swift?](https://stackoverflow.com/a/28016692/2303865) – Leo Dabus May 24 '22 at 23:42

1 Answers1

1

Date is just a container for the amount of time which has passed since some anchor point (ie milliseconds since the Unix Epoch), it doesn't "convert" the value, what it does do is, when you use "print", it make use of the platforms locale/timezone to present a "human readable" presentation of the time it represents

For example...

let dateStr = "2022-05-024T01:40:11.126-08:00"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
let date = dateFormatter.date(from: dateStr)!
print(date)

prints 2022-05-24 09:40:11 +0000

But, if I change the formatter's timezone, for example...

let utcFormatter = DateFormatter()
utcFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
utcFormatter.timeZone = TimeZone(abbreviation: "UTC")
let utcDate = utcFormatter.date(from: dateStr)!
print(utcDate)

it still prints 2022-05-24 09:40:11 +0000

Okay, it's printing in UTC anyway, so lets trying a different timezone:

let auFormatter = DateFormatter()
auFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
auFormatter.timeZone = TimeZone(abbreviation: "AEST")
let auDate = auFormatter.date(from: dateStr)!
print(auDate)

it still prints 2022-05-24 09:40:11 +0000

If we read the docs it actually says "The representation is useful for debugging only."

If you want the presentation done differently, use a different formatter, for example...

let dateStr = "2022-05-024T01:40:11.126-08:00"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
let date = dateFormatter.date(from: dateStr)!
print(date)

dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
print(dateFormatter.string(from: date))

dateFormatter.timeZone = TimeZone(secondsFromGMT: -(8 * 60 * 60))
print(dateFormatter.string(from: date))

dateFormatter.timeZone = TimeZone(abbreviation: "AEST")
print(dateFormatter.string(from: date))

Which prints...

2022-05-24 09:40:11 +0000        // print(date)
2022-05-24T09:40:11.126Z         // UTC
2022-05-24T01:40:11.126-08:00    // -8
2022-05-24T19:40:11.126+10:00    // AEST

(obviously you could also configure the Locale for different representations)

They all represent the same date/time value, just at different time zones

You could also check the different date values using Date#timeIntervalSinceReferenceDate or Date#timeIntervalSince1970, for example...

let dateStr = "2022-05-024T01:40:11.126-08:00"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
print(dateFormatter.date(from: dateStr)!.timeIntervalSince1970)

dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
print(dateFormatter.date(from: dateStr)!.timeIntervalSince1970)

dateFormatter.timeZone = TimeZone(secondsFromGMT: -(8 * 60 * 60))
print(dateFormatter.date(from: dateStr)!.timeIntervalSince1970)

dateFormatter.timeZone = TimeZone(abbreviation: "AEST")
print(dateFormatter.date(from: dateStr)!.timeIntervalSince1970)

which prints...

1653385211.126
1653385211.126
1653385211.126
1653385211.126

And as the docs state, "The interval between the date value and 00:00:00 UTC on 1 January 1970."

In this case, the formatter timezone has not effect on the parsing, only the presentation (the locale can fix parsing issues, but that's another topic)

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366