It turns out that you can't use an MySQL expression in a conditional: the above MySQL doesn't work.
Here is an example db_select() query that I came up with, that finds the difference between two flagging timestamps, and then makes sure that it's between two thresholds. I'm concerned that it's calculating the difference 3 times, but there doesn't seem to be a way around it, since the "duration" alias can't be used anywhere else, not even with raw MySQL.
$query = db_select('node', 'n');
$query->leftJoin('flagging', 'fass', 'fass.entity_id = n.nid AND fass.fid = :assigned', array(':assigned' => $task_assigned_fid));
$query->leftJoin('flagging', 'fcom', 'fcom.entity_id = n.nid AND fcom.fid = :completed', array(':completed' => $task_completed_fid));
$query->condition('fcom.timestamp', $this->date_endpoint0, '<');
$query->condition('fcom.timestamp', $this->date_endpoint1, '>=');
$query->condition('n.type', 'task', '=');
$query->isNotNull('fass.uid');
$query->isNotNull('fcom.uid');
$query->fields('n', array('nid'));
$query->fields('fass', array('timestamp'));
$query->fields('fcom', array('timestamp'));
// Note that we are calculating the difference three times. I'd prefer to do it once.
$query->addExpression('fcom.timestamp - fass.timestamp', 'duration');
$query->where('(CAST(fcom.timestamp as SIGNED) - CAST(fass.timestamp as SIGNED)) < :threshold0', array(':threshold0' => $threshold0));
$query->where('(CAST(fcom.timestamp as SIGNED) - CAST(fass.timestamp as SIGNED)) > :threshold1', array(':threshold1' => $threshold1));