Date and Time Manipulation

6 368 0
Date and Time Manipulation

Đang tải... (xem toàn văn)

Thông tin tài liệu

19 ■ ■ ■ CHAPTER 3 Date and Time Manipulation O n occasion, the need for date math arises, such as when you’re trying to calculate a time interval between events. The calculations seem easy enough because there are pre- cise numbers of seconds, minutes, and hours in a day. It gets tricky, though, when you consider the fact that values have to roll over when, for example, Monday turns into Tues- day or June becomes July. For instance, calculating the difference in minutes between 6:53 am and 7:04 am is easy enough: you can multiply the hours (6 and 7) by 60 for each value, add the minutes that do not make up the next full hour, then subtract to find the difference. But what if you want the difference in minutes between 11:57 pm and 1:13 am? This calculation is more com- plex because it involves a change in day. And the complexity only increases when the date interval spans months or years. Date in Days The following script shows one way to make date and time calculations much easier. Because UNIX and Linux calculate time based on a starting point of January 1, 1970, the script measures time in seconds since that date. Although the use of seconds may seem cumbersome, the math is simple, as you’ll see in the bit of code in the “Days Since Epoch” section of this chapter. You reduce the date and time values to numbers of seconds elapsed since the base date then manipulate these values. All of the issues that arise when spanning across calendar increments, such as days or months, simply disappear. You might use this type of calculation when determining the age of a user’s password. The third field of an account entry in a system /etc/shadow file contains the day value on which the password was changed for a particular account, as counted from 1/1/1970 (the epoch). This number can be used for various purposes—for example, to determine when passwords are about to expire so as to facilitate user notifications. You can find an exam- ple of this in Chapter 36 in connection with password aging. Converting all temporal quantities to elapsed time also reduces the complexity of making time comparisons. Suppose, for example, that you would like to monitor time synchronization between multiple network nodes. When you convert the time on a 20 CHAPTER 3 ■ DATE AND TIME MANIPULATION system to seconds elapsed since the beginning of the UNIX epoch, the calculation becomes a simple subtraction. ■ Caution Yes, the Network Time Protocol (NTP) keeps system clocks in sync. However, not all systems run NTP implementations. Also, clocks on some aging hardware keep such poor time that even NTP can‘t keep them in sync. NTP implementations can generally keep system clocks synchronized, but if a particular clock drifts beyond the panic threshold, NTP will not update the clock. Additionally, even where NTP is ubiq- uitous, systems can fail. The following “Days Since Epoch” script calculates the number of days between two dates. The valid dates for this equation (taken from the Gregorian calendar) range from October 15, 1582 to December 31, 9999. Dates outside this range (or dates from different calendars) require a different equation. This script is a fairly longhand way of getting these values, but the benefit is that it will run on most any system using ksh or bash. The alternatives may not. The script is based on the following formula. When the program runs, it calculates and displays the number of days that have elapsed since January 1, 1970 by determining the number for 1/1/1970 and subtracting that from the number for the current date. (Year*365)+(Year/4)-(Year/100)+(Year/400)+(Month*306001/10000)+(Day) There are a couple of caveats to using this formula to account for dates that land on a number line. In that case, before you perform the calculation, the values of Month and Year may need to be altered: for the months of January (1) and February (2), you must add 13 to Month and subtract 1 from Year; for all other months you simply add 1 to Month to return the correct value. The Day value to be used is always the day of the month. Thus, the equa- tion applied to January 1, 1970, is as follows: (1969*365)+(1969/4)-(1969/100)+(1969/400)+(14*306001/10000)+1 Days Since Epoch The start of the script sets the variables for the current time and date. Since the epoch (1/1/1970) is fixed, its value can be calculated once and the constant 719591 used in its place, thus saving some CPU cycles. #!/bin/sh epoch_days=719591 second=`date +'%S'` minute=`date +'%M'` hour=`date +'%k'` day=`date +'%d'` month=`date +'%m' | sed 's/0*//'` year=`date +'%Y'` CHAPTER 3 ■ DATE AND TIME MANIPULATION 21 You could improve the script’s performance as follows, although it reduces readability. Instead of performing a date call to set each time and date variable, you could make one date call that outputs space-delimited values, then place those values into an array. To initialize the array in ksh, use set -A DATE `date +"%S %M %k %d %m %Y" In bash, use declare -a DATE=( `date +"%S %M %k %d %m %Y"` ) For example, to access the third array element in either bash or ksh, use something like echo ${DATE[2]} where 2 is referencing the third element in the DATE array. Note that the first element in an array would be accessed with a subscript of 0. The following code makes the initial changes to the month and year variables the equa- tion needs: if [ $month -gt 2 ] then month=$(($month+1)) else month=$(($month+13)) year=$(($year-1)) fi If the month is not January or February (greater than 1 or 2), you have to add 1 to the month. Otherwise you have to add 13 to the month and subtract 1 from the year. The following code calculates the day value for today. Once you know this, you subtract the epoch value from that value to get the number of days since the start of the epoch. The script then outputs that value. The output is left unformatted in case you want to use the number as input for another command or process. today_days=$((($year*365)+($year/4)-\ ($year/100)+($year/400)+\ ($month*306001/10000)+$day)) days_since_epoch=$(($today_days-$epoch_days)) echo $days_since_epoch You may find it useful to have two versions of this script: one that outputs the elapsed time in days and the other that outputs it in seconds. seconds_since_epoch=`echo "($days_since_epoch*86400)+\ ($hour*3600)+($minute*60)+$second" | bc` The calculation to convert from days to seconds is fairly trivial. It may also be useful to turn the code for the calculations into functions and put them in your central library as discussed in Chapter 2. You then would need only to source this library into your current environment and call the function whenever needed. 22 CHAPTER 3 ■ DATE AND TIME MANIPULATION Alternatives for Finding the Date in Seconds There are two other ways to calculate the number of seconds since the epoch. Both of them are much simpler than the preceding script, but they require system utilities that you may not have installed, such as Perl and the latest GNU utilities. Most administrators would probably install whatever is needed to get the job done, but there are controlled production environments where it’s not that simple—sometimes many requirements must be met and testing must be performed before any changes are made to a system. In those cases, it is simpler to come up with a solution that utilizes existing resources as opposed to installing more-advanced tools. The first alternative uses the GNU version of the date command. If you have this ver- sion, you can produce output that is almost identical to that of the script discussed in the section “Days Since Epoch” except that, because the number of seconds since epoch in that script is calculated based on GMT, it may be out of sync with your local time zone. If so, you may want to add the appropriate number of seconds for your local time zone. (This may not be necessary if you’re using the values to simply calculate the difference between two arbitrary dates/times in which the local time zone information is irrele- vant.)The following date command is much simpler than deriving the calculations manually. This returns the number of seconds since epoch directly. gnu_seconds_since_epoch=`date +%s` There is also a Perl function for performing the same task. You can access it like this: perl_seconds_since_epoch=`perl -e 'print time'` Evaluating for the Current Day and Time Say you want to schedule a job, such as a system monitor, to run at particular times or on certain days. You want to know whether there are issues on the system, but you don’t necessarily want to be jarred awake by your pager simply to learn that the message is non- critical; you’d like to get those routine notices by page during the day and by e-mail at other times. The following script determines whether the current day and hour are within a certain time frame that you set. This code would be called from another script, which actually performs the notifications. Two sets of day and hour parameters (for a total of four) are passed to the script when it is called. These parameters specify a range of days (Sunday through Monday) and a range of hours when pages may be sent during those days. The script returns a 0 if the cur- rent day and hour are within those parameters and gives the user a message stating the CHAPTER 3 ■ DATE AND TIME MANIPULATION 23 same. If the current day and hour values do not lie within the given range, a different mes- sage is output and the function returns a 1 (representing failure). #!/bin/sh if [ $# -ne 4 ] then echo Usage: $0 {day begin} {day end} {hour begin} {hour end} echo " Days are 0-6 where 0 is Sunday." echo " Hours are 0-23." exit fi The script starts by determining how many parameters have been sent to the script. Recall that four is the expected number. If four parameters haven’t been sent, such as if the script calling this code were written incorrectly, you should output a usage message containing some explanation of how the script should be invoked. The usage explanation provided here shows that the four parameters that should be passed are DAY_BEGIN, DAY_END, HOUR_BEGIN, and HOUR_END. All of these values are integers in which the day values range from 0–6 where Sunday is 0, and the hours range from 0–23. If the parameter count is correct, the code assigns the parameters to variables with more meaningful names, such as DAY_BEGIN and DAY_END instead of 1 and 2. Making this change helps the readability and it is easier to see what is happening. DAY_BEGIN=$1 DAY_END=$2 HOUR_BEGIN=$3 HOUR_END=$4 Next, the variables for the current day and hour need to be set. DAY=`date +%w` HOUR=`date +%H` The code here is the main check to determine whether it is time to notify the adminis- trator. The large if statement compares the current DAY and HOUR values with the values that were passed to the script. if [ $DAY -ge $DAY_BEGIN -a $DAY -le $DAY_END\ -a $HOUR -ge $HOUR_BEGIN -a $HOUR -le $HOUR_END ] then echo "It is time to notify" return 0 else echo "It is not time to notify" return 1 fi 24 CHAPTER 3 ■ DATE AND TIME MANIPULATION ■ Note The valid day and hour ranges include the end points specified by the parameters. That is, if the script was invoked with DAY values of 1 and 5, the test should succeed on Monday, Friday, and on the days in between. In a real-world implementation, you would probably replace the echo lines with code for performing actual notification, such as a call to a paging utility such as QuickPage. 1 As mentioned earlier, I’ve assumed for simplicity that the actual notification is handled by the code that calls this script. That script might be an exhaustive monitoring utility that performs many types of monitoring tasks. Each monitor could call this script with differ- ent parameters based on the level of criticality. The calling script would then evaluate the return code by accessing the $? variable to determine whether to send a notification. To simplify this script, you could hard-code the DAY_BEGIN/DAY_END and HOUR_BEGIN/ HOUR_END ranges instead of assigning them the values of the passed parameters. You would then remove the validation check for the number of parameters passed. 1. QuickPage is an application that allows you to send messages to an alphanumeric pager. More infor- mation can be found at http://www.qpage.org. . 19 ■ ■ ■ CHAPTER 3 Date and Time Manipulation O n occasion, the need for date math arises, such as when you’re trying to calculate a time interval between. months or years. Date in Days The following script shows one way to make date and time calculations much easier. Because UNIX and Linux calculate time based

Ngày đăng: 05/10/2013, 08:51

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan