book
  • README
  • cheatsheet
    • bash
      • builtin
      • syntactic sugar
      • cmd
      • havefun
    • text-processing
      • awk
      • sed
      • html
      • json
      • regex
      • unicode
    • osx
    • curl
    • tricky
    • widget
    • proxy
    • colors
    • math
    • media
    • ssl
      • keystore
      • verification
      • server
      • client
      • tricky
    • windows
      • powershell
      • choco
      • wsl
      • wt
      • shortcut
      • clsid
      • env
      • shell:folder
  • vim
    • nvim
    • install
    • color
    • plugins
      • usage
      • other plugins
      • deprecated
    • tricky
    • viml
    • windows
    • troubleshooting
  • devops
    • admin tools
    • ssh
    • git
      • config
      • alias
      • submodule
      • eol
      • example
      • gerrit
        • gerrit API
      • github
      • troubleshooting
      • tricky
      • statistics
    • pre-commit
    • release-tools
    • tmux
      • cheatsheet
    • ansible
    • vault
    • artifactory
      • api
      • cli
      • aql
      • nginx cert
    • klocwork
      • kwadmin
      • kwserver
      • api
      • q&a
    • elk
    • mongodb
    • android
    • mobile
  • jenkins
    • config
      • windows
    • appearance
    • troubleshooting
    • jenkinsfile
      • utility
      • parallel
      • build
      • envvar
      • properties
      • trigger
      • node
    • script
      • job
      • build
      • stage
      • agent
      • security & authorization
      • exception
      • monitor
      • tricky
    • api
      • blueocean
    • cli
    • plugins
      • kubernetes
      • docker
      • shared-libs
      • lockable-resource
      • ansicolor
      • badge
      • groovy-postbuild
      • simple-theme
      • customizable-header
      • artifactory
      • jira-steps
      • job-dsl
      • build-timeline
      • crumbIssuer
      • coverage
      • uno-choice
      • tricky
  • virtualization
    • kubernetes
      • init
        • kubespray
        • kubeadm
          • environment
          • crio v1.30.4
          • docker v1.15.3
          • HA
        • addons
        • etcd
      • kubectl
        • pod
        • deploy
        • replicasets
        • namespace
        • secrets
      • node
      • certificates
      • events
      • kubeconfig
      • kubelet
      • troubleshooting
      • cheatsheet
      • auth
      • api
      • tools
        • monitor
        • helm
        • network
        • minikube
    • docker
      • run & exec
      • voume
      • remove
      • show info
      • dockerfile
      • dockerd
      • tricky
      • troubleshooting
      • windows
    • crio
    • podman
  • ai
    • prompt
  • osx
    • apps
      • init
      • brew
    • defaults
    • system
    • network
    • script
    • tricky
  • linux
    • devenv
    • util
      • time & date
      • output formatting
      • params
      • tricky
    • nutshell
    • disk
    • network
    • troubleshooting
    • system
      • apt/yum/snap
      • authorization
      • apps
      • x11
    • ubuntu
      • systemctl
      • x
    • rpi
  • programming
    • groovy
    • python
      • config
      • basic
      • list
      • pip
      • q&a
    • others
    • archive
      • angular
      • maven
      • mysql
        • installation
        • logs
      • ruby
        • rubyInstallationQ&A
  • tools
    • fonts
    • html & css
    • Jira & Confluence
    • node & npm
      • gitbook
      • hexo
      • github.page
      • code themes
    • app
      • microsoft office
      • vscode
      • virtualbox
      • iterm2
      • browser
      • skype
      • teamviewer
      • others
  • quotes
  • english
Powered by GitBook
On this page
  • timezone
  • date
  • convert
  • chrony
  • systemd-timesyncd

Was this helpful?

  1. linux
  2. util

time & date

PreviousutilNextoutput formatting

Last updated 7 months ago

Was this helpful?

references:

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

  • 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 year

  • 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

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

    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:]

  • 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
  • $ 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
  • $ 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
$ 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]

    • $ 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:]

    • 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 上海交通大学

  • /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"

[!NOTE|label:references:]

is required to build docs

|

* imarslo: groovy time
Unix_time
apt-get install tzdata noninteractive
Cingulata/Dockerfile.bfv
setting it via ENV should be actively discouraged
apt-get install tzdata noninteractive
What is epoch time?
tzdb timezone descriptions
Shell command: date
Most common Bash date commands for timestamping
via awk
Convert unix timestamp to hh:mm:ss:SSS (where SSS is milliseconds)
CST to UTC conversion
convert to another timezone
convert to different timezone with daylight saving
another
How to find the difference in days between two dates?
simple one-liner
since now
asciidoctor 2.0.22
asciidoctor
chrony配置
时钟同步
CentOS使用Chrony部署内网NTP时间服务器
Chrony详解:代替ntp的时间同步服务
Systemd and ntpd problems
ntp pool project
授时中心
North America — north-america.pool.ntp.org
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
chrony 详解
systemd-timesyncd
* iMarslo: epel install
NTP Pool Project
timesyncd.conf
systemd-timesyncd.service
timezone
timezone setup
tzdata installation with noninteractive
date
epoch
timestamps
format
IOS 8601
rfc-3339
utc
timezone
common formats
convert
timestamps to epoch
epoch to timestamps
convert in different timezone
get daylight saving
how many days from timestamps
calculate time different
transfer date format
since now
chrony
install
conf
commands
/usr/libexec/chrony-helper
set local time with chrony
systemd-timesyncd
install
config
commands
* iMarslo: clock/date/time