Adding 4th table to join jumps processing time from seconds to over 20 minutes
SQL is not making up rows.
If that join is producing more rows than you expect then figure it out.
Are you sure ts.JobSubTypeId is a task code?
That name does not sound like a task code. 

Try this - it will show you were the volume is coming from
In your query each count is a row  

  -- this is the raw count from Timesheets
  SELECT ts.JobSubTypeId, count(*) as countRaw
  FROM JobsDB.dbo.Timesheets AS ts
  WHERE ts.WeekEnding &gt;= '2014-01-01' 
  GROUP BY ts.JobSubTypeId
  ORDER BY count(*) desc;

  -- this is the count brought in by the join to TaskCode
  SELECT ts.JobSubTypeId, count(*) as countJoin
  FROM JobsDB.dbo.Timesheets AS ts
  LEFT JOIN dbo.TaskCode AS tc
         ON tc.Code = ts.JobSubTypeId
  WHERE ts.WeekEnding &gt;= '2014-01-01' 
  GROUP BY ts.JobSubTypeId
  ORDER BY count(*) desc;

  -- this is the raw counts in TaskCode 
  SELECT tc.Code, count(*) as countCode
  FROM dbo.TaskCode AS tc
  GROUP BY tc.Code
  ORDER BY count(*) desc;


The fact that when you finally ran the second query and it ran fast is a very strong indication you have a volume and not an index issue.  That count(*) had to touch those rows.

Even if JobSubTypeId is Code that is clearly not a sufficient join   

ON tc.Code = ts.JobSubTypeId


TaskCode has a number of very detailed columns
Your are clearly bring in massive data from other projects