-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlibtime
123 lines (107 loc) · 3.28 KB
/
libtime
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#!/usr/bin/env bash
# shellcheck disable=SC1091
. bpm
bpm::include assign
# Get a timestamp (seconds only).
#
# $1 - Destination variable name.
#
# Examples
#
# time::stamp seconds
# echo "$seconds" # 1499716539
#
# Returns nothing.
time::stamp() {
local "${1-}" && assign::value "$1" "$(date +%s)"
}
# Determine the difference between two timestamps. Works with low resolution
# and high resolution time stamps.
#
# $1 - Destination variable name.
# $2 - Starting time (the smaller number).
# $3 - Ending time.
#
# The time is limited to an accuracy of 9 digits beyond the decimal point
# because Bash can be compiled to use 32-bit math, whose limit is a signed
# 2147483648, easily holding 9 digits. It also works when we have to hold
# the extra digit from carrying a 1 from the whole numbers.
#
# Examples
#
# time::stampDiff result 1499716539 1499716649.266348007
# echo "$result" # 110.266348007
#
# Returns nothing.
time::stampDiff() {
local end len start result
# Adding a dot at the end to ensure we have at least 2 entries in
# the resulting arrays.
start="$2."
start=( "${start%%.*}" "${start#*.}" )
start[1]="${start[1]%.}"
end="$3."
end=( "${end%%.*}" "${end#*.}" )
end[1]="${end[1]%.}"
len="${#start[1]}"
if [[ "${#end[1]}" -gt "$len" ]]; then
len="${#end[1]}"
fi
# Calculate the seconds of difference.
result="$((end[0] - start[0]))"
# Only calculate this if there are decimals.
if [[ "$len" -gt 0 ]]; then
# Pad the right side of the strings to make them even.
# This simplifies subtraction. printf is not used here because
# we could get unreasonably large numbers and we don't want to error.
while [[ "${#start[1]}" -lt "$len" ]]; do
start[1]+=0
done
while [[ "${#end[1]}" -lt "$len" ]]; do
end[1]+=0
done
# Only care about 9 digits after the decimal.
# Lead with a "1" to avoid treating numbers like 059141135 as octal.
start[1]="1${start[1]:0:9}"
end[1]="1${end[1]:0:9}"
if [[ "${end[1]}" -lt "${start[1]}" ]]; then
# Need to borrow from the whole seconds
end[1]="2${end[1]:1:9}"
result=$((result - 1))
fi
printf -v result "%s.%0${len}d" "$result" "$((end[1] - start[1]))"
fi
local "${1-}" && assign::value "$1" "$result"
}
# Get a high-resolution timestamp, at least at millisecond resolution.
#
# $1 - Destination variable name.
#
# Examples
#
# # Bash 3.x and 4.x
# time::stampHr timestamp
# echo "$timestamp" # 1499716649.266348007
#
# # Bash 5.x (much, much faster)
# time::stampHr timestamp
# echo "$timestamp" # 1551362098.463254
#
# Returns nothing.
if [[ -n "$EPOCHREALTIME" ]]; then
# Slightly less precision, significant speed increase
# EPOCHREALTIME=1551362098.463254
time::stampHr() {
local "${1-}" && assign::value "$1" "$EPOCHREALTIME"
}
elif [[ "$(date +%N)" == "N" ]]; then
# BSD version of date. Fall back to Python
time::stampHr() {
local "${1-}" && assign::value "$1" "$(python -c 'from time import time; print "%.9f" % time();')"
}
else
# GNU version of date. Faster.
time::stampHr() {
local "${1-}" && assign::value "$1" "$(date +%s.%N)"
}
fi