Com datas (e horas) muitas coisas se tornam mais simples se você usar
>= start AND < end
. Por exemplo:
SELECT
user_id
FROM
user_logs
WHERE
login_date >= '2014-02-01'
AND login_date < '2014-03-01'
Nesse caso, você ainda precisa calcular a data de início do mês que precisa, mas isso deve ser direto de várias maneiras.
A data de término também é simplificada; basta adicionar exatamente um mês. Sem mexer com 28, 30, 31, etc.
Essa estrutura também tem a vantagem de poder manter o uso de índices.
Muitas pessoas podem sugerir um formulário como o seguinte, mas não usar índices:
WHERE
DATEPART('year', login_date) = 2014
AND DATEPART('month', login_date) = 2
Isso envolve calcular as condições para cada linha na tabela (uma varredura) e não usar o índice para encontrar o intervalo de linhas que corresponderá (uma busca de intervalo).