๐Ÿ”ข Bash Specialty: Arithmetic, Dates & Time

Comprehensive Reference Guide โ€” Detailed examples with explanations for system administrators

๐Ÿ“‹ Table of Contents

Overview

Bash provides powerful built-in capabilities for arithmetic operations and date/time manipulation. This guide covers the essential techniques every Linux system administrator needs to master, from basic calculations to complex date arithmetic used in log rotation, backup scheduling, and system monitoring scripts.

Key Concepts

Arithmetic: Bash supports integer arithmetic natively through $(( )), let, and expr. For floating-point math, use bc or awk.

Date/Time: The date command is incredibly versatile, supporting format strings, date arithmetic, parsing, and timezone conversions.

Part 1: Bash Arithmetic Operations

Arithmetic Syntax Methods

MethodSyntaxUse CaseNotes
$(( ))result=$((5 + 3))Most common, recommendedPOSIX compliant, returns value
letlet result=5+3Variable assignmentNo spaces around operators
exprresult=$(expr 5 + 3)Legacy scriptsRequires spaces, slower
bcecho "5.5 + 3.2" | bcFloating-point mathExternal command, very powerful

Arithmetic Operators

OperatorDescriptionExampleResult
+Addition$((5 + 3))8
-Subtraction$((10 - 4))6
*Multiplication$((6 * 7))42
/Division (integer)$((17 / 5))3
%Modulo (remainder)$((17 % 5))2
**Exponentiation$((2 ** 10))1024
++Increment$((i++))i + 1
--Decrement$((i--))i - 1
<<Bit shift left$((1 << 4))16
>>Bit shift right$((16 >> 2))4
&Bitwise AND$((12 & 10))8
|Bitwise OR$((12 | 10))14

Arithmetic Examples

1
Basic Arithmetic with Variables

Fundamental arithmetic operations commonly used in system scripts.

#!/bin/bash
# Basic arithmetic operations with variables

a=15
b=4

sum=$((a + b))
diff=$((a - b))
product=$((a * b))
quotient=$((a / b))
remainder=$((a % b))

echo "Variables: a=$a, b=$b"
echo "Sum: $sum"
echo "Difference: $diff"
echo "Product: $product"
echo "Quotient: $quotient (integer division)"
echo "Remainder: $remainder"

# Exponentiation
power=$((2 ** 8))
echo "2^8 = $power"

# Compound operations
compound=$(( (a + b) * 2 - a / b ))
echo "Compound: $compound"
Output: Variables: a=15, b=4 Sum: 19 Difference: 11 Product: 60 Quotient: 3 (integer division) Remainder: 3 2^8 = 256 Compound: 35
โš ๏ธ Integer Division
Bash arithmetic only handles integers. 15 / 4 = 3, not 3.75. For floating-point, use bc.
2
Increment/Decrement and Assignment Operators
#!/bin/bash
# Increment, decrement, and compound assignment

count=10
echo "Initial: $count"

# Post-increment (use then increment)
echo "Post-increment: $((count++))"
echo "After: $count"

# Pre-increment (increment then use)
echo "Pre-increment: $((++count))"

# Compound assignments
value=100
((value += 25))
echo "After += 25: $value"

((value *= 2))
echo "After *= 2: $value"

((value /= 5))
echo "After /= 5: $value"
Output: Initial: 10 Post-increment: 10 After: 11 Pre-increment: 12 After += 25: 125 After *= 2: 250 After /= 5: 50
3
Floating-Point Arithmetic with bc
#!/bin/bash
# Floating-point arithmetic with bc

# Basic division
result=$(echo "scale=2; 15 / 4" | bc)
echo "15 / 4 = $result"

# Percentage calculation
total=847
used=523
percent=$(echo "scale=2; ($used / $total) * 100" | bc)
echo "Usage: ${percent}%"

# Square root
sqrt=$(echo "scale=4; sqrt(2)" | bc)
echo "sqrt(2) = $sqrt"

# Pi calculation
pi=$(echo "scale=10; 4*a(1)" | bc -l)
echo "Pi = $pi"

# Disk usage example
disk_total=500000000000
disk_used=327000000000
disk_percent=$(echo "scale=1; ($disk_used / $disk_total) * 100" | bc)
echo "Disk: ${disk_percent}%"
Output: 15 / 4 = 3.75 Usage: 61.74% sqrt(2) = 1.4142 Pi = 3.1415926532 Disk: 65.4%
4
Bitwise Operations for System Administration
#!/bin/bash
# Bitwise operations for permissions and flags

# Permission bits
read_bit=4
write_bit=2
exec_bit=1

rwx=$((read_bit | write_bit | exec_bit))
rw=$((read_bit | write_bit))
echo "rwx = $rwx, rw = $rw"

# Check permission
perms=5  # r-x
if (( perms & write_bit )); then
    echo "Write IS set"
else
    echo "Write NOT set"
fi

# Powers of 2 with shift
for i in {0..7}; do
    echo "2^$i = $((1 << i))"
done

# Network mask from CIDR
cidr=24
mask=$(( 0xFFFFFFFF << (32 - cidr) ))
echo "/$cidr mask: $(( (mask >> 24) & 0xFF )).$(( (mask >> 16) & 0xFF )).$(( (mask >> 8) & 0xFF )).$(( mask & 0xFF ))"
Output: rwx = 7, rw = 6 Write NOT set 2^0 = 1 2^1 = 2 2^2 = 4 ... /24 mask: 255.255.255.0
5
Arithmetic in Loops and Arrays
#!/bin/bash
# Arithmetic in loops and arrays

# C-style for loop - sum 1 to 10
sum=0
for ((i=1; i<=10; i++)); do
    ((sum += i))
done
echo "Sum 1-10: $sum"

# Array statistics
data=(23 45 67 89 12 34 56 78 90 11)
count=${#data[@]}
sum=0
min=${data[0]}
max=${data[0]}

for val in "${data[@]}"; do
    ((sum += val))
    ((val < min)) && min=$val
    ((val > max)) && max=$val
done

avg=$(echo "scale=2; $sum / $count" | bc)
echo "Count: $count, Sum: $sum"
echo "Min: $min, Max: $max, Avg: $avg"

# Fibonacci
fib[0]=0; fib[1]=1
for ((i=2; i<10; i++)); do
    ((fib[i] = fib[i-1] + fib[i-2]))
done
echo "Fibonacci: ${fib[*]}"
Output: Sum 1-10: 55 Count: 10, Sum: 505 Min: 11, Max: 90, Avg: 50.50 Fibonacci: 0 1 1 2 3 5 8 13 21 34
6
Arithmetic Comparisons and Conditionals
#!/bin/bash
# Arithmetic comparisons

value=42

# Using (( )) for tests
if ((value > 40)); then
    echo "$value > 40 is TRUE"
fi

# Range check
if ((value >= 40 && value <= 50)); then
    echo "$value is in range 40-50"
fi

# Practical: disk warning
disk=78
if ((disk >= 90)); then
    echo "CRITICAL: ${disk}%"
elif ((disk >= 70)); then
    echo "WARNING: ${disk}%"
else
    echo "OK: ${disk}%"
fi

# Divisibility (FizzBuzz style)
for n in {1..15}; do
    if ((n % 3 == 0 && n % 5 == 0)); then
        echo "$n: FizzBuzz"
    elif ((n % 3 == 0)); then
        echo "$n: Fizz"
    elif ((n % 5 == 0)); then
        echo "$n: Buzz"
    fi
done
Output: 42 > 40 is TRUE 42 is in range 40-50 WARNING: 78% 3: Fizz 5: Buzz 6: Fizz ... 15: FizzBuzz
7
Number Base Conversions
#!/bin/bash
# Number base conversions

# Different base inputs
echo "Decimal 255: 255"
echo "Hex 0xFF: $((0xFF))"
echo "Octal 0377: $((0377))"
echo "Binary 2#11111111: $((2#11111111))"

# Decimal to other bases
value=200
printf "Decimal %d = Hex %X = Octal %o\n" $value $value $value

# IP to integer
ip="192.168.1.100"
IFS='.' read -r a b c d <<< "$ip"
int=$(( (a << 24) + (b << 16) + (c << 8) + d ))
printf "IP %s = %d\n" "$ip" "$int"

# Chmod octal to symbolic
for perm in 755 644 700; do
    mode=$((8#$perm))
    sym=""
    for i in 0 1 2; do
        d=$(( (mode >> (2-i)*3) & 7 ))
        ((d & 4)) && sym+="r" || sym+="-"
        ((d & 2)) && sym+="w" || sym+="-"
        ((d & 1)) && sym+="x" || sym+="-"
    done
    echo "$perm = $sym"
done
Output: Decimal 255: 255 Hex 0xFF: 255 Octal 0377: 255 Binary 2#11111111: 255 Decimal 200 = Hex C8 = Octal 310 IP 192.168.1.100 = 3232235876 755 = rwxr-xr-x 644 = rw-r--r-- 700 = rwx------
8
Random Numbers and Practical Calculations
#!/bin/bash
# Random numbers and conversions

# Random in range
echo "Random 1-100: $(( RANDOM % 100 + 1 ))"
echo "Random die: $(( RANDOM % 6 + 1 ))"

# Bytes to human readable
bytes_to_human() {
    local b=$1
    local units=("B" "KB" "MB" "GB" "TB")
    local u=0
    while ((b >= 1024 && u < 4)); do
        b=$(echo "scale=2; $b / 1024" | bc)
        ((u++))
    done
    echo "$b ${units[$u]}"
}

echo "1048576 bytes = $(bytes_to_human 1048576)"
echo "5368709120 bytes = $(bytes_to_human 5368709120)"

# Seconds to human
secs=90061
days=$((secs / 86400))
hrs=$(( (secs % 86400) / 3600 ))
mins=$(( (secs % 3600) / 60 ))
echo "$secs seconds = ${days}d ${hrs}h ${mins}m"

# Percentage change
old=150; new=180
change=$((new - old))
pct=$(echo "scale=1; ($change * 100) / $old" | bc)
echo "Change: $old โ†’ $new = ${pct}%"
Output: Random 1-100: 67 Random die: 4 1048576 bytes = 1.00 MB 5368709120 bytes = 5.00 GB 90061 seconds = 1d 1h 1m Change: 150 โ†’ 180 = 20.0%
9
Using awk for Advanced Arithmetic
#!/bin/bash
# Advanced arithmetic with awk

# Basic
echo | awk '{print "15/4 =", 15/4}'
echo | awk '{print "2^10 =", 2^10}'

# Math functions
awk 'BEGIN {
    print "sin(1) =", sin(1)
    print "sqrt(2) =", sqrt(2)
    print "exp(1) =", exp(1)
}'

# Statistics from data
echo "23 45 67 89 12" | tr ' ' '\n' | awk '
{
    sum += $1
    count++
    if (NR==1 || $1 < min) min=$1
    if (NR==1 || $1 > max) max=$1
}
END {
    print "Count:", count
    print "Sum:", sum
    print "Mean:", sum/count
    print "Min:", min, "Max:", max
}'
Output: 15/4 = 3.75 2^10 = 1024 sin(1) = 0.841471 sqrt(2) = 1.41421 exp(1) = 2.71828 Count: 5 Sum: 236 Mean: 47.2 Min: 12 Max: 89
10
System Resource Calculator
#!/bin/bash
# System resource calculations

echo "=== Memory Analysis ==="
total_kb=16384000
used_kb=12582912
free_kb=$((total_kb - used_kb))

total_gb=$(echo "scale=2; $total_kb / 1048576" | bc)
used_pct=$(echo "scale=1; ($used_kb * 100) / $total_kb" | bc)

echo "Total: ${total_gb} GB"
echo "Used: ${used_pct}%"

if (( $(echo "$used_pct > 90" | bc -l) )); then
    echo "Status: CRITICAL"
elif (( $(echo "$used_pct > 75" | bc -l) )); then
    echo "Status: WARNING"
else
    echo "Status: OK"
fi

echo ""
echo "=== CPU Load ==="
cores=8
load=4.25
util=$(echo "scale=0; ($load * 100) / $cores" | bc)
echo "Load: $load on $cores cores = ${util}%"

echo ""
echo "=== Network Rate ==="
rx_start=10485760000
rx_end=10737418240
interval=60
rx_rate=$(( (rx_end - rx_start) / interval ))
rx_mbps=$(echo "scale=2; ($rx_rate * 8) / 1000000" | bc)
echo "RX: $rx_mbps Mbps"
Output: === Memory Analysis === Total: 15.62 GB Used: 76.8% Status: WARNING === CPU Load === Load: 4.25 on 8 cores = 53% === Network Rate === RX: 33.55 Mbps

Part 2: Dates & Time Operations

Quick Reference

date โ€” Display current date/time
date +FORMAT โ€” Custom format
date -d "STRING" โ€” Parse date string
date -d "DATE +/- OFFSET" โ€” Date arithmetic

Common Format Specifiers

SpecifierDescriptionExample
%Y4-digit year2025
%mMonth (01-12)11
%dDay (01-31)18
%HHour (00-23)14
%MMinute (00-59)30
%SSecond (00-59)45
%AFull weekdayTuesday
%BFull monthNovember
%sUnix epoch1731958245
%ZTimezoneEST
%zTZ offset-0500

Date & Time Examples

1
Basic Date Formatting
#!/bin/bash
# Basic date formatting

echo "Default: $(date)"
echo "UTC: $(date -u)"

# Common formats
echo "ISO 8601: $(date +%Y-%m-%dT%H:%M:%S%z)"
echo "ISO Date: $(date +%Y-%m-%d)"
echo "US Date: $(date +%m/%d/%Y)"
echo "EU Date: $(date +%d/%m/%Y)"

# For filenames
echo "Filename: $(date +%Y%m%d_%H%M%S)"
echo "Daily: $(date +%Y-%m-%d)"

# Time formats
echo "24-hour: $(date +%H:%M:%S)"
echo "12-hour: $(date '+%I:%M:%S %p')"

# Special
echo "Epoch: $(date +%s)"
echo "Week: $(date +%W)"
echo "Day of year: $(date +%j)"

# Practical
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Log message"
echo "backup-$(date +%Y%m%d-%H%M%S).tar.gz"
Output: Default: Tue Nov 18 14:30:45 EST 2025 UTC: Tue Nov 18 19:30:45 UTC 2025 ISO 8601: 2025-11-18T14:30:45-0500 ISO Date: 2025-11-18 US Date: 11/18/2025 EU Date: 18/11/2025 Filename: 20251118_143045 24-hour: 14:30:45 12-hour: 02:30:45 PM Epoch: 1731958245 [2025-11-18 14:30:45] Log message backup-20251118-143045.tar.gz
2
Date Arithmetic
#!/bin/bash
# Date arithmetic with -d

echo "Today: $(date '+%Y-%m-%d')"

# Adding time
echo "Tomorrow: $(date -d 'tomorrow' '+%Y-%m-%d')"
echo "+3 days: $(date -d '+3 days' '+%Y-%m-%d')"
echo "+1 week: $(date -d '+1 week' '+%Y-%m-%d')"
echo "+1 month: $(date -d '+1 month' '+%Y-%m-%d')"
echo "+1 year: $(date -d '+1 year' '+%Y-%m-%d')"

# Subtracting
echo "Yesterday: $(date -d 'yesterday' '+%Y-%m-%d')"
echo "-7 days: $(date -d '-7 days' '+%Y-%m-%d')"
echo "-30 days: $(date -d '-30 days' '+%Y-%m-%d')"
echo "-3 months: $(date -d '-3 months' '+%Y-%m-%d')"

# Time arithmetic
echo "+2 hours: $(date -d '+2 hours' '+%H:%M:%S')"
echo "-30 min: $(date -d '-30 minutes' '+%H:%M:%S')"

# Retention dates
echo "Delete before:"
echo "  7 days: $(date -d '-7 days' '+%Y-%m-%d')"
echo "  30 days: $(date -d '-30 days' '+%Y-%m-%d')"
echo "  90 days: $(date -d '-90 days' '+%Y-%m-%d')"
Output: Today: 2025-11-18 Tomorrow: 2025-11-19 +3 days: 2025-11-21 +1 week: 2025-11-25 +1 month: 2025-12-18 Yesterday: 2025-11-17 -7 days: 2025-11-11 -30 days: 2025-10-19 +2 hours: 16:30:45 Delete before: 7 days: 2025-11-11 30 days: 2025-10-19 90 days: 2025-08-20
3
Parsing and Converting Dates
#!/bin/bash
# Date parsing and conversion

# Various input formats
echo "From 'Nov 18, 2025': $(date -d 'Nov 18, 2025' '+%Y-%m-%d')"
echo "From '11/18/2025': $(date -d '11/18/2025' '+%Y-%m-%d')"
echo "From '2025-11-18': $(date -d '2025-11-18' '+%Y-%m-%d')"

# Format conversion
us_date="11/18/2025"
iso=$(date -d "$us_date" '+%Y-%m-%d')
echo "US โ†’ ISO: $us_date โ†’ $iso"

# Epoch conversions
epoch=$(date +%s)
echo "Now: $epoch"
echo "From epoch: $(date -d @1731958245 '+%Y-%m-%d %H:%M:%S')"

human="2025-11-18 14:30:45"
to_epoch=$(date -d "$human" '+%s')
echo "'$human' โ†’ $to_epoch"

# Parse syslog format
syslog="Nov 18 14:30:45"
parsed=$(date -d "$syslog" '+%Y-%m-%d %H:%M:%S')
echo "Syslog: $syslog โ†’ $parsed"
Output: From 'Nov 18, 2025': 2025-11-18 From '11/18/2025': 2025-11-18 From '2025-11-18': 2025-11-18 US โ†’ ISO: 11/18/2025 โ†’ 2025-11-18 Now: 1731958245 From epoch: 2025-11-18 14:30:45 '2025-11-18 14:30:45' โ†’ 1731958245 Syslog: Nov 18 14:30:45 โ†’ 2025-11-18 14:30:45
๐Ÿ’ก Epoch Parsing
Use @ prefix for epoch: date -d @1731958245
4
Calculating Time Differences
#!/bin/bash
# Time difference calculations

date1="2025-01-01"
date2="2025-11-18"

epoch1=$(date -d "$date1" '+%s')
epoch2=$(date -d "$date2" '+%s')
diff=$((epoch2 - epoch1))

echo "From $date1 to $date2:"
echo "  $((diff / 86400)) days"
echo "  $((diff / 3600)) hours"

# Age calculation
birth="1982-06-25"
today=$(date '+%Y-%m-%d')
age_days=$(( ($(date -d "$today" '+%s') - $(date -d "$birth" '+%s')) / 86400 ))
echo "Age: $((age_days / 365)) years"

# Days until event
event="2025-12-25"
now=$(date '+%s')
event_epoch=$(date -d "$event" '+%s')
days=$(( (event_epoch - now) / 86400 ))
echo "Days until $event: $days"

# Script timing
start=$(date '+%s')
sleep 1
end=$(date '+%s')
echo "Elapsed: $((end - start)) seconds"
Output: From 2025-01-01 to 2025-11-18: 321 days 7704 hours Age: 43 years Days until 2025-12-25: 37 Elapsed: 1 seconds
5
Working with Timezones
#!/bin/bash
# Timezone operations

echo "Local: $(date '+%H:%M %Z')"
echo "UTC: $(TZ=UTC date '+%H:%M %Z')"

echo ""
echo "US Timezones:"
echo "  Eastern: $(TZ=America/New_York date '+%H:%M %Z')"
echo "  Central: $(TZ=America/Chicago date '+%H:%M %Z')"
echo "  Mountain: $(TZ=America/Denver date '+%H:%M %Z')"
echo "  Pacific: $(TZ=America/Los_Angeles date '+%H:%M %Z')"

echo ""
echo "International:"
echo "  London: $(TZ=Europe/London date '+%H:%M %Z')"
echo "  Tokyo: $(TZ=Asia/Tokyo date '+%H:%M %Z')"

# Convert specific time
eastern="2025-11-18 14:00:00"
epoch=$(TZ=America/New_York date -d "$eastern" '+%s')
echo ""
echo "Meeting: $eastern Eastern"
echo "  Pacific: $(TZ=America/Los_Angeles date -d @$epoch '+%H:%M %Z')"
echo "  UTC: $(TZ=UTC date -d @$epoch '+%H:%M %Z')"
echo "  Tokyo: $(TZ=Asia/Tokyo date -d @$epoch '+%H:%M %Z (%Y-%m-%d)')"
Output: Local: 14:30 EST UTC: 19:30 UTC US Timezones: Eastern: 14:30 EST Central: 13:30 CST Mountain: 12:30 MST Pacific: 11:30 PST International: London: 19:30 GMT Tokyo: 04:30 JST Meeting: 2025-11-18 14:00:00 Eastern Pacific: 11:00 PST UTC: 19:00 UTC Tokyo: 04:00 JST (2025-11-19)
6
Weekday Operations
#!/bin/bash
# Weekday operations

echo "Today: $(date '+%A') ($(date '+%u'))"

# Find weekdays
echo "Next Monday: $(date -d 'next monday' '+%Y-%m-%d')"
echo "Last Friday: $(date -d 'last friday' '+%Y-%m-%d')"

# Check weekend
dow=$(date '+%u')
if ((dow >= 6)); then
    echo "It's the weekend!"
else
    echo "It's a weekday"
fi

# First/last of month
echo "First of month: $(date -d "$(date '+%Y-%m-01')" '+%Y-%m-%d (%A)')"
echo "Last of month: $(date -d "$(date '+%Y-%m-01') +1 month -1 day" '+%Y-%m-%d (%A)')"

# Business days check
is_weekend() {
    (($(date -d "$1" '+%u') >= 6))
}

# Count business days
start="2025-11-01"
end="2025-11-18"
bdays=0
curr="$start"
while [[ "$curr" < "$end" ]]; do
    is_weekend "$curr" || ((bdays++))
    curr=$(date -d "$curr +1 day" '+%Y-%m-%d')
done
echo "Business days $start to $end: $bdays"
Output: Today: Tuesday (2) Next Monday: 2025-11-24 Last Friday: 2025-11-14 It's a weekday First of month: 2025-11-01 (Saturday) Last of month: 2025-11-30 (Sunday) Business days 2025-11-01 to 2025-11-18: 11
7
Log Rotation and File Dating
#!/bin/bash
# Log rotation filenames

echo "=== Filename Formats ==="
echo "Daily: app-$(date '+%Y-%m-%d').log"
echo "Hourly: app-$(date '+%Y-%m-%d_%H').log"
echo "Full: app-$(date '+%Y%m%d_%H%M%S').log"
echo "Weekly: app-$(date '+%Y-W%W').log"
echo "Monthly: app-$(date '+%Y-%m').log"

echo ""
echo "=== Rotation Names ==="
base="application.log"
for i in {1..5}; do
    echo "${base}.$(date -d "-$i days" '+%Y-%m-%d')"
done

echo ""
echo "=== Backup Naming ==="
echo "Daily: backup-$(date '+%Y-%m-%d').tar.gz"
echo "Weekly: backup-$(date -d 'last sunday' '+%Y-%m-%d').tar.gz"
echo "Monthly: backup-$(date '+%Y-%m').tar.gz"

echo ""
echo "=== Cleanup Schedule ==="
echo "Delete daily older than: $(date -d '-7 days' '+%Y-%m-%d')"
echo "Delete weekly older than: $(date -d '-4 weeks' '+%Y-%m-%d')"
echo "Delete monthly older than: $(date -d '-12 months' '+%Y-%m-%d')"
Output: === Filename Formats === Daily: app-2025-11-18.log Hourly: app-2025-11-18_14.log Full: app-20251118_143045.log === Rotation Names === application.log.2025-11-17 application.log.2025-11-16 application.log.2025-11-15 ... === Cleanup Schedule === Delete daily older than: 2025-11-11 Delete weekly older than: 2025-10-21 Delete monthly older than: 2024-11-18
8
Relative Date Expressions
#!/bin/bash
# Natural language dates

echo "=== Basic ==="
echo "now: $(date -d 'now' '+%Y-%m-%d %H:%M')"
echo "today: $(date -d 'today' '+%Y-%m-%d')"
echo "yesterday: $(date -d 'yesterday' '+%Y-%m-%d')"
echo "tomorrow: $(date -d 'tomorrow' '+%Y-%m-%d')"

echo ""
echo "=== Time Terms ==="
echo "noon: $(date -d 'noon' '+%H:%M')"
echo "midnight: $(date -d 'midnight' '+%H:%M')"

echo ""
echo "=== Complex ==="
echo "3 days ago: $(date -d '3 days ago' '+%Y-%m-%d')"
echo "2 weeks hence: $(date -d '2 weeks hence' '+%Y-%m-%d')"
echo "next year: $(date -d 'next year' '+%Y-%m-%d')"

echo ""
echo "=== Report Periods ==="
echo "Today: $(date '+%Y-%m-%d')"
echo "This week: $(date -d 'last monday' '+%Y-%m-%d') to $(date -d 'next sunday' '+%Y-%m-%d')"
echo "This month: $(date '+%Y-%m-01') to $(date -d "$(date '+%Y-%m-01') +1 month -1 day" '+%Y-%m-%d')"

echo ""
echo "=== Quarter ==="
month=$(date '+%-m')
quarter=$(( (month - 1) / 3 + 1 ))
echo "Current: Q$quarter"
Output: === Basic === now: 2025-11-18 14:30 today: 2025-11-18 yesterday: 2025-11-17 tomorrow: 2025-11-19 === Time Terms === noon: 12:00 midnight: 00:00 === Report Periods === Today: 2025-11-18 This week: 2025-11-17 to 2025-11-23 This month: 2025-11-01 to 2025-11-30 === Quarter === Current: Q4
9
High-Precision Timing
#!/bin/bash
# Nanosecond timing

echo "Epoch: $(date '+%s')"
echo "With ns: $(date '+%s%N')"
echo "Milliseconds: $(date '+%s%3N')"

# Benchmark function
benchmark() {
    local start=$(date '+%s%N')
    "$@"
    local end=$(date '+%s%N')
    local ms=$(( (end - start) / 1000000 ))
    echo "Elapsed: ${ms}ms"
}

benchmark sleep 0.1

# Code timing
start=$(date '+%s%N')
for i in {1..1000}; do echo "$i" > /dev/null; done
end=$(date '+%s%N')
echo "Loop: $(( (end - start) / 1000 )) ยตs"

# Unique IDs
echo "ID: $(date '+%s%N')-$$-$RANDOM"

# Using SECONDS
SECONDS=0
sleep 1
echo "SECONDS: $SECONDS"
Output: Epoch: 1731958245 With ns: 1731958245123456789 Milliseconds: 1731958245123 Elapsed: 100ms Loop: 2100 ยตs ID: 1731958245123456789-12345-28463 SECONDS: 1
๐Ÿ’ก SECONDS Variable
Bash's $SECONDS counts since shell start. Reset with SECONDS=0.
10
System Maintenance Scheduler
#!/bin/bash
# Maintenance scheduler

echo "=== Current Time ==="
echo "Local: $(date '+%Y-%m-%d %H:%M:%S %Z')"
echo "UTC: $(date -u '+%Y-%m-%d %H:%M:%S %Z')"
echo "Day: $(date '+%j')/365, Week: $(date '+%W')/52"

echo ""
echo "=== Maintenance Window ==="
hour=$(date '+%H')
dow=$(date '+%u')

if ((dow >= 6)); then
    echo "โœ“ Weekend - extended window"
elif ((hour >= 2 && hour < 4)); then
    echo "โœ“ In window (2-4 AM)"
else
    echo "โš  Outside window"
fi

echo ""
echo "=== Retention Policy ==="
printf "%-20s %s\n" "Daily backups:" "$(date -d '-7 days' '+%Y-%m-%d')"
printf "%-20s %s\n" "Weekly backups:" "$(date -d '-4 weeks' '+%Y-%m-%d')"
printf "%-20s %s\n" "Monthly backups:" "$(date -d '-12 months' '+%Y-%m-%d')"

echo ""
echo "=== Upcoming ==="
today=$(date '+%s')
for event in "2025-11-27:Thanksgiving" "2025-12-25:Christmas" "2026-01-01:New Year"; do
    IFS=':' read -r dt name <<< "$event"
    days=$(( ($(date -d "$dt" '+%s') - today) / 86400 ))
    echo "  $name: $days days"
done

echo ""
echo "=== Global Team ==="
for loc in "HQ:America/New_York" "West:America/Los_Angeles" "EU:Europe/London"; do
    IFS=':' read -r n tz <<< "$loc"
    printf "  %-6s %s\n" "$n" "$(TZ=$tz date '+%H:%M %Z')"
done
Output: === Current Time === Local: 2025-11-18 14:30:45 EST UTC: 2025-11-18 19:30:45 UTC Day: 322/365, Week: 46/52 === Maintenance Window === โš  Outside window === Retention Policy === Daily backups: 2025-11-11 Weekly backups: 2025-10-21 Monthly backups: 2024-11-18 === Upcoming === Thanksgiving: 9 days Christmas: 37 days New Year: 44 days === Global Team === HQ 14:30 EST West 11:30 PST EU 19:30 GMT

Best Practices & Tips

Arithmetic

โœ“ Do
โœ— Avoid

Date/Time

โœ“ Do
โœ— Avoid

Common Patterns

# Safe arithmetic with default
result=${value:-0}
((result++))

# Floating-point
result=$(echo "scale=2; $a / $b" | bc)

# Dated filename
file="backup-$(date '+%Y%m%d-%H%M%S').tar.gz"

# Time difference
elapsed=$(($(date '+%s') - start))

# Validate date
date -d "$input" &>/dev/null && echo "Valid"

# Last day of month
last=$(date -d "$(date '+%Y-%m-01') +1 month -1 day" '+%d')