Not sure the best way to accomplish this.
I get these results to a text file from a mysql query. I would like to the sort 4th column with the oldest entry first.
10.xxx.xxx.xxx 70:xx:xx:xx:xx:xx Wed Apr 3 17:00:52 2013 Mon Apr 15 09:42:33 2013
10.xxx.xxx.xxx 70:xx:xx:xx:xx:xx Mon Apr 8 14:01:05 2013 Mon Apr 15 09:42:33 2013
10.xxx.xxx.xxx 70:xx:xx:xx:xx:xx Fri Apr 5 13:00:56 2013 Mon Apr 15 09:42:33 2013
10.xxx.xxx.xxx 70:xx:xx:xx:xx:xx Mon Apr 8 08:00:59 2013 Mon Apr 8 08:00:59 2013 10.xxx.xxx.xxx 70:xx:xx:xx:xx:xx Thu Mar 28 14:15:12 2013 Fri Apr 5 09:00:55 2013
10.xxx.xxx.xxx 70:xx:xx:xx:xx:xx Thu Mar 28 14:15:12 2013 Fri Apr 5 07:00:53 2013
sort -r -k10 test does not seem to cut it.
A Perl solution using Time::Piece (in the Perl standard library since 5.10.0) and a Schwartzian Transform.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
say map { $_->[0] }
sort { $a->[1] cmp $b->[1] }
map { [ $_, sortdate($_) ] } <DATA>;
sub sortdate {
my $date = join ' ', (split)[2 .. 6];
return Time::Piece->strptime($date, '%a %b %d %H:%M:%S %Y')->datetime;
}
__END__
10.xxx.xxx.xxx 70:xx:xx:xx:xx:xx Wed Apr 3 17:00:52 2013 Mon Apr 15 09:42:33 2013
10.xxx.xxx.xxx 70:xx:xx:xx:xx:xx Mon Apr 8 14:01:05 2013 Mon Apr 15 09:42:33 2013
10.xxx.xxx.xxx 70:xx:xx:xx:xx:xx Fri Apr 5 13:00:56 2013 Mon Apr 15 09:42:33 2013
10.xxx.xxx.xxx 70:xx:xx:xx:xx:xx Mon Apr 8 08:00:59 2013 Mon Apr 8 08:00:59 2013
10.xxx.xxx.xxx 70:xx:xx:xx:xx:xx Thu Mar 28 14:15:12 2013 Fri Apr 5 09:00:55 2013
10.xxx.xxx.xxx 70:xx:xx:xx:xx:xx Thu Mar 28 14:15:12 2013 Fri Apr 5 07:00:53 2013
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
(
FOR /f "tokens=1-7*" %%a IN (sqlout.txt) DO (
SET "month="
FOR %%m IN (01 Jan 02 Feb 03 Mar 04 Apr 11 Nov 12 Dec) DO IF NOT DEFINED month (
IF %%d==%%m SET month=!prev!
SET prev=%%m
)
SET /a day=100+%%e
ECHO(%%g!month!!day!%%f*%%a %%b %%c %%d %%e %%f %%g %%h
)
)>tempfile.1
(
FOR /f "delims=" %%i IN ('sort tempfile.1') DO (
SET line=%%i
ECHO(!line:**=!
)
) >sortedoutput.txt
DEL tempfile.1 /F /Q
On the sample data, there are 8 significant columns. Of these, the fourth is month, fifth date, sixth time and seventh year. I have no idea what you mean by the "fourth" column being "the" date since there are two separate dates in each line.
The process simply picks up the fourth column and looks through a list of month numbers (2-digit) and month abbreviations. It's easier to save the previous element for use when the next is compared, so when the monthname matches the fourth column in %%d, the month variable is set, and that will turn off any further processing of the month.
You may have noticed I've not listed all of the months This gives you something to do. It obviously won't work unless all of the months are entered in the list.
Next we deal with the fifth column, and add 100 to the day number, producing a number from 101 to 131. These numbers all have three characters.
Next we ECHO out a string of
the year from column 7 in %%g
the 2-character month number in month
the 3-digit augmented day number
the time from column 6
an asterisk
each of the elements of the original line
Next step is to read each of those lines after sorting.
set the sorted line into line
echo everything from line except the part up to the first asterisk.
Related
I'm attempting to write a script that changes the background color of each column containing a weekend date. For some reason, the script gets thrown off for the month of March and I have no idea why.
For purposes of debugging, I limited the script to only change Sundays. Here is what I know:
Script loops through each column in sequential order as expected without skipping a column (col 2 - col 85)
Script colors the wrong dates in March
March 8 appears to be the culprit
it reads the date 3/8, correctly as a Sunday, but it also reads the following
Monday (3/9) as "Sun Mar 08" instead of "Mon Mar 09". So it
reads both Sunday (3/8) and Monday (3/9) as "Sun Mar 08".
dates remain off by 1 for the rest of March
"Sun Apr 05" gets skipped all together - goes from "Sat Apr 04" to "Mon Apr 06"
Dates resume as expected on "Mon Apr 06"
Happens to 2019 dates as well (dates off by one starting the 2nd Sunday in March to the 2nd Sunday in April)
I'm 100% perplexed. I've googled endlessly and tried so many things to no avail! Anyone have a clue what I'm missing or doing incorrectly?! Any help would be greatly appreciated!
Here's the script:
//Change column background color for weekend dates
function colorAll() {
var sheet = SpreadsheetApp.getActiveSheet();
var startCol = 2; //start with column B
var endCol = sheet.getLastColumn(); // find last column in the sheet
for (var c = startCol; c <= endCol; c++) { //loop through columns
colorCol(c);
}
}
//Change background color for each column passed to 'c'
function colorCol(c) {
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getRange(1, c, 5, 1); //row 1, column "c", selection size = 5 rows by 1 column
var data = dataRange.getValues();
var col = data[0];
var date = new Date(col);
var dayOfWeek = date.getDay();
//Logs values being passed to each variable in order to help debug process
Logger.log("*** Processing column number: " + c + " now ***");
Logger.log(col);
Logger.log(date);
Logger.log(dayOfWeek);
//If the day of week is Sunday:
if (dayOfWeek == 0) {
dataRange.setBackground("#E8E8E8"); //set weekends to grey
} else {
dataRange.setBackground("#ffffff"); //set non-weekends to white
}
// //If day of week is Sat or Sun:
// if (dayOfWeek == 0 || dayOfWeek == 6) {
// if (col[0] === "") {
// dataRange.setBackgroundRGB(255, 255, 255);
// } else {
// dataRange.setBackground("#E8E8E8");
// }
// }
}
I put together the following google sheet for testing. Permissions are set so anyone with the link can edit so have at it :)
By double clicking B1, you can choose whatever start day you want. The bottom 3 rows return the week day number as read by sheets (1-7), the week day number as read by apps script (0-6), and the corresponding number for each column (B=2, C=3, etc).
Also, in case it helps...
Latest log for the dates surrounding March 8
expected date pattern = 6, 0, 1, 2, 3
returned date pattern = 6, 0, 0, 1, 2
[20-03-10 10:13:05:886 PDT] ***Processing column number: 7 now***
[20-03-10 10:13:05:887 PDT] [Sat Mar 07 00:00:00 GMT-06:00 2020]
[20-03-10 10:13:05:888 PDT] Sat Mar 07 00:00:00 GMT-06:00 2020
[20-03-10 10:13:05:890 PDT] 6.0
[20-03-10 10:13:06:207 PDT] *** Processing column number: 8 now ***
[20-03-10 10:13:06:209 PDT] [Sun Mar 08 00:00:00 GMT-06:00 2020]
[20-03-10 10:13:06:211 PDT] Sun Mar 08 00:00:00 GMT-06:00 2020
[20-03-10 10:13:06:212 PDT] 0.0
[20-03-10 10:13:06:555 PDT] *** Processing column number: 9 now ***
[20-03-10 10:13:06:558 PDT] [Sun Mar 08 23:00:00 GMT-06:00 2020]
[20-03-10 10:13:06:561 PDT] Sun Mar 08 23:00:00 GMT-06:00 2020
[20-03-10 10:13:06:563 PDT] 0.0
[20-03-10 10:13:06:915 PDT] *** Processing column number: 10 now ***
[20-03-10 10:13:06:917 PDT] [Mon Mar 09 23:00:00 GMT-06:00 2020]
[20-03-10 10:13:06:918 PDT] Mon Mar 09 23:00:00 GMT-06:00 2020
[20-03-10 10:13:06:920 PDT] 1.0
[20-03-10 10:13:07:343 PDT] *** Processing column number: 11 now ***
[20-03-10 10:13:07:345 PDT] [Tue Mar 10 23:00:00 GMT-06:00 2020]
[20-03-10 10:13:07:347 PDT] Tue Mar 10 23:00:00 GMT-06:00 2020
[20-03-10 10:13:07:348 PDT] 2.0
Log for the dates surrounding April 5
expected date pattern = 5, 6, 0, 1
returned date pattern = 5, 6, 1, 2
[20-03-10 10:13:15:446 PDT] *** Processing column number: 35 now ***
[20-03-10 10:13:15:447 PDT] [Fri Apr 03 23:00:00 GMT-06:00 2020]
[20-03-10 10:13:15:449 PDT] Fri Apr 03 23:00:00 GMT-06:00 2020
[20-03-10 10:13:15:450 PDT] 5.0
[20-03-10 10:13:16:032 PDT] *** Processing column number: 36 now ***
[20-03-10 10:13:16:036 PDT] [Sat Apr 04 23:00:00 GMT-06:00 2020]
[20-03-10 10:13:16:038 PDT] Sat Apr 04 23:00:00 GMT-06:00 2020
[20-03-10 10:13:16:039 PDT] 6.0
[20-03-10 10:13:16:334 PDT] *** Processing column number: 37 now ***
[20-03-10 10:13:16:336 PDT] [Mon Apr 06 00:00:00 GMT-05:00 2020]
[20-03-10 10:13:16:338 PDT] Mon Apr 06 00:00:00 GMT-05:00 2020
[20-03-10 10:13:16:339 PDT] 1.0
[20-03-10 10:13:16:652 PDT] *** Processing column number: 38 now ***
[20-03-10 10:13:16:658 PDT] [Tue Apr 07 00:00:00 GMT-05:00 2020]
[20-03-10 10:13:16:678 PDT] Tue Apr 07 00:00:00 GMT-05:00 2020
[20-03-10 10:13:16:684 PDT] 2.0
Thank you in advance for your time and help!
UPDATE: Adding screenshot of the aforementioned google sheet for reference
debugScript_colorAll screenshot
(note: it says I'm not allowed to embed images yet since I am a new user. Apparently a link to the image is the best I can do. Sorry Cooper)
The problem in this case is a mismatch between the timezone in your script and the timezone in your sheet, and more specifically that one of those timezones is observing a daylight-savings time change while the other is either not, or is observing it a month later.
The sudden time change to 23:00:00 on the "second" March 8th in your logs is the main clue. Note how the previous times are at 00:00:00 - midnight.
Your sheet is set to "Central Time", while your script is set to "Central Time - Mexico City". Apparently they disagree in March.
One solution is to ensure both your script and sheet are in the same timezone.
In the sheet this is found under File -> Settings. In the script under File -> Properties.
If you want to preserve the different timezones, or if you want the script to be timezone, you will need to take further action in your code to manually handle the difference, which can be complex. (It can also be as simple as ensuring the dates are at noon, instead of midnight).
Try this:
function colorAll() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var sc=2;
var vs=sh.getRange(1,sc,1,sh.getLastColumn()).getValues()[0];
vs.forEach(function(c,i){
var dow=new Date(c).getDay();
//Sun - Sat = 0 - 6
if(dow==6 || dow==0) {
sh.getRange(1,i+sc,5,1).setBackground('#E8E8E8');
}else{
sh.getRange(1,i+sc,5,1).setBackground('#FFFFFF');
}
});
}
Animation:
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have a log from my application like below as an example:
{Fri Mar 16 19:07:47 Program: job-a: <blah><blah>
Fri Mar 16 19:07:47 Program: job-a: <blah><blah>
Fri Mar 16 19:07:48 Program: job-b: <blah><blah>
Fri Mar 16 19:07:48 Program: job-b: <blah><blah>
Fri Mar 16 19:07:50 Program: job-b: <blah><blah>
Fri Mar 16 19:07:51 Program: job-b: <blah><blah>
Fri Mar 16 19:07:52 Program: job-a: <blah><blah>
Fri Mar 16 19:07:52 Program: job-a: <blah><blah>
Fri Mar 16 19:07:53 Program: job-a: <blah><blah>
Fri Mar 16 19:07:54 Program: job-a: <blah><blah>
Fri Mar 16 19:07:55 Program: job-a: <blah><blah>
Fri Mar 16 19:08:00 Program: job-a: <blah><blah>
Fri Mar 16 19:08:01 Program: job-a: <blah><blah>
Fri Mar 16 20:33:52 Program: job-c: <blah><blah>
Fri Mar 16 20:45:56 Program: job-c: <blah><blah>}
For each Job name (job-a, job-b, job-c) in this case, I need to find the first and last occurrences of the line to identify the start and end times.
i.e. I need to output the program/job name, start_time and end_time as shown in my sample output below. I have shown the expected output as comma separated, but I don't really care about the delimiter as I'm only interested in the values. Ignore the curly braces at the beginning and end in the sample input/output.
job-a, Fri Mar 16 19:07:47, Fri Mar 16 19:08:01
job-b, Fri Mar 16 19:07:48, Fri Mar 16 19:07:51
job-c, Fri Mar 16 20:33:52, Fri Mar 16 20:45:56
You could do with awk and here I'm just showing how you can get first and last occurrences of each job.
awk '!first[$6]{ first[$6]=$4 } { last[$6]=$4 }
END{ for (x in last) print x, first[x], last[x] }' OFS=', ' infile
job-a:, 19:07:47, 19:08:01
job-b:, 19:07:48, 19:07:51
job-c:, 20:33:52, 20:45:56
Here is an example in Perl:
use feature qw(say);
use strict;
use warnings;
my $fn = 'log.txt';
open ( my $fh, '<', $fn ) or die "Could not open file '$fn': $!";
my %jobs;
while (my $line = <$fh>) {
chomp $line;
next if $line !~ /job/;
my ($date, $job ) = $line =~ /^(.*?)\s*Program:\s*(job.*?):/;
if (exists $jobs{$job}) {
$jobs{$job}->{end} = $date;
}
else {
$jobs{$job}->{start} = $date;
}
}
close $fh;
for my $job (sort keys %jobs) {
say join ", ", $job, $jobs{$job}->{start}, $jobs{$job}->{end};
}
I am trying to find the first occurrence of a date, happens to be in 'MMM dd" format, within a coloumn, by using findIndex method.
The following code isnt able to achieve it
function copyInvoiceDetailsToDB() {
var sss = SpreadsheetApp.getActiveSpreadsheet();
var ss = sss.getSheetByName('Import MT Order Sheet'); //Source Sheet
var compareDate = ss.getRange(1,4).getValue(); // Search item
///var mmm = Utilities.formatDate(compareDate,"IST", 'MMM dd');
var reldata = ss.getRange('A3:AA'+ a).getValues();
var tss = SpreadsheetApp.openById("1xhPD6tlJiU33_tdnC82p-
e9rWA8mmMtI0g9jDLkk6s0"); // sheet being searched
var ss = tss.getSheetByName('DB');
var ssdata = ss.getRange('A:A').getValues(); // Range containing the values
var a = ssdata.indexOf(compareDate);
Logger.log(a);
Logger.log(compareDate);
Logger.log(ssdata);
return;
Generates the following log.
Please help me understand where I must be going wrong.
[17-11-22 02:40:11:568 IST] -1.0
[17-11-22 02:40:11:569 IST] Nov 22
[17-11-22 02:40:11:572 IST] [[], [Sun Nov 19 00:00:00 GMT+05:30 2017], [Mon Nov 20 00:00:00 GMT+05:30 2017], [Mon Nov 20 00:00:00 GMT+05:30 2017], [Mon Nov 20 00:00:00 GMT+05:30 2017], [Tue Nov 21 00:00:00 GMT+05:30 2017], [Tue Nov 21 00:00:00 GMT+05:30 2017], [Wed Nov 22 00:00:00 GMT+05:30 2017], [Wed Nov 22 00:00:00 GMT+05:30 2017], [Wed Nov 22 00:00:00 GMT+05:30 2017], [Wed Nov 22 00:00:00 GMT+05:30 2017], [Wed Nov 22 00:00:00 GMT+05:30 2017], [Wed Nov 22 00:00:00 GMT+05:30 2017], [Wed Nov 22 00:00:00 GMT+05:30 2017], [Wed Nov 22 00:00:00 GMT+05:30 2017], [Wed Nov 22 00:00:00
How about this answer? From your question, I understood as follows.
You want to retrieve the first occurrence (the row number?) of a date using a string 'MMM dd".
You want to understand for retrieving values using indexOf().
About retrieving values from array using indexOf()
When you want to retrieve a value from an array using indexOf(), the array has to be 1 dimensional array. This is pointed out by Sandy Good.
When a value is retrieved from an 1 dimensional array using indexOf(), it doesn't retrieve the value included in each element, it retrieves the same value for each element.
["foo", "bar", "baz"].indexOf("ba") is -1.
This means that there is no "ba" in each element in the array.
["foo", "bar", "baz"].indexOf("bar") is 1.
This means that there is "bar" at index 1 of the array.
When it retrieves the value included in each element, each element has to be used as a string.
["foo", "bar", "baz"].indexOf("ba") is -1.
"bar".indexOf("ba") is 0.
This means that the string of "ba" is found at 1st string in "bar". So in the case of "bbbar".indexOf("ba"), the result is 2.
The modification point reflected them is as follows.
Modification point :
From :
var a = ssdata.indexOf(compareDate);
Logger.log(a);
To :
var a;
for (var i in ssdata) {
if (ssdata[i][0].indexOf(compareDate) > -1) {
a = i;
break;
}
}
Logger.log(a);
a is the index with the value included "Nov 22" in the array of ssdata. If you want to the row number, please add 1 to it.
When your result shown at the log is used, a is 7.
References :
Array.prototype.indexOf()
String.prototype.indexOf()
If I misunderstand your question, I'm sorry.
I am trying to touch a file(for referencing date) with a future date something like -
Current date - $date
Fri Jan 6 03:59:55 EST 2017
touch -t 201702032359.59 /var/tmp/ME_FILE_END
on checking the timestamp of the file as -
$ ls -lrt /var/tmp/ME_FILE_END
getting an output with only date and not the entire timestamp(hhmm.sec)
-rw-r--r-- 1 abcproc abc 0 Feb 3 2017 /var/tmp/ME_FILE_END
But for a date with is less than or equal to current it gives correct result -
touch -t 201612010000.00 /var/tmp/ME_FILE_START
ls -lrt /var/tmp/ME_FILE_START
-rw-r--r-- 1 abcproc abc 0 Dec 1 00:00 /var/tmp/ME_FILE_START
Can someone please suggest why this discrepancy ?
It's just the way ls displays the date. When far from now, the modification time is not displayed.
If you want details regarding the last access / modification / change time, you should be using stat.
stat /var/tmp/ME_FILE_END
You will see the expected output.
For example:
[10:29:41]dabi#gaia:~$ touch -t 201702032359.59 /var/tmp/ME_FILE_END
[10:29:43]dabi#gaia:~$ ls -ltr /var/tmp/ME_FILE_END
-rw-rw-r-- 1 dabi dabi 0 feb. 3 2017 /var/tmp/ME_FILE_END
[10:29:47]dabi#gaia:~$ stat /var/tmp/ME_FILE_END
File : '/var/tmp/ME_FILE_END'
Size : 0 Blocks : 0 I/O blocks : 4096 empty file
Device : 803h/2051d Inode : 5374373 Links : 1
Access : (0664/-rw-rw-r--) UID : ( 1000/ dabi) GID : ( 1000/ dabi)
Access : 2017-02-03 23:59:59.000000000 +0100
Change : 2017-02-03 23:59:59.000000000 +0100
Change : 2017-01-06 10:29:43.364630503 +0100
Birth : -
I've seen this question answered in other languages but not the Korn Shell. I need to prevent a script from being run on the last business day of the month (we can assume M-F are business days, ignore holidays).
This function works in Bash, Korn shell and zsh, but it requires a date command (such as GNU date) that has the -d option:
function lbdm { typeset lbdm ldm dwn m y; (( m = $1 + 1 )); if [[ $m = 13 ]]; then m=1; (( y = $2 + 1 )); else y=$2; fi; ldm=$(date -d "$m/1/$y -1 day"); dwn=$(date -d "$ldm" +%u);if [[ $dwn = 6 || $dwn = 7 ]]; then ((offset = 5 - $dwn)); lbdm=$(date -d "$ldm $offset day"); else lbdm=$ldm; fi; echo $lbdm; }
Run it like this:
$ lbdm 10 2009
Fri Oct 30 00:00:00 CDT 2009
Here is a demo script broken into separate lines and with better variable names and some comments:
for Month in {1..12} # demo a whole year
do
Year=2009
LastBusinessDay=""
(( Month = $Month + 1 )) # use the beginning of the next month to find the end of the one we're interested in
if [[ $Month = 13 ]]
then
Month=1
(( Year++ ))
fi;
# these two calls to date could be combined and then parsed out
# this first call is in "American" order, but could be changed - everything else is localized - I think
LastDayofMonth=$(date -d "$Month/1/$Year -1 day") # get the day before the first of the month
DayofWeek=$(date -d "$LastDayofMonth" +%u) # the math is easier than Sun=0 (%w)
if [[ $DayofWeek = 6 || $DayofWeek = 7 ]] # if it's Sat or Sun
then
(( Offset = 5 - $DayofWeek )) # then make it Fri
LastBusinessDay=$(date -d "$LastDayofMonth $Offset day")
else
LastBusinessDay=$LastDayofMonth
fi
echo "$LastDayofMonth - $DayofWeek - $LastBusinessDay"
done
Output:
Sat Jan 31 00:00:00 CST 2009 - 6 - Fri Jan 30 00:00:00 CST 2009
Sat Feb 28 00:00:00 CST 2009 - 6 - Fri Feb 27 00:00:00 CST 2009
Tue Mar 31 00:00:00 CDT 2009 - 2 - Tue Mar 31 00:00:00 CDT 2009
Thu Apr 30 00:00:00 CDT 2009 - 4 - Thu Apr 30 00:00:00 CDT 2009
Sun May 31 00:00:00 CDT 2009 - 7 - Fri May 29 00:00:00 CDT 2009
Tue Jun 30 00:00:00 CDT 2009 - 2 - Tue Jun 30 00:00:00 CDT 2009
Fri Jul 31 00:00:00 CDT 2009 - 5 - Fri Jul 31 00:00:00 CDT 2009
Mon Aug 31 00:00:00 CDT 2009 - 1 - Mon Aug 31 00:00:00 CDT 2009
Wed Sep 30 00:00:00 CDT 2009 - 3 - Wed Sep 30 00:00:00 CDT 2009
Sat Oct 31 00:00:00 CDT 2009 - 6 - Fri Oct 30 00:00:00 CDT 2009
Mon Nov 30 00:00:00 CST 2009 - 1 - Mon Nov 30 00:00:00 CST 2009
Thu Dec 31 00:00:00 CST 2009 - 4 - Thu Dec 31 00:00:00 CST 2009
Note: I discovered during testing that if you try to use this for dates around World War II that it fails due to wartime time zones like CWT and CPT.
Edit: Here's a version that should run on AIX and other systems that can't use the above. It should work on Bourne, Bash, Korn and zsh.
function lbdN { cal $1 $2 | awk 'NF == 0 {next} FNR > 2 {week = $0} END {num = split(week, days); lbdN = days[num]; if ( num == 1 ) { lbdN -= 2 }; if ( num == 7 ) { lbdN-- }; print lbdN }'; }
You may have to make adjustments if your cal starts weeks on Monday.
Here's how you can use it:
month=12; year=2009 # if these are unset or null, the current month/year will be used
if [[ $(date +%d) == $(lbdN $month $year) ]];
then
echo "Don't do stuff today"
else
echo "It's not the last business day of the month"
fi
making appropriate adjustments for your shell's if...then syntax, of course.
Edit: Bug Fix: The previous version of lbdN failed when February ends on Saturday the 28th because of the way it used tail. The new version fixes that. It uses only cal and awk.
Edit: For completeness, I thought it would be handy to include functions for the first business day of the month.
Requires date with -d:
function fbdm { typeset dwn d; dwn=$(date -d "$1/1/$2" +%u); d=1; if [[ $dwn = 6 || $dwn = 7 ]]; then (( d = 9 - $dwn )); fi; echo $(date -d "$1/$d/$2"); }
For May 2010:
Mon May 3 00:00:00 CDT 2010
Requires cal and awk only:
function fbdN { cal $1 $2 | awk 'FNR == 3 { week = $0 } END { num = split(week, days); fbdN = days[1]; if ( num == 1 ) { fbdN += 2 }; if ( num == 7 ) { fbdN++ }; print fbdN }'; }
For August 2010:
2