malcommac / SwiftDate

🐔 Toolkit to parse, validate, manipulate, compare and display dates, time & timezones in Swift.
MIT License
7.64k stars 770 forks source link

.toISODate(region: Region.ISO) Not working as expected #775

Open morgz opened 3 years ago

morgz commented 3 years ago

The docs state this should return the date in the region specified in the ISO string. This is not the case unless I'm missing something. It converts to GMT.

po "2017-08-05T16:04:03+02:00".toISODate(region: Region.ISO)
▿ Optional<DateInRegion>
  ▿ some : {abs_date='2017-08-05T14:04:03Z', rep_date='2017-08-05T14:04:03Z', region={calendar='gregorian', timezone='GMT', locale='en_US_POSIX'}
    ▿ date : 2017-08-05 14:04:03 +0000
      - timeIntervalSinceReferenceDate : 523634643.0
    ▿ region : {calendar='gregorian', timezone='GMT', locale='en_US_POSIX'}
      ▿ calendar : gregorian (fixed)
        - identifier : gregorian
        - kind : "fixed"
        ▿ locale : Optional<Locale>
          ▿ some : en_US_POSIX (fixed)
            - identifier : "en_US_POSIX"
            - kind : "fixed"
        ▿ timeZone : GMT (fixed)
          - identifier : "GMT"
          - kind : "fixed"
          ▿ abbreviation : Optional<String>
            - some : "GMT"
          - secondsFromGMT : 0
          - isDaylightSavingTime : false
        - firstWeekday : 1
        - minimumDaysInFirstWeek : 1
    - customFormatter : nil
dagronf commented 3 years ago

I'm very new to this library so I could be wrong here, but doesn't Region.ISO define GMT as the timezone? From Region.swift:83...

/// ISO Region is defined by the gregorian calendar, gmt timezone and english posix locale
public static var ISO: Region {

By specifying Region.ISO as the region you are telling it to create a DateInRegion object that reflects the specified string in the GMT timezone.

let vdate = "2017-08-05T16:04:03+02:00".toISODate(region: Region.ISO)

Optional({abs_date='2017-08-05T14:04:03Z', rep_date='2017-08-05T14:04:03Z', region={calendar='gregorian', timezone='GMT', locale='en_US_POSIX'})

If you don't specify a Region, the returned DateInRegion reflects the timezone defined in the string (which is what I think you wanted?)

let vdate = "2017-08-05T16:04:03+02:00".toISODate()

Optional({abs_date='2017-08-05T14:04:03Z', rep_date='2017-08-05T16:04:03+02:00', region={calendar='gregorian', timezone='GMT+0200', locale='en_US_POSIX'})

Just to be confusing (which dates are!) the date object (type Date) in the DateInRegion result does not have the concept of a timezone - it's just a point in time. To print it for a particular timezone, create a formatter and set the zone on the formatter eg.

let df = ISO8601DateFormatter()
df.timeZone = vdate!.region.timeZone
Swift.print(df.string(from: vdate!.date))

/// Produces "2017-08-05T16:04:03+02:00"