Time Zone using Current Location scriptable?

hkim
Contributor II

I'm looking for a programatic way to be able to set that setting in Date & Time. Any ideas?

36 REPLIES 36

blackholemac
Valued Contributor III

The ability to use "Current Location" would be a great, but if it helps you as to what we do to set the timezone, I will gladly expound. We are all in the American Eastern Time Zone so I hardcode for "America/New_York"

We also have Network Time Servers at each of our locations. So to set both the timezone via command line on our images, I have a script that runs the following two commands:

systemsetup -settimezone "America/New_York"
systemsetup -setnetworktimeserver "yourntpserver.yourdomainhere.com"

So, now that we have the syntax of the commands covered, let me start the skeleton of a script for you...knowing that I lack the knowledge of how to finish this concept. If nothing else, this should give you some food for thought:

#!/bin/sh

###Variable Declaration###
#This is my main challenge. How do write a command(s) that will
#populate this variable by either pulling the network segment or 
#Casper location data for a given Mac in the data base, and then how 
#do we transform what is pulled from the database into something
#systemsetup understands such as 'America/New_York' or say 'Europe/Berlin'.

TimeZone="`<hoped for command the populates this variable here>`"

systemsetup -settimezone "$TimeZone"

exit 0

Hopefully some better scripters weigh in on this...and who knows...maybe there is a way to set it using "Current Location", but the man page for the systemsetup command does not cover that.

hkim
Contributor II

Further investigation on my 10.8.3 computer yielded that the actual file being touched is /Library/Preferences/com.apple.timezone.auto.plist I wonder if it's touching other files as well.

Time to fire up PlistBuddy to try to script it.

ericbenfer
Contributor III

As always TEST TEST TEST in a dev environment first.
This works for me. It only seems to do the first lookup after opening the Date & Time prefs.

#!/bin/sh

# Use "/usr/sbin/systemsetup -listtimezones" to see a list of available list time zones.
TimeZone="America/New_York"
TimeServer="time.apple.com"

############# Pause for network services #############
/bin/sleep 10
#################################################

/usr/sbin/systemsetup -setusingnetworktime off 

#Set an initial time zone
/usr/sbin/systemsetup -settimezone $TimeZone

#Set specific time server
/usr/sbin/systemsetup -setnetworktimeserver $TimeServer

# enable location services
/bin/launchctl unload /System/Library/LaunchDaemons/com.apple.locationd.plist
uuid=`/usr/sbin/system_profiler SPHardwareDataType | grep "Hardware UUID" | cut -c22-57`
/usr/bin/defaults write /var/db/locationd/Library/Preferences/ByHost/com.apple.locationd.$uuid LocationServicesEnabled -int 1
/usr/sbin/chown -R _locationd:_locationd /var/db/locationd
/bin/launchctl load /System/Library/LaunchDaemons/com.apple.locationd.plist

# set time zone automatically using current location 
/usr/bin/defaults write /Library/Preferences/com.apple.timezone.auto Active -bool true

/usr/sbin/systemsetup -setusingnetworktime on 

/usr/sbin/systemsetup -gettimezone
/usr/sbin/systemsetup -getnetworktimeserver

exit 0

hkim
Contributor II

Just to answer my own question here's what I've come up with, pretty or elegant? No. Effective? Seems to be.

#!/bin/bash uuid=/usr/sbin/system_profiler SPHardwareDataType | grep "Hardware UUID" | cut -c22-57 /bin/launchctl unload /System/Library/LaunchDaemons/com.apple.locationd.plist /usr/bin/defaults write /private/var/db/locationd/Library/Preferences/ByHost/com.apple.locationd.$uuid LocationServicesEnabled -int 1 /usr/bin/defaults write /private/var/db/locationd/Library/Preferences/ByHost/com.apple.locationd.notbackedup.$uuid LocationServicesEnabled -int 1 /usr/sbin/chown -R _locationd:_locationd /var/db/locationd /bin/launchctl load /System/Library/LaunchDaemons/com.apple.locationd.plist exit 0

For Auto Time Zone similar idea

#!/bin/sh /usr/bin/sudo /usr/bin/defaults write /Library/Preferences/com.apple.timezone.auto Active -bool True exit 0

atrivas
New Contributor

@ericbenfer Thanks for the TimeServer, TimeZone, Location Service on script. It was everything I needed!

bpavlov
Honored Contributor

I was actually looking at this myself. Am I right in that this only works after opening up Date and Time? There's got to be a way to kick off the "Determining location..." portion that the System Preference pane. I'll be looking a bit more into this, but figured I'd ask.

bpavlov
Honored Contributor

I just want to describe a few other things I tried in investigating this. I went ahead and implemented the script as is. Ran command in Terminal:

opensnoop -v

and then opened up Date and Time preferences

Lots of stuff going on but the main ones I saw were TimeZoneToAdmin, timezoned, locationd, and references to GeoKit.framework. Most of it was located in here: /System/Library/PreferencePanes/DateAndTime.prefPane/Contents/Resources/TimeZone.prefPane/Contents/Resources/timezoned.app

Unfortunately, I didn't get much further than that. Unloading and re-loading the plist doesn't seem to do much either. Tried looking at Developer documentation for anything related to timezone settings and there are references to Core Location services but I wouldn't know what to do with that at this point in time.

But here's what I discovered which I find rather interesting: if you disable and re-enable wireless it automatically re-syncs after a 2-3 seconds (this assumes it reconnects to a wireless network with an active internet connection). Doesn't work with Ethernet. I'm wondering if disabling the wireless and re-enabling the wireless as part of the script would automatically sync to the right timezone. The downside is if the computer only has a wireless connection and for whatever reason cannot reconnect to the network (and therefore the JSS) you may run into logs for the policy not completing successfully. Something to think about.

bpavlov
Honored Contributor

Running a simple commands of:

/usr/sbin/networksetup -setairportpower en0 off
/usr/sbin/networksetup -setairportpower en0 on

This assumes your wireless is en0. If it's not, you can run this command to determine what device name is listed as:

/usr/sbin/networksetup -listallhardwareports

Alternatively you can also use the Hardware Port name too:

/usr/sbin/networksetup -setairportpower Wi-Fi off
/usr/sbin/networksetup -setairportpower Wi-Fi on

But that may differ depending on the OS you're running. I think it was AirPort at one point and may have changed in either 10.7 or 10.8 to Wi-Fi.

Anyways this is all informational. I'll personally let OS naturally detect it either on a restart which a user is bound to do or when they connect to the wireless for the first time.

notinuse
New Contributor

I found that this change would only be respected if the plist file was in xml format. Weird, huh?

This is my setup for enabling location-based time zone (Note; location services need to also be enabled, as above:

/bin/rm /Library/Preferences/com.apple.timezone.auto.plist
/usr/bin/defaults write /Library/Preferences/com.apple.timezone.auto Active -bool true
/usr/bin/plutil -convert xml1 /Library/Preferences/com.apple.timezone.auto.plist

chad_fox
Contributor II

What worked for me is to create a package using composer containing the com.apple.timezone.auto.plist set to true. I then pushed this out via policy and added it to our Casper Imaging configuration.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict> <key>Active</key> <true/>
</dict>
</plist>

ncworster
New Contributor III

Thanks @ericbenfer ! Worked great for me.

cgiordano
Contributor

So the script itself works for me but the problem that I'm seeing is that this will only set the timezone to Eastern but if the person sits in the Pacific timezone then it won't update the time on the machine until after they've launched the Date & Time preference pane. Is there any way to get the time zone to set itself correctly based off their geo automatically?

NoahRJ
Contributor II

@cgiordano I ran into the same problem - we were previously unloading and loading the LaunchD located in /System/Library/LaunchDaemons/com.apple.locationd.plist to get the change to stick, but SIP in Sierra neutered that. Finally had some time to dig in today and found this little gem that forces the auto timezone if you've set all the other stuff properly for automatic timezone discovery and enabling Location Services.

Since the bulk of the auto timezone stuff is a shell script and the above is in Python, I just loaded it in as a heredoc after all the bash code:

/usr/bin/python << EOF
from Foundation import NSBundle
TZPP = NSBundle.bundleWithPath_("/System/Library/PreferencePanes/DateAndTime.prefPane/Contents/Resources/TimeZone.prefPane")
TimeZonePref          = TZPP.classNamed_('TimeZonePref')
ATZAdminPrefererences = TZPP.classNamed_('ATZAdminPrefererences')

atzap  = ATZAdminPrefererences.defaultPreferences()
pref   = TimeZonePref.alloc().init()
atzap.addObserver_forKeyPath_options_context_(pref, "enabled", 0, 0)
result = pref._startAutoTimeZoneDaemon_(0x1)
EOF

brock_walters
Contributor

Hey Guys!

Correct me if I'm wrong - the issue is not that the script doesn't work anymore. It's that Location Services have to be enabled for the automatic Date & Time function to work.

I am able to enable Location Services with the following bit of stuff in a 1st run script in the most up-to-date version macOS 10.12:

hdwruid=$(/usr/sbin/system_profiler SPHardwareDataType | /usr/bin/awk '/Hardware UUID/{print $NF}')
loginfo "Hardware UUID: $hdwruid"
loginfo "enabling Location Services..."
osref=$(/usr/bin/sw_vers -productVersion | /usr/bin/awk -F. '{print $2}')

locd_osx(){
/bin/rm -rf /private/var/db/locationd/Library/Preferences/ByHost/*
/usr/bin/defaults write /private/var/db/locationd/Library/Preferences/ByHost/com.apple.locationd."$hdwruid" LocationServicesEnabled -int 1
/usr/sbin/chown -R _locationd:_locationd /private/var/db/locationd
}

locd_macos(){
osbld=$(/bin/cat /System/Library/CoreServices/SystemVersion.plist | /usr/bin/sed -n 's/^[[:space:]]//g;6p')
osnam=$(/bin/cat /System/Library/CoreServices/SystemVersion.plist | /usr/bin/sed -n 's/^[[:space:]]//g;10p')
osvrs=$(/bin/cat /System/Library/CoreServices/SystemVersion.plist | /usr/bin/sed -n 's/^[[:space:]]//g;12p')
osstr=$(echo "$osnam$osvrs/$osbld" | /usr/bin/sed 's/<[^>]*>//g')
/bin/rm -rf /private/var/db/locationd/Library/Preferences/ByHost/*
locsrvc
/usr/bin/defaults write /private/var/db/locationd/Library/Preferences/ByHost/com.apple.locationd."$hdwruid".plist LocationServicesEnabled -int 1
/usr/sbin/chown -R _locationd:_locationd /private/var/db/locationd/
/bin/chmod 600 /private/var/db/locationd/Library/Preferences/ByHost/com.apple.locationd."$hdwruid".plist
}

if [ "$osref" -le 11 ]
then
    locd_osx
else
    locd_macos
fi

It might be a little bit of overkill to repopulate the .plist but this has worked for me since, like, forever.

NoahRJ
Contributor II

Hiya @brock.walters -- the issue we had run into is that we had bundled all this up in a Self Service job for our users who are traveling, and even after enabling location services and writing to the proper plists to set timezone auto adjust (code below), we were no longer able to unload/reload the com.apple.locationd.plist to enact the change in Sierra with SIP enabled. Opening up System Preferences and selecting the Time Zone radio button in Date & Time seemed to wake the system up and force it to detect that it should be setting TZ automatically, but I had difficulty until I came across that Python code above determining a way to do this with no user interaction and no restart.

  # Enable location services and enforce ownership; path is no longer UUID dependent in Sierra
  /usr/bin/defaults write /var/db/locationd/Library/Preferences/ByHost/com.apple.locationd LocationServicesEnabled -int 1
  /usr/bin/defaults write /var/db/locationd/Library/Preferences/ByHost/com.apple.locationd.notbackedup. LocationServicesEnabled -int 1
  /usr/sbin/chown -R _locationd:_locationd /var/db/locationd

  # Update Time Zone preference to auto-adjust based upon location
  /usr/bin/defaults write /Library/Preferences/com.apple.timezone.auto Active -bool YES
  /usr/bin/defaults write /Library/Preferences/com.apple.locationmenu ShowSystemServices -bool YES

cgiordano
Contributor

@NoahRJ That's an interesting find...What does your final script look like if you don't mind my asking?

@brock.walters My use case is the same as Noah's if we have users that travel the time zone doesn't always automatically update so forcing a check-in for the time server would seem to be the way to go. We'd rather walk them through running a policy in Self Service as opposed to having to walk them through opening the Date & Time System Preference.

NoahRJ
Contributor II

@cgiordano Sure thing - full script is below:

#!/bin/sh

#Get device interface for wireless
WiFiDI=$(/usr/sbin/networksetup -listallhardwareports | grep -A1 Wi-Fi | grep Device | awk '{print $2}')

#Get the version of Mac OS
OS_Version=$(sw_vers -productVersion)

if [[ $OS_Version == 10.11* ]]; then
  uuid=$(/usr/sbin/system_profiler SPHardwareDataType | grep "Hardware UUID" | cut -c22-57)
  #Enable location services and enforce ownership
  /usr/bin/defaults write /var/db/locationd/Library/Preferences/ByHost/com.apple.locationd."$uuid" LocationServicesEnabled -int 1
  /usr/bin/defaults write /var/db/locationd/Library/Preferences/ByHost/com.apple.locationd.notbackedup."$uuid" LocationServicesEnabled -int 1
  /usr/sbin/chown -R _locationd:_locationd /var/db/locationd

  #Update Time Zone preference to auto-adjust based upon location
  /usr/bin/defaults write /Library/Preferences/com.apple.timezone.auto Active 1
  /usr/bin/defaults write /Library/Preferences/com.apple.locationmenu ShowSystemServices 1

elif [[ $OS_Version == 10.12* ]]; then
  #Enable location services and enforce ownership; path is no longer UUID dependent in Sierra
  /usr/bin/defaults write /var/db/locationd/Library/Preferences/ByHost/com.apple.locationd LocationServicesEnabled -int 1
  /usr/bin/defaults write /var/db/locationd/Library/Preferences/ByHost/com.apple.locationd.notbackedup. LocationServicesEnabled -int 1
  /usr/sbin/chown -R _locationd:_locationd /var/db/locationd

  #Update Time Zone preference to auto-adjust based upon location
  /usr/bin/defaults write /Library/Preferences/com.apple.timezone.auto Active -bool YES
  /usr/bin/defaults write /Library/Preferences/com.apple.locationmenu ShowSystemServices -bool YES

else
  echo "not running macOS 10.11 or 10.12"
fi

#Wi-Fi must be powered on to determine current location
/usr/sbin/networksetup -setairportpower $WiFiDI on

#Pause to enable location services to load properly
sleep 3

#Re-enable network time
/usr/sbin/systemsetup -setusingnetworktime on

#Python code snippet to reload AutoTimeZoneDaemon
/usr/bin/python << EOF
from Foundation import NSBundle
TZPP = NSBundle.bundleWithPath_("/System/Library/PreferencePanes/DateAndTime.prefPane/Contents/Resources/TimeZone.prefPane")
TimeZonePref          = TZPP.classNamed_('TimeZonePref')
ATZAdminPrefererences = TZPP.classNamed_('ATZAdminPrefererences')

atzap  = ATZAdminPrefererences.defaultPreferences()
pref   = TimeZonePref.alloc().init()
atzap.addObserver_forKeyPath_options_context_(pref, "enabled", 0, 0)
result = pref._startAutoTimeZoneDaemon_(0x1)
EOF

sleep 1

#Get the time from time server
/usr/sbin/systemsetup -getnetworktimeserver

#Detect the newly set timezone
/usr/sbin/systemsetup -gettimezone

exit 0

cgiordano
Contributor

Wow. That totally worked for me. The only interesting this that I found is that it said that the timezone was set to NY but then it updated the time and changed the timezone to LA which is correct since I'm sitting with this machine in Seattle. I copied and pasted your script with

sudo ./test.sh 
Password:
Network Time is already on.
Network Time Server: time.apple.com
Time Zone: America/New_York

Why does it say that it's America/New_York when it then updates to America/Los_Angeles? It's not a huge deal since it's showing the correct time but just a curious thing....

NoahRJ
Contributor II

Hmm, try increasing the sleep time from 1 to a higher number (maybe sleep 5) toward the bottom of the script and then run again. The /usr/sbin/systemsetup -gettimezone command that detects the set timezone might jump the gun and run before the python script has had time to fully work its magic.

I use that as a check to make sure the proper timezone was set (since error codes aren't always the most forthcoming), but you don't need it for anything aside from verification.

cgiordano
Contributor

Yup. That seems to have done the trick. I also added to the script just to echo the date/time before running the script and the date/time as the last step so you can look back historically in the policy log or the machine policy log to confirm that the date/time is actually getting updated.

## Tell the time prior to the script running
echo "The current time is `date`"
## Tell the new time after everything has been updated
echo "The new, correct time is now set as `date`"

Thanks for this Noah and everyone. This is great!

tuinte
Contributor III

Just wanted to chime in and say I added an OR condition onto the 10.12 one for 10.13 and it still works great in High Sierra.

elif [[ $OS_Version == 10.12* ]] || [[ $OS_Version == 10.13* ]]; then

Thanks, @NoahRJ.

jriv
New Contributor III

So are you using this as a Self Service policy? Or automatically pushed?

tuinte
Contributor III

We’re using it in a deployment policy. For new/re-imaged/DEP’d machines. Seems to work fine just firing it at computers with Remote as well, so should be good in a mass Recurring Check-In-type policy, too. Test a bit, obviously.

shan3
New Contributor

Anyone having success on 10.13.4? Getting errors with the python script

AttributeError: 'TimeZonePref' object has no attribute '_startAutoTimeZoneDaemon_'

Thank you all for your contributions, this thread has been hugely helpful.

tuinte
Contributor III

Hadn't run the script on a 10.13.4 machine yet, but just tested, and yeah, I'm getting the same.

I'll be able to look into it later this week, but can't say I'm very familiar with Python, so someone else may prove more helpful.

Jesper
New Contributor III

Testing on 10.13.4 I also get the error mentioned by @shan3 .

ewinterbourne
New Contributor III

It's a real shame the python code no longer works on 10.13.4 and above. This was a great find, but once again apple broken something useful.

On top of this I have noticed that this code no longer works on 10.13.3/10.13.4 and newer. I'm still looking into it, but no luck. /usr/bin/defaults write /Library/Preferences/com.apple.timezone.auto Active -bool YES

this command no longer ticks the option to set time zone automatically using current location

Nix4Life
Valued Contributor

I get the opposite on 10.13.4, The box gets ticked, however the map does not show until I click on another tab

Benmc1
New Contributor II

@ewinterbourne I'm still getting the same problem with that command in 10.13.5, Trying to find a way around it but no joy as of yet.

oartola
New Contributor II

I have tried running this script in 10.14.1 and still getting no response from the machine when it comes to ticking the box, under Date & Time. Has anyone been able to find a resolution to this?

mack525
Contributor II

@oartola We've been using this https://github.com/jamfprofessionalservices/Jamf-Scripts/blob/master/Set%20Time%20Zone.sh Along with a self service policy.

DFree
New Contributor III

I'm late to the party on this.

Did anyone ever figure out a fix for @NoahRJ 's script above to work properly in Mojave?

Also, @mack525 your link no longer works.

mack525
Contributor II

@DFree It must have been moved. Check out my Github page for the script

hdsreid
Contributor III
/usr/bin/defaults write /var/db/locationd/Library/Preferences/ByHost/com.apple.locationd LocationServicesEnabled -int 1

I'm using this as part of my enrollment provisioning on DEPNotify. When the user logs in, before DEPNotify launches, the time is PST. I prompt for reboot at the end of my DEPNotify script and after reboot, the location services kicks in and the time zone is automatically set by current location. It can take a few minutes for it to kick in

bwoods
Valued Contributor

Create a blank package with the script below (postinstall). Then add it to your prestage enrollment.

#!/bin/bash


## configure ntp server

/bin/cat > /etc/ntp.conf << 'NEW_NTP_CONF'
server time.apple.com
NEW_NTP_CONF

## configure automatic timezone

/usr/bin/defaults write /var/db/locationd/Library/Preferences/ByHost/com.apple.locationd LocationServicesEnabled -int 1

uuid=$(/usr/sbin/system_profiler SPHardwareDataType | grep "Hardware UUID" | cut -c22-57)
/usr/bin/defaults write /var/db/locationd/Library/Preferences/ByHost/com.apple.locationd.$uuid LocationServicesEnabled -int 1


## Set date and time automatically
/usr/bin/defaults write /Library/Preferences/com.apple.timezone.auto Active -bool YES
/usr/bin/defaults write /private/var/db/timed/Library/Preferences/com.apple.timed.plist TMAutomaticTimeOnlyEnabled -bool YES
/usr/bin/defaults write /private/var/db/timed/Library/Preferences/com.apple.timed.plist TMAutomaticTimeZoneEnabled -bool YES
/usr/sbin/systemsetup -setusingnetworktime on
/usr/sbin/systemsetup -gettimezone
/usr/sbin/systemsetup -getnetworktimeserver

### Restart location services daemon (locationd)
/usr/bin/killall locationd

exit 0;     ## Success
exit 1;     ## Failure

laggardkernel
New Contributor

Modifying ByHost plist and those under /private/var/db has no effect. It doesn't toggle the checkbox in System Preferences. At least true for High Sierra, Mojave.