Percursos
/
Julia
Julia
/
Exercícios
/
Marcações de beleza
Marcações de beleza

Marcações de beleza

Exercício de aprendizagem

Introdução

"Datas e horas são algo que ensinamos a crianças pequenas. Quão difícil pode ser?"

Muitos programadores já cometeram esse erro, e a experiência que se segue costuma ter um efeito negativo na sua saúde e felicidade.

Quem faz programação não trivial com datas e horas deve, no mínimo, estar preparado para compreender e mitigar potenciais problemas.

Este documento procura dar uma visão geral de como a Julia trata datas e horas, mas será necessário consultar o manual para mais detalhes. Há também um Wikibook cujas explicações alguns leitores podem achar mais claras, e que inclui um diagrama útil da hierarquia de tipos.

O módulo Dates

A maior parte da funcionalidade básica está em Dates, um módulo incluído numa instalação padrão, mas que não faz parte da biblioteca padrão.

Para usar o módulo, há duas opções:

  1. Acrescentar import Dates e depois preceder todas as chamadas de funções com Dates.
  2. Acrescentar using Dates, o que traz todo o módulo para o espaço de nomes atual (exceto alguns nomes problemáticos).
# option 1
julia> import Dates

julia> Dates.now()
2025-06-21T16:02:39.080

julia> now()  # wrong: need to include `Dates.` after an import
ERROR: UndefVarError: `now` not defined in `Main`


# option 2
julia> using Dates

julia> now()  # functions are now in the namespace
2025-06-21T16:03:04.161

O módulo Dates é grande e complicado, mas fornece quatro tipos principais de funcionalidade:

  • Dates.Date, que inclui dia, mês e ano, mas não a hora do dia.
  • Dates.Time, que inclui a hora do dia, mas não a data.
  • Dates.DateTime, que combina data e hora.
  • Dates.Period, que trata intervalos de tempo/data.

Repara que um DateTime geralmente não inclui informação de fuso horário (o Python chamaria a isto um datetime "naive"). Uma exceção é now(), que obtém a hora local do relógio do teu sistema e que a pode converter para UTC, se for necessário.

Talvez as necessidades mais frequentes sejam:

  • Analisar um formato de entrada adequado para construir um tipo Dates.
  • Obter o formato numérico ou de string necessário a partir de um tipo Dates.
  • Aplicar um deslocamento a um valor Date, Time ou DateTime.
  • Calcular o intervalo entre dois desses valores.
  • Obter a data atual (com today()) e/ou a hora (com now()).
Note

Para reduzir a distração visual, a maior parte do código de exemplo no resto deste documento assume using Dates e evita incluir o nome do módulo Dates. nas chamadas de funções.

Formatos de data e hora

Há muitas formas de escrever datas e horas, que tendem a ser específicas de cada cultura. As datas só com números, como "7/6/23", são ambíguas e confusas, e já levaram a muitos erros dispendiosos em organizações multinacionais (o autor fala por amarga experiência pessoal).

O padrão internacional está definido na ISO 8601 e tem duas vantagens principais:

  • A análise é rápida e inequívoca.
  • A ordenação é fácil, pois a data/hora pode ser tratada como texto normal e ordenada alfabeticamente.

Vimos num exemplo anterior que Date.now() devolvia 2025-06-21T16:03:04.161.

Isto é composto por várias partes:

  • YYYY-MM-DD para a parte da data.
  • hh:mm:ss para a parte da hora.
  • Opcionalmente, milissegundos (ou uma unidade ainda menor) depois do ponto decimal.

Outros formatos de string serão abordados numa secção posterior.

Datas

Dates.Date é um tipo relativamente simples, só de data, sem qualquer compreensão de horas ou fusos horários.

# constructor with year, month, day arguments
julia> date1 = Date(2025, 06, 23)
2025-06-23

# constructor with ISO 8601 string
julia> date2 = Date("2025-06-23")
2025-06-23

julia> date1 == date2
true

julia> typeof(date1)
Date

Há funções de acesso para as partes individuais da data, e estas formam pares que se distinguem pelo uso de minúsculas ou maiúsculas.

# lowercase returns an integer
julia> month(date1)
6

julia> typeof(month(date1))
Int64

# Propercase returns a Period type
julia> Month(date1)
6 months

julia> typeof(Month(date1))
Month

Funções de consulta

Há uma variedade de funções com alguma compreensão do calendário. O exemplo seguinte mostra apenas algumas.

julia> date1
2025-06-23

julia> dayofweek(date1) # 1 = Monday, 7 = Sunday
1

julia> dayname(date1)
"Monday"

julia> daysinmonth(date1)
30

julia> isleapyear(date1)
false

julia> lastdayofmonth(date1)
2025-06-30

Horas

Dates.Time é o tipo básico só de hora. Não tem qualquer compreensão de datas: as horas passam automaticamente para Time(0, 0, 0) à meia-noite.

O formato completo do construtor é Time(hour, min, sec, millisec, microsec) ou o equivalente em ISO 8601.

Todos os parâmetros são opcionais e assumem 0 por omissão.

julia> Time(14, 57, 25, 142)
14:57:25.142

julia> Time("14:57:25.142")
14:57:25.142

julia> Time(14, 57, 25, 142, 32)
14:57:25.142032

Tal como com Date, as partes individuais estão disponíveis através de funções de acesso:

julia> minute(t) # => integer
57

julia> Minute(t) # => Period
57 minutes

DateTimes

Dates.DateTime combina a maior parte das características dos tipos Date e Time.

julia> dt1 = DateTime(2025, 6, 23, 14, 57, 25, 142)
2025-06-23T14:57:25.142

# date1 and t were defined in previous examples
julia> dt2 = DateTime(date1, t)
2025-06-23T14:57:25.142

Os parâmetros de ano, mês e dia assumem 1 por omissão, e os parâmetros de hora assumem todos 0 por omissão.

Manter todos estes parâmetros na ordem certa pode ser um desafio, por isso o formato ISO pode ser preferível para a entrada.

Em alternativa, um DateTime pode ser construído a partir de um Date e um Time, como no exemplo acima.

Períodos

Cada um dos componentes de data/hora tem o seu próprio tipo Period, desde Year até Nanosecond, que representa um intervalo de tempo. Estes são particularmente úteis para a aritmética.

julia> dt1
2025-06-23T14:57:25.142

julia> Year(21)
21 years

julia> Second(61)
61 seconds

julia> dt1 + Year(21) - Second(61)
2046-06-23T14:56:24.142

julia> Date(2025, 07, 03) - Date(2025, 04, 25)
69 days

Ao trabalhar com tipos Period, a Julia tenta ser inteligente em relação a irregularidades do calendário, como a duração dos meses, arredondando quando é necessário.

# February has fewer days than January
julia> Date(2025, 1, 31) + Month(1) 
2025-02-28

Representações em string

Já mencionámos o padrão ISO 8601, que é a representação de data/hora predefinida da Julia ao formatar ou analisar strings.

Obviamente, muitos outros formatos são usados com frequência, muitas vezes de formas específicas de cada cultura. Para os tratar, a Julia tem o tipo DateFormat, que pode ser construído a partir de uma string de formato com a complexidade que se quiser.

# dateformat"" string syntax
julia> dtfmt = dateformat"d/m/y"
dateformat"d/m/y"

julia> typeof(dtfmt)
DateFormat{Symbol("d/m/y"), Tuple{Dates.DatePart{'d'}, Dates.Delim{Char, 1}, Dates.DatePart{'m'}, Dates.Delim{Char, 1}, Dates.DatePart{'y'}}}

# DateFormat constructor
julia> DateFormat("d/m/y")
dateformat"d/m/y"

O exemplo acima é muito simples: apenas uma data no formato dia/mês/ano comum na Europa. São mostradas duas variantes da sintaxe, mas o resultado é idêntico.

Um DateFormat pode depois ser usado para analisar qualquer string adequada:

julia> DateTime("14/7/2023", dtfmt)
2023-07-14T00:00:00

Criar um DateFormat envolve um custo significativo, por isso fazer este passo apenas uma vez (como aqui com dtfmt) ajuda no desempenho quando se percorrem muitas strings de data/hora.

Os formatos podem ser muito mais complexos do que isto, por isso consulta o manual para mais detalhes.

O mesmo DateFormat também pode ser usado para produzir uma data/hora em qualquer formato de string desejado, com a função Dates.format().

Infelizmente, parece haver um conflito de espaço de nomes com format (pelo menos na versão 1.11.5 da Julia), por isso é melhor incluir o prefixo Dates. mesmo depois de using Dates.

julia> dt1
2025-06-23T14:57:25.142

julia> Dates.format(dt1, dateformat"e, u d")
"Mon, Jun 23"

Como está documentado, "e, u d" dá a representação textual abreviada do dia da semana e do mês.

A representação textual assume o inglês por omissão. Podem ser adicionadas outras línguas, embora o suporte para isso seja atualmente pouco satisfatório.

Instruções

Neste exercício vais trabalhar num agendador de marcações para um salão de beleza em Nova Iorque que abriu a 15 de setembro de 2012.

Tens cinco tarefas, todas relacionadas com datas de marcação. Os horários estão no formato de 24 horas (sem AM/PM).

1. Converter uma data de marcação só com números

Implementa a função schedule_appointment() para converter uma representação textual de uma data de marcação no formato DateTime correspondente.

Repara que o valor de entrada está no formato dos Estados Unidos: mês/dia/ano.

julia> schedule_appointment("07/25/2023 13:45:00")
2023-07-25T13:45:00

2. Verificar se uma marcação já passou

Implementa a função has_passed(), que recebe uma data de marcação e verifica se a marcação já passou:

julia> has_passed(DateTime(1999, 12, 31, 9, 0, 0))
true

3. Verificar se a marcação é à tarde

Implementa a função is_afternoon_appointment(), que recebe uma data de marcação e verifica se a marcação é à tarde (>= 12:00 e < 18:00):

julia> is_afternoon_appointment(DateTime(2023, 3, 29, 15, 0, 0))
true

4. Descrever a data e a hora da marcação

Implementa a função description(), que recebe uma data de marcação e devolve uma descrição dessa data e hora:

julia> describe(DateTime(2023, 3, 29, 15, 0, 0))
"You have an appointment on Wednesday, March 29, 2023 at 15:00"

5. Devolver a data de aniversário

Implementa a função anniversary_date(), que devolve a data de aniversário deste ano, que é 15 de setembro:

julia> anniversary_date()  # run during 2025
2025-09-15
Editar via GitHub A ligação abre numa nova janela ou separador
Julia Exercism

Estás pronto para começar Marcações de beleza?

Inscreve-te no Exercism para aprenderes e dominares Julia com 35 conceitos128 exercícios, e mentoria humana real, tudo grátis.