お知らせ

  • 利用規約を守って投稿してください。また、よくある質問および投稿の手引きも参照してください。
  • メッセージの投稿にはアカウントが必要です。未登録の方は、ユーザ登録ページからアカウントを作成することができます。

#1 2019-04-06 00:15:55

daihyoushain
新しいメンバ
登録日: 2019-04-06

日付計算ソフトを公開しました

Ubuntu愛好者の皆様はじめまして。
バージョン14の頃からUbuntuを使っている者です。
現在は16.04 LTS 64ビット版を業務に使っています。
先月下旬より私が代表社員を務める会社の業務及び宣伝のために
業種、個人、法人の区別なく有用であると考えるフリーウェアを公開しています。
ソフトの内容は入力した日付のX日後またはX日前の日付の表示です。
どうぞご利用ください。
ダウンロードページ http://www.satoricorpo.com/sw.html

オフライン

 

#2 2019-04-07 08:27:37

kznj
メンバ
登録日: 2013-12-03

Re: 日付計算ソフトを公開しました

以下は、#1で公開されたプログラムにちゃちゃを入れるつもりではないし、ましてや妨害するつもりでもないので、その点をご理解ください。
 
公開されたプログラムを拝見してて、GUIのほうはちと手間がかかりますが、CUIの方ならインタラクティブにしない限りbashのスクリプトで同等のものがなんとかなりそうなので作ってみました。
といっても、calコマンドと、dateコマンドを使っただけなんですが……
 
最初は差分計算を自前でやろうとしたんですが、年と月まではよくても、日の計算のところで閏年の扱いが"1500日後"とかめんどくさくなってしまいました。
ところが現在のdateコマンド(GNU製のdate)には、--date=STRING形式で指定した時に、STRINGの"2019/4/6 200 days ago"とかをちゃんと解釈してくれて"2019/4/6の200日前"の日付を出力してくれる素敵な機能があります。
しかも、年の差分、月の差分、日の差分を別々に、且つ、〜〜前(ago)と、〜〜後の混在指定が可能です。
 
この機能、"man date"にはあまりはっきりとは書かれておらず、次のような表現に留まっています。
"The --date=STRING is a mostly free format human readable date string such as "Sun, 29 Feb 2004 16:21:42 -0800" or  "2004-02-29  16:21:42"  or even "next Thursday".  A date string may contain items indicating calendar date, time of day, time zone, day of week, relative time, relative date, and numbers. "
(--date=STRINGは、ほとんど自由形式の人間が読める日付文字列であり、"Sun、29 Feb 2004 16:21:42 -0800" や "2004-02-29 16:21:42" や "次の木曜日" でさえ指定出来ます。日付文字列には、カレンダーの日付、时刻、タイムゾーン、曜日、相対的な時間、相対的な日付、そして数字を示す項目を含むことができます。)
 
この辺の勉強も含めて作ってみました。
ほとんどネタかオモチャのようなものであって、動作確認も当方が使っているubuntu Desktop 16.04 LTSでしか行っていません。
その点ご理解のほどよろしくお願いいたします。
実際に動かしてみて「これバグか?」とか、スクリプトなので「なんでこんな書き方してるんだ?」とかのツッコミは歓迎致しますが、お手柔らかに。
 
以下はソースコードです。ダウンロードされる場合はこちら calcData.sh から。

コード:

#!/bin/bash

set -u
C_SCRIPT_NAME=`basename $0`
C_SCRIPT_FULL_PATH=`realpath $0`
C_SCRIPT_PATH=`dirname ${C_SCRIPT_FULL_PATH}`

#---------------------------------------------------------------------
#--- functions
#---------------------------------------------------------------------

function printUsage() {
    local scriptName=$1

    cat << USG
${scriptName}の使い方は……
    ${scriptName}    [ -T 起点とする<日付> ]
            [ -Y "年"の<差分値>  ] [ -M "月"の<差分値>  ] [ -D "日"の<差分値>  ]
            [ -h ]
    <日付>        := YYYYMMDD
    <差分値>    := [+|-] 数値

    例1:    ${scriptName} -Y 2  -D 10   (本日から)2年と10日後の日付を求める
    例2:    ${scriptName} -Y -2 -D +10  (本日から)2年前の日付から、更に10日後の日付を求める
    例3:    ${scriptName} -T 21120903 -Y -100 -D +10    2112/9/3("ドラえもん"の製造日)から100年前の日付から、更に10日後の日付を求める
    例4:    ${scriptName} -h   使い方(=現在表示してる内容)を表示する

    特記事項    -Tのパラメータ指定の無い場合は、当日を起点とする日付として扱う

USG
    return 0
}

function isDate() {
    local val=$1
    local year month day

    if [ ${#val} -ne 8 ]; then
        return 255
    fi
    if [[ ! ${val} =~ ^[0-9][0-9][0-9][0-9][0-1][0-9][0-3][0-9]$ ]];then
        return 255
    fi
#    year=${val:0:4}
    month=${val:4:2}
    day=${val:6:2}
    month=${month#0}    # 2桁が前提なので先頭1文字に0があったら削除
    day=${day#0}        # (同上)
    if [ ${month} -lt 1 \
      -o ${month} -gt 12 ]; then
        return 255
    fi
    if [ ${day} -lt 1 \
      -o ${day} -gt 31 ]; then
        return 255
    fi
    return 0
}

function isNum() {
    local val=$1

    if [[ ${val} =~ ^[+\-]*[0-9]+$ ]];then
        return 0
    else
        return 255
    fi
}

function suppressZero() {
    local val=$1

    if [[ $val =~ ^(0+)(.*)$ ]]; then
        val=${BASH_REMATCH[2]}
    fi

    echo $val
}

#---------------------------------------------------------------------
#--- main
#---------------------------------------------------------------------

targetDate=""
formatString=""

declare -a deltaVals
deltaVals[0]="";deltaVals[1]="";deltaVals[2]="";
declare -a deltaMessages
deltaMessages[0]="年";deltaMessages[1]="ヶ月";deltaMessages[2]="日";
declare -a units
units[0]="years";units[1]="months";units[2]="days"

while getopts ':T:Y:M:D:h' OPT ; do 
    case ${OPT} in
    T)    isDate ${OPTARG}
        if [ $? -ne 0 ]; then
            echo "-${OPT}には日付を指定してください。"$'\n'
            printUsage ${C_SCRIPT_NAME}
            exit 255
        fi
        targetDate=${OPTARG}
        ;;
    Y)  isNum ${OPTARG}
        if [ $? -ne 0 ]; then
            echo "-${OPT}には年数を指定してください。"$'\n'
            printUsage ${C_SCRIPT_NAME}
            exit 255
        fi
        deltaVals[0]=${OPTARG}
        ;;
    M)  isNum ${OPTARG}
        if [ $? -ne 0 ]; then
            echo "-${OPT}には月数を指定してください。"$'\n' 
            printUsage ${C_SCRIPT_NAME}
            exit 255
        fi
        deltaVals[1]=${OPTARG}
        ;;
    D)  isNum ${OPTARG}
        if [ $? -ne 0 ]; then
            echo "-${OPT}には日数を指定してください。"$'\n' 
            printUsage ${C_SCRIPT_NAME}
            exit 255
        fi
        deltaVals[2]=${OPTARG}
        ;;
    h|*)    printUsage ${C_SCRIPT_NAME}
            exit 255
            ;;
    esac
done


# 差分のパラメータが指定されない時には"-D 0"として解釈させる
if [ "${deltaVals[0]}" == "" \
  -a "${deltaVals[1]}" == "" \
  -a "${deltaVals[2]}" == "" ];then
    deltaVals[0]="0"
fi

# パラメータを解釈する
valueRaw="";valueNum="";valueAbs="";string=""
message="";formerMessage=""
for (( i=$((${#deltaVals[@]}-1)); i>=0; i-- )) ; do    # 降順ループ(日→月→年)
    if [ "${deltaVals[${i}]}" != "" ]; then
        valueRaw=${deltaVals[${i}]}
        case ${valueRaw:0:1} in
        -)    valueAbs=${valueRaw:1}
            valueAbs=`suppressZero ${valueAbs}`
            valueNum=$((0-${valueAbs}))
            ;;
        +)    valueAbs=${valueRaw:1}
            valueAbs=`suppressZero ${valueAbs}`
            valueNum=$((${valueAbs}+0))
            ;;
        *)    valueAbs=${valueRaw}
            valueAbs=`suppressZero ${valueAbs}`
            valueNum=$((${valueAbs}+0))
            ;;
        esac
        message=${deltaMessages[${i}]}
        if [ ${valueNum} -ge 0 ]; then
            formatString=${formatString}${valueAbs}" "${units[${i}]}" "
            message=${valueAbs}${message}"後"
        else
            formatString=${formatString}${valueAbs}" "${units[${i}]}" ago "
            message=${valueAbs}${message}"前"
        fi
        if [ "${formerMessage}" != "" ]; then
            message=${message}"の、そこから"
        fi
        formerMessage=${message}
    else
        message=""
    fi
    deltaMessages[${i}]=${message}
done

if [ "${targetDate}" == "" ]; then
    targetDate="now"
    targetDateMessage="起点日付[本日]"
else
    targetDateMessage="起点日付"   
fi

dateTarget=`date --date "${targetDate}" +%Y/%m/%d`
targetDateMessage=${targetDateMessage}"("${dateTarget}")"
dateTargetCal=${dateTarget//\//-}
dateTargets=(`echo ${dateTarget//\// }`)

dateRaw=${dateTarget##\/}

# 日付を計算する
if [ "${formatString}"  != "" ]; then
    dateRaw=`date --date "${dateRaw} ${formatString}" +%Y%m%d`
fi

dateResult=`date --date ${dateRaw} +%Y/%m/%d`
dateResultCal=${dateResult//\//-}
dateResults=(`echo ${dateResult//\// }`)

# カレンダー表示(起算日分)
echo "≪${targetDateMessage}のカレンダー≫"
cal ${dateTargets[1]} ${dateTargets[0]} -H ${dateTargetCal}
echo ""

# 結果日付表示
cat <<EOF
あなたが知りたい日付は、
${targetDateMessage}から ${deltaMessages[0]} ${deltaMessages[1]} ${deltaMessages[2]} の
    ${dateResult}
です

EOF

# カレンダー表示(結果分)
echo "≪${dateResult}のカレンダー≫"
cal ${dateResults[1]} ${dateResults[0]} -H ${dateResultCal}
echo ""

exit 0

 

calcDate.shの使い方は……
    calcDate.sh    [ -T 起点とする<日付> ]
            [ -Y "年"の<差分値>  ] [ -M "月"の<差分値>  ] [ -D "日"の<差分値>  ]
            [ -h ]
    <日付>        := YYYYMMDD
    <差分値>    := [+|-] 数値

    例1:    calcDate.sh -Y 2  -D 10   (本日から)2年と10日後の日付を求める
    例2:    calcDate.sh -Y -2 -D +10  (本日から)2年前の日付から、更に10日後の日付を求める
    例3:    calcDate.sh -T 21120903 -Y -100 -D +10    2112/9/3("ドラえもん"の製造日)から100年前の日付から、更に10日後の日付を求める
    例4:    calcDate.sh -h   使い方(=現在表示してる内容)を表示する

    特記事項    -Tのパラメータ指定の無い場合は、当日を起点とする日付として扱う

以上です

オフライン

 

Board footer

Powered by FluxBB