未加星标

Doing Date Math on the Command Line, Part I

字体大小 | |
[系统(linux) 所属分类 系统(linux) | 发布者 店小二05 | 时间 2018 | 作者 红领巾 ] 0人收藏点击收藏

If you've ever used a spreadsheet, you've probably used or seen functions for doing date math―in other words, taking one date and adding some number of days or months to it to get a new date, or taking two dates and finding the number days between them. The same thing can be done from the command line using the lowly date command, possibly with a little help from Bash's arithmetic.

The two most important features of the date command to understand for doing date math are the +FORMAT option and the --date option. The formatting option allows you to format the date in different ways or get just certain parts of the date, such as the year, the month, the day and so on:

$ date '+%Y' 2018 $ date '+%m' 09 $ date '+%d' 16

There are a few dozen formatting options; see the date(1) man page for more.

The second option, the --date (or -d ) option, allows you to specify the date to use, rather than the current date:

$ date --date 'March 1, 2015' "+%Y" 2015 $ date --date='March 1, 2015' "+%m" 03 $ date -d 'March 1, 2015' "+%d" 01

The interesting part of the --date option is that it allows you to specify date strings in a variety of ways. For example, given the above date of "March 1, 2015", you can calculate dates relative to it:

$ date --date 'March 1, 2015 +7 days' Sun Mar 8 00:00:00 MST 2015 $ date --date 'March 1, 2015 -1 year' Sat Mar 1 00:00:00 MST 2014 $ date --date 'March 1, 2015 +12 days +12 hours +15 minutes' Fri Mar 13 12:15:00 MST 2015

You also can use strings that refer to previous or upcoming days of the week (relative to the current date):

$ date --date 'last Monday' Mon Sep 10 00:00:00 MST 2018 $ date --date 'next Monday' Mon Sep 17 00:00:00 MST 2018

Note, however, that combining a date and things like "next Monday" does not work. The date(1) man page has a bit more information about the types of date strings you can specify, however, the GNU Info date page has much more complete documentation.

So now that you've seen the basics of doing date math, let's use it to do something. This example comes from some recent scripts I was working on while organizing linux Journal 's online archives. Each month we publish a new issue. Each issue has an issue number that's one more than the previous issue. Issue numbers are easy to deal with when specifying arguments to a script, but readers tend to think more in terms of months and years. So in a couple places I needed to generate months and years from issue numbers.

To not complicate the example, let's ignore a couple breaks in LJ 's publishing history. So, let's use issue #284 from March 2018 as the starting point and make all calculations relative to it. The script takes one or more issue numbers and prints out the month and year corresponding to that issue number:

$ cat date1.sh 1 for inum in $* 2 do 3 [[ "$inum" =~ ^[0-9]{1,4}$ ]] || { echo "Invalid issue number: $inum"; continue; } 4 5 month=$(date --date="March 1, 2018 +$((inum - 284)) month" +'%B') 6 year=$(date --date="March 1, 2018 +$((inum - 284)) month" +'%Y') 7 printf "Issue %d is from %s, %s\n" $inum $month $year 8 done $ bash date1.sh 284 285 Issue 284 is from March, 2018 Issue 285 is from April, 2018

Lines 5 and 6 calculate the number of issues that have elapsed since issue 284 using Bash's arithmetic expression syntax: $((inum - 284)) . That result then is used to add that many months onto the date of the first issue, which gives the date of the issue in question. Then the date command's format options provides the month and year (the %B and %Y format specifiers, respectively). Those values next are used to print out the month and year of the issue. And just in case you were wondering, issue #1000 will be coming out in November 2077.

One thing that can you trip you up when doing date math is that if you use dates near the end of the month when adding or subtracting months, you can end up with unexpected results. This is because the date command uses the same value for the length of each month when it adds months and ignores the fact that not all months are the same length. So, for example, look what happens if you change the reference date in the script above from the start of the month to the end of the month:

$ cat date2.sh 5 month=$(date --date="March 31, 2018 +$((inum - 284)) month" +'%B') 6 year=$(date --date="March 31, 2018 +$((inum - 284)) month" +'%Y') $ bash date2.sh 284 285 Issue 284 is from March, 2018 Issue 285 is from May, 2018

This incorrectly labels issue 285 as being in May rather than April. You can verify this if you run the effective date command by itself:

$ date --date="March 31, 2018 +1 month" Tue May 1 00:00:00 MST 2018

Since April has only 30 days, you end up skipping to the first of May.

The other common type of date math that I mentioned above is calculating the difference between two dates. Unfortunately, the date command doesn't support this directly. To do that, you need to convert the dates in question into the number of seconds since the epoch (using the %s format specifier), and then subtract the values and divide by the number of seconds in a day (86,400) to get the days in between:

$ cat date3.sh start_date="March 1, 2018" end_date="March 31, 2018" sdate=$(date --date="$start_date" '+%s') edate=$(date --date="$end_date" '+%s') days=$(( (edate - sdate) / 86400 )) echo "$days days between $start_date and $end_date" $ bash date3.sh 30 days between March 1, 2018 and March 31, 2018

In part two of this article, I plan to tackle how to get a specific previous day of the week relative to a specific date (which, as I noted above, is not directly doable with the date command). In other words, I want to be able to do something that effectively does the following:

$ date --date 'March 1, 2015 previous Monday' # won't work date: invalid date ‘March 1 2015 previous Monday’

本文系统(linux)相关术语:linux系统 鸟哥的linux私房菜 linux命令大全 linux操作系统

tags: date,March,month,issue
分页:12
转载请注明
本文标题:Doing Date Math on the Command Line, Part I
本站链接:https://www.codesec.net/view/604893.html


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 系统(linux) | 评论(0) | 阅读(8)