日付を取得する

昨日の日付を取得する

拡張された date コマンド「GNU date」が使用可能な場合

date -d '1 days ago'

-d 'N days ago' オプションで N 日前の日付を取得できる。

Linux では拡張された GNU date コマンドが使用できるので、簡単に過去の日付を取得できる。

$ date
2007年  6月  2日 土曜日 23:05:20 JST
#↑そのまま実行すると当日の日時が表示される。

$ date -d '1 days ago'
2007年  6月  1日 金曜日 23:05:31 JST
#↑1日前を指定すると、現在日時から24時間前の日時が表示される。

「GNU date」が使用できない場合

TZ=JST+15 date

→ 一時的に環境変数 TZ を変更した上で date コマンドを実行する。

古い UNIX マシンなどでは、「GNU date」が使用できない場合が多い。そういった環境では、一時的にタイムゾーンを変更して date コマンドを実行することで、過去の日付を取得することができる

$ echo $TZ
JST-9
#デフォルトのタイムゾーン。

$ date
Sun Jun 26 03:38:04 2005
#↑date コマンドを普通に実行すると今日の日付。

$ TZ=JST+15 date
Sat Jun 25 03:39:03 2005
#↑環境変数 TZ を変更して date コマンドを打つと昨日の日付。

$ echo $TZ
JST-9
#↑実行後もタイムゾーンはデフォルトのまま。

【参考】 一時的に変数を設定

コマンド実行時に TZ=JST+15 date +%m/%d/%Y のように同一行で変数の設定を行うことで、そのコマンドに対してのみ有効になるよう変数を設定することができる。

この場合は ; (セミコロン)で区切ってはいけない。; で区切る場合は ( TZ=JST+15; date +%m/%d/%Y ) のように () で囲む必要がある。

明日の日付を取得する

拡張された date コマンド「GNU date」が使用可能な場合

date -d '1 days'

-d 'N days' オプションで N 日後の日付を取得できる。

Linux では拡張された GNU date コマンドが使用できるので、前述の昨日の日付と同様に、簡単に過去の日付を取得できる。

「GNU date」が使用できない場合

TZ=JST-33 date

→ 一時的に環境変数 TZ を変更した上で date コマンドを実行する。

GNU date が使用できない場合も、前述の昨日の日付取得と同様に、環境変数 TZ を一時的に変更することにより取得することが可能である。

先月の月を取得する

※ GNU date が使用可能な環境を前提とする。

先月の月は、以下のように date コマンドの -d オプションに 1 months ago を指定し、現在より1ヶ月前の日付を求めることで取得可能である。

だが、この方法には大きな落とし穴がある。

$ date '+%m'
06
#↑現在の月は6月。

$ date -d '1 months ago' '+%m'
05
#↑先月の月は5月。

実行結果のとおり、問題なく前月の月が取得できているように見えるが、例えば、2011年3月31日にこのコマンドを実行したとする。

$ date -d '2011-03-31 1 months ago' '+%m'
03
#↑2011年3月31日に実行したことにするため、-d オプションにその日付を指定し、さらにその1ヶ月前の日付を取得する。

3月の前の月なので2月を期待するが、実行結果は上記のとおり3月(「03」)となっている。

わかりやすいように表示形式を変更して実行してみる。

$ date -d '2011-03-31 1 months ago' '+%F'
2011-03-03

2011年3月31日の 1 months ago は2011年2月31日となるが、2月31日は存在しないため2011年2月28日にあふれた3日分を加算した日付が、コマンドの実行結果となる。

冷静に考えれば当然のことだが、1 months ago に目を取られてこのことを見逃しがちなので注意が必要だ。

正確に先月の月を取得するには、当月の1日から1ヶ月前の日付を求めればよい。

date -d "`date '+%Y-%m-01'` 1 months ago" '+%m'

→ 当月の1日を明示的に指定した上で、さらに 1 months ago を指定する。

実際に実行してみる。

$ date -d "`date '+%Y-%m-01'` 1 months ago" '+%m'
05
#↑当日の日付から先月の月を取得。

date -d "2011-03-01 1 months ago" '+%m'
02
#↑2011年3月31日に実行した場合と同等のコマンドを実行しても、正常に前の月が取得できているのが確認できる。

ちなみに、先月の月を求めたいだけなら、無理をして 1 months ago を使う必要もないが、参考のために記載した。

普通にやるなら以下のように、単純に今月の月から -1 すればよい。

$ date '+%-m'
6
#↑現在は6月。

$ last_month=$(expr $(date '+%-m') - 1); [ $last_month -eq 0 ] && last_month=12
$ echo $last_month
5

日付のフォーマットを指定する

date '+フォーマット'

+ を先頭に付け、日時の各情報を表す記号でフォーマットを指定する。

フォーマットの指定には「年」「月」「日」「時」「分」などを表す特殊な書式を使用する。

取得する情報 書式
1970/01/01 00:00:00 からの経過秒 %s
年(西暦4桁) %Y
年(西暦下2桁) %y
月(01~12) %m
月(Jan~Dec) %b
月(January~December) %B
日(01~31) %d
日( 1~31) ※空白含む2桁 %e
曜日(Sun~Sat) %a
曜日(Sunday~Saturday) %A
曜日(0~6) ※0は日曜日 %w
時(00~23) %H
時(01~12) %I
時( 0~23) ※空白を含む2桁 %k
時( 1~12) ※空白を含む2桁 %l
分(00~59) %M
秒(00~59) %S
AM/PM %p
am/pm %P
改行 %n

フォーマットを指定して日時を表示するには、以下のようにパラメータを指定して date コマンドを実行する。

フォーマット コマンド
yyyy/mm/dd date '+%Y/%m/%d'
yyyy/mm/dd (Sun..Sat) date '+%Y/%m/%d(%a)'
yy/mm/dd date '+%y/%m/%d'
yyyy-mm-dd date '+%F'
mm/dd/yy date '+%D'
hh:mm (24時間制) date '+%R'
hh:mm:ss (24時間制) date '+%T'
hh:mm:ss AM/PM (12時間制) date '+%r'

実際にコマンドを実行してみる。実行した日時は2005年9月11日午前1時18分頃である。

$ date '+%Y/%m/%d'
2005/09/11

$ date '+%Y/%m/%d(%a)'
2005/09/11(Sun)

$ date '+%y/%m/%d'
05/09/11

$ date '+%F'
2005-09-11

$ date '+%D'
09/11/05

$ date '+%R'
01:18

$ date '+%T'
01:18:01

$ date '+%r'
01:18:06 AM

$ date '+%Y/%m/%d%n%r'
2005/09/11
01:18:27 AM
#↑%n を使用することで、出力に改行を含めることができる。

他にも表示できる情報はあるが、通常の用途ならこれらの情報のみで十分であろう。

日付取得の応用

※ 以下、GNU date コマンドが使用可能であることを前提とする。

過去・未来の日付を求める

現在日時から指定した時間分の過去・未来の日時を求める。

現在日時から10秒前の日時を求める

date -d '10 seconds ago'

現在日時から10秒後の日時を求める

date -d '10 seconds'

現在日時から10分前の日時を求める

date -d '10 minutes ago'

現在日時から10分後の日時を求める

date -d '10 minutes'

現在日時から10時間前の日時を求める

date -d '10 hours ago'

現在日時から10時間後の日時を求める

date -d '10 hours'

現在日時から10日前の日時を求める

date -d '10 days ago'

現在日時から10日後の日時を求める

date -d '10 days'

現在日時から10ヶ月前の日時を求める

date -d '10 months ago'

現在日時から10ヶ月後の日時を求める

date -d '10 months'

現在日時から10年前の日時を求める

date -d '10 years ago'

現在日時から10年後の日時を求める

date -d '10 years'

日付のフォーマットを指定して実行

上記のコマンドはそれぞれフォーマットを指定して実行することも可能である。

date -d '12 hours ago' '+%Y-%m-%d [%H:%M:%S]'

指定した日時で実行

date コマンドで表示される日時を現在日時ではなく、次のように指定した日時で date コマンドを実行することも可能である

# 現在日時を「2006/01/01 12:13:14」としてコマンドを実行する
date -d '2006/01/01 12:13:14'

# フォーマットの指定も可能
date -d '2006/01/01 12:13:14' '+%Y %m %d - %H %M %S'

→ date コマンドに日時を指定すると、現在日時ではなく指定した日時で結果が表示される。

特定の日時から指定した時間分の過去・未来の日時を求める

さらに特定の日時から指定した時間分の過去・未来の日時を求めることも可能である。

date -d '2006/01/01 12:13:14 1 months ago'

# フォーマットの指定も可能
date -d '2006/01/01 12:13:14 1 months ago' '+%Y %m %d - %H %M %S'

日付の比較を行う

ログファイルなどから取得した日付を、どちらが古い、もしくは新しい日付であるか比較したい場合は以下のシェルスクリプト (date_comparison.sh) のようにする。

#/bin/bash

# 1970-01-01 00:00:00 からの経過秒に変換する
DATE_1=`date -d "$1" '+%s'`
DATE_2=`date -d "$2" '+%s'`

# 2つの日付を表示しておく
echo "DATE 1: $1"
echo "DATE 2: $2"

# 2つの日付を比較し、結果を表示する
if [ $DATE_1 -eq $DATE_2 ]; then
  echo "指定された2つの日付は同一日時です。"
elif [ $DATE_1 -gt $DATE_2 ]; then
  echo "DATE 1 の方が新しい日付です。"
elif [ $DATE_1 -lt $DATE_2 ]; then
  echo "DATE 2 の方が新しい日付です。"
fi

exit 0

このシェルスクリプト date_comparison.sh の実行結果は、以下のとおりとなる。

$ ./date_comparison.sh "2006/01/01 00:00:00" "2006/01/01 00:00:00"
DATE 1: 2006/01/01 00:00:00
DATE 2: 2006/01/01 00:00:00
指定された2つの日付は同一日時です。

$ ./date_comparison.sh "2006/01/01 00:00:01" "2006/01/01 00:00:00"
DATE 1: 2006/01/01 00:00:01
DATE 2: 2006/01/01 00:00:00
DATE 1 の方が新しい日付です。

$ ./date_comparison.sh "2006/01/01 00:00:00" "2006/01/01 00:00:01"
DATE 1: 2006/01/01 00:00:00
DATE 2: 2006/01/01 00:00:01
DATE 2 の方が新しい日付です。

日付は date コマンドのフォーマット指定で '+%s' を使用することにより、「1970-01-01 00:00:00」からの経過秒に変換する。

これによって、日付の比較を単純な数値の比較とすることができる。つまり秒に変換してあるので、新しい日付の方が大きい数値ということになる。

ちなみに、'+%s' を使用した date コマンドの実行結果は以下のようになる。

$ date -d '2006/01/01 00:00:00' '+%s'
1136041200

$ date -d '2006/01/01 00:00:01' '+%s'
1136041201

UTC シリアル値を一般的な日付フォーマットに変換する

UTC 時刻のシリアル値は、date コマンドのフォーマットに %s を指定することで求められる。逆にシリアル値から通常の日付を求めるシェルスクリプト (utcserial2date.sh) を作成してみる。

#!/bin/bash

echo "$1" | grep -E '^([0-9]{10}|[0-9]{13})$' >/dev/null 2>&1 || exit 1

echo "$1" | awk '{
  print utcserial2date($1)
}
function utcserial2date(serial,  msec) {
  if(length(serial) == 13) {
    msec = substr(serial, 11)
    serial = substr(serial, 0, 10)

    return strftime("%Y-%m-%d %H:%M:%S", serial) ":" msec
  }
  return strftime("%Y-%m-%d %H:%M:%S", serial)
}'

exit 0

このシェルスクリプトの引数にシリアル値を指定すると、「yyyy-MM-dd hh:mm:ss」形式で出力される。

$ ./utcserial2date.sh `date '+%s'`
2010-05-12 01:55:09

通常のシリアル値にミリ秒が付加された13桁のシリアル値にも対応する。

$ ./utcserial2date.sh `date '+%s999'`
2010-05-12 01:55:29:999

単純にシリアル値から変換を行うだけのワンライナーは次のとおり。

date '+%s' | awk '{print strftime("%Y-%m-%d %H:%M:%S", $1)}'

ちなみに date コマンドの部分を echo “1273597263” などとすることで、任意のシリアル値を変換可能だ。