Created
May 24, 2024 18:02
-
-
Save robertmryan/98669fcb526c37e449551521e90f91d5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ViewController: NSViewController { | |
let calendar = Calendar.autoupdatingCurrent | |
var previousIdentifier: String = Calendar.current.timeZone.identifier | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
// poll to see if the identifier changed | |
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in | |
guard let self else { | |
timer.invalidate() | |
return | |
} | |
let identifier = calendar.timeZone.identifier | |
if previousIdentifier != identifier { | |
print("Time zone changed from", previousIdentifier, "to", identifier) | |
previousIdentifier = identifier | |
} | |
} | |
// better, let the OS tell us when the time zone changes | |
NotificationCenter.default.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: .main) { [weak self] _ in | |
guard let self else { | |
return | |
} | |
print("Time zone changed to", calendar.timeZone.identifier) | |
} | |
} | |
} |
@kortschak – I’m not a Go programmer, but I would have thought that you could os.Exit(…)
.
E.g., this exits after 30 seconds:
package main
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation
#include <Foundation/Foundation.h>
const char *currentTimezone()
{
static NSCalendar *calendar;
// the static is set only once
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
calendar = [NSCalendar autoupdatingCurrentCalendar];
});
return calendar.timeZone.name.UTF8String;
}
*/
import "C"
import (
"fmt"
"time"
"os"
)
func main() {
// poll for location updates
go func() {
for {
time.Sleep(time.Second)
fmt.Println(CurrentTimeZone())
}
}()
// exit after 30 seconds
go func() {
time.Sleep(time.Second * 30)
os.Exit(0)
}()
// process GCD events
C.dispatch_main()
}
// Current returns the current system local timezone. If CurrentTimeZone fails it
// returns time.UTC and a non-nil error.
func CurrentTimeZone() (*time.Location, error) {
tz := C.GoString(C.currentTimezone())
loc, err := time.LoadLocation(tz)
if err != nil {
return time.UTC, err
}
return loc, nil
}
Also, FWIW, this illustrates the use of autoupdatingCurrentCalendar
with static
local variable. Again, I see no need to contort ourselves like this from Go, but just as a proof of concept that autoupdatingCurrentCalendar
does what one expects.
Yeah, that is how I would have to do it. The reason it's ugly is that it brings in this pattern which is not required on the other platforms that the application targets and complicates the logic for termination control.
I agree that you've shown that it does what's expected and thank you for digging into what is necessary to get it to work in this context.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Unfortunately this requires that
dispatch_main
runs in the main thread. I can't see a way to make this work with the existing application's need to control it's own termination. I think maybe it can be done, but it will be ugly.