1

Why there is a TimeZone with an API significantly different than NSTimeZone?

Say NSTimeZone has init(name: String) and TimeZone does not.

NSTimeZone has abbreviation property and in TimeZone abbreviation is a function that takes Date as a parameter (and nil is not an option)

Interestingly enough TimeZone(identifier:) digests abbreviations just fine.

HangarRash
  • 7,314
  • 5
  • 5
  • 32
Anton Tropashko
  • 5,486
  • 5
  • 41
  • 66
  • 2
    Although your question has already been closed as being phrased in an opinion-based manner, I'd dispute your premise that `TimeZone` has fewer features than `NSTimeZone`: `TimeZone` _is_ `NSTimeZone`, updated with an API surface more befitting Swift. Obj-C, for example, doesn't have default method arguments, so `NSTimeZone` _needs_ both an `abbreviation` property and an `-abbreviationForDate:` method, while `TimeZone` offers the single `abbreviation(for:)` method with a default parameter, covering both cases. – Itai Ferber Aug 09 '23 at 16:48
  • 1
    To answer your "why": Foundation offers quite a few of these "bridged" types (`Calendar`/`NSCalendar`, `Data`/`NSData`, `URL`/`NSURL`, etc.) in order to offer API surfaces which better fit in with Swift. – Itai Ferber Aug 09 '23 at 16:50
  • In which cases abbreviation differs depending on the date? – Anton Tropashko Aug 10 '23 at 10:21
  • 3
    The most common reason an abbreviation changes with date is Daylight Savings; the `America/New_York` time zone, for instances, uses the abbreviation `EST` ("Eastern Standard Time") for 6 months of the year, and `EDT` ("Eastern Daylight Time") for the other 6. The abbreviation used depends on the date you check, and most time zones that have DST do this. Abbreviations can also change over time as time zones are renamed, which means that a time zone may have used a different abbreviation in the past than it does now (so giving a past date may give a different result). – Itai Ferber Aug 10 '23 at 11:59
  • And btw how does NSTimeZone.abbreviation works in EST/EDT case – Anton Tropashko Aug 10 '23 at 15:04
  • *"Say NSTimeZone has init(name: String) and TimeZone does not."* - For `NSTimeZone`, the `name` parameter is a timezone identifier. It's a poorly named parameter. In `TimeZone` it was renamed more clearly to `init(identifier:)`. – HangarRash Aug 10 '23 at 15:14
  • *"NSTimeZone has abbreviation property and in TimeZone abbreviation is a function that takes Date as a parameter"* - `NSTimeZone` also has an `abbreviation` function that takes a `Date`. The `abbreviation` property is a shortcut for calling the function with today's date. The `abbreviation` function of `TimeZone` has a default `date` parameter of "now". It seems your whole question is based on invalid assumptions that the APIs are significantly different. `TimeZone` has simply been made more "Swift-like" than the old Objective-C based `NSTimeZone`. – HangarRash Aug 10 '23 at 15:19
  • Yes, and Itai Ferber did a stellar job eduficating me on the subject of the bridging of NSTimeZone into the version with the NS prefix castrated out of it. – Anton Tropashko Aug 15 '23 at 15:52

1 Answers1

3

The Foundation framework offers quite a few type pairs where the API of the original NS-prefixed type, as imported from the original Objective-C code, was less than optimal for Swift. Among these type pairs are

and others.

TimeZone and NSTimeZone are one such pair, where NSTimeZone is an Objective-C type which is exposed to Swift as-is, while TimeZone is a native Swift wrapper around NSTimeZone with an updated API. That updated API is intentionally different, because the original Objective-C API may be suboptimal in Swift.

For example, as you note, NSTimeZone offers both an abbreviation property and an -abbreviationForDate: method, while TimeZone only offers the method. It's important to note that the abbreviation property just returns the result of calling -abbreviationForDate:, passing in [NSDate now]; i.e., it exists only because Objective-C doesn't support default arguments for methods, so abbreviation is a convenience. Swift, however, does have default arguments, so TimeZone.abbreviation(for:) unifies these: if you want to pass a specific Date, you can, but you don't have to.

There are other reasons for disparate APIs on paired types like this:

  • -[NSTimeZone initWithName:] is an API that's poorly named: although its parameter is called "name", the actual argument is supposed to be a time zone identifier, which has a completely different format. This has to be called out in the NSTimeZone documentation in several places (e.g., "Although many NSTimeZone symbols include the word “name”, they actually refer to IDs."), which isn't great: ideally, the API should speak for itself. When TimeZone was introduced, the Foundation team had an opportunity to improve on the name of the API, so they introduced the same initializer on TimeZone as TimeZone.init(identifier:)

  • Following the Foundation conventions of mutable collections, NSData is an immutable data type which has a mutable counterpart in NSMutableData. Beside the complications that come from NSMutableData being a subclass of NSData (and NSData being a "class cluster"), Swift doesn't need to make this sort of distinction: when you work with value types, you don't need both mutable and immutable variants — you get mutability with var/let. Data, then, is a value type implementation which unifies the interfaces that NSData and NSMutableData offer into a single type (also removing some warts along the way)

  • Many language features in Swift are difficult to replicate on existing Objective-C types, or would require a complete rethink of the type and its interface in order to be effective in Swift. This is the case with NSAttributedString/NSMutableAttributedString and AttributedString: NSAttributedString is an extremely dynamic type, offering few available tools for convenience and safety; AttributedString makes use of a wide range of tools that Swift provides to offer type safety, autocompletion, and a host of conveniences that necessarily require a completely different API surface

In all, it's very rare for the Swift variant of a type pair like this to offer less API than its Objective-C counterpart — and where API was removed, it's almost always for safety, ergonomics, or in favor of better APIs. But in general, the Swift variants typically have significantly more functionality, even if how that functionality is accessed is a little different.

Itai Ferber
  • 28,308
  • 5
  • 77
  • 83