git: 8cfe06ee4415 - main - bsdconfig: add datetime module for live system clock

From: Devin Teske <dteske_at_FreeBSD.org>
Date: Sun, 16 Aug 2026 03:19:10 UTC
The branch main has been updated by dteske:

URL: https://cgit.FreeBSD.org/src/commit/?id=8cfe06ee4415795cc77934fb5c17bdf2c2fd3816

commit 8cfe06ee4415795cc77934fb5c17bdf2c2fd3816
Author:     Devin Teske <dteske@FreeBSD.org>
AuthorDate: 2026-08-16 03:17:13 +0000
Commit:     Devin Teske <dteske@FreeBSD.org>
CommitDate: 2026-08-16 03:17:13 +0000

    bsdconfig: add datetime module for live system clock
    
    Provide bsdconfig datetime (menu), date, and time to set the running
    system clock via dialog(1)/bsddialog(1) --calendar and --timebox with
    mustberoot.  Unlike bsdinstall's time helper, this operates on the live
    system rather than a CHROOT-staged install target, and calls
    adjkerntz(8) after a successful change so the CMOS stays in sync.
    
    Reviewed by:    bcr
    Differential Revision:  https://reviews.freebsd.org/D58487
---
 usr.sbin/bsdconfig/Makefile                       |   1 +
 usr.sbin/bsdconfig/bsdconfig.8                    |  10 +-
 usr.sbin/bsdconfig/datetime/INDEX                 |  57 ++++++++
 usr.sbin/bsdconfig/datetime/Makefile              |   9 ++
 usr.sbin/bsdconfig/datetime/Makefile.depend       |  10 ++
 usr.sbin/bsdconfig/datetime/Makefile.inc          |   1 +
 usr.sbin/bsdconfig/datetime/USAGE                 |  36 +++++
 usr.sbin/bsdconfig/datetime/date                  |  73 ++++++++++
 usr.sbin/bsdconfig/datetime/datetime              | 154 ++++++++++++++++++++++
 usr.sbin/bsdconfig/datetime/include/Makefile      |   4 +
 usr.sbin/bsdconfig/datetime/include/datetime.hlp  |  19 +++
 usr.sbin/bsdconfig/datetime/include/messages.subr |  41 ++++++
 usr.sbin/bsdconfig/datetime/share/Makefile        |   4 +
 usr.sbin/bsdconfig/datetime/share/datetime.subr   | 142 ++++++++++++++++++++
 usr.sbin/bsdconfig/datetime/time                  |  73 ++++++++++
 15 files changed, 632 insertions(+), 2 deletions(-)

diff --git a/usr.sbin/bsdconfig/Makefile b/usr.sbin/bsdconfig/Makefile
index a3b72d248a14..d308c90557ef 100644
--- a/usr.sbin/bsdconfig/Makefile
+++ b/usr.sbin/bsdconfig/Makefile
@@ -3,6 +3,7 @@
 PACKAGE=	bsdconfig
 
 SUBDIR=	console \
+	datetime \
 	diskmgmt \
 	docsinstall \
 	dot \
diff --git a/usr.sbin/bsdconfig/bsdconfig.8 b/usr.sbin/bsdconfig/bsdconfig.8
index aa81785a3acc..0ad74a2e3b2f 100644
--- a/usr.sbin/bsdconfig/bsdconfig.8
+++ b/usr.sbin/bsdconfig/bsdconfig.8
@@ -1,5 +1,5 @@
 .\" Copyright (c) 2012 Ron McDowell
-.\" Copyright (c) 2012-2013 Devin Teske
+.\" Copyright (c) 2012-2026 Devin Teske
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
@@ -23,7 +23,7 @@
 .\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd June 9, 2026
+.Dd July 27, 2026
 .Dt BSDCONFIG 8
 .Os
 .Sh NAME
@@ -95,6 +95,10 @@ listing.
 .Bl -tag -width ".Cm syscons_screenmap"
 .It Cm console
 Utilities to customize the behavior of the system console.
+.It Cm date
+Set the system date, preserving the current time-of-day.
+.It Cm datetime
+Set the system date and/or time on the running machine.
 .It Cm defaultrouter
 Shortcut to the Default Router/Gateway menu under networking.
 .It Cm diskmgmt
@@ -207,6 +211,8 @@ Shortcut to the Screenmap menu under console for
 .It Cm vt_ttys
 Shortcut to the Ttys menu under console for
 .Xr vt 4 .
+.It Cm time
+Set the system time-of-day, preserving the current calendar date.
 .It Cm timezone
 Set the regional timezone of the local machine.
 .It Cm ttys
diff --git a/usr.sbin/bsdconfig/datetime/INDEX b/usr.sbin/bsdconfig/datetime/INDEX
new file mode 100644
index 000000000000..9f85e68bdc85
--- /dev/null
+++ b/usr.sbin/bsdconfig/datetime/INDEX
@@ -0,0 +1,57 @@
+# Copyright (c) 2026 Devin Teske
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+#
+# Title that will be shown in the bsdconfig menu.
+#
+menu_title="Date / Time"
+
+#
+# A short descriptive line shown at the bottom of the bsdconfig menu. keep it
+# short because any line longer than the terminal width will be truncated.
+#
+menu_help="Set the system date and/or time"
+
+#
+# Two-part variable that defines an action to take when `keyword' is passed on
+# a bsdconfig command line. Variable takes the form "keyword|command" and
+# multiple occurrences of the variable (with different `keyword's, or different
+# `keyword's AND `command's) are allowed.  If `command' begins with a '/' then
+# the full path to the program is needed. If `command' begins with anything
+# else it is a path relative to the directory this INDEX file is in. `keyword'
+# can be i18n'ed but `command' is the name of a script.
+#
+menu_selection="datetime|datetime"
+menu_selection="date|date"
+menu_selection="time|time"
+
+#
+# ------------ Items below this line do NOT need i18n translation ------------
+#
+# Name of the program to be run when this menu choice is selected. If it begins
+# with a '/' then the full path to the program is needed. If it begins with
+# anything else it is a path relative to the directory this INDEX file is in.
+#
+menu_program="datetime"
diff --git a/usr.sbin/bsdconfig/datetime/Makefile b/usr.sbin/bsdconfig/datetime/Makefile
new file mode 100644
index 000000000000..600340a075c0
--- /dev/null
+++ b/usr.sbin/bsdconfig/datetime/Makefile
@@ -0,0 +1,9 @@
+SUBDIR= include share
+
+FILESDIR=	${LIBEXECDIR}/bsdconfig/085.datetime
+FILES=		INDEX USAGE
+
+SCRIPTSDIR=	${FILESDIR}
+SCRIPTS=	date datetime time
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/datetime/Makefile.depend b/usr.sbin/bsdconfig/datetime/Makefile.depend
new file mode 100644
index 000000000000..11aba52f82cf
--- /dev/null
+++ b/usr.sbin/bsdconfig/datetime/Makefile.depend
@@ -0,0 +1,10 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/datetime/Makefile.inc b/usr.sbin/bsdconfig/datetime/Makefile.inc
new file mode 100644
index 000000000000..01b5f23410c8
--- /dev/null
+++ b/usr.sbin/bsdconfig/datetime/Makefile.inc
@@ -0,0 +1 @@
+.include "../Makefile.inc"
diff --git a/usr.sbin/bsdconfig/datetime/USAGE b/usr.sbin/bsdconfig/datetime/USAGE
new file mode 100644
index 000000000000..cb2fdc733853
--- /dev/null
+++ b/usr.sbin/bsdconfig/datetime/USAGE
@@ -0,0 +1,36 @@
+# Copyright (c) 2026 Devin Teske
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+Usage: bsdconfig @PROGRAM_NAME@ [OPTIONS]
+
+OPTIONS:
+	-d         Provide lots of debugging info on standard-out when running.
+	-D file    Send debugging info to file. If file begins with a plus-sign
+	           debug info is sent to both standard-out and file (minus the
+	           leading plus).
+	-h         Print this usage statement and exit.
+	-S         Secure X11 mode (implies `-X'). As root, always prompt-for
+	           and validate sudo(8) username/password before starting.
+	-X         Use Xdialog(1) in place of dialog(1).
diff --git a/usr.sbin/bsdconfig/datetime/date b/usr.sbin/bsdconfig/datetime/date
new file mode 100755
index 000000000000..dde5be929090
--- /dev/null
+++ b/usr.sbin/bsdconfig/datetime/date
@@ -0,0 +1,73 @@
+#!/bin/sh
+#-
+# Copyright (c) 2026 Devin Teske
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." "$0"
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/mustberoot.subr
+f_include $BSDCFG_SHARE/datetime/datetime.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="085.datetime"
+
+f_index_menusel_keyword $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" ipgm &&
+	pgm="${ipgm:-$pgm}"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts h$GETOPTS_STDARGS flag; do
+	case "$flag" in
+	h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm" ;;
+	esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_title "$msg_set_date"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Set the system date (Cancel/ESC leaves the clock unchanged)
+#
+f_dialog_calendar_set_date
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/datetime/datetime b/usr.sbin/bsdconfig/datetime/datetime
new file mode 100755
index 000000000000..5f42d79278f6
--- /dev/null
+++ b/usr.sbin/bsdconfig/datetime/datetime
@@ -0,0 +1,154 @@
+#!/bin/sh
+#-
+# Copyright (c) 2026 Devin Teske
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." "$0"
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/mustberoot.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="085.datetime"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+DATETIME_HELPFILE=$BSDCFG_LIBE/$APP_DIR/include/datetime.hlp
+
+f_index_menusel_keyword $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" ipgm &&
+	pgm="${ipgm:-$pgm}"
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+	local prompt=
+	local menu_list="
+		'D' '$msg_date'
+		'T' '$msg_time'
+		'X' '$msg_exit'
+	" # END-QUOTE
+	local defaultitem= # Calculated below
+	local hline="$hline_arrows_tab_enter"
+
+	local height width rows
+	eval f_dialog_menu_size height width rows \
+	                        \"\$DIALOG_TITLE\"     \
+	                        \"\$DIALOG_BACKTITLE\" \
+	                        \"\$prompt\"           \
+	                        \"\$hline\"            \
+	                        $menu_list
+
+	# Obtain default-item from previously stored selection
+	f_dialog_default_fetch defaultitem
+
+	local menu_choice
+	menu_choice=$( eval $DIALOG \
+		--title \"\$DIALOG_TITLE\"         \
+		--backtitle \"\$DIALOG_BACKTITLE\" \
+		--hline \"\$hline\"                \
+		--ok-label \"\$msg_ok\"            \
+		--cancel-label \"\$msg_cancel\"    \
+		--help-button                      \
+		--help-label \"\$msg_help\"        \
+		${USE_XDIALOG:+--help \"\"}        \
+		--default-item \"\$defaultitem\"   \
+		--menu \"\$prompt\"                \
+		$height $width $rows               \
+		$menu_list                         \
+		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
+	)
+	local retval=$?
+	f_dialog_data_sanitize menu_choice
+	f_dialog_menutag_store "$menu_choice"
+
+	# Only update default-item on success
+	[ $retval -eq $DIALOG_OK ] && f_dialog_default_store "$menu_choice"
+
+	return $retval
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts h$GETOPTS_STDARGS flag; do
+	case "$flag" in
+	h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm" ;;
+	esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_title "$msg_date_time"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+	dialog_menu_main
+	retval=$?
+	f_dialog_menutag_fetch mtag
+	f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
+
+	if [ $retval -eq $DIALOG_HELP ]; then
+		f_show_help "$DATETIME_HELPFILE"
+		continue
+	elif [ $retval -ne $DIALOG_OK ]; then
+		f_die
+	fi
+
+	command=
+	case "$mtag" in
+	X) break ;;
+	D) command=date ;; # Set Date
+	T) command=time ;; # Set Time
+	esac
+
+	if [ "$command" ]; then
+		$BSDCFG_LIBE/$APP_DIR/$command ${USE_XDIALOG:+-X}
+	else
+		f_die 1 "$msg_unknown_date_time_menu_selection"
+	fi
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/datetime/include/Makefile b/usr.sbin/bsdconfig/datetime/include/Makefile
new file mode 100644
index 000000000000..da1d4daaa5c0
--- /dev/null
+++ b/usr.sbin/bsdconfig/datetime/include/Makefile
@@ -0,0 +1,4 @@
+FILESDIR=	${LIBEXECDIR}/bsdconfig/085.datetime/include
+FILES=		messages.subr datetime.hlp
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/datetime/include/datetime.hlp b/usr.sbin/bsdconfig/datetime/include/datetime.hlp
new file mode 100644
index 000000000000..7b0b0ed7c023
--- /dev/null
+++ b/usr.sbin/bsdconfig/datetime/include/datetime.hlp
@@ -0,0 +1,19 @@
+These screens allow you to set the system date and time on the
+running system.
+
+Date
+====
+
+Choose Date to open a calendar pre-filled with the current local
+date. Confirming applies that calendar day while preserving the
+current time-of-day.
+
+Time
+====
+
+Choose Time to open a time box pre-filled with the current local
+time. Confirming applies that time-of-day while preserving the
+current calendar date.
+
+Timezone is configured separately (bsdconfig timezone). Setting
+the clock here does not change which zone /etc/localtime names.
diff --git a/usr.sbin/bsdconfig/datetime/include/messages.subr b/usr.sbin/bsdconfig/datetime/include/messages.subr
new file mode 100644
index 000000000000..55e40553c403
--- /dev/null
+++ b/usr.sbin/bsdconfig/datetime/include/messages.subr
@@ -0,0 +1,41 @@
+# Copyright (c) 2026 Devin Teske
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+hline_arrows_tab_enter="Press arrows, TAB or ENTER"
+msg_cancel="Cancel"
+msg_date="Date"
+msg_date_time="Date / Time"
+msg_error="ERROR!"
+msg_exit="Exit"
+msg_help="Help"
+msg_ok="OK"
+msg_set_date="Set Date"
+msg_set_time="Set Time"
+msg_system_date_set="System date set to:\n\n%s"
+msg_system_time_set="System time set to:\n\n%s"
+msg_time="Time"
+msg_unable_to_set_date="Unable to set the system date."
+msg_unable_to_set_time="Unable to set the system time."
+msg_unknown_date_time_menu_selection="Unknown date/time menu selection"
diff --git a/usr.sbin/bsdconfig/datetime/share/Makefile b/usr.sbin/bsdconfig/datetime/share/Makefile
new file mode 100644
index 000000000000..dbf9035a2c73
--- /dev/null
+++ b/usr.sbin/bsdconfig/datetime/share/Makefile
@@ -0,0 +1,4 @@
+FILESDIR=	${SHAREDIR}/bsdconfig/datetime
+FILES=		datetime.subr
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/datetime/share/datetime.subr b/usr.sbin/bsdconfig/datetime/share/datetime.subr
new file mode 100644
index 000000000000..8c016ade9b7c
--- /dev/null
+++ b/usr.sbin/bsdconfig/datetime/share/datetime.subr
@@ -0,0 +1,142 @@
+if [ ! "$_DATETIME_DATETIME_SUBR" ]; then _DATETIME_DATETIME_SUBR=1
+#
+# Copyright (c) 2026 Devin Teske
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." datetime/datetime.subr
+f_include $BSDCFG_SHARE/dialog.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="085.datetime"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ FUNCTIONS
+
+# f_datetime_adjkerntz
+#
+# Best-effort CMOS sync after changing the system clock with date(1).
+#
+f_datetime_adjkerntz()
+{
+	f_quietly adjkerntz -a
+}
+
+# f_dialog_calendar_set_date
+#
+# Prompt with dialog(1) --calendar and set the system date, preserving the
+# current time-of-day. Returns dialog status (Cancel/ESC) without dying.
+#
+f_dialog_calendar_set_date()
+{
+	local prompt="$msg_set_date"
+	local hline="$hline_arrows_tab_enter"
+	local cheight cwidth input_date ret_date retval
+	local cur_tod setstr
+
+	f_dialog_calendar_size cheight cwidth \
+		"$DIALOG_TITLE" "$DIALOG_BACKTITLE" "$prompt" "$hline"
+
+	input_date=$( date "+%d %m %Y" )
+	ret_date=$( eval $DIALOG \
+		--title \"\$DIALOG_TITLE\"         \
+		--backtitle \"\$DIALOG_BACKTITLE\" \
+		--hline \"\$hline\"                \
+		--ok-label \"\$msg_ok\"            \
+		--cancel-label \"\$msg_cancel\"    \
+		--calendar \"\$prompt\"            \
+		$cheight $cwidth                   \
+		$input_date                        \
+		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
+	)
+	retval=$?
+	f_dialog_data_sanitize ret_date
+	f_dprintf "retval=%u ret_date=[%s]" $retval "$ret_date"
+	[ $retval -eq $DIALOG_OK ] || return $retval
+
+	cur_tod=$( date "+%H:%M:%S" )
+	setstr=$( date -j -f "%d/%m/%Y %T" -- \
+		"$ret_date $cur_tod" "+%Y%m%d%H%M.%S" ) ||
+		f_die 1 "$msg_unable_to_set_date"
+
+	f_eval_catch "$0" date 'date "%s"' "$setstr" ||
+		f_die 1 "$msg_unable_to_set_date"
+	f_datetime_adjkerntz
+	f_show_msg "$msg_system_date_set" "$( date )"
+	return $SUCCESS
+}
+
+# f_dialog_timebox_set_time
+#
+# Prompt with dialog(1) --timebox and set the system time, preserving the
+# current calendar date. Returns dialog status (Cancel/ESC) without dying.
+#
+f_dialog_timebox_set_time()
+{
+	local prompt="$msg_set_time"
+	local hline="$hline_arrows_tab_enter"
+	local input_time ret_time retval
+	local cur_day setstr
+
+	#
+	# bsddialog(1) --timebox wants total rows (min 7), not dialog(1)-style
+	# text height. Match bsdinstall time: autosize height, width 40.
+	#
+	input_time=$( date "+%H %M %S" )
+	ret_time=$( eval $DIALOG \
+		--title \"\$DIALOG_TITLE\"         \
+		--backtitle \"\$DIALOG_BACKTITLE\" \
+		--hline \"\$hline\"                \
+		--ok-label \"\$msg_ok\"            \
+		--cancel-label \"\$msg_cancel\"    \
+		--timebox \"\$prompt\"             \
+		0 40                               \
+		$input_time                        \
+		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
+	)
+	retval=$?
+	f_dialog_data_sanitize ret_time
+	f_dprintf "retval=%u ret_time=[%s]" $retval "$ret_time"
+	[ $retval -eq $DIALOG_OK ] || return $retval
+
+	cur_day=$( date "+%d/%m/%Y" )
+	setstr=$( date -j -f "%d/%m/%Y %T" -- \
+		"$cur_day $ret_time" "+%Y%m%d%H%M.%S" ) ||
+		f_die 1 "$msg_unable_to_set_time"
+
+	f_eval_catch "$0" date 'date "%s"' "$setstr" ||
+		f_die 1 "$msg_unable_to_set_time"
+	f_datetime_adjkerntz
+	f_show_msg "$msg_system_time_set" "$( date )"
+	return $SUCCESS
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." datetime/datetime.subr
+
+fi # ! $_DATETIME_DATETIME_SUBR
diff --git a/usr.sbin/bsdconfig/datetime/time b/usr.sbin/bsdconfig/datetime/time
new file mode 100755
index 000000000000..908d756b0d8a
--- /dev/null
+++ b/usr.sbin/bsdconfig/datetime/time
@@ -0,0 +1,73 @@
+#!/bin/sh
+#-
+# Copyright (c) 2026 Devin Teske
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." "$0"
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/mustberoot.subr
+f_include $BSDCFG_SHARE/datetime/datetime.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="085.datetime"
+
+f_index_menusel_keyword $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" ipgm &&
+	pgm="${ipgm:-$pgm}"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts h$GETOPTS_STDARGS flag; do
+	case "$flag" in
+	h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm" ;;
+	esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_title "$msg_set_time"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Set the system time (Cancel/ESC leaves the clock unchanged)
+#
+f_dialog_timebox_set_time
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################