Last Week on My Mac: Picking dates and times
When Apple offers us the first Macs with M4 chips they should please those who want more precise timing. As their CPU cores use the ARMv9.2-A instruction set architecture, they should feature 1 GHz timers, introduced in ARMv9.1-A. One of the surprises of the first three families of M-series chips has been their relatively coarse-grained time resolution: their Mach Absolute Time increments every 41.67 nanoseconds, while the M4 should be capable of 1 nanosecond increments, as supported by Intel CPUs.
If such momentary time intervals are hard to envisage, we’ve long been able to measure brief moments in time. Second hands on clocks were an occasional feature over four centuries ago, and became commonplace in the nineteenth century, when the advent of railways synchronised time across continents so that trains could run on schedule.
Date Pickers
Macs have multiple clocks, and a common way to access date and time using the Date structure from Foundation. Apple infers that this resolves to ‘sub-millisecond’ times, and Dates are commonly set down to the second. Look in Ulbow and some other of my apps and you’ll see the AppKit interface for this, in a Date Picker with NSDatePicker. Much of those date back to Mac OS X 10.4.
In this case, I set its style to textFieldAndStepper to let the user specify year, month, date, hours, minutes and seconds precisely. As with many other apps, second resolution is essential when working with the log, as a Mac can accumulate thousands or even tens of thousands of log entries in each second.
This has its equivalent in SwiftUI, using the same term of Date Picker, shown here in my prototype log browser LogUI. What’s missing here are the seconds, which are only allowed in watchOS.
In SwiftUI, a Date Picker comes with set components, and those including seconds, hourMinuteAndSecond, aren’t available in macOS, iOS or iPadOS, only in watchOS. The others have to make do with hourAndMinute without seconds, which explains why I’ve had to tag on a separate view to handle seconds.
Not only is there no support for entering seconds in the SwiftUI Date Picker for macOS, but times set using it pick their own value for seconds, which appears to be random, rather than fixing the seconds value at zero. Thus, its value in any Date entered using SwiftUI could range between 0 and 59.
Using AppKit, obtaining the Date set using its Date Picker is simple: for a picker of
@IBOutlet var textBaseDate: NSDatePicker!
the code
let startDate = self.textBaseDate.dateValue
returns the date and time set, including seconds, in startDate.
Adding support for seconds
Dates are opaque structures, and don’t give direct access to components within them such as seconds. To cater for SwiftUI’s shortcomings, more code is required. In the view, the Date obtained from the Date Picker has to be supplemented by a separate value for seconds:
@State private var theStartDate = Date()
@State private var theSecs = “00”
DatePicker(“Start”, selection: $theStartDate, displayedComponents: [.date, .hourAndMinute])
TextField(“:”, text: $theSecs)
sets theStartDate to the date with uncontrolled seconds, and theSecs to the number of seconds entered separately by the user.
Then the code that incorporates the seconds into the Date has to work through an intermediate Calendar to do so. It first deconstructs the Date into its components:
let calendar = Calendar(identifier: .gregorian)
var components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date)
then sets the seconds correctly, and reconstructs the corrected Date:
components.second = theDateSecs
let dateWithSecs = calendar.date(from: components)!
SwiftUI
SwiftUI was first released for macOS Catalina and iOS 13 in 2019, so celebrated its fifth birthday last month. That makes it only two years younger than APFS, but the contrast in maturity between them could hardly be greater. AppKit may have the advantage of age, in that it was released with the first Mac OS X in 2001, but by the time it was five, midway between 10.4 Tiger and 10.5 Leopard, it was both extensive and mature. AppKit didn’t face the challenge of being cross-platform, though, and parallels with UIKit in iOS came later.
SwiftUI has also rushed forward in novel fields, laying greatest emphasis on iOS. Without sound foundations, though, it risks failure. If it still can’t perform basic functions long-supported by AppKit, then few macOS apps will adopt it, and it will stay playing second fiddle. That would be a bad outcome for all those involved, not least users expecting consistency and high quality in the human interface across Macs and Apple’s devices.
Any good five year-old should be able to tell the time including seconds. Yet SwiftUI hasn’t yet caught up with those German clockmakers of the sixteenth century and their second hands, and seems stuck in the age of sundials. How can it possibly cope with the first Macs based on M4 chips with their nanosecond resolution?