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)
doneISOフォーマット
このスクリプトでは曜日・週番号の取得に GNU date の以下のフォーマット指定子を利用しています. iso_day と isoweek は ISO 8601 の規定に従った値を返す点がポイントです.
| 変数 | date 指定子 |
説明 | 例(2025-01-01 Wed) |
|---|---|---|---|
weekday |
%a |
ロケール依存の曜日の略称 | Wed |
iso_day |
%u |
ISO 8601 の曜日番号.月曜=1 〜 日曜=7 | 3 |
isoweek |
%V |
ISO 8601 の週番号(01〜53) |
01 |
ISO 8601 における曜日・週番号の数え方は次のルールに基づきます.
- 週の始まりは月曜日(
%uでは月曜=1,日曜=7).%w(日曜=0〜土曜=6)とは番号付けが異なる点に注意. - 週番号
%Vは「その年の最初の木曜日を含む週」を第1週とする.すなわち,年をまたぐ週は「木曜日が属する年」に帰属する.- そのため,1月初旬の日付が前年の第52・53週に,12月末の日付が翌年の第01週に割り当てられる場合がある.
- 暦年ベースの週番号
%U(日曜始まり)・%W(月曜始まり)とは値が一致しないことがある.