moved the date limitation into the join rather than the where clause. Can I still do better than 25 seconds?
Yeah... you can get it much snappier that 25 seconds. This is not an answer that I can just plop out here for you, but I can give you some suggestions to work towards a resolution. First, SQL Server Management Studio has a feature that shows you the execution plan. You can have SQL Server show you how it plans to execute the query:

Secondly, SQL Server doesn't like anything negative (i.e. NOT statements). And if I recollect, a LEFT OUTER JOIN is somewhat negative. Depending on what you are trying to accomplish, you would be better of doing a LEFT JOIN and then using COALESCE to make sure no NULL values end up in your results...or doing more than one query versus trying to get it all into one statement...thus the beauty of a UDF.
Third, dates can be picky as well. When you have a date that uses a < or > operator, the query has to sort itself before testing (I am pretty sure...I know that a BETWEEN or doing a <= and >= on the same date does). So this can be a performance issue as well. So in this case, you can create a UDF that just does this test for you on a passed parameter so that it isn't part of the query and performance can increase as well.
Finally, SQL Server comes with some statistics command that can help. For example, you can turn on the following:
SET STATISTICS PROFILE ON - This will spit out the actual execution path that was used when the query takes place. You will use this within the Management Studio.
SET STATISTICS TIME ON - This will show you exactly how long each portion of the execution took in the Messages window when a query is performed.
On both of these commands you will have to turn it on for each connection that you have (i.e. if you have more than one query window open).
But that is basically how we work through a speed and performance issue when dealing with large datasets and complicated queries.