Answers:
对于GNU date(1),“日期后的n周”很容易:
$ 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
我不知道一种简单的方法来计算两个日期之间的差,但是您可以使用shell函数在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的过渡,则其中一天只有23小时长;您可以通过加总½天来补偿。
echo $(( (((d1-d2) > 0 ? (d1-d2) : (d2-d1)) + 43200) / 86400 )) days
对于一组便携式工具,请尝试我自己的dateutils。您的两个例子可以归结为一类:
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
dateadd -i '%m%d%Y' 01012015 +1d
似乎没有用,它只是无限期地挂在那里...如果日期规范由一个字符,任何一个字符分隔……任何想法出了什么问题,它都可以工作)
一个用于计算我在地球上行走的天数的python示例:
$ python
>>> from datetime import date as D
>>> print (D.today() - D(1980, 6, 14)).days
11476
ychaouche@ychaouche-PC ~ $ python -c "from datetime import date as d; print (d.today() - d(1980, 6, 14)).days"
12813
ychaouche@ychaouche-PC ~ $
我通常更喜欢将时间/日期设置为unix utime格式(自纪元开始,以七十年代开始的秒数,UTC)。这样,它总是归结为简单的减法或秒的加法。
问题通常变成将日期/时间转换为这种格式。
在shell环境/脚本中,您可以使用。date '+%s'
在撰写本文时,当前时间是1321358027
。
与2011-11-04(我的生日)比较date '+%s' -d 2011-11-04
,产生1320361200
。减:expr 1321358027 - 1320361200
给出996827
秒,即expr 996827 / 86400
= 11天前。
从utime(1320361200格式)到日期的转换非常容易,例如使用标准库在C,PHP或perl中进行。使用GNU时date
,-d
可以在参数前面加上@
“自大纪元以来的秒数”格式。
date -d @1234567890
从纪元以来的秒数转换为您指定的任何日期格式。
info date
,尤其是自大纪元节点以来的秒数:“如果在数字前加上'@',则表示内部时间戳(以秒为单位)。”
这是在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)
在两种情况下,Date都能给出正确的输出,但是在第二种情况下,您输入的是错误的问题。重要的是一年中的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
。首先减去日期,然后减去月份,然后减去年份。(由于think date
年改变了2月的长度,我认为一次调用中将年和月相结合是不安全的。)
如果图形工具适合您,我衷心推荐qalculate
(一个强调单位转换的计算器,它带有GTK和KDE接口IIRC)。在那里你可以说例如
days(1900-05-21, 1900-01-01)
获取日期之间的天数(140,因为1900年不是a年),但是当然您也可以对时间进行相同的操作:
17:12:45 − 08:45:12
产生8.4591667
小时,或者,如果将输出设置为时间格式,则产生8:27:33
。
qalc
然后尝试help days
。
qcalc
例如:qalc -t 'days(1900-05-21, 1900-01-01)'
-> 140
我经常使用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_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
行将值out分配给变量DATEfirstnum。该-d
标志在这种情况下以2014年5月14日的时间格式显示字符串,并+"%j"
告知date
将输出格式设置为仅一年中的某一天(1-365)。DAYSdif
两天的差额。DAYSdif
。这适用于的GNU版本date
,但不适用于PC-BSD / FreeBSD版本。我coreutils
从端口树安装,并改用命令/usr/local/bin/gdate
。
DATEfirstnum=$(date -d "$1" +%s)
DATElastnum=$(date -d "$2" +%s)
此外,此脚本将无法计算两个不同年份之间的差额。+%j
指的是一年中的某一天(001..366),因此./date_difference.sh 12/31/2001 12/30/2014
输出-1。正如其他答案所指出的那样,您需要将两个日期都转换为自1970-01-01 00:00:00 UTC以来的秒数。
$
内部算术表达式:$((DATElastnum - DATEfirstnum))
也可以。
借助dannas解决方案,可以使用以下代码在一行中完成此操作:
python -c "from datetime import date as d; print(d.today() - d(2016, 7, 26))"
(适用于Python 2.x和Python3。)
还有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
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
将日期时间更改为seconds.nanoseconds自1970-01-01 00:00:00 UTC。 bc
计算两个数字之间的差,除法因子得到不同的单位。 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
请注意,由于一个月或一年的长度并不总是相同的,所以那里没有一个“正确”的答案,尽管现在可以使用365.24天作为合理的近似值。