From 3ed0a9d9ffa6630ebcf35df7c52a6d788540a5c1 Mon Sep 17 00:00:00 2001 From: Test User Date: Mon, 2 Feb 2026 09:39:39 -0700 Subject: [PATCH] fix(date): improve cross-platform date command compatibility Fixes date command errors on macOS with Homebrew GNU coreutils: - 'date: invalid option -- v' when GNU date runs BSD syntax - 'syntax error in expression' when stat returns filesystem metadata Changes: - Replace uname-based detection with capability detection (try/fallback) - Try GNU commands first, fall back to BSD, then ultimate fallbacks - Add date -r fallback for file mtime (most portable) This handles mixed environments where uname returns "Darwin" but GNU coreutils are in PATH from Homebrew. Credit: @farce1 (PR #119) --- lib/date_utils.sh | 38 +++++++++++++++++++------------------- ralph_loop.sh | 21 +++++++++++++-------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/lib/date_utils.sh b/lib/date_utils.sh index 83e03eb..b889548 100644 --- a/lib/date_utils.sh +++ b/lib/date_utils.sh @@ -5,33 +5,33 @@ # 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() { - local os_type - os_type=$(uname) - - if [[ "$os_type" == "Darwin" ]]; then - # macOS (BSD date) - # Use manual formatting and add colon to timezone offset - date -u +"%Y-%m-%dT%H:%M:%S%z" | sed 's/\(..\)$/:\1/' - else - # Linux (GNU date) - use -u flag for UTC - date -u -Iseconds + # 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() { - local os_type - os_type=$(uname) - - if [[ "$os_type" == "Darwin" ]]; then - # macOS (BSD date) - use -v flag for date arithmetic - date -v+1H '+%H:%M:%S' - else - # Linux (GNU date) - use -d flag for date arithmetic - date -d '+1 hour' '+%H:%M:%S' + # 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) diff --git a/ralph_loop.sh b/ralph_loop.sh index c2e3b73..ed21484 100755 --- a/ralph_loop.sh +++ b/ralph_loop.sh @@ -626,16 +626,21 @@ get_session_file_age_hours() { return fi - local os_type - os_type=$(uname) - + # Get file modification time using capability detection + # Handles macOS with Homebrew coreutils where stat flags differ local file_mtime - if [[ "$os_type" == "Darwin" ]]; then - # macOS (BSD stat) - file_mtime=$(stat -f %m "$file" 2>/dev/null) + + # Try GNU stat first (Linux, macOS with Homebrew coreutils) + if file_mtime=$(stat -c %Y "$file" 2>/dev/null) && [[ -n "$file_mtime" && "$file_mtime" =~ ^[0-9]+$ ]]; then + : # success + # Try BSD stat (native macOS) + elif file_mtime=$(stat -f %m "$file" 2>/dev/null) && [[ -n "$file_mtime" && "$file_mtime" =~ ^[0-9]+$ ]]; then + : # success + # Fallback to date -r (most portable) + elif file_mtime=$(date -r "$file" +%s 2>/dev/null) && [[ -n "$file_mtime" && "$file_mtime" =~ ^[0-9]+$ ]]; then + : # success else - # Linux (GNU stat) - file_mtime=$(stat -c %Y "$file" 2>/dev/null) + file_mtime="" fi # Handle stat failure - return -1 to indicate error