指定期間の日付一覧CSVテーブル作成シェルスクリプト

shellscript
作者

Ryo Nakagami

公開

2026-04-09

更新日

2026-06-15

date-table シェルスクリプト

コマンド

$ date-table 2025-01-01 2025-01-03
date,weekday,iso_day_of_week,isoweek,day_of_year
2025-01-01,Wed,3,01,001
2025-01-02,Thu,4,01,002
2025-01-03,Fri,5,01,003

シェルスクリプト

#!/bin/bash
# -----------------------------------------------------------------------------
# Author: Ryo Nakagami
# Revised: 2025-12-09
# Script: date-table
# Description:
#   Generates a CSV table of dates and their properties for a given date range.
#   Outputs columns for date, weekday, ISO day of week, ISO week number, and
#   day of year, with options to select which columns to display.
#
#   Steps:
#     1. Parse and validate command-line options and arguments.
#     2. Validate input dates (format and calendar existence).
#     3. Set output columns based on options (default: all columns).
#     4. Print CSV header.
#     5. Iterate from start to end date, printing each row with selected fields.
#
# Options:
#    -a    Show weekday column
#    -u    Show ISO day of week column
#    -V    Show ISO week number column
#    -j    Show day of year column
#    -h    Show this help message
#
# Usage:
#   ./date-table [-a] [-u] [-V] [-j] <start-date> <end-date>
#     # Outputs a CSV table for the date range, with selected columns.
#
# Notes:
#   - Requires bash, GNU date, and coreutils installed.
#   - Dates must be in YYYY-MM-DD format.
#   - Exits with error if dates are invalid or out of order.
# -----------------------------------------------------------------------------
set -euo pipefail


# --- Validate YYYY-MM-DD ---
validate_ymd() {
    local d="$1"

    # Format check
    if [[ ! $d =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then
        echo "Error: Invalid format '$d'. Expected YYYY-MM-DD." >&2
        exit 1
    fi

    # Calendar existence check
    local norm
    if ! norm=$(date -d "$d" +%Y-%m-%d 2>/dev/null); then
        echo "Error: '$d' is not a real date." >&2
        exit 1
    fi

    # Reject auto-corrected dates (e.g., 2025-02-30 → 2025-03-02)
    if [[ "$norm" != "$d" ]]; then
        echo "Error: '$d' is not a valid calendar date." >&2
        exit 1
    fi
}

# --- Option parsing ---
show_weekday=false
show_iso_day=false
show_isoweek=false
show_day_of_year=false
opt_specified=false

while getopts "auVj" opt; do
    opt_specified=true
    case $opt in
        a) show_weekday=true ;;
        u) show_iso_day=true ;;
        V) show_isoweek=true ;;
        j) show_day_of_year=true ;;
        *)
          # shellcheck disable=SC2119
          echo "Error: invalid options"
          exit 1;;
    esac
done
 
shift $((OPTIND - 1))

if [[ $# -ne 2 ]]; then
    echo "Usage: $0 [-a] [-u] [-V] [-j] <start-date> <end-date>" >&2
    exit 1
fi

start_date="$1"
end_date="$2"

validate_ymd "$start_date"
validate_ymd "$end_date"

# Ensure start <= end
if [[ "$start_date" > "$end_date" ]]; then
    echo "Error: start_date > end_date" >&2
    exit 1
fi

# If no options specified → output all
if ! $opt_specified; then
    show_weekday=true
    show_iso_day=true
    show_isoweek=true
    show_day_of_year=true
fi

# --- Print header ---
printf "date"
$show_weekday    && printf ",weekday"
$show_iso_day    && printf ",iso_day_of_week"
$show_isoweek    && printf ",isoweek"
$show_day_of_year && printf ",day_of_year"
printf "\n"

# --- Generate rows ---
current="$start_date"
while true; do

    weekday=$(date -d "$current" +%a)
    iso_day=$(date -d "$current" +%u)
    isoweek=$(date -d "$current" +%V)
    doy=$(date -d "$current" +%j)

    printf "%s" "$current"
    $show_weekday     && printf ",%s" "$weekday"
    $show_iso_day     && printf ",%s" "$iso_day"
    $show_isoweek     && printf ",%s" "$isoweek"
    $show_day_of_year && printf ",%s" "$doy"

    printf "\n"

    [[ "$current" == "$end_date" ]] && break

    current=$(date -d "$current +1 day" +%Y-%m-%d)
done

ISOフォーマット

このスクリプトでは曜日・週番号の取得に GNU date の以下のフォーマット指定子を利用しています. iso_dayisoweekISO 8601 の規定に従った値を返す点がポイントです.

変数 date 指定子 説明 例(2025-01-01 Wed)
weekday %a ロケール依存の曜日の略称 Wed
iso_day %u ISO 8601 の曜日番号.月曜=1 〜 日曜=7 3
isoweek %V ISO 8601 の週番号(0153 01

ISO 8601 における曜日・週番号の数え方は次のルールに基づきます.

  • 週の始まりは月曜日%u では月曜=1,日曜=7).%w(日曜=0〜土曜=6)とは番号付けが異なる点に注意.
  • 週番号 %V は「その年の最初の木曜日を含む週」を第1週とする.すなわち,年をまたぐ週は「木曜日が属する年」に帰属する.
    • そのため,1月初旬の日付が前年の第52・53週に,12月末の日付が翌年の第01週に割り当てられる場合がある.
    • 暦年ベースの週番号 %U(日曜始まり)・%W(月曜始まり)とは値が一致しないことがある.