124 lines
4.1 KiB
Bash
124 lines
4.1 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# date_utils.sh - Cross-platform date utility functions
|
|
# Provides consistent date formatting and arithmetic across GNU (Linux) and BSD (macOS) systems
|
|
|
|
# Get current timestamp in ISO 8601 format with seconds precision
|
|
# Returns: YYYY-MM-DDTHH:MM:SS+00:00 format
|
|
# Uses capability detection instead of uname to handle macOS with Homebrew coreutils
|
|
get_iso_timestamp() {
|
|
# Try GNU date first (works on Linux and macOS with Homebrew coreutils)
|
|
local result
|
|
if result=$(date -u -Iseconds 2>/dev/null) && [[ -n "$result" ]]; then
|
|
echo "$result"
|
|
return
|
|
fi
|
|
# Fallback to BSD date (native macOS) - add colon to timezone offset
|
|
date -u +"%Y-%m-%dT%H:%M:%S%z" | sed 's/\(..\)$/:\1/'
|
|
}
|
|
|
|
# Get time component (HH:MM:SS) for one hour from now
|
|
# Returns: HH:MM:SS format
|
|
# Uses capability detection instead of uname to handle macOS with Homebrew coreutils
|
|
get_next_hour_time() {
|
|
# Try GNU date first (works on Linux and macOS with Homebrew coreutils)
|
|
if date -d '+1 hour' '+%H:%M:%S' 2>/dev/null; then
|
|
return
|
|
fi
|
|
# Fallback to BSD date (native macOS)
|
|
if date -v+1H '+%H:%M:%S' 2>/dev/null; then
|
|
return
|
|
fi
|
|
# Ultimate fallback - compute using epoch arithmetic
|
|
local future_epoch=$(($(date +%s) + 3600))
|
|
date -r "$future_epoch" '+%H:%M:%S' 2>/dev/null || date '+%H:%M:%S'
|
|
}
|
|
|
|
# Get current timestamp in a basic format (fallback)
|
|
# Returns: YYYY-MM-DD HH:MM:SS format
|
|
get_basic_timestamp() {
|
|
date '+%Y-%m-%d %H:%M:%S'
|
|
}
|
|
|
|
# Get current Unix epoch time in seconds
|
|
# Returns: Integer seconds since 1970-01-01 00:00:00 UTC
|
|
get_epoch_seconds() {
|
|
date +%s
|
|
}
|
|
|
|
# Convert ISO 8601 timestamp to Unix epoch seconds
|
|
# Input: ISO timestamp (e.g., "2025-01-15T10:30:00+00:00")
|
|
# Returns: Unix epoch seconds on stdout
|
|
# Returns non-zero on parse failure.
|
|
parse_iso_to_epoch_strict() {
|
|
local iso_timestamp=$1
|
|
|
|
if [[ -z "$iso_timestamp" || "$iso_timestamp" == "null" ]]; then
|
|
return 1
|
|
fi
|
|
|
|
local normalized_iso
|
|
normalized_iso=$(printf '%s' "$iso_timestamp" | sed -E 's/\.([0-9]+)(Z|[+-][0-9]{2}:[0-9]{2})$/\2/')
|
|
|
|
# Try GNU date -d (Linux, macOS with Homebrew coreutils)
|
|
local result
|
|
if result=$(date -d "$iso_timestamp" +%s 2>/dev/null) && [[ "$result" =~ ^[0-9]+$ ]]; then
|
|
echo "$result"
|
|
return 0
|
|
fi
|
|
|
|
# Try BSD date -j (native macOS)
|
|
# Normalize timezone for BSD parsing (Z → +0000, ±HH:MM → ±HHMM)
|
|
local tz_fixed
|
|
tz_fixed=$(printf '%s' "$normalized_iso" | sed -E 's/Z$/+0000/; s/([+-][0-9]{2}):([0-9]{2})$/\1\2/')
|
|
if result=$(date -j -f "%Y-%m-%dT%H:%M:%S%z" "$tz_fixed" +%s 2>/dev/null) && [[ "$result" =~ ^[0-9]+$ ]]; then
|
|
echo "$result"
|
|
return 0
|
|
fi
|
|
|
|
# Fallback: manual epoch arithmetic from ISO components
|
|
# Parse: YYYY-MM-DDTHH:MM:SS (ignore timezone, assume UTC)
|
|
local year month day hour minute second
|
|
if [[ "$normalized_iso" =~ ^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2}) ]]; then
|
|
year="${BASH_REMATCH[1]}"
|
|
month="${BASH_REMATCH[2]}"
|
|
day="${BASH_REMATCH[3]}"
|
|
hour="${BASH_REMATCH[4]}"
|
|
minute="${BASH_REMATCH[5]}"
|
|
second="${BASH_REMATCH[6]}"
|
|
|
|
# Use date with explicit components if available
|
|
if result=$(date -u -d "${year}-${month}-${day} ${hour}:${minute}:${second}" +%s 2>/dev/null) && [[ "$result" =~ ^[0-9]+$ ]]; then
|
|
echo "$result"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
# Convert ISO 8601 timestamp to Unix epoch seconds
|
|
# Input: ISO timestamp (e.g., "2025-01-15T10:30:00+00:00")
|
|
# Returns: Unix epoch seconds on stdout
|
|
# Falls back to current epoch on parse failure (safe default)
|
|
parse_iso_to_epoch() {
|
|
local iso_timestamp=$1
|
|
local result
|
|
|
|
if result=$(parse_iso_to_epoch_strict "$iso_timestamp"); then
|
|
echo "$result"
|
|
return 0
|
|
fi
|
|
|
|
# Ultimate fallback: return current epoch (safe default)
|
|
date +%s
|
|
}
|
|
|
|
# Export functions for use in other scripts
|
|
export -f get_iso_timestamp
|
|
export -f get_next_hour_time
|
|
export -f get_basic_timestamp
|
|
export -f get_epoch_seconds
|
|
export -f parse_iso_to_epoch_strict
|
|
export -f parse_iso_to_epoch
|