timezone
timezone setup
$ sudo dpkg-reconfigure tzdata
tzdata installation with noninteractive
[!NOTE|label:references:]
# in bash
$ DEBIAN_FRONTEND=noninteractive sudo apt-get install -y tzdata
# or
$ export DEBIAN_FRONTEND=noninteractive
$ sudo apt install -y tzdata
# or
$ echo 'tzdata tzdata/Areas select Europe' | debconf-set-selections
$ echo 'tzdata tzdata/Zones/Europe select Paris' | debconf-set-selections
$ DEBIAN_FRONTEND="noninteractive" sudo apt install -y tzdata
# or
$ sudo ln -fs /usr/share/zoneinfo/America/New_York /etc/localtime
$ export DEBIAN_FRONTEND=noninteractive
$ sudo apt-get install -y tzdata
$ sudo dpkg-reconfigure --frontend noninteractive tzdata
or
[!NOTE|label:references:]
$ sudo ln -snf /usr/share/zoneinfo/$(curl https://ipapi.co/timezone) /etc/localtime
$ sudo apt install -y tzdata
or in dockerfile
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata
or ENV in dockerfile
[!NOTE|label:references:]
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends tzdata
or ARG
in dockerfile
[!NOTE|label:references:]
from ubuntu:bionic
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y tzdata
RUN unlink /etc/localtime
RUN ln -s /usr/share/zoneinfo/America/New_York /etc/localtime
date
epoch
references:
It is the number of seconds that have elapsed since the Unix epoch, minus leap seconds; the Unix epoch is 00:00:00 UTC on 1 January 1970
$ date -u -d '1970-01-01 00:00:00' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 00:00:00 +00:00
Unix: 0
$ date -d '1970-01-01 00:00:00' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 00:00:00 +08:00
Unix: -28800
$ date -u -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-02 00:00:00 +00:00
Unix: 86400
$ date -d '2023-01-01' +%s; date -d '2023-01-01 - 1 year' +%s
1672560000
1641024000
# using now
$ date -d'now' +%s; date -d 'now - 1 day' +%s
1706952065
1706865665
$ date '+%s%3N'
1602231334983
$ date '+%s'
1602231334
timestamps
format
[!TIP]
yyyy-MM-dd'T'HH:mm:ss.SSSZ
DATE FORMAT OPTION
MEANING
EXAMPLE OUTPUT
locale’s full weekday name
Week of Year with Sunday as first day of week
ISO Week of Year with Monday as first day of week
Hour (HH) in 24-hour clock format
Hour in 12-hour clock format
locale’s equivalent of AM or PM
same as %p but in lower case
classical date format
$ secs=259200
$ date -u -d @${secs} +"%F"
1970-01-04
$ date -u -d @${secs} +"%T"
00:00:00
$ date -u -d @${secs} +"%F %T"
1970-01-04 00:00:00
$ date -u -d @${secs} -Is
1970-01-04T00:00:00+00:00
date format with timezone
$ date -u +"%Y-%m-%dT%H:%M:%SZ"
2020-10-09T08:14:47Z
$ date +%FT%T.%3N%:z
2020-10-09T17:27:18.491+08:00
$ date -u +"%Y-%m-%dT%H:%M:%S.%3NZ"
2020-10-09T08:14:47.167Z
$ date +%Y-%m-%d-T%H:%M:%S.%3N%z
2020-10-09-T17:27:18.491+0800
details
$ date -u -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
date: parsed relative part: +1 hour(s)
date: input timezone: parsed date/time string (-02)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
date: new time = 1547884800 epoch-seconds
date: timezone: Universal Time
date: final: 1547884800.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC)
date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC+00)
2019-01-19_08:00:00UTC
IOS 8601
2015-12-11T20:28+01:00 or 2015-12-11T19:28Z
2015-12-11T20:28:30+01:00 or 2015-12-11T19:28:30Z
YYYY-MM-DD'T'hh:mm:ss.sTZD
2015-12-11T20:28:30.45+01:00 or 2015-12-11T19:28:30.45Z
where:
MM
= two-digit month (01=January, etc.)
DD
= two-digit day of month (01 through 31)
hh
= two digits of hour (00 through 23) (am/pm NOT allowed)
mm
= two digits of minute (00 through 59)
ss
= two digits of second (00 through 59)
s
= one or more digits representing a decimal fraction of a second (i.e. milliseconds)
TZD
= time zone designator (Z or +hh:mm or -hh:mm)
$ date -I
2020-10-09
$ date -Is && date -Isecond
2020-10-09T16:31:47+08:00
2020-10-09T16:31:47+08:00
$ date -Ih
2020-10-09T16+08:00
$ date -Im
2020-10-09T16:31+08:00
rfc-3339
$ date --rfc-3339=date
2020-10-09
$ date --rfc-3339=ns
2020-10-09 17:32:14.158684000+08:00
$ date --rfc-3339=seconds
2020-10-09 17:32:14+08:00
utc
$ date
Fri Oct 9 17:09:34 CST 2020
$ date -u
Fri Oct 9 09:09:34 UTC 2020
timezone
[!NOTE|label:references:]
list all timezone:
$ timedatectl list-timezones | more
# or
$ tree /usr/share/zoneinfo/
$ date '+%Z'
CST
$ date '+%z'
+0800
$ date '+%:z'
+08:00
$ date '+%::z'
+08:00:00
$ date '+%:::z'
+08
$ echo $TZ
Asia/Beijing
$ timedatectl
Local time: Tue 2023-08-22 05:58:45 CST
Universal time: Mon 2023-08-21 21:58:45 UTC
RTC time: Mon 2023-08-21 21:53:46
Time zone: Asia/Beijing (CST, +0800)
NTP enabled: yes
NTP synchronized: yes
RTC in local TZ: no
DST active: n/a
$ date -d "2024-03-11" +"%Z"
PDT
$ date -d "2024-03-10" +"%Z"
PST
common formats
[!NOTE|label:references:] Shell command: date Most common Bash date commands for timestamping
FORMAT/RESULT
COMMAND
OUTPUT
YYYYMMDD_hhmmss (UTC version)
date --utc +%Y%m%d_%H%M%SZ
YYYYMMDD_hhmmss (with local TZ)
Seconds since UNIX epoch:
Nanoseconds since UNIX epoch:
Nanoseconds since UNIX epoch:
ISO8601 UTC timestamp + ms
ISO8601 UTC timestamp + ms
2020-10-09T08:48:45.520UTC
ISO8601 Local TZ timestamp
convert
$ date +"%Y-%m-%dT%H:%M:%SZ"
2020-10-09T17:16:37Z
$ date -u +"%Y-%m-%dT%H:%M:%SZ"
2020-10-09T09:16:37Z
$ date -d $(date -u +"%Y-%m-%dT%H:%M:%SZ")
Fri Oct 9 17:16:37 CST 2020
HUMAN-READABLE TIME
SECONDS
timestamps to epoch
$ echo $EPOCHSECONDS
1602235097
$ date -d $(date -u +"%Y-%m-%dT%H:%M:%SZ") +%s
1602235097
$ date --date=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ") +%s%3N
1602235097801
$ date -d '2023-01-01' +%s; date -d '2023-01-01 - 1 day' +%s
1672560000
1672473600
$ date -d '2023-01-01' +%s; date -d '2023-01-01 - 1 year' +%s
1672560000
1641024000
# using now
$ date -d'now' +%s; date -d 'now - 1 day' +%s
1706952065
1706865665
epoch to timestamps
$ date -u +"%Y-%m-%dT%H:%M:%S.%3NZ"
2020-10-09T09:18:17.795Z
$ date -d @1602235097 +%c
Fri Oct 9 17:18:17 2020
$ date -d @1602235097
Fri Oct 9 17:18:17 CST 2020
$ date -d @1602235097 -u
Fri Oct 9 09:18:17 UTC 2020
$ date -d @1602235097 -R
Fri, 09 Oct 2020 02:18:17 -0700
via awk
$ date -d @1602235097 +%c
Fri Oct 9 02:18:17 2020
$ echo 1602235097 | awk '{ print strftime("%c", $0); }'
Fri Oct 9 02:18:17 2020
epoch with 13 digits
# wrong
$ date -d @1718731558409 +%c
Thu 08 Jun 56434 01:53:29 AM PDT
# solution: epoch/1000
$ date -d @$((1718731558409/1000)) +%c
Tue 18 Jun 2024 10:25:58 AM PDT
convert in different timezone
[!NOTE|label:references:]
timezone can be found via:
$ cat /usr/share/zoneinfo
# or
$ timedatectl list-timezones | more
$ TZ="Asia/Shanghai" date -d @$(date -d "2023-01-01 00:00:00 GMT" +"%s")
Sun Jan 1 08:00:00 CST 2023
$ TZ="America/Los_Angeles" date -d @$(date -d "2023-01-01 00:00:00 GMT" +"%s")
Sat Dec 31 16:00:00 PST 2022
convert to another timezone
$ date --date='TZ="GTM" 15:00 tomorrow'
Tue Aug 22 08:00:00 PDT 2023
$ echo $TZ
America/Los_Angeles
$ date --date='TZ="Asia/Shanghai" 16:00 tomorrow'
Wed Aug 23 01:00:00 PDT 2023
$ echo $TZ
America/Los_Angeles
$ TZ="Asia/Shanghai" date -d 'TZ="America/Los_Angeles" 0:00 tomorrow'
Tue Aug 22 15:00:00 CST 2023
convert to different timezone with daylight saving
$ getDateTime() { echo "$1 | "$( TZ="$1" date '+%Y-%m-%d-%H-%M-%S %Z %z' ); }
$ getDateTime Asia/Hong_Kong
Asia/Hong_Kong | 2024-03-01-13-08-02 HKT +0800
$ getDateTime America/Los_Angeles
America/Los_Angeles | 2024-02-29-21-08-08 PST -0800
$ getDateTime America/New_York
America/New_York | 2024-03-01-00-08-08 EST -0500
$ getDateTime Pacific/Honolulu
Pacific/Honolulu | 2024-02-29-19-08-08 HST -1000
$ getDateTime Asia/Hong_Kong
Asia/Hong_Kong | 2024-03-01-13-08-09 HKT +0800
get daylight saving
$ date -d "2024-03-11" +%Z
PDT
$ date -d "2024-03-10" +%Z
PST
$ echo $(( ($(date -d "2024-03-10 UTC" +%s) - $(date -d "2024-03-10 PST" +%s))/(60*60) ))
-8
$ echo $(( ($(date -d "2024-03-11 UTC" +%s) - $(date -d "2024-03-11 PDT" +%s))/(60*60) ))
-7
another
$ if perl -e 'exit ((localtime)[8])' ; then
echo winter
else
echo summer
fi
how many days from timestamps
[!NOTE|label:references:]
$ echo $(( ($(date --date="230301" +%s) - $(date --date="240301" +%s) )/(60*60*24) )) days
-366 days
# with timezone
# PST/PDT according to daylight saving
# v
$ echo $(( ($(date -d "2024-03-01 PST" +%s) - $(date -d "2023-03-01 UTC" +%s)) / (60*60*24) ))
366
calculate time different
$ date -d 'now + 3 weeks'
Fri Oct 30 20:32:04 CST 2020
$ date -d 'now + 3 weeks' +%s
1604061130
$ date -d 'Jan 1 + 11 weeks'
Wed Mar 18 00:00:00 CST 2020
$ date -d 'Jan 1 2021 + 11 weeks'
Fri Mar 19 00:00:00 CST 2021
time described by STRING
$ date -u +"%Y-%m-%dT%H:%M:%S.%3NZ" -d '90 day ago'
2020-07-11T08:14:03.145Z
$ date -u +"%Y-%m-%dT%H:%M:%S.%3NZ" -d '3 months ago'
2020-07-09T08:14:47.164Z
$ date -u -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_03:00:00
$ date -d "$(date -Iseconds -d "2018-12-10 00:00:00") - 5 hours - 20 minutes - 5 seconds"
Sun Dec 9 18:39:55 CST 2018
$ date -d "2018-12-10 00:00:00 5 hours ago 20 minutes ago 5 seconds ago"
Sun Dec 9 18:39:55 CST 2018
$ date -d '2023-01-01 - 1 year' +"%Y-%m-%d %H:%M:%S"
2022-01-01 00:00:00
# or: https://www.commandlinefu.com/commands/view/2336/get-yesterdays-date-or-a-previous-time
$ date -d '1 day ago'
$ date -d '11 hour ago'
$ date -d '2 hour ago - 3 minute'
$ date -d '16 hour'
two times different
$ seconds=$(date +%s)
$ printf "%d days %(%H hours %M minutes %S seconds)T\n" $((seconds/86400)) $seconds
18544 days 18 hours 35 minutes 48 seconds
simple one-liner
$ secs=259200
$ printf '%dh:%dm:%ds\n' $(($secs/3600)) $(($secs%3600/60)) $(($secs%60))
72h:0m:0s
with leading zero
$ printf '%02dh:%02dm:%02ds\n' $(($secs/3600)) $(($secs%3600/60)) $(($secs%60))
72h:00m:00s
with days
$ printf '%dd:%dh:%dm:%ds\n' $(($secs/86400)) $(($secs%86400/3600)) $(($secs%3600/60)) $(($secs%60))
3d:0h:0m:0s
with nanoseconds
$ printf '%02dh:%02dm:%02fs\n' $(echo -e "$secs/3600\n$secs%3600/60\n$secs%60"| bc | xargs echo)
72h:00m:0.000000s
datediff
(ddiff
)
$ datediff -f "%d days, %H hours, %M mins, %S secs" "$(date +'%Y-%m-%d %H:%M:%S')" "$(date +'%Y-%m-%d %H:%M:%S' -d '3 days ago')"
-3 days, 0 hours, 0 mins, 0 secs
or with specific format
$ ddiff -i '%Y%m%d%H%M%S' 20190817040001 20200312000101
17956860s
$ ddiff -f "%d days, %H hours, %M mins, %S secs" -i '%Y%m%d%H%M%S' 20190817040001 20200312000101
207 days, 20 hours, 1 mins, 0 secs
calculate with epoch
$ awk -v t=$(( $(date -d $(date +"%Y-%m-%dT%H:%M:%SZ") +%s) - $(date -d $(date +"%Y-%m-%dT%H:%M:%SZ" -d '3 days ago') +%s) )) 'BEGIN{
printf "%d:%02d:%06.3f\n", t/3600, (t/60)%60, t%60}'
72:00:00.000
transfer date format
[!TIP]
$ date +'%Y%m%d%H%M%S'
20201009184852
$ d1=$(date +'%Y%m%d%H%M%S')
$ date --date "$(echo $d1 | sed -nr 's/(....)(..)(..)(..)(..)(..)/\1-\2-\3 \4:\5:\6/p')"
Fri Oct 9 18:48:52 CST 2020
$ date -ud "1970-01-01 + 1234567890 seconds"
Fri Feb 13 23:31:30 UTC 2009
chrony
install
from package management
# centos/rhel
$ sudo yum install -y chrony
from source
[!NOTE]
asciidoctor is required to build docs
$ gem install asciidoctor
$ mkdir -p /opt/chrony
$ git clone https://gitlab.com/chrony/chrony.git /opt/chrony && cd $_
$ ./configure --prefix=/usr/local --mandir=/usr/share/man
$ make && make docs
$ sudo make install && sudo make install docs
conf
[!NOTE|label:references:]
ntp pool project | 授时中心
s2g.time.edu.cn
华东南地区网络中心
s2h.time.edu.cn
四川大学网络管理中心
s2j.time.edu.cn
大连理工大学网络中心
s2k.time.edu.cn
CERNET桂林主节点
ntp.sjtu.edu.cn
| 202.120.2.101
上海交通大学
/etc/chrony.conf
# default
$ cat /etc/chrony.conf | sed -r '/^(#.*)$/d' | sed -r '/^\s*$/d'
pool 2.centos.pool.ntp.org iburst
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
keyfile /etc/chrony.keys
leapsectz right/UTC
logdir /var/log/chrony
# modified
$ cat /etc/chrony.conf | sed -r '/^(#.*)$/d' | sed -r '/^\s*$/d'
pool 2.rhel.pool.ntp.org iburst
driftfile /var/lib/chrony/drift
makestep 1.0 3
stratumweight 0
rtcsync
hwtimestamp *
allow 0.0.0.0/0
bindcmdaddress 127.0.0.1
bindcmdaddress ::1
local stratum 10
keyfile /etc/chrony.keys
leapsectz right/UTC
logdir /var/log/chrony
generatecommandkey
maxdistance 600.0
/usr/lib/systemd/system/chronyd.service
$ cat /usr/lib/systemd/system/chronyd.service
[Unit]
Description=NTP client/server
Documentation=man:chronyd(8) man:chrony.conf(5)
After=ntpdate.service sntp.service ntpd.service
Conflicts=ntpd.service systemd-timesyncd.service
ConditionCapability=CAP_SYS_TIME
[Service]
Type=forking
PIDFile=/run/chrony/chronyd.pid
EnvironmentFile=-/etc/sysconfig/chronyd
ExecStart=/usr/sbin/chronyd $OPTIONS
ExecStartPost=/usr/libexec/chrony-helper update-daemon
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=full
[Install]
WantedBy=multi-user.target
commands
services
$ sudo systemctl enable chronyd.service
Created symlink /etc/systemd/system/multi-user.target.wants/chronyd.service → /usr/lib/systemd/system/chronyd.service.
$ sudo systemctl is-active chronyd.service
active
$ sudo systemctl is-enabled chronyd.service
enabled
server
$ sudo chronyd -q 'server 0.north-america.pool.ntp.org iburst'
2024-04-02T23:51:52Z chronyd version 3.5 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCDNS +SECHASH +IPV6 +DEBUG)
2024-04-02T23:51:52Z Initial frequency -19.492 ppm
2024-04-02T23:51:57Z System clock wrong by 0.003261 seconds (step)
2024-04-02T23:51:57Z chronyd exiting
chronyc
$ chronyc sources -v
210 Number of sources = 4
.-- Source mode '^' = server, '=' = peer, '#' = local clock.
/ .- Source state '*' = current synced, '+' = combined , '-' = not combined,
| / '?' = unreachable, 'x' = time may be in error, '~' = time too variable.
|| .- xxxx [ yyyy ] +/- zzzz
|| Reachability register (octal) -. | xxxx = adjusted offset,
|| Log2(Polling interval) --. | | yyyy = measured offset,
|| \ | | zzzz = estimated error.
|| | | \
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^- 212.227.240.160 3 8 377 103 -5334us[-5080us] +/- 101ms
^? ntp1.glypnod.com 2 6 3 37 -869us[ -609us] +/- 14ms
^* LAX.CALTICK.NET 2 7 377 36 -408us[ -147us] +/- 12ms
^- 131.153.171.22 2 8 377 101 -5931us[-5677us] +/- 60ms
$ chronyc sourcestats -v
210 Number of sources = 4
.- Number of sample points in measurement set.
/ .- Number of residual runs with same sign.
| / .- Length of measurement set (time).
| | / .- Est. clock freq error (ppm).
| | | / .- Est. error in freq.
| | | | / .- Est. offset.
| | | | | | On the -.
| | | | | | samples. \
| | | | | | |
Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev
==============================================================================
212.227.240.160 25 17 31m +0.029 0.853 -560us 586us
ntp1.glypnod.com 2 0 64 -0.104 2000.000 -869us 4000ms
LAX.CALTICK.NET 12 4 1099 +0.014 2.198 +654ns 614us
131.153.171.22 25 14 31m -0.834 2.524 -4084us 1801us
$ chronyc tracking
Reference ID : 2D3F360D (LAX.CALTICK.NET)
Stratum : 3
Ref time (UTC) : Tue Apr 02 22:53:49 2024
System time : 0.000157978 seconds fast of NTP time
Last offset : +0.000261040 seconds
RMS offset : 0.001216694 seconds
Frequency : 19.554 ppm slow
Residual freq : +0.014 ppm
Skew : 2.387 ppm
Root delay : 0.024124343 seconds
Root dispersion : 0.000968660 seconds
Update interval : 128.2 seconds
Leap status : Normal
$ sudo chronyc clients
Hostname NTP Drop Int IntL Last Cmd Drop Int Last
===============================================================================
localhost 0 0 - - - 13 0 4 1
/usr/libexec/chrony-helper
$ cat /usr/libexec/chrony-helper
#!/bin/bash
# This script configures running chronyd to use NTP servers obtained from
# DHCP and _ntp._udp DNS SRV records. Files with servers from DHCP are managed
# externally (e.g. by a dhclient script). Files with servers from DNS SRV
# records are updated here using the dig utility. The script can also list
# and set static sources in the chronyd configuration file.
chronyc=/usr/bin/chronyc
chrony_conf=/etc/chrony.conf
chrony_service=chronyd.service
helper_dir=/var/run/chrony-helper
added_servers_file=$helper_dir/added_servers
network_sysconfig_file=/etc/sysconfig/network
dhclient_servers_files="/var/lib/dhclient/chrony.servers.*"
dnssrv_servers_files="$helper_dir/dnssrv@*"
dnssrv_timer_prefix=chrony-dnssrv@
. $network_sysconfig_file &> /dev/null
chrony_command() {
$chronyc -a -n -m "$1"
}
is_running() {
chrony_command "tracking" &> /dev/null
}
get_servers_files() {
[ "$PEERNTP" != "no" ] && echo "$dhclient_servers_files"
echo "$dnssrv_servers_files"
}
is_update_needed() {
for file in $(get_servers_files) $added_servers_file; do
[ -e "$file" ] && return 0
done
return 1
}
update_daemon() {
local all_servers_with_args all_servers added_servers
if ! is_running; then
rm -f $added_servers_file
return 0
fi
all_servers_with_args=$(cat $(get_servers_files) 2> /dev/null)
all_servers=$(
echo "$all_servers_with_args" |
while read -r server serverargs; do
echo "$server"
done | sort -u)
added_servers=$( (
cat $added_servers_file 2> /dev/null
echo "$all_servers_with_args" |
while read -r server serverargs; do
[ -z "$server" ] && continue
chrony_command "add server $server $serverargs" &> /dev/null &&
echo "$server"
done) | sort -u)
comm -23 <(echo -n "$added_servers") <(echo -n "$all_servers") |
while read -r server; do
chrony_command "delete $server" &> /dev/null
done
added_servers=$(comm -12 <(echo -n "$added_servers") <(echo -n "$all_servers"))
if [ -n "$added_servers" ]; then
echo "$added_servers" > $added_servers_file
else
rm -f $added_servers_file
fi
}
get_dnssrv_servers() {
local name=$1 output
if ! command -v dig &> /dev/null; then
echo "Missing dig (DNS lookup utility)" >&2
return 1
fi
output=$(dig "$name" srv +short +ndots=2 +search 2> /dev/null) || return 0
echo "$output" | while read -r _ _ port target; do
server=${target%.}
[ -z "$server" ] && continue
echo "$server port $port ${NTPSERVERARGS:-iburst}"
done
}
check_dnssrv_name() {
local name=$1
if [ -z "$name" ]; then
echo "No DNS SRV name specified" >&2
return 1
fi
if [ "${name:0:9}" != _ntp._udp ]; then
echo "DNS SRV name $name doesn't start with _ntp._udp" >&2
return 1
fi
}
update_dnssrv_servers() {
local name=$1
local srv_file=$helper_dir/dnssrv@$name servers
check_dnssrv_name "$name" || return 1
servers=$(get_dnssrv_servers "$name")
if [ -n "$servers" ]; then
echo "$servers" > "$srv_file"
else
rm -f "$srv_file"
fi
}
set_dnssrv_timer() {
local state=$1 name=$2
local srv_file=$helper_dir/dnssrv@$name servers
local timer
timer=$dnssrv_timer_prefix$(systemd-escape "$name").timer || return 1
check_dnssrv_name "$name" || return 1
if [ "$state" = enable ]; then
systemctl enable "$timer"
systemctl start "$timer"
elif [ "$state" = disable ]; then
systemctl stop "$timer"
systemctl disable "$timer"
rm -f "$srv_file"
fi
}
list_dnssrv_timers() {
systemctl --all --full -t timer list-units | grep "^$dnssrv_timer_prefix" | \
sed "s|^$dnssrv_timer_prefix\(.*\)\.timer.*|\1|" |
while read -r name; do
systemd-escape --unescape "$name"
done
}
prepare_helper_dir() {
mkdir -p $helper_dir
exec 100> $helper_dir/lock
if ! flock -w 20 100; then
echo "Failed to lock $helper_dir" >&2
return 1
fi
}
is_source_line() {
local pattern="^[ \t]*(server|pool|peer|refclock)[ \t]+[^ \t]+"
[[ "$1" =~ $pattern ]]
}
list_static_sources() {
while read -r line; do
if is_source_line "$line"; then
echo "$line"
fi
done < $chrony_conf
}
set_static_sources() {
local new_config tmp_conf
new_config=$(
sources=$(
while read -r line; do
is_source_line "$line" && echo "$line"
done)
while read -r line; do
if ! is_source_line "$line"; then
echo "$line"
continue
fi
tmp_sources=$(
local removed=0
echo "$sources" | while read -r line2; do
if [ "$removed" -ne 0 ] || [ "$line" != "$line2" ]; then
echo "$line2"
else
removed=1
fi
done)
[ "$sources" == "$tmp_sources" ] && continue
sources=$tmp_sources
echo "$line"
done < $chrony_conf
echo "$sources"
)
tmp_conf=${chrony_conf}.tmp
cp -a $chrony_conf $tmp_conf &&
echo "$new_config" > $tmp_conf &&
mv $tmp_conf $chrony_conf || return 1
systemctl try-restart $chrony_service
}
print_help() {
echo "Usage: $0 COMMAND"
echo
echo "Commands:"
echo " update-daemon"
echo " update-dnssrv-servers NAME"
echo " enable-dnssrv NAME"
echo " disable-dnssrv NAME"
echo " list-dnssrv"
echo " list-static-sources"
echo " set-static-sources < sources.list"
echo " is-running"
echo " command CHRONYC-COMMAND"
}
case "$1" in
update-daemon|add-dhclient-servers|remove-dhclient-servers)
is_update_needed || exit 0
prepare_helper_dir && update_daemon
;;
update-dnssrv-servers)
prepare_helper_dir && update_dnssrv_servers "$2" && update_daemon
;;
enable-dnssrv)
set_dnssrv_timer enable "$2"
;;
disable-dnssrv)
set_dnssrv_timer disable "$2" && prepare_helper_dir && update_daemon
;;
list-dnssrv)
list_dnssrv_timers
;;
list-static-sources)
list_static_sources
;;
set-static-sources)
set_static_sources
;;
is-running)
is_running
;;
command|forced-command)
chrony_command "$2"
;;
*)
print_help
exit 2
esac
exit $?
set local time with chrony
[!NOTE|label:references:]
$ sudo timedatectl set-time "2020-02-23 12:23:01" # <<========设置系统时间,因为开启了时间同步所以报错
Failed to set time: Automatic time synchronization is enabled
$ sudo systemctl stop chronyd
$ sudo timedatectl set-time "2020-02-23 12:23:01" # <<==========stop chronyd 后修改系统时间,报错依旧
Failed to set time: Automatic time synchronization is enabled
$ sudo systemctl status chronyd
● chronyd.service - NTP client/server
Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
Active: inactive (dead) since 四 2021-04-15 15:45:37 CST; 21s ago
Docs: man:chronyd(8)
man:chrony.conf(5)
Process: 13722 ExecStartPost=/usr/libexec/chrony-helper update-daemon (code=exited, status=0/SUCCESS)
Process: 13716 ExecStart=/usr/sbin/chronyd $OPTIONS (code=exited, status=0/SUCCESS)
Main PID: 13720 (code=exited, status=0/SUCCESS)
...
$ date
2021年 04月 15日 星期四 15:46:13 CST
$ sudo timedatectl set-ntp false
$ sudo timedatectl set-time "2020-02-23 12:23:01"
$ sudo systemctl status chronyd
● chronyd.service - NTP client/server
Loaded: loaded (/usr/lib/systemd/system/chronyd.service; disabled; vendor preset: enabled)
Active: inactive (dead)
Docs: man:chronyd(8)
man:chrony.conf(5)
...
$ sudo timedatectl status # <<============ 显示当前系统和RTC设置
Local time: 日 2020-02-23 12:23:39 CST
Universal time: 日 2020-02-23 04:23:39 UTC
RTC time: 日 2020-02-23 04:23:39
Time zone: Asia/Shanghai (CST, +0800)
NTP enabled: no
NTP synchronized: no
RTC in local TZ: no
DST active: n/a
$ sudo timedatectl set-ntp true
$ sudo timedatectl status
Local time: 日 2020-02-23 12:24:14 CST
Universal time: 日 2020-02-23 04:24:14 UTC
RTC time: 日 2020-02-23 04:24:14
Time zone: Asia/Shanghai (CST, +0800)
NTP enabled: yes
NTP synchronized: no
RTC in local TZ: no
DST active: n/a
$ sudo systemctl start chronyd
$ sudo timedatectl status
Local time: 四 2021-04-15 15:48:52 CST
Universal time: 四 2021-04-15 07:48:52 UTC
RTC time: 日 2020-02-23 04:24:44
Time zone: Asia/Shanghai (CST, +0800)
NTP enabled: yes
NTP synchronized: yes
RTC in local TZ: no
DST active: n/a
$ sudo timedatectl set-time "2020-02-23 12:23:01"
Failed to set time: Automatic time synchronization is enabled
$ sudo timedatectl set-ntp false # <<============= 禁用基于NTP的网络时间同步
$ sudo systemctl status chronyd
● chronyd.service - NTP client/server
Loaded: loaded (/usr/lib/systemd/system/chronyd.service; disabled; vendor preset: enabled)
Active: inactive (dead)
Docs: man:chronyd(8)
man:chrony.conf(5)
...
$ sudo timedatectl set-time "2020-02-23 12:23:01" # <<=========== 再次设置时间成功
$ sudo timedatectl set-ntp true # <<============ 启用基于NTP的网络时间同步
$ sudo systemctl status chronyd
● chronyd.service - NTP client/server
Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
Active: active (running) since 日 2020-02-23 12:23:25 CST; 4s ago
Docs: man:chronyd(8)
man:chrony.conf(5)
Process: 16110 ExecStartPost=/usr/libexec/chrony-helper update-daemon (code=exited, status=0/SUCCESS)
Process: 16103 ExecStart=/usr/sbin/chronyd $OPTIONS (code=exited, status=0/SUCCESS)
Main PID: 16105 (chronyd)
Tasks: 1
CGroup: /system.slice/chronyd.service
└─16105 /usr/sbin/chronyd
...
$ date
2021年 04月 15日 星期四 15:52:14 CST
systemd-timesyncd
[!NOTE]
issue in chrony
with timedatactl
$ timedatectl
Local time: Tue 2024-04-02 16:11:02 PDT
Universal time: Tue 2024-04-02 23:11:02 UTC
RTC time: Tue 2024-04-02 23:11:02
Time zone: America/Los_Angeles (PDT, -0700)
System clock synchronized: yes
NTP service: n/a
RTC in local TZ: no
$ sudo timedatectl set-ntp on
Failed to set ntp: NTP not supported
install
[!NOTE|label:references:]
# centos 8
$ sudo dnf reinstall https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
$ sudo yum install -y systemd-timesyncd
enable and start services
$ sudo systemctl enable systemd-timesyncd.service
Created symlink /etc/systemd/system/dbus-org.freedesktop.timesync1.service → /usr/lib/systemd/system/systemd-timesyncd.service.
Created symlink /etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service → /usr/lib/systemd/system/systemd-timesyncd.service.
$ sudo systemctl start systemd-timesyncd.service
$ sudo systemctl is-active systemd-timesyncd.service
active
$ sudo systemctl is-enabled systemd-timesyncd.service
enabled
config
[!NOTE]
$ cat /etc/systemd/timesyncd.conf | sed -r '/^(#.*)$/d' | sed -r '/^\s*$/d'
[Time]
NTP=0.north-america.pool.ntp.org 1.north-america.pool.ntp.org 2.north-america.pool.ntp.org 3.north-america.pool.ntp.org
FallbackNTP=0.pool.ntp.org 1.pool.ntp.org 0.fr.pool.ntp.org
# or
$ sudo systemd-analyze cat-config systemd/timesyncd.conf | sed -r '/^(#.*)$/d' | sed -r '/^\s*$/d'
[Time]
NTP=0.north-america.pool.ntp.org 1.north-america.pool.ntp.org 2.north-america.pool.ntp.org 3.north-america.pool.ntp.org
FallbackNTP=0.pool.ntp.org 1.pool.ntp.org 0.fr.pool.ntp.org
commands
show-timesync
$ timedatectl show-timesync --all
LinkNTPServers=
SystemNTPServers=0.north-america.pool.ntp.org 1.north-america.pool.ntp.org 2.north-america.pool.ntp.org 3.north-america.pool.ntp.org
RuntimeNTPServers=
FallbackNTPServers=0.pool.ntp.org 1.pool.ntp.org 0.fr.pool.ntp.org
ServerName=0.north-america.pool.ntp.org
ServerAddress=104.131.155.175
RootDistanceMaxUSec=5s
PollIntervalMinUSec=32s
PollIntervalMaxUSec=34min 8s
PollIntervalUSec=1min 4s
NTPMessage={ Leap=0, Version=4, Mode=4, Stratum=2, Precision=-30, RootDelay=3.097ms, RootDispersion=6.774ms, Reference=408E7A25, OriginateTimestamp=Tue 2024-04-02 16:59:33 PDT, ReceiveTimestamp=Tue 2024-04-02 16:59:33 PDT, TransmitTimestamp=Tue 2024-04-02 16:59:33 PDT, DestinationTimestamp=Tue 2024-04-02 16:59:33 PDT, Ignored=no PacketCount=1, Jitter=0 }
Frequency=1375360
timesync-status
$ timedatectl timesync-status
Server: 104.131.155.175 (0.north-america.pool.ntp.org)
Poll interval: 1min 4s (min: 32s; max 34min 8s)
Leap: normal
Version: 4
Stratum: 2
Reference: 408E7A25
Precision: 0 (-30)
Root distance: 8.322ms (max: 5s)
Offset: +4.077ms
Delay: 24.042ms
Jitter: 0
Packet count: 1
Frequency: +20.986ppm
check log
$ journalctl -u systemd-timesyncd --no-hostname --since "1 day ago"
Last updated