Pular para o conteúdo

Datas e horas

Arcane.Time: construir, formatar, comparar e fazer aritmética com datas.

Construir#

dataforge
adopt Arcane.Time as Time

Time.now()                        # agora, com hora
Time.today()                      # hoje à meia-noite
Time.date(2026, 12, 25)
Time.datetime(2026, 3, 15, 14, 30, 0)
Time.parse("2026-06-15")          # interpreta vários formatos

parse tenta ISO, brasileiro e as variantes com hora — sem você precisar dizer qual é.

Formatar#

ChamadaResultado
to_date_string(d)25/12/2026
to_time_string(d)14:30:00
to_br(d)25/12/2026 14:30:00
to_iso(d)2026-12-25T00:00:00
format(d, "%d/%m")livre, com códigos strftime

Componentes#

dataforge
Time.year(d)  Time.month(d)  Time.day(d)
Time.hour(d)  Time.minute(d)  Time.second(d)
Time.weekday(d)          # 0 = segunda
Time.weekday_name(d)     # "sexta-feira"
Time.month_name(d)       # "dezembro"
Time.quarter(d)          # 1..4
Time.day_of_year(d)      # 1..366

Os nomes vêm em português — é a língua do módulo, e evita traduzir "Friday" em cada relatório.

Aritmética#

dataforge
Time.add_days(d, 10)      Time.add_weeks(d, 2)
Time.add_months(d, 1)     Time.add_years(d, 1)
Time.add_hours(d, 3)      Time.add_minutes(d, 45)

Todas devolvem uma data nova — a original não muda. Para subtrair, passe um número negativo.

O caso difícil: add_months#

O que é "31 de janeiro mais um mês"? Não existe 31 de fevereiro.

dataforge
Time.add_months(Time.date(2026, 1, 31), 1)     # 28/02/2026

A regra é grampear no último dia válido do mês de destino — o que Java, C# e a maioria das bibliotecas fazem.

Diferenças#

dataforge
d := Time.diff(inicio, fim)

d.days             # 364
d.total_hours      # 8736.0
d.total_seconds    # 31449600.0
d.human            # "364d 0h"

Ter todos os formatos calculados evita a conta de conversão espalhada pelo código.

Humanizar#

dataforge
Time.humanize(45)       # "45s"
Time.humanize(90)       # "1min 30s"
Time.humanize(3725)     # "1h 2min"
Time.humanize(90000)    # "1d 1h"

A função escolhe a unidade sozinha — é o que você quer numa interface, onde "31449600 segundos" não diz nada.

Comparar#

dataforge
Time.is_before(a, b)      Time.is_after(a, b)
Time.is_same_day(a, b)    Time.is_weekend(d)
Time.is_leap_year(2024)   Time.age(nascimento)

is_same_day existe porque comparar dois DateTime diretamente compararia também a hora — duas coisas no mesmo dia, às 9h e às 15h, não são iguais.

Limites de período#

dataforge
Time.start_of_day(d)     Time.end_of_day(d)
Time.start_of_month(d)   Time.end_of_month(d)
Time.days_in_month(2024, 2)     # 29

start_of_day e end_of_day são o que você usa para filtrar "tudo de hoje" numa consulta — sem eles, comparar com Time.today() deixa de fora tudo depois da meia-noite.

Cronometrar#

dataforge
medida := Time.measure(trabalho_pesado)
out medida.result, round(medida.ms, 2)

crono := Time.stopwatch()
crono.start()
# ... trabalho
out round(crono.stop() * 1000, 2)

start depois de stop retoma — o acumulado não se perde. Isso permite medir só as partes que interessam.