Skip to main content
The timedate module provides comprehensive time and date manipulation functions for bash scripts, with portable implementations supporting both GNU date and BSD date (macOS).

Portability

The module automatically detects the available date implementation:
  • GNU date - Full functionality with date arithmetic
  • BSD date (macOS) - Full functionality with adapted syntax
  • Pure bash fallback - Basic functionality when date features are limited

Timestamp functions

Unix timestamp operations for precise time tracking.
Get current unix timestamp (seconds since epoch).Returns: Integer timestamp
ts=$(timedate::timestamp::unix)
echo "Current timestamp: $ts"
Implementation:
date +%s
Get current unix timestamp in milliseconds.Returns: Timestamp in milliseconds
ts_ms=$(timedate::timestamp::unix_ms)
echo "Timestamp: $ts_ms ms"
Get current unix timestamp in nanoseconds.Returns: Timestamp in nanoseconds
ts_ns=$(timedate::timestamp::unix_ns)
Convert unix timestamp to human-readable format.Parameters:
  • timestamp - Unix timestamp
  • format - strftime format (optional, default: “%Y-%m-%d %H:%M:%S”)
Returns: Formatted date string
timedate::timestamp::to_human 1700000000
# Returns: 2023-11-14 22:13:20

timedate::timestamp::to_human 1700000000 "%B %d, %Y"
# Returns: November 14, 2023
Convert human-readable date to unix timestamp.Parameters:
  • date_string - Date in “YYYY-MM-DD HH:MM:SS” format
Returns: Unix timestamp
ts=$(timedate::timestamp::from_human "2024-01-15 12:00:00")
echo "Timestamp: $ts"

Date functions

Date manipulation and querying operations.

Current date information

Get current date in YYYY-MM-DD format.
today=$(timedate::date::today)
echo "Today: $today"  # e.g., 2024-03-15
Format a date with custom format string.Parameters:
  • format - strftime format (optional, default: “%Y-%m-%d”)
  • timestamp - Unix timestamp (optional, default: now)
timedate::date::format "%B %d, %Y"  # March 15, 2024
timedate::date::format "%Y/%m/%d" 1700000000
Get current year (YYYY).
year=$(timedate::date::year)  # e.g., 2024
Get current month (01-12).
month=$(timedate::date::month)  # e.g., 03
Get current day of month (01-31).
day=$(timedate::date::day)  # e.g., 15
Get day of week (1=Monday, 7=Sunday, ISO 8601).
dow=$(timedate::date::day_of_week)
[[ $dow == 6 || $dow == 7 ]] && echo "Weekend!"
Get full day name (e.g., Monday).
name=$(timedate::date::day_name)
echo "Today is $name"
Get abbreviated day name (e.g., Mon).
short=$(timedate::date::day_name::short)  # Mon, Tue, etc.
Get day of year (001-366).
doy=$(timedate::date::day_of_year)
echo "Day $doy of the year"
Get ISO 8601 week number (01-53).
week=$(timedate::date::week_of_year)
echo "Week $week"
Get quarter of year (1-4).
q=$(timedate::date::quarter)
echo "Q$q"

Date arithmetic

Add n days to a date.Parameters:
  • date - Date in YYYY-MM-DD format
  • n - Number of days to add
Returns: New date in YYYY-MM-DD format
future=$(timedate::date::add_days "2024-01-15" 10)
echo "$future"  # 2024-01-25
Subtract n days from a date.Parameters:
  • date - Date in YYYY-MM-DD format
  • n - Number of days to subtract
Returns: New date in YYYY-MM-DD format
past=$(timedate::date::sub_days "2024-01-15" 5)
echo "$past"  # 2024-01-10
Add n months to a date.Parameters:
  • date - Date in YYYY-MM-DD format
  • n - Number of months to add
Returns: New date
future=$(timedate::date::add_months "2024-01-15" 3)
echo "$future"  # 2024-04-15
Add n years to a date.Parameters:
  • date - Date in YYYY-MM-DD format
  • n - Number of years to add
Returns: New date
future=$(timedate::date::add_years "2024-01-15" 2)
echo "$future"  # 2026-01-15
Calculate number of days between two dates.Parameters:
  • date1 - First date (YYYY-MM-DD)
  • date2 - Second date (YYYY-MM-DD)
Returns: Number of days (can be negative)
diff=$(timedate::date::days_between "2024-01-01" "2024-12-31")
echo "$diff days"  # 365
Get yesterday’s date.
yesterday=$(timedate::date::yesterday)
Get tomorrow’s date.
tomorrow=$(timedate::date::tomorrow)

Date ranges

Get start of current week (Monday).Returns: Date in YYYY-MM-DD format
monday=$(timedate::date::week_start)
Get end of current week (Sunday).Returns: Date in YYYY-MM-DD format
sunday=$(timedate::date::week_end)
Get first day of current month.
first=$(timedate::date::month_start)  # e.g., 2024-03-01
Get last day of current month.
last=$(timedate::date::month_end)  # e.g., 2024-03-31
Get first day of current year.
jan1=$(timedate::date::year_start)  # e.g., 2024-01-01
Get last day of current year.
dec31=$(timedate::date::year_end)  # e.g., 2024-12-31

Date navigation

Get next occurrence of a weekday from today.Parameters:
  • weekday_number - Day (1=Mon, 2=Tue, …, 7=Sun)
Returns: Date in YYYY-MM-DD format
next_friday=$(timedate::date::next_weekday 5)
next_monday=$(timedate::date::next_weekday 1)
Get previous occurrence of a weekday.Parameters:
  • weekday_number - Day (1=Mon, …, 7=Sun)
Returns: Date in YYYY-MM-DD format
last_friday=$(timedate::date::prev_weekday 5)
Get number of days in a specific month.Parameters:
  • year - Year (YYYY)
  • month - Month (01-12)
Returns: Number of days (28-31)
days=$(timedate::date::days_in_month 2024 02)
echo "$days"  # 29 (2024 is leap year)

Date comparison

Compare two dates.Parameters:
  • date1 - First date (YYYY-MM-DD)
  • date2 - Second date (YYYY-MM-DD)
Returns: -1 (before), 0 (equal), or 1 (after)
result=$(timedate::date::compare "2024-01-15" "2024-12-31")
[[ $result == -1 ]] && echo "First date is earlier"
Check if date1 is before date2.Returns: 0 if true, 1 if false
timedate::date::is_before "2024-01-01" "2024-12-31" && echo "Yes"
Check if date1 is after date2.Returns: 0 if true, 1 if false
timedate::date::is_after "2024-12-31" "2024-01-01" && echo "Yes"
Check if date falls between start and end (inclusive).Parameters:
  • date - Date to check
  • start - Range start
  • end - Range end
Returns: 0 if in range, 1 otherwise
timedate::date::is_between "2024-06-15" "2024-01-01" "2024-12-31"

Time functions

Time-of-day operations and time checking.
Get current time in HH:MM:SS format.
time=$(timedate::time::now)
echo "Current time: $time"
Get current time in custom format.Parameters:
  • format - strftime format (optional, default: “%H:%M:%S”)
timedate::time::format "%I:%M %p"  # 02:30 PM
Get current hour (00-23).
hour=$(timedate::time::hour)
Get current minute (00-59).
minute=$(timedate::time::minute)
Get current second (00-59).
second=$(timedate::time::second)
Get timezone abbreviation (e.g., UTC, EST, PST).
tz=$(timedate::time::timezone)
Get timezone offset from UTC (e.g., +0800, -0500).
offset=$(timedate::time::timezone_offset)

Time checking

Check if current time is before specified time.Parameters:
  • Time in HH:MM format
Returns: 0 if true, 1 if false
timedate::time::is_before "12:00" && echo "It's morning"
Check if current time is after specified time.
timedate::time::is_after "17:00" && echo "Work day done"
Check if current time is between two times.Parameters:
  • start - Start time (HH:MM)
  • end - End time (HH:MM)
timedate::time::is_between "09:00" "17:00" && echo "Business hours"
Check if currently business hours (Mon-Fri, 09:00-17:00 default).Parameters:
  • start - Start time (optional, default: 09:00)
  • end - End time (optional, default: 17:00)
Returns: 0 if business hours, 1 otherwise
timedate::time::is_business_hours && echo "Office is open"
timedate::time::is_business_hours "08:00" "18:00"
Check if currently morning (00:00-11:59).
timedate::time::is_morning && echo "Good morning!"
Check if currently afternoon (12:00-17:59).
timedate::time::is_afternoon && echo "Good afternoon!"
Check if currently evening (18:00-23:59).
timedate::time::is_evening && echo "Good evening!"

Timing utilities

Sleep with a progress indicator.Parameters:
  • seconds - Duration to sleep
  • message - Status message (optional, default: “Waiting”)
timedate::time::sleep 5 "Processing"
# Output: Processing... 5s, 4s, 3s, 2s, 1s, done
Start a stopwatch, returns a token.Returns: Timestamp token for later use
token=$(timedate::time::stopwatch::start)
# ... do work ...
elapsed=$(timedate::time::stopwatch::stop $token)
echo "Took $elapsed ms"
Stop a stopwatch and get elapsed time.Parameters:
  • token - Token from stopwatch::start
Returns: Elapsed milliseconds
start=$(timedate::time::stopwatch::start)
sleep 2
elapsed=$(timedate::time::stopwatch::stop $start)
echo "Duration: $elapsed ms"

Duration functions

Human-readable duration formatting and parsing.
Format seconds into human-readable duration.Parameters:
  • seconds - Total seconds
Returns: Formatted string (e.g., “1d 2h 3m 4s”)
timedate::duration::format 90061
# Returns: 1d 1h 1m 1s

timedate::duration::format 3665
# Returns: 1h 1m 5s
Format milliseconds into human-readable duration.Parameters:
  • milliseconds - Total milliseconds
Returns: Formatted string
timedate::duration::format_ms 500
# Returns: 500ms

timedate::duration::format_ms 65000
# Returns: 1m 5s
Parse a duration string into seconds.Parameters:
  • duration_string - String like “1d 2h 3m 4s”
Returns: Total seconds
seconds=$(timedate::duration::parse "1h 30m")
echo "$seconds"  # 5400
Convert timestamp to relative time description.Parameters:
  • timestamp - Unix timestamp
Returns: Human-readable relative time
ts=$(date -d "2 hours ago" +%s)
timedate::duration::relative $ts
# Returns: "2 hours ago"

future=$(date -d "3 days" +%s)
timedate::duration::relative $future
# Returns: "in 3 days"

Calendar functions

Calendar calculations and holiday determination.
Check if a year is a leap year.Parameters:
  • year - Year (YYYY)
Returns: 0 if leap year, 1 otherwise
timedate::calendar::is_leap_year 2024 && echo "Leap year"
timedate::calendar::is_leap_year 2023 || echo "Not leap year"
Get number of days in a year.Parameters:
  • year - Year (YYYY)
Returns: 365 or 366
days=$(timedate::calendar::days_in_year 2024)  # 366
Check if a date falls on Saturday or Sunday.Parameters:
  • date - Date in YYYY-MM-DD format
Returns: 0 if weekend, 1 otherwise
timedate::calendar::is_weekend "2024-03-16" && echo "Weekend!"
Check if a date falls on a weekday (Monday-Friday).Parameters:
  • date - Date in YYYY-MM-DD format
Returns: 0 if weekday, 1 otherwise
timedate::calendar::is_weekday "2024-03-15" && echo "Workday"
Get ISO week number for a date.Parameters:
  • date - Date in YYYY-MM-DD format
Returns: Week number (01-53)
week=$(timedate::calendar::iso_week "2024-06-15")
Get day of year for a date.Parameters:
  • date - Date in YYYY-MM-DD format
Returns: Day number (001-366)
doy=$(timedate::calendar::day_of_year "2024-12-31")  # 366
Get quarter for a date.Parameters:
  • date - Date in YYYY-MM-DD format
Returns: Quarter (1-4)
q=$(timedate::calendar::quarter "2024-06-15")  # 2
Calculate Easter date using Meeus/Jones/Butcher algorithm.Parameters:
  • year - Year (YYYY)
Returns: Easter date in YYYY-MM-DD format
easter=$(timedate::calendar::easter 2024)
echo "Easter 2024: $easter"  # 2024-03-31
Count weekdays between two dates.Parameters:
  • start - Start date (YYYY-MM-DD)
  • end - End date (YYYY-MM-DD)
Returns: Number of weekdays
days=$(timedate::calendar::weekdays_between "2024-01-01" "2024-01-31")
echo "$days business days"
Display calendar for a month (like cal command).Parameters:
  • year - Year (optional, default: current)
  • month - Month (optional, default: current)
timedate::calendar::month 2024 12
# Displays December 2024 calendar

Timezone functions

Timezone conversion and information.
Convert a timestamp to a different timezone.Parameters:
  • timestamp - Unix timestamp
  • timezone - TZ database name (e.g., “America/New_York”)
Returns: Formatted date/time in target timezone
timedate::tz::convert 1700000000 "America/New_York"
# Returns: 2023-11-14 17:13:20 EST

timedate::tz::convert 1700000000 "Asia/Tokyo"
# Returns: 2023-11-15 07:13:20 JST
Get current time in a specific timezone.Parameters:
  • timezone - TZ database name
Returns: Current date/time in timezone
timedate::tz::now "Europe/London"
timedate::tz::now "Australia/Sydney"
Get current timezone name.Returns: Timezone abbreviation
tz=$(timedate::tz::current)
echo "Current timezone: $tz"  # e.g., UTC, EST
Get UTC offset in seconds.Returns: Offset in seconds (can be negative)
offset=$(timedate::tz::offset_seconds)
hours=$((offset / 3600))
echo "UTC offset: $hours hours"
Check if currently in daylight saving time.Returns: 0 if DST, 1 otherwise
timedate::tz::is_dst && echo "Daylight saving time active"
List all available timezones.Returns: List of TZ database names
timedate::tz::list | head -20
List timezones filtered by region.Parameters:
  • region - Region name (e.g., “America”, “Europe”)
Returns: Filtered list of timezones
timedate::tz::list::region America
# Lists: America/New_York, America/Chicago, etc.

Usage examples

Task scheduler with date checking

#!/bin/bash
source timedate.sh

# Run task only on weekdays during business hours
if timedate::calendar::is_weekday "$(timedate::date::today)" && \
   timedate::time::is_business_hours; then
    echo "Running scheduled task..."
    ./backup.sh
else
    echo "Outside business hours, skipping"
fi

Calculate age from birthdate

birth="1990-05-15"
today=$(timedate::date::today)
days=$(timedate::date::days_between "$birth" "$today")
years=$((days / 365))
echo "Approximately $years years old"

Benchmark script execution

start=$(timedate::time::stopwatch::start)

# Run your script
./process_data.sh

elapsed=$(timedate::time::stopwatch::stop $start)
echo "Processing took: $(timedate::duration::format_ms $elapsed)"

Multi-timezone meeting planner

meeting_ts=$(timedate::timestamp::from_human "2024-03-20 14:00:00")

echo "Meeting times:"
echo "New York: $(timedate::tz::convert $meeting_ts 'America/New_York')"
echo "London:   $(timedate::tz::convert $meeting_ts 'Europe/London')"
echo "Tokyo:    $(timedate::tz::convert $meeting_ts 'Asia/Tokyo')"

Calculate project deadline

start=$(timedate::date::today)
workdays=60

# Add weekdays only
count=0
current="$start"
while [[ $count -lt $workdays ]]; do
    current=$(timedate::date::add_days "$current" 1)
    timedate::calendar::is_weekday "$current" && ((count++))
done

echo "60 business days from now: $current"

Build docs developers (and LLMs) love