Considerando um ano, mês e dia, como encontro o próximo dia da semana nessa data ou depois? Por exemplo, se eu tiver 28/04/2025, como encontro a sexta-feira seguinte a 28/04/2025, que é 02/05/2025?
Que tal encontrar o dia da semana anterior em vez do próximo?
Posso começar com int
valores, colocá-los chrono
e depois retirá int
-los?
Se a data de entrada já estiver no dia da semana de destino, o que é necessário para alterar entre obter a data de entrada ou obter uma semana a partir da data de entrada?
Para responder à primeira pergunta, é melhor dividi-la em partes:
Vamos chamar a data de início de:
date
, e o dia da semana de destino de:wd
.weekday
dedate
. Chame isso destarting_wd
.wd
que faltam parastarting_wd
. Chame isso denum_days
.num_days
àdate
.Isso pode parecer algo como:
Isso pode ser exercitado assim:
que imprime:
Notas:
weekday
dedate
já forwd
, isso adiciona 0days
e retornadate
.weekdays
é encapsulada para que você não precise se preocupar com ela. Não importa quais valoreswd
estarting_wd
tenham,num_days
sempre estará no intervalo dedays{0}
adays{6}
. Você pode pensar nissoweekdays
como um "intervalo circular".year_month_day
está correto, mas é ineficiente para esta operação. O tráficosys_days
seria mais eficiente.Para resolver este último problema, poderíamos alterar o tipo de retorno e o tipo de entrada do parâmetro
date
parasys_days
:Notas:
year_month_day
é uma{y, m, d}
estrutura de dados.sys_days
é uma{count of days since epoch}
estrutura de dados. Ambos representam uma data. E as conversões de um para o outro não perdem informações.2025-05-02
.year_month_day
(o tipo da expressãoApril/28/2025
) parasys_days
.date
antessys_days
de adicionarnum_days
.year_month_day
, essas conversões são feitas implicitamente. Portanto, essas conversões custam apenas aos clientes que precisam delas (pague apenas pelo que usar, de acordo com o princípio do design).Agora é fácil ver que é trivial eliminar os temporários locais e fazer disso uma linha:
Neste caso você precisa subtrair o número que
days
date
está à frente dewd
:Se conduzido por:
a saída agora é:
Se você tiver seus
year
,month
eday
como inteiros, isso se parece com:O tipo de retorno é
sys_days
, que é implicitamente conversível parayear_month_day
. Use os getters:.year()
,.month()
e.day()
:Neste caso ,
y
has typeyear
,m
has typemonth
ed
has typeday
. Se você quiser que sejaint
, basta converter explicitamente paraint
:month
eday
ter conversões explícitas paraunsigned
esse propósito.Nota: Essas conversões explícitas são exatamente o inverso de ir na outra direção: de tipos integrais para cronológicos:
Esta é uma API simétrica e fácil de lembrar.
Observação: para permitir que o compilador detecte erros de lógica no seu código, é melhor não converter para tipos integrais, mas sim permanecer dentro do sistema de tipos chrono. Isso transforma erros de lógica em erros de tempo de compilação. Mas se você precisar interoperar com outra biblioteca de datas, números inteiros geralmente são a única maneira de fazer isso.
Esta é uma transformação muito fácil: basta incrementar o
date
anterior ao algoritmo (ou decrementar no caso deprev_weekday
):Observação: o LLVM ainda não implementou o operador de incremento em
time_point
(em abril de 2025). Você pode contornar isso comdate += std::chrono::days{1};
.Pontos de bônus: aplique
constexpr
enext_weekday
funcionará também em tempo de compilação: