Execute info 'Date input formats'
para ver quais formatos são permitidos.
O formato de data AAAA-DDD parece não estar lá e tentando
$ date -d '2011-011'
date: invalid date '2011-011'
mostra que não funciona, então acho que njd
está correto, a melhor maneira é usar uma ferramenta externa diferente de bash
e date
.
Se você realmente quiser usar apenas bash e ferramentas básicas de linha de comando, você pode fazer algo assim:
julian_date_to_yyyymmdd()
{
date=$1 # assume all dates are in YYYYMMM format
year=${date%???}
jday=${date#$year}
for m in 'seq 1 12'; do
for d in 'seq 1 31'; do
yyyymmdd=$(printf "%d%02d%02d" $year $m $d)
j=$(date +"%j" -d "$yyyymmdd" 2>/dev/null)
if test "$jday" = "$j"; then
echo "$yyyymmdd"
return 0
fi
done
done
echo "Invalid date" >&2
return 1
}
Mas essa é uma maneira bem lenta de fazer isso.
Uma maneira mais rápida, mas mais complexa, é realizar um loop por mês, encontrar o último dia do mês e, em seguida, ver se o dia juliano está nesse intervalo.
# year_month_day_to_jday <year> <month> <day> => <jday>
# returns 0 if date is valid, non-zero otherwise
# year_month_day_to_jday 2011 2 1 => 32
# year_month_day_to_jday 2011 1 32 => error
year_month_day_to_jday()
{
# XXX use local or typeset if your shell supports it
_s=$(printf "%d%02d%02d" "$1" "$2" "$3")
date +"%j" -d "$_s"
}
# last_day_of_month_jday <year> <month>
# last_day_of_month_jday 2011 2 => 59
last_day_of_month_jday()
{
# XXX use local or typeset if you have it
_year=$1
_month=$2
_day=31
# GNU date exits with 0 if day is valid, non-0 if invalid
# try counting down from 31 until we find the first valid date
while test $_day -gt 0; do
if _jday=$(year_month_day_to_jday $_year $_month $_day 2>/dev/null); then
echo "$_jday"
return 0
fi
_day=$((_day - 1))
done
echo "Invalid date" >&2
return 1
}
# first_day_of_month_jday <year> <month>
# first_day_of_month_jday 2011 2 => 32
first_day_of_month_jday()
{
# XXX use local or typeset if you have it
_year=$1
_month=$2
_day=1
if _jday=$(year_month_day_to_jday $_year $_month 1); then
echo "$_jday"
return 0
else
echo "Invalid date" >&2
return 1
fi
}
# julian_date_to_yyyymmdd <julian day> <4-digit year>
# e.g. julian_date_to_yyyymmdd 32 2011 => 20110201
julian_date_to_yyyymmdd()
{
jday=$1
year=$2
for m in $(seq 1 12); do
endjday=$(last_day_of_month_jday $year $m)
if test $jday -le $endjday; then
startjday=$(first_day_of_month_jday $year $m)
d=$((jday - startjday + 1))
printf "%d%02d%02d\n" $year $m $d
return 0
fi
done
echo "Invalid date" >&2
return 1
}