Como pesquisar por mês ou ano no Laravel?

Eu já ensinei aqui no blog [como criar filtros de pesquisa no Laravel através de um intervalo de datas]({% post_url 2020-11-09-criando-filtros-de-pesquisa-por-intervalo-de-datas-no-laravel %}). Porém há outro caso muito comum, que é quando precisamos pesquisar através apenas do mês e ano de uma coluna.


Pesquisando dados por mês ou ano

No Laravel, você pode fazer um filtro de pesquisa em um campo do tipo DATETIME ou TIMESTAMP facilmente. Por exemplo, ao utilizar o Eloquent, você precisaria apenas chamar os métodos whereYear ou whereMonth para filtrar pelo ano ou mês (respectivamente) da data registrada em uma coluna de uma tabela.

No exemplo abaixo, temos um controller que retorna uma lista de produtos. Iremos criar um filtro de pesquisa, que devolva um resultado baseado no ano e mês em que esses produtos foram criados. Utilizaremos o campo created_at para fazer isso.

class ProdutosController extends Controller
{
    function index(Request $request) 
    {
        $query = Produto::query();
    if ($request->has('ano')) {
        $query->whereYear('created_at', '=', $request->ano);
    }

    if ($request->has('mes')) {
        $query->whereMonth('created_at', '=', $request->mes);
    }

    return $query->paginate(); // ou $query->get() se quiser retornar tudo
}

}

Route::get('/produtos', 'ProdutosController@index');

No nosso exemplo acima, para realizar a pesquisa, bastaria informar o mês e o ano na query string para obter os resultados filtrados.

Veja:

/produtos?mes=2&ano=2021

O $request->has() aplicado aos campos mese ano faz com que a pesquisa seja opcional. Caso um desses campos não sejam informados, não será adicionado a condição ao seu resultado.

Exemplo:

/produtos?ano=2021 

Explicando o funcionamento de whereYear e WhereMonth no Laravel

O método whereYear modifica a SQL internamente, adicionando YEAR(created_at). Esta função do SGBD específico (Mysql, Sqlite e afins) faz com que seja capturado apenas o ano da coluna informada. Já whereMonth adiciona MONTH(created_at). O próprio SGBD cuidará de executar a pesquisa baseada no ano e mês informados.

Exemplificando melhor, suponhamos que você tenha o valor 2015-02-12 12:03:00 registrado na sua coluna created_at. Os valores retornados seriam os seguintes:

SELECT  YEAR('2015-02-12 12:03:00'); /* 2015 */
SELECT MONTH('2015-02-12 12:03:00'); /* 2 */

Testando a formação da sua SQL Query

Para testar como uma SQL é criada ao chamar o Query Builder do Laravel, você pode utilizar o toSql.

Veja:

echo Produto::whereYear('created_at', '=', 2021)->whereMonth('created_at', '=', 2)->toSql();

Isso irá gerar a saída:

select * from `produto` where year(`created_at`) = ? and month(`created_at`) = ?