私はしばしば次のようないくつかの簡単な日付計算をしたいです:
私は通常、カレンダーを開いて日数を数えますが、この種の計算に使用できるプログラム/スクリプトがあるはずだと思います。助言がありますか?
「n週間後の日付」は、GNU date(1):
$ date -d 'now + 3 weeks'
Tue Dec 6 23:58:04 EST 2011
$ date -d 'Aug 4 + 3 weeks'
Thu Aug 25 00:00:00 EST 2011
$ date -d 'Jan 1 1982 + 11 weeks'
Fri Mar 19 00:00:00 EST 1982
2つの日付の差を計算する簡単な方法はわかりませんが、シェル関数を使用してdate(1)に小さなロジックをラップできます。
datediff() {
d1=$(date -d "$1" +%s)
d2=$(date -d "$2" +%s)
echo $(( (d1 - d2) / 86400 )) days
}
$ datediff '1 Nov' '1 Aug'
91 days
スワップd1
およびd2
日付の計算を逆にしたい場合、または少し複雑にして重要でない場合。さらに、間隔にDST以外の [〜#〜] dst [〜#〜] への遷移がある場合、1日は23時間しかありません。合計に½日を追加することで補正できます。
echo $(( (((d1-d2) > 0 ? (d1-d2) : (d2-d1)) + 43200) / 86400 )) days
ポータブルツールのセットについては、独自の dateutils を試してください。あなたの2つの例は1ライナーに要約されます:
ddiff 2011-11-15 2012-04-11
=>
148
または週と日で:
ddiff 2011-11-15 2012-04-11 -f '%w %d'
=>
21 1
そして
dadd 2011-11-15 21w
=>
2012-04-10
Ubuntuのインストールに関する重要な注意:
これらのまったく同じdateutilsはUbuntuパッケージとして使用できるため、Sudo apt install dateutilsを使用してインストールできます。ただし、コマンドの前にdateutilsを付ける必要があります。 dateutils.ddiff 2019-03-28 2019-05-16
のような接頭辞
A python私が惑星を歩いた日数を計算する例:
$ python
>>> from datetime import date as D
>>> print (D.today() - D(1980, 6, 14)).days
11476
私は通常、UNIXのutime形式(70年代が始まったときのエポックからの秒数、UTC)で時刻/日付を使用することを好みます。その方法は、常に単純な減算または秒の加算に要約されます。
問題は通常、日付/時刻をこの形式に変換することになります。
シェル環境/スクリプトでは、date '+%s'
で取得できます。執筆時点では、現在の時刻は1321358027
です。
2011年11月4日(私の誕生日)と比較すると、date '+%s' -d 2011-11-04
、1320361200
になります。減算:expr 1321358027 - 1320361200
は996827
秒を与えます。つまり、expr 996827 / 86400
= 11日前です。
Utime(1320361200形式)から日付への変換は、C、PHPまたはPerl、標準ライブラリを使用して)で行うのは非常に簡単です。GNU date
、-d
引数の前に@
を追加して、「エポック以降の秒数」形式を示すことができます。
グラフィカルツールで問題がなければ、qalculate
を強くお勧めします(単位変換に重点を置いた計算機で、GTKおよびKDEインターフェース、IIRCが付属しています)。そこであなたは言うことができます.
days(1900-05-21, 1900-01-01)
日付間の日数(1900年はうるう年ではなかったため、140)を取得しますが、もちろん同じことを時間に対して行うこともできます。
17:12:45 − 08:45:12
8.4591667
時間、または出力を時間形式に設定した場合は8:27:33
。
これはdate -d "$death_date - $y years - $m months - $d days"
(家系図の場合)生年月日を取得します。そのコマンドは間違っています。月はすべて同じ長さではないので、(date + offset) - offset != date
。年/月/日の年齢は、生年月日からの経過日数です。
$ date --utc -d 'mar 28 1867 +72years +11months +2days'
Fri Mar 1 00:00:00 UTC 1940
$ date --utc -d 'mar 1 1940 -72years -11months -2days'
Sat Mar 30 00:00:00 UTC 1867
# (2 days later than our starting point)
日付はどちらの場合も正しい出力を示しますが、2番目の場合は間違った質問をしていました。日数を加算/減算する前に、1年の11か月+/- 11をカバーすることが重要です。例えば:
$ date --utc -d 'mar 31 1939 -1month'
Fri Mar 3 00:00:00 UTC 1939
$ date --utc -d 'mar 31 1940 -1month' # leap year
Sat Mar 2 00:00:00 UTC 1940
$ date --utc -d 'jan 31 1940 +1month' # leap year
Sat Mar 2 00:00:00 UTC 1940
減算が加算の逆演算になるためには、演算の順序を逆にする必要があります。追加すると、年、月、日が追加されます。減算で逆の順序を使用した場合は、開始点に戻ります。そうではないので、日オフセットが異なる長さの月の月の境界を超えている場合はそうではありません。
終了日と経過日数から遡って作業する必要がある場合は、date
を複数回呼び出すことで実行できます。最初に日を減算し、次に月、次に年を減算します。 (うるう年は2月の長さを変更するため、年と月を単一のdate
呼び出しで組み合わせるのは安全ではないと私は思います。)
Dannasソリューションの助けを借りて、これは次のコードで1行で実行できます。
python -c "from datetime import date as d; print(d.today() - d(2016, 7, 26))"
(Python 2.xとPython 3.の両方で機能します。)
同じ暦年の2つの日付の差を計算する別の方法として、次の方法を使用できます。
date_difference.sh
1 #!/bin/bash
2 DATEfirstnum=`date -d "2014/5/14" +"%j"`
3 DATElastnum=`date -d "12/31/14" +"%j"`
4 DAYSdif=$(($DATElastnum - $DATEfirstnum))
5 echo "$DAYSdif"
date
の値を変数DATEfirstnumに割り当てます。 -d
フラグは文字列を時間形式で表示します。この場合は2014年5月14日で、+"%j"
はdate
に出力を年の日付のみ(1-365)にフォーマットするように指示します。DAYSdif
を割り当てます。DAYSdif
の値を表示しています。これはGNU date
のバージョンでは機能しますが、PC-BSD/FreeBSDバージョンでは機能しません。ポートツリーからcoreutils
をインストールし、コマンド/usr/local/bin/gdate
を使用しました代わりに。
日付の計算にSQLを頻繁に使用しています。例: MySQL 、 PostgreSQL または SQLite :
bash-4.2$ mysql <<< "select datediff(current_date,'1980-06-14')"
datediff(current_date,'1980-06-14')
11477
bash-4.2$ psql <<< "select current_date-'1980-06-14'"
?column?
----------
11477
(1 row)
bash-4.2$ sqlite2 <<< "select julianday('now')-julianday('1980-06-14');"
11477.3524537035
また、JavaScriptの気分だけを感じる場合もあります。例 SpiderMonkey 、 WebKit 、 Seed または Node.js :
bash-4.2$ js -e 'print((new Date()-new Date(1980,5,14))/1000/60/60/24)'
11477.477526192131
bash-4.2$ jsc-1 -e 'print((new Date()-new Date(1980,5,14))/1000/60/60/24)'
11477.47757960648
bash-4.2$ seed -e '(new Date()-new Date(1980,5,14))/1000/60/60/24'
11477.4776318287
bash-4.2$ node -pe '(new Date()-new Date(1980,5,14))/1000/60/60/24'
11624.520061481482
(JavaScript Date
オブジェクトのコンストラクターに月を渡すときに注意してください。0から始まります。)
date
とbashは日付の違いを実行できます(OS Xオプションを表示)。後者の日付を最初に配置します。
echo $((($(date -jf%D "04/03/16" +%s) - $(date -jf%D "03/02/16" +%s)) / 86400))
# 31
これはかなり古いスレッドですが、興味深いものを発見しました。 BusyBox(v1.19)が組み込まれたシステムで立ち往生していて、超便利なnow - 10 days
表記はそこで失敗します。実際、非常に限られた入力フォーマットのセットが-d
オプション。
Recognized TIME formats:
hh:mm[:ss]
[YYYY.]MM.DD-hh:mm[:ss]
YYYY-MM-DD hh:mm[:ss]
[[[[[YY]YY]MM]DD]hh]mm[.ss]
ただし、一部の計算は入力日に行うことができます。
これらの形式を考慮して、表示する日付の日をゼロに設定すると、前月の最終日が得られることがわかりました。
$ date -d 2020.03.00-12:00
Sat Feb 29 12:00:00 EST 2020
負の数を入力すると、さらに戻ります。
$ date -d 2020.03.-10-12:00
Wed Feb 19 12:00:00 EST 2020
これがGNUの日付でも機能するかどうかは誰でも確認できますか?(now - 10 days
は非常に優れています)
camhの答え はそのほとんどを処理しますが、丸め、タイムゾーンなどを処理するように改善できます。さらに、いくつかの追加の精度とユニットを選択する機能が得られます。
datediff() {
#convert dates to decimal seconds since 1970-01-01 00:00:00 UTC
date1seconds=$(date +%s.%N -d "$date1")
date2seconds=$(date +%s.%N -d "$date2")
#Calculate time difference in various time units
timeseconds=$(printf "%0.8f\n" $(bc <<<"scale=9; ($date2sec-$date1sec)"))
timeminutes=$(printf "%0.8f\n" $(bc <<<"scale=9; ($date2sec-$date1sec)/60"))
timehours=$(printf "%0.8f\n" $(bc <<<"scale=9; ($date2sec-$date1sec)/3600"))
timedays=$(printf "%0.8f\n" $(bc <<<"scale=9; ($date2sec-$date1sec)/86400"))
timeweeks=$(printf "%0.8f\n" $(bc <<<"scale=9; ($date2sec-$date1sec)/604800"))
}
-d
は、変換する日時を指定していることをdate
に通知します。 +%s.%N
は、日時を1970-01-01 00:00:00 UTC以降のseconds.nanosecondsに変更します。 bc
は2つの数値の差を計算し、分割係数は異なる単位を取得します。 printf
は、必要に応じて小数点の前に0を追加し(bc
はしない)、丸めが最も近い値になるようにします(bc
は切り捨てるだけです)。 awk
を使用することもできます。
ファンキーなテストケースでこれを実行してみましょう。
date1='Tue Jul 9 10:18:04.031 PST 2020'
date2='Wed May 8 15:19:34.447 CDT 2019'
datediff "$date1" "$date2"
echo $timeseconds seconds
-36971909.584000000 seconds
echo $timeminutes minutes
-616198.493066667 minutes
echo $timehours hours
-10269.974884444 hours
echo $timedays days
-427.915620185 days
echo $timeweeks weeks
-61.130802884 weeks
1か月または1年の長さが常に同じであるとは限らないので、「正しい」答えは1つではないことに注意してください。ただし、今日では妥当な概算として365.24日を使用できます。
GNUユニットの時間計算とGNU日付の組み合わせ:
$ gunits $(gdate +%s)sec-$(gdate +%s -d -1234day)sec 'yr;mo;d;hr;min;s'
3 yr + 4 mo + 16 d + 12 hr + 37 min + 26.751072 s
$ gunits $(gdate +%s -d '2015-1-2 3:45:00')sec-$(gdate +%s -d '2013-5-6 7:43:21')sec 'yr;mo;d;hr;min;s'
1 yr + 7 mo + 27 d + 13 hr + 49 min + 26.206759 s
(gunitsはLinuxの単位、gdateは日付です)
#!/bin/bash
#Simplest calculator two dates difference. By default in days
# Usage:
# ./datediff.sh first_date second_date [-(s|m|h|d) | --(seconds|minutes|hours|days)]
first_date=$(date -d "$1" "+%s")
second_date=$(date -d "$2" "+%s")
case "$3" in
"--seconds" | "-s") period=1;;
"--minutes" | "-m") period=60;;
"--hours" | "-h") period=$((60*60));;
"--days" | "-d" | "") period=$((60*60*24));;
esac
datediff=$(( ($first_date - $second_date)/($period) ))
echo $datediff
これはかなり古いスレッドですが、少なくとも既知の日付からN単位の時間を加算および減算することに関して、BusyBoxで興味深いものを発見しました。ただし、2つの既知の日付の間隔を決定するための別の方法についてはそれほどではありません。
BusyBoxが組み込まれたシステムで立ち往生しており、非常に便利なnow - 10 days
表記がそこで失敗します。実際、-d
オプションで使用できる入力フォーマットは非常に限られています。
$ busybox date --help
BusyBox v1.19.0 (2019-07-14 10:52:19 UTC) multi-call binary.
Usage: date [OPTIONS] [+FMT] [TIME]
Display time (using +FMT), or set time
[-s,--set] TIME Set time to TIME
-u,--utc Work in UTC (don't convert to local time)
-R,--rfc-2822 Output RFC-2822 compliant date string
-I[SPEC] Output ISO-8601 compliant date string
SPEC='date' (default) for date only,
'hours', 'minutes', or 'seconds' for date and
time to the indicated precision
-r,--reference FILE Display last modification time of FILE
-d,--date TIME Display TIME, not 'now'
-D FMT Use FMT for -d TIME conversion
Recognized TIME formats:
hh:mm[:ss]
[YYYY.]MM.DD-hh:mm[:ss]
YYYY-MM-DD hh:mm[:ss]
[[[[[YY]YY]MM]DD]hh]mm[.ss]
ただし、一部の計算は入力日に行うことができます。これらの形式を考えると、入力日付の日数をゼロに設定すると、前月の最終日が得られることがわかりました。
$ date -d 2020.03.00-12:00
Sat Feb 29 12:00:00 EST 2020
さらに、負の数を入力すると、逆に減算され続けます。
$ date -d 2020.03.-10-12:00
Wed Feb 19 12:00:00 EST 2020
そのため、既知の日付でいくつかの簡単な計算を行って、BusyBox date
呼び出しの-d
オプションにフィードする値を生成できます。
#!/bin/bash
#Other shells not tested.
start_year=2020
start_month=1
start_day=20
offset_year=-2
offset_month=4
offset_day=5
new_year=$(( $start_year + $offset_year ))
new_month=$(( $start_month + $offset_month ))
new_day=$(( $start_day + $offset_day ))
new_date$( busybox date -d $new_year.$new_month.$new_day-12:00 +%Y-%m-%d )
echo $new_date
出力:
2018-05-25
これがGNU、BSD、またはMacOS date
でも機能するかどうかを誰かが確認できますか? GNU now - 10 days
の方がはるかに優れていることは確かに感謝しますが、これをできるだけ移植性のあるものにすることに興味があります。 Androidは非常に異なっていることを確認しました(どちらのアプローチもそこで機能しません)。
date -d
はGNU日付に固有であり、POSIXでは定義されていません:
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/date.html
他の人が述べたように、これは適切なプログラミング言語により適しているかもしれません。たとえば、PHP:
<?php
$o1 = date_create('2020-02-26');
$o2 = date_create('2020-02-16');
$o3 = date_diff($o2, $o1);
echo 'days: ', $o3->d, "\n";
結果:
days: 10