Return the uptime for this system.

    .. versionchanged:: 2015.8.9
        The uptime function was changed to return a dictionary of easy-to-read
        key/value pairs containing uptime information, instead of the output
        from a ``cmd.run`` call.

    .. versionchanged:: 2016.11.0
        Support for OpenBSD, FreeBSD, NetBSD, MacOS, and Solaris

    .. versionchanged:: 2016.11.4
        Added support for AIX

    CLI Example:

    .. code-block:: bash

        salt '*' status.uptime

def uptime():
    '''
    Return the uptime for this system.

    .. versionchanged:: 2015.8.9
        The uptime function was changed to return a dictionary of easy-to-read
        key/value pairs containing uptime information, instead of the output
        from a ``cmd.run`` call.

    .. versionchanged:: 2016.11.0
        Support for OpenBSD, FreeBSD, NetBSD, MacOS, and Solaris

    .. versionchanged:: 2016.11.4
        Added support for AIX

    CLI Example:

    .. code-block:: bash

        salt '*' status.uptime
    '''
    curr_seconds = time.time()

    # Get uptime in seconds
    if salt.utils.platform.is_linux():
        ut_path = "/proc/uptime"
        if not os.path.exists(ut_path):
            raise CommandExecutionError("File {ut_path} was not found.".format(ut_path=ut_path))
        with salt.utils.files.fopen(ut_path) as rfh:
            seconds = int(float(rfh.read().split()[0]))
    elif salt.utils.platform.is_sunos():
        # note: some flavors/versions report the host uptime inside a zone
        #       https://support.oracle.com/epmos/faces/BugDisplay?id=15611584
        res = __salt__['cmd.run_all']('kstat -p unix:0:system_misc:boot_time')
        if res['retcode'] > 0:
            raise CommandExecutionError('The boot_time kstat was not found.')
        seconds = int(curr_seconds - int(res['stdout'].split()[-1]))
    elif salt.utils.platform.is_openbsd() or salt.utils.platform.is_netbsd():
        bt_data = __salt__['sysctl.get']('kern.boottime')
        if not bt_data:
            raise CommandExecutionError('Cannot find kern.boottime system parameter')
        seconds = int(curr_seconds - int(bt_data))
    elif salt.utils.platform.is_freebsd() or salt.utils.platform.is_darwin():
        # format: { sec = 1477761334, usec = 664698 } Sat Oct 29 17:15:34 2016
        bt_data = __salt__['sysctl.get']('kern.boottime')
        if not bt_data:
            raise CommandExecutionError('Cannot find kern.boottime system parameter')
        data = bt_data.split("{")[-1].split("}")[0].strip().replace(' ', '')
        uptime = dict([(k, int(v,)) for k, v in [p.strip().split('=') for p in data.split(',')]])
        seconds = int(curr_seconds - uptime['sec'])
    elif salt.utils.platform.is_aix():
        seconds = _get_boot_time_aix()
    else:
        return __salt__['cmd.run']('uptime')

    # Setup datetime and timedelta objects
    boot_time = datetime.datetime.utcfromtimestamp(curr_seconds - seconds)
    curr_time = datetime.datetime.utcfromtimestamp(curr_seconds)
    up_time = curr_time - boot_time

    # Construct return information
    ut_ret = {
        'seconds': seconds,
        'since_iso': boot_time.isoformat(),
        'since_t': int(curr_seconds - seconds),
        'days': up_time.days,
        'time': '{0}:{1}'.format(up_time.seconds // 3600, up_time.seconds % 3600 // 60),
    }

    if salt.utils.path.which('who'):
        who_cmd = 'who' if salt.utils.platform.is_openbsd() else 'who -s'  # OpenBSD does not support -s
        ut_ret['users'] = len(__salt__['cmd.run'](who_cmd).split(os.linesep))

    return ut_ret