Run SQL Job monthly at day 16. If it's a weekend, run it in the next business day ( dont care if is a holiday)
It's not beautiful, but you could wrap all of your conditions into a CASE like so:
DECLARE @IsGood bit;
SET @IsGood = SELECT CASE WHEN DAY(GETDATE()) = 16 AND DATEPART(WEEKDAY, GETDATE()) NOT IN (1, 7) THEN 1
                          WHEN DAY(GETDATE()) IN (17, 18) AND DATEPART(WEEKDAY, GETDATE()) = 2 THEN 1
                          ELSE 0 END;

IF @IsGood &lt;&gt; 1
    RAISERROR ('Nope. Not today.', 16, 1); 

Throw that into a scheduled job that runs on the 16th, 17th, and 18th of every month, and you'll be good.