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
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"
$ 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