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
- What is epoch time?
$ 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
yyyy-MM-dd'T'HH:mm:ss
DATE FORMAT OPTION | MEANING | EXAMPLE OUTPUT |
---|---|---|
date +%c |
locale’s date time | Sat May 9 11:49:47 2020 |
date +%x |
locale’s date | 05/09/20 |
date +%X |
locale’s time | 11:49:47 |
date +%A |
locale’s full weekday name | Saturday |
date +%B |
locale’s full month name | May |
date +%m-%d-%Y |
MM-DD-YYYY date format | 05-09-2020 |
date +%D |
MM/DD/YY date format | 05/09/20 |
date +%F |
YYYY-MM-DD date format | 2020-05-09 |
date +%T |
HH:MM:SS time format | 11:44:15 |
date +%u |
Day of Week | 6 |
date +%U |
Week of Year with Sunday as first day of week | 18 |
date +%V |
ISO Week of Year with Monday as first day of week | 19 |
date +%j |
Day of Year | 130 |
date +%Z |
Timezone | PDT |
date +%m |
Month of year (MM) | 05 |
date +%d |
Day of Month (DD) | 09 |
date +%Y |
Year (YY) | 2020 |
date +%H |
Hour (HH) | 11 |
date +%H |
Hour (HH) in 24-hour clock format | 11 |
date +%I |
Hour in 12-hour clock format | 11 |
date +%p |
locale’s equivalent of AM or PM | AM |
date +%P |
same as %p but in lower case | am |
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
FORMAT EXAMPLE YYYY 2015 YYYY-MM 2015-12 YYYY-MM-DD 2015-12-11 YYYY-MM-DD'T'hh:mmTZD 2015-12-11T20:28+01:00 or 2015-12-11T19:28Z YYYY-MM-DD'T'hh:mm:ssTZD 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:
YYYY
= four-digit yearMM
= 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/
- tzdb timezone descriptions
$ 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 |
---|---|---|
YYYY-MM-DD |
date -I |
2020-10-09 |
YYYY-MM-DD_hh:mm:ss |
date +%F_%T |
2020-10-09_16:48:45 |
YYYYMMDD_hhmmss |
date +%Y%m%d_%H%M%S |
20201009_164845 |
YYYYMMDD_hhmmss (UTC version) |
date --utc +%Y%m%d_%H%M%SZ |
20201009_084845Z |
YYYYMMDD_hhmmss (with local TZ) |
date +%Y%m%d_%H%M%S%Z |
20201009_164845CST |
YYYYMMSShhmmss |
date +%Y%m%d%H%M%S |
20201009164845 |
YYYYMMSShhmmssnnnnnnnnn |
date +%Y%m%d%H%M%S%N |
20201009164845495302000 |
YYMMDD_hhmmss |
date +%y%m%d_%H%M%S |
201009_164845 |
Seconds since UNIX epoch: |
date +%s |
1602233325 |
Nanoseconds only: |
date +%N |
505337000 |
Nanoseconds since UNIX epoch: |
date +%s%N |
1602233325508581000 |
Nanoseconds since UNIX epoch: |
date +%s%3N |
1602233325508 |
ISO8601 UTC timestamp |
date --utc +%FT%TZ |
2020-10-09T08:48:45Z |
ISO8601 UTC timestamp |
date --utc +%FT%T%Z |
2020-10-09T08:48:45UTC |
ISO8601 UTC timestamp + ms |
date --utc +%FT%T.%3NZ |
2020-10-09T08:48:45.517Z |
ISO8601 UTC timestamp + ms |
date --utc +%FT%T.%3N%Z |
2020-10-09T08:48:45.520UTC |
ISO8601 Local TZ timestamp |
date +%FT%T%Z |
2020-10-09T16:48:45CST |
YYYY-MM-DD (Short day) |
date +%F\(%a\) |
2020-10-09(Fri) |
YYYY-MM-DD (Long day) |
date +%F\(%A\) |
2020-10-09(Friday) |
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 |
---|---|
1 hour | 3600 seconds |
1 day | 86400 seconds |
1 week | 604800 seconds |
1 month (30.44 days) | 2629743 seconds |
1 year (365.24 days) | 31556926 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
-
$ 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 epoch with milliseconds
Convert unix timestamp to hh:mm:ss:SSS (where SSS is milliseconds)
d=$(date +%s%3N) s=${d%???} ms=${d#"$s"} date -d "@$s" +"%F %T.$ms %z"
result
2020-10-09 18:28:34.534 +0800 d: 1602239314534 s: 1602239314 ms: 534
convert in different timezone
[!NOTE|label:references:]
- CST to UTC conversion
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
-
$ 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
since now
$ 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 2.0.22
- 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:]
- chrony配置
- 时钟同步
- CentOS使用Chrony部署内网NTP时间服务器
- Chrony详解:代替ntp的时间同步服务
- Systemd and ntpd problems
- ntp pool project | 授时中心
- North America — north-america.pool.ntp.org
210.72.145.44
国家授时中心ntp.aliyun.com
阿里云s1a.time.edu.cn
北京邮电大学s1b.time.edu.cn
清华大学s1c.time.edu.cn
北京大学s1d.time.edu.cn
东南大学s1e.time.edu.cn
清华大学s2a.time.edu.cn
清华大学s2b.time.edu.cn
清华大学s2c.time.edu.cn
北京邮电大学s2d.time.edu.cn
西南地区网络中心s2e.time.edu.cn
西北地区网络中心s2f.time.edu.cn
东北地区网络中心s2g.time.edu.cn
华东南地区网络中心s2h.time.edu.cn
四川大学网络管理中心s2j.time.edu.cn
大连理工大学网络中心s2k.time.edu.cn
CERNET桂林主节点s2m.time.edu.cn
北京大学ntp.sjtu.edu.cn
|202.120.2.101
上海交通大学- How to configure chrony as an NTP client or server in Linux
- RedHat 7: Chapter 18. Configuring NTP Using the chrony Suite
- RedHad 8: Chapter 15. Configuring time synchronization
- RedHat 9: Chapter 13. Configuring time synchronization
- How to Sync Time in CentOS 8 using Chrony
/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
- systemd-timesyncd
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"