How to Set the Time Zone in macOS Using Shell Scripting

This guide will teach you how to set the time zone in macOS using shell scripting. Accurate system time is critical for IT professionals and Managed Service Providers (MSPs). Whether it’s ensuring proper authentication, synchronizing logs, or maintaining compliance with regulatory requirements, time synchronization is the backbone of reliable IT infrastructure.

On macOS devices, managing time zones and synchronization settings can be tedious if done manually across large fleets. That’s where shell scripting comes into play. This blog post explores a shell script that automates time zone and synchronization management for macOS, providing IT teams with a scalable and reliable solution.

Background

Time configuration might appear to be a minor system setting, but it has far-reaching implications. Incorrect time zones can lead to issues with Kerberos authentication, misaligned logs, and broken scheduling services. For MSPs managing hundreds of endpoints, manual intervention is inefficient and error-prone. The provided shell script simplifies these tasks by automating:

  • Listing available time zones
  • Setting a specific time zone
  • Enabling or disabling automatic time zone detection
  • Configuring a custom network time synchronization server
  • Forcing an immediate time sync

This makes it a versatile tool for IT professionals who need consistency across environments.

The Script

#!/usr/bin/env bash
#
# Description: This script sets the time zone and synchronization settings for macOS.
# By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
# Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
# Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
# Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
# Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
# Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
# Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
# EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).
#
# Preset Parameter: --listTimeZones
#   List all time zones available on the system.
#
# Preset Parameter: --setTimeZone
#   Specify a time zone to set. Use the "List Time Zones" option to get a list of available time zones. If the automatic time zone setting is enabled, it will be disabled. Example Time Zone: America/New_York
#
# Preset Parameter: --setTimeZoneAutomatically
#   Set the time zone automatically based on the physical location of the device. Valid values are "Enable" or "Disable". Enabling will also enable Location Services and Wi-Fi if they are not already enabled. Leave blank to not modify the setting.
#
# Preset Parameter: --setSyncServer
#   Specify the server to use for time synchronization. Only one server can be set. Example: time.apple.com
#
# Preset Parameter: --syncNow
#   Sync time after updating settings for the time sync service.
#
# Minimum OS Architecture Supported: macOS 12+
# Version: 1.0
# Release Notes: Initial Release

_arg_listTimeZones=false
_arg_setTimeZone=""
_arg_setTimeZoneAutomatically=""
_arg_setSyncServer=""
_arg_syncNow=false

die() {
    local _ret="${2:-1}"
    echo "$1" >&2
    test "${_PRINT_HELP:-no}" = yes && print_help >&2
    exit "${_ret}"
}

print_help() {
    printf '\n\n%s\n\n' 'Usage: [--listTimeZones] [--setTimeZone <timezone>] [--setTimeZoneAutomatically <Enable|Disable>] [--setSyncServer <server>] [--syncNow]'
    printf '%s\n' 'Preset Parameter: --listTimeZones'
    printf '\t%s\n' 'List all time zones available on the system.'
    printf '%s\n' 'Preset Parameter: --setTimeZone'
    printf '\t%s\n' 'Specify a time zone to set. Use the "List Time Zones" option to get a list of available time zones. If the automatic time zone setting is enabled, it will be disabled. Example Time Zone: America/New_York'
    printf '%s\n' 'Preset Parameter: --setTimeZoneAutomatically'
    printf '\t%s\n' 'Set the time zone automatically based on the physical location of the device. Valid values are "Enable" or "Disable". Enabling will also enable Location Services and Wi-Fi if they are not already enabled. Leave blank to not modify the setting.'
    printf '%s\n' 'Preset Parameter: --setSyncServer'
    printf '\t%s\n' 'Specify the server to use for time synchronization. Only one server can be set. Example: time.apple.com'
    printf '%s\n' 'Preset Parameter: --syncNow'
    printf '\t%s\n' 'Sync time after updating settings for the time sync service.'
}

parse_commandline() {
    while test $# -gt 0; do
        _key="$1"
        case "$_key" in
        --listTimeZones)
            _arg_listTimeZones=true
            shift
            ;;
        --setTimeZone)
            test $# -lt 2 && die "[Error] Missing value for the optional argument '$_key'." 1
            _arg_setTimeZone="$2"
            shift 2
            ;;
        --setTimeZone=*)
            _arg_setTimeZone="${_key##--setTimeZone=}"
            ;;
        --setTimeZoneAutomatically)
            test $# -lt 2 && die "[Error] Missing value for the optional argument '$_key'." 1
            _arg_setTimeZoneAutomatically="$2"
            shift 2
            ;;
        --setTimeZoneAutomatically=*)
            _arg_setTimeZoneAutomatically="${_key##--setTimeZoneAutomatically=}"
            ;;
        --setSyncServer)
            test $# -lt 2 && die "[Error] Missing value for the optional argument '$_key'." 1
            _arg_setSyncServer="$2"
            shift 2
            ;;
        --setSyncServer=*)
            _arg_setSyncServer="${_key##--setSyncServer=}"
            ;;
        --syncNow)
            _arg_syncNow=true
            shift
            ;;
        --syncNow=*)
            _arg_syncNow="${_key##--syncNow=}"
            ;;
        --help | -h)
            _PRINT_HELP=yes die
            ;;
        *)
            _PRINT_HELP=yes die "[Error] Got an unexpected argument '$1'" 1
            ;;
        esac
    done
}

# Function to get a list of available time zones
function GetTimeZoneList() {
    local timezones
    if timezones=$(systemsetup -listtimezones | grep -v "Time Zone" | awk '{print $1}') && [ -z "$timezones" ]; then
        echo "[Error] No time zones found." 1>&2
        return 1
    fi

    echo "[Info] Available Time Zones:"
    echo "$timezones"
}

# Function to test if location services is enabled
function TestLocationServices() {
    # Check if location services are enabled
    if ! value=$(defaults read /var/db/locationd/Library/Preferences/ByHost/com.apple.locationd LocationServicesEnabled 2>/dev/null); then
        return 1
    elif [[ "$value" -eq 1 ]]; then
        return 0
    else
        return 1
    fi
}

# Function to get the wifi adapter name
function GetWifiAdapter() {
    local adapter
    if ! adapter=$(networksetup -listallhardwareports | awk -F: '/Wi-Fi/{getline; print $2;}' | xargs); then
        return 1
    fi

    echo "$adapter"
}

# Function to test if the given wifi adapter is turned on
function TestWifiAdapter() {
    local wifiAdapter=$1

    wifiStatus=$(networksetup -getairportpower "$wifiAdapter")

    if [[ "$wifiStatus" =~ "Off" ]]; then
        return 1
    else
        return 0
    fi
}

# Function to verify if the requirements for automatic time zone setting are met
function VerifyAutomaticTimeZoneRequirements() {
    local wifiAdapter
    # Check if location services are enabled
    if ! TestLocationServices; then
        autoTZBrokenReason="Location Services disabled"
        return 1
    fi

    # Get the Wi-Fi adapter
    if ! wifiAdapter=$(GetWifiAdapter); then
        autoTZBrokenReason="Wi-Fi adapter not found"
        return 1
    fi

    # Check if the Wi-Fi adapter is available and enabled
    if ! TestWifiAdapter "$wifiAdapter"; then
        autoTZBrokenReason="Wi-Fi adapter not enabled"
        return 1
    fi

    return 0
}

# Function to set the automatic time zone setting
function SetAutomaticTimeZone() {
    local action="$1"
    local wifiAdapter

    if [ -z "$action" ]; then
        echo "[Error] No action specified. Use 'Enable' or 'Disable'."
        return 1
    fi

    if [ "$action" != "Enable" ] && [ "$action" != "Disable" ]; then
        echo "[Error] Invalid action specified. Use 'Enable' or 'Disable'."
        return 1
    fi

    # If enabling automatic time zone, we need to ensure that location services and Wi-Fi are enabled
    if [ "$action" = "Enable" ]; then
        # Check if location services are enabled
        # If not enabled, enable it
        if ! TestLocationServices; then
            echo "[Info] Enabling location services..."
            if ! defaults write /var/db/locationd/Library/Preferences/ByHost/com.apple.locationd LocationServicesEnabled -int 1; then
                echo "[Error] Failed to enable location services."
                return 1
            fi
            echo "[Info] Successfully enabled location services."
        fi

        # Get the Wi-Fi adapter
        if ! wifiAdapter=$(GetWifiAdapter); then
            echo "[Error] No Wi-Fi adapter found. Automatic time zone setting requires Wi-Fi."
            return 1
        fi

        # Check if the Wi-Fi adapter is available and enabled
        # If not enabled, enable it
        if ! TestWifiAdapter "$wifiAdapter"; then
            echo "[Info] Enabling Wi-Fi..."
            if ! networksetup -setairportpower "$wifiAdapter" on; then
                echo "[Error] Failed to enable Wi-Fi."
                return 1
            fi
            echo "[Info] Successfully enabled Wi-Fi."
        fi

        # Clear the autoTZBrokenReason variable in case it was set previously
        autoTZBrokenReason=""
    fi

    # Enable or disable automatic time zone
    if [ "$action" = "Enable" ]; then
        # Set the plist file to enable automatic time zone
        if ! defaults write /private/var/db/timed/Library/Preferences/com.apple.timed.plist TMAutomaticTimeZoneEnabled -bool YES; then
            echo "[Error] Failed to enable automatic time zone setting."
            return 1
        fi
    else
        if ! defaults write /private/var/db/timed/Library/Preferences/com.apple.timed.plist TMAutomaticTimeZoneEnabled -bool NO; then
            echo "[Error] Failed to disable automatic time zone setting."
            return 1
        fi
    fi

    # Modifying the plist file will change the ownership, so we need to set it back to the _timed user
    if ! chown "_timed:_timed" /private/var/db/timed/Library/Preferences/com.apple.timed.plist; then
        echo "[Error] Failed to set ownership of the plist file."
        return 1
    fi

    # Reset the locationd service to apply changes
    if ! killall locationd; then
        echo "[Error] Failed to restart locationd service."
        return 1
    fi
}

# Function to restart the network time service
function RestartNetworkTimeService() {
    # Restart the time server
    if ! systemsetup -setusingnetworktime off 2>/dev/null 1>/dev/null; then
        echo "[Error] Failed to stop time server."
        return 1
    fi
    sleep 1
    if ! systemsetup -setusingnetworktime on 2>/dev/null 1>/dev/null; then
        echo "[Error] Failed to start time server."
        return 1
    fi
}

# Function to set the time zone
function SetTimeZone() {
    local timezone="$1"
    if [ -z "$timezone" ]; then
        echo "[Error] No time zone specified."
        return 1
    fi

    # Check if the time zone contains invalid characters
    if ! [[ "$timezone" =~ ^[a-zA-Z0-9/_]+$ ]]; then
        echo "[Error] Time Zone contains invalid characters. Only alphanumeric characters, underscores, and forward slashes are allowed."
        return 1
    fi

    # Check if the time zone is valid
    if ! systemsetup -listtimezones 2>/dev/null | grep -q "$timezone"; then
        echo "[Error] Invalid time zone: $timezone"
        return 1
    fi

    # If there is no reason for the automatic time zone being broken, enable it to see what the automatic time zone would be
    # Then, warn if the automatic time zone is different than the requested time zone
    if [ -z "$autoTZBrokenReason" ]; then
        if SetAutomaticTimeZone "Enable"; then
            # Wait for the automatic time zone to be set
            sleep 10
            autoTimeZone=$(systemsetup -gettimezone | awk '{print $3}')
            if [ "$autoTimeZone" != "$timezone" ]; then
                echo "[Warning] The automatic time zone for this device would be '$autoTimeZone' but the selected time zone is '$timezone'."
                echo "[Info] If you want to use the automatic time zone, please enable the 'Set Time Zone Automatically' option."
            fi

            # If we are not disabling the automatic time zone later, disable it here so we can set the time zone
            if [ "$_arg_setTimeZoneAutomatically" != "Disable" ]; then
                # Print this message only if the automatic time zone was enabled at script runtime
                if [ "$autoTimeZoneBeforeChange" = "1" ]; then
                    echo "[Info] Disabling the automatic time zone setting so that we can set the specified time zone."
                fi
                SetAutomaticTimeZone "Disable"
            fi
        fi
    fi

    # Set the time zone
    if systemsetup -settimezone "$timezone" 2>/dev/null 1>/dev/null; then
        return 0
    else
        echo "[Error] Failed to set time zone."
        return 1
    fi
}

# Function to set the sync server
function SetSyncServer() {
    local server="$1"

    # Error if a server was not provided
    if [ -z "$server" ]; then
        echo "[Error] No sync server specified."
        return 1
    fi

    # Check if the server responds on UDP 123 (NTP port)
    if ! nc -z -u "$server" 123 > /dev/null 2>&1; then
        echo "[Error] The server at '$server' did not respond on UDP port 123."
        return 1
    fi

    # Check if network time is enabled and enable it if not
    if systemsetup -getusingnetworktime 2>/dev/null | grep -q "Off"; then
        echo "[Info] Network time is currently disabled. Enabling it now."

        if systemsetup -setusingnetworktime on 2>/dev/null 1>/dev/null; then
            echo "[Info] Network time enabled."
        else
            echo "[Error] Failed to enable network time."
            return 1
        fi
    fi

    # Set the sync server
    if systemsetup -setnetworktimeserver "$server" 2>/dev/null 1>/dev/null; then
        return 0
    else
        echo "[Error] Failed to set sync server."
        return 1
    fi
}

# Function to sync the time immediately
function SyncNow() {
    # Look for the sntp or ntpdate command to synchronize time
    if command -v sntp >/dev/null; then
        if sntp -sS "$(systemsetup -getnetworktimeserver | awk '{print $4}')" 2>/dev/null 1>/dev/null; then
            return 0
        else
            return 1
        fi
    elif command -v ntpdate >/dev/null; then
        if ntpdate -u "$(systemsetup -getnetworktimeserver | awk '{print $4}')" 2>/dev/null 1>/dev/null; then
            return 0
        else
            return 1
        fi
    else
        echo "[Error] No time sync command found. Either sntp or ntpdate should be available."
        return 1
    fi
}

# Execute command line parsing function with the passed arguments
parse_commandline "$@"

# If environment variables for the script parameters are set, override the command line argument values
if [[ $listTimeZones == "true" ]]; then
    _arg_listTimeZones=true
fi
if [[ -n $setTimeZone ]]; then
    _arg_setTimeZone=$(echo "$setTimeZone" | xargs) # Remove leading/trailing whitespace
fi
if [[ -n $setTimeZoneAutomatically ]]; then
    _arg_setTimeZoneAutomatically=$(echo "$setTimeZoneAutomatically")
fi
if [[ -n $setSyncServer ]]; then
    _arg_setSyncServer=$(echo "$setSyncServer" | xargs) # Remove leading/trailing whitespace
fi
if [[ $syncNow == "true" ]]; then
    _arg_syncNow=true
fi

# Error if no arguments are provided
if [[ $_arg_listTimeZones == false && -z "$_arg_setTimeZone" && -z "$_arg_setSyncServer" && $_arg_syncNow == false && -z "$_arg_setTimeZoneAutomatically" ]]; then
    _PRINT_HELP=yes die "[Error] No arguments provided. At least one argument is required to run this script." 1
fi

# Check if the script is being run as root. If not, exit with an error message.
if [[ $(id -u) -ne 0 ]]; then
    _PRINT_HELP=no die "[Error] This script must be run with root permissions. Try running it with sudo or as the system/root user." 1
fi

# Initialize the exit code
exitCode=0

# List time zones if requested
if [[ $_arg_listTimeZones == true ]]; then
    if [[ -n "$_arg_setTimeZone" ]] || [[ -n "$_arg_setSyncServer" ]] || [[ $_arg_syncNow == true ]] || [[ -n "$_arg_setTimeZoneAutomatically" ]]; then
        echo "[Error] The 'Set Time Zone', 'Set Time Zone Automatically', 'Set Sync Server', and 'Sync Now' options cannot be used together with 'List Time Zones'."
        echo ""
        exitCode=1
    fi
    if ! GetTimeZoneList; then
        echo "[Error] Failed to retrieve time zone list."
        exitCode=1
    fi
    exit $exitCode
fi

# Error if an invalid value is provided for setTimeZoneAutomatically
if [[ $_arg_setTimeZoneAutomatically && ! $_arg_setTimeZoneAutomatically =~ ^(Enable|Disable)$ ]]; then
    _PRINT_HELP=yes die "[Error] Invalid value for 'Set Time Zone Automatically'. Use 'Enable' or 'Disable'." 1
fi

# Error if setTimeZone is provided and setTimeZoneAutomatically is set to Enable
if [[ $_arg_setTimeZone && $_arg_setTimeZoneAutomatically = "Enable" ]]; then
    _PRINT_HELP=yes die "[Error] You cannot enable automatic time zones and specify a time zone at the same time." 1
fi

# Check if setSyncServer has more than one server
if [ "$(
    echo "$_arg_setSyncServer" |
        tr ',' ' ' |  # Replace commas with spaces
        tr ' ' '\n' | # Split into lines
        wc -l         # Count lines
)" -gt 1 ]; then
    die "[Error] Multiple time sync servers are not supported. Please provide a single server." 1
fi

# Initiate variable to track if settings are changed
_settingsChanged=false

# Get the current time zone and sync server settings
if ! syncServerBeforeChange=$(systemsetup -getnetworktimeserver | awk '{print $4}'); then
    die "[Error] Failed to retrieve current sync server." 1
fi

if ! timeZoneBeforeChange=$(systemsetup -gettimezone | awk '{print $3}'); then
    die "[Error] Failed to retrieve current time zone." 1
fi

if ! autoTimeZoneBeforeChange=$(defaults read /private/var/db/timed/Library/Preferences/com.apple.timed.plist TMAutomaticTimeZoneEnabled 2>/dev/null); then
    autoTimeZoneBeforeChange=0 # Default to 0 if the key does not exist
fi

# Check if automatic time zone is broken so that autoTZBrokenReason can be set
VerifyAutomaticTimeZoneRequirements

echo ""

# Set the time zone if specified
if [ -n "$_arg_setTimeZone" ]; then
    if [ "$timeZoneBeforeChange" = "$_arg_setTimeZone" ]; then
        echo "[Info] Time zone is already set to '$_arg_setTimeZone'."
    else
        echo "[Info] Changing the time zone from '$timeZoneBeforeChange' to '$_arg_setTimeZone'."

        if SetTimeZone "$_arg_setTimeZone"; then
            echo "[Info] Successfully changed the time zone from '$timeZoneBeforeChange' to '$_arg_setTimeZone'."
            _settingsChanged=true
        else
            echo "[Error] Failed to set the time zone to '$_arg_setTimeZone'."
            exitCode=1
        fi
    fi
    echo ""
fi

# Set automatic time zone if specified
if [ -n "$_arg_setTimeZoneAutomatically" ]; then
    currentValue=$(defaults read /private/var/db/timed/Library/Preferences/com.apple.timed.plist TMAutomaticTimeZoneEnabled 2>/dev/null)

    # If a reason for automatic time zone being broken is set, we will force the change
    if [ -n "$autoTZBrokenReason" ]; then
        forceChange=true
    fi

    if [ "$_arg_setTimeZoneAutomatically" = "Enable" ]; then
        if [ "$currentValue" = "1" ] && [ "$forceChange" != true ]; then
            echo "[Info] The automatic time zone setting is already enabled."
        else
            echo "[Info] Enabling the automatic time zone setting."

            # Enable automatic time zone setting
            if SetAutomaticTimeZone "Enable"; then
                sleep 10
                echo "[Info] Successfully enabled the automatic time zone setting."
                _settingsChanged=true
            else
                echo "[Error] Failed to enable the automatic time zone setting."
                exitCode=1
            fi
        fi
    elif [ "$_arg_setTimeZoneAutomatically" = "Disable" ]; then
        if [ "$currentValue" = "0" ] || [ -z "$currentValue" ]; then
            echo "[Info] The automatic time zone setting is already disabled."
        else
            echo "[Info] Disabling the automatic time zone setting."

            # Disable automatic time zone setting
            if SetAutomaticTimeZone "Disable"; then
                echo "[Info] Successfully disabled the automatic time zone setting."
                _settingsChanged=true
            else
                echo "[Error] Failed to disable the automatic time zone setting."
                exitCode=1
            fi
        fi
    fi
    echo ""
fi

# Set the sync server if specified
if [ -n "$_arg_setSyncServer" ]; then
    if [ "$syncServerBeforeChange" = "$_arg_setSyncServer" ]; then
        echo "[Info] Time sync server is already set to '$_arg_setSyncServer'."
    else
        echo "[Info] Changing the time sync server from '$syncServerBeforeChange to '$_arg_setSyncServer'."

        if SetSyncServer "$_arg_setSyncServer"; then
            echo "[Info] Successfully changed the time sync server from '$syncServerBeforeChange' to '$_arg_setSyncServer'."
            _settingsChanged=true
        else
            echo "[Error] Failed to set the sync server to '$_arg_setSyncServer'."
            exitCode=1
        fi
    fi
    echo ""
fi

# If settings were changed, restart the time service and print the previous settings
if [ "$_settingsChanged" = true ]; then
    echo "[Info] Settings have been changed. Restarting the time service to apply changes."

    # Restart the time service to apply changes
    if ! RestartNetworkTimeService; then
        echo "[Error] Failed to restart the time service."
        exitCode=1
    else
        echo "[Info] Time service restarted successfully."
    fi

    echo ""
    echo "*** Previous Time Sync Settings: ***"
    if [ -n "$timeZoneBeforeChange" ]; then
        echo "Time Zone: $timeZoneBeforeChange"
    fi
    if [ -n "$syncServerBeforeChange" ]; then
        echo "Sync Server: $syncServerBeforeChange"
    fi

    if [ -n "$autoTimeZoneBeforeChange" ]; then
        if [ "$autoTimeZoneBeforeChange" = "0" ]; then
            echo "Automatic Time Zone: Disabled"
        else
            if [ -n "$autoTZBrokenReason" ]; then
                echo "Automatic Time Zone: Enabled but not working (Reason: $autoTZBrokenReason)"
            else
                echo "Automatic Time Zone: Enabled"
            fi
        fi
    fi
fi

echo ""

# Retrieve the current time sync settings
echo "*** Current Time Sync Settings: ***"
if ! currentTimeZone=$(systemsetup -gettimezone | awk '{print $3}'); then
    echo "[Error] Failed to retrieve current time zone."
    exitCode=1
fi

if ! currentSyncServer=$(systemsetup -getnetworktimeserver | awk '{print $4}'); then
    echo "[Error] Failed to retrieve current sync server."
    exitCode=1
fi

if ! currentAutoTimeZone=$(defaults read /private/var/db/timed/Library/Preferences/com.apple.timed.plist TMAutomaticTimeZoneEnabled 2>/dev/null); then
    currentAutoTimeZone=0 # Default to 0 if the key does not exist
fi

# Print the current settings
if [ -n "$currentTimeZone" ]; then
    echo "Time Zone: $currentTimeZone"
fi
if [ -n "$currentSyncServer" ]; then
    echo "Sync Server: $currentSyncServer"
fi

if [ -n "$currentAutoTimeZone" ]; then
    if [ "$currentAutoTimeZone" = "0" ]; then
        echo "Automatic Time Zone: Disabled"
    else
        if [ -n "$autoTZBrokenReason" ]; then
            echo "Automatic Time Zone: Enabled but not working (Reason: $autoTZBrokenReason)"
        else
            echo "Automatic Time Zone: Enabled"
        fi
    fi
fi

# Sync the time immediately if requested
if [ "$_arg_syncNow" = "true" ]; then
    echo ""
    echo "[Info] Syncing the time with the new settings."
    if ! SyncNow; then
        die "[Error] Failed to synchronize time." 1
    else
        echo "[Info] Time synchronized successfully."
    fi
fi

# Get the current time and print it
currentTime=$(date +"%Y-%m-%d %T")

echo ""
echo "*** Current System Time: ***"
echo "$currentTime"

exit $exitCode

 

Detailed Breakdown

The script begins by parsing command-line arguments, allowing administrators to choose specific operations:

  1. Listing time zones
    The –listTimeZones flag uses systemsetup -listtimezones to output all available macOS time zones.
  2. Setting a time zone
    The –setTimeZone <timezone> parameter validates the requested time zone and applies it using systemsetup -settimezone.
  3. Automatic time zone management
    Using –setTimeZoneAutomatically Enable|Disable, the script toggles macOS’s automatic time zone detection. If enabling, it ensures Location Services and Wi-Fi are active, restarting services as needed.
  4. Setting a synchronization server
    With –setSyncServer <server>, administrators can point macOS to a preferred NTP server. The script validates connectivity by checking UDP port 123.
  5. Immediate synchronization
    The –syncNow option forces synchronization via sntp or ntpdate.

Behind the scenes, the script also safeguards against conflicts (e.g., preventing simultaneous use of –setTimeZone and –setTimeZoneAutomatically Enable), checks for root permissions, and reports both current and previous configurations for auditing.

Potential Use Cases

Imagine an MSP managing remote macOS devices spread across multiple regions. A client reports authentication failures because their laptops show incorrect times. Instead of remote desktop sessions, the MSP deploys this script via their RMM tool. With one command, they enforce –setSyncServer time.apple.com –syncNow across all endpoints, ensuring consistent time settings and resolving authentication issues within minutes.

Comparisons

Traditionally, administrators would manually adjust settings through System Preferences or use standalone commands like systemsetup. While effective for one machine, these methods lack scalability. Configuration management tools like Jamf provide enterprise-level solutions but may be excessive for smaller environments. This script strikes a balance—lightweight, easily deployable, and compatible with RMM tools like NinjaOne.

Implications

Accurate time synchronization directly impacts IT security. Authentication protocols rely on precise timekeeping, and even slight drift can cause failures. For forensic investigations, misaligned logs can complicate timelines and jeopardize compliance. Automating these configurations reduces human error and enforces organizational standards across distributed environments.

Recommendations

  • Test before deployment: Run the script on a pilot group before broad rollout.
  • Use a trusted NTP server: Prefer vendor or corporate NTP servers to ensure reliability.
  • Audit settings regularly: Use the reporting functionality to validate compliance.
  • Document policies: Define when to use automatic vs. manual time zones.

Final Thoughts

Managing time zone and synchronization settings on macOS doesn’t need to be complex. This shell script provides a straightforward, repeatable solution for IT professionals and MSPs who value precision and efficiency. When paired with NinjaOne’s automation and policy deployment capabilities, administrators can push this script fleet-wide, ensuring all devices remain synchronized and compliant without manual intervention. The result is a more secure, consistent, and reliable environment across the enterprise.

FAQs

No, the script enforces a single server. This avoids conflicts and ensures consistency.

Yes, enabling requires Location Services and Wi-Fi, which could have privacy implications. IT admins should weigh this before deploying.

Automatic time zone setting won’t work without Wi-Fi, and the script will provide clear error messaging.

Yes, system-level changes demand administrative privileges.

Next Steps

Building an efficient and effective IT team requires a centralized solution that acts as your core service delivery tool. NinjaOne enables IT teams to monitor, manage, secure, and support all their devices, wherever they are, without the need for complex on-premises infrastructure.

Learn more about NinjaOne Remote Script Deployment, check out a live tour, or start your free trial of the NinjaOne platform.

Categories:

You might also like