Trilhas
/
Julia
Julia
/
Exercícios
/
Agendando para a beleza
Agendando para a beleza

Agendando para a beleza

Exercício de aprendizagem

Introdução

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

Muitos programadores cometeram esse erro, e a experiência que vem depois costuma fazer mal à saúde e à felicidade deles.

Quem faz programação não trivial com datas e horários deveria, no mínimo, estar preparado para entender e mitigar possíveis problemas.

Este documento vai tentar dar uma visão geral de como Julia lida com datas e horários, mas será necessário consultar o manual para mais detalhes. Existe também um Wikibook cujas explicações alguns leitores podem achar mais claras, e ele 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 em uma instalação padrão, mas que não faz parte da biblioteca padrão.

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

  1. Adicione import Dates e depois escreva Dates. antes de todas as chamadas de função.
  2. Adicione using Dates, o que traz o módulo inteiro para o namespace atual (exceto por 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 oferece quatro tipos principais de funcionalidade:

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

Observe que um DateTime geralmente não inclui informações de fuso horário (Python chamaria isso de datetime "naive"). Uma exceção é now(), que pega o horário local do relógio do seu sistema e pode convertê-lo para UTC, se necessário.

Talvez as necessidades mais frequentes sejam:

  • Fazer o parse de 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 o horário (com now()).
Note

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

Formatos de data e hora

Há muitas maneiras de escrever datas e horários, e elas tendem a ser específicas de cada cultura. Datas só com números, como "7/6/23", são ambíguas, confusas e já causaram muitos erros caros em organizações multinacionais (o autor fala isso por amarga experiência pessoal).

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

  • O parse é rápido e sem ambiguidade.
  • A ordenação é fácil, pois o datetime pode ser tratado como texto normal e ordenado alfabeticamente.

Vimos em um exemplo anterior que Date.now() retornou 2025-06-21T16:03:04.161.

Isso é formado por várias partes:

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

Outros formatos de string serão discutidos em uma seção posterior.

Datas

Dates.Date é um tipo relativamente simples, que representa apenas datas e não entende horários nem 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

Existem funções de acesso para as partes individuais da data, e elas vêm em pares diferenciados pelo uso de maiúsculas e minú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

Existem várias funções que têm alguma noção do calendário. O próximo exemplo 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

Horários

Dates.Time é o tipo básico que representa apenas horários. Ele não entende datas: os horários voltam 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 padrã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

Assim como com Date, as partes individuais ficam disponíveis com funções de acesso:

julia> minute(t) # => integer
57

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

DateTimes

Dates.DateTime combina a maior parte dos recursos 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 padrão, e todos os parâmetros de horário assumem 0.

Manter todos esses parâmetros em ordem pode ser um desafio, então o formato ISO pode ser preferível para a entrada.

Como 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 seu próprio tipo Period, de Year até Nanosecond, representando um intervalo de tempo. Eles são especialmente úteis para 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, 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

Mencionamos antes o padrão ISO 8601, que é a representação padrão de data/hora de Julia ao formatar ou fazer o parse de strings.

Obviamente, muitos outros formatos são usados com frequência, muitas vezes de maneiras específicas de cada cultura. Para lidar com isso, Julia tem o tipo DateFormat, que pode ser construído a partir de uma string de formato com complexidade arbitrária.

# 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 é bem 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 então ser usado para fazer o parse de qualquer string adequada:

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

Criar um DateFormat envolve uma sobrecarga considerável, então fazer isso apenas uma vez (como aqui com dtfmt) ajuda no desempenho quando você percorre muitas strings de data/hora em um laço.

Os formatos podem ser muito mais complexos do que isso, então consulte o manual para mais detalhes.

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

Infelizmente, parece haver um conflito de namespace com format (pelo menos na versão 1.11.5 de Julia), então é 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 documentado, "e, u d" fornece a representação de texto abreviada para dia da semana e mês.

A representação de texto assume o inglês por padrão. Outros idiomas podem ser adicionados, embora o suporte para isso atualmente seja pouco ideal.

Instruções

Neste exercício você vai trabalhar em um agendador de compromissos para um salão de beleza em Nova York que abriu em 15 de setembro de 2012.

Você tem cinco tarefas, e todas elas envolvem datas de compromissos. Os horários estão no formato de 24 horas (sem AM/PM).

1. Analisar a data do compromisso em formato numérico

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

Repare que a entrada está no formato americano mês/dia/ano.

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

2. Verificar se um compromisso já passou

Implemente a função has_passed() que recebe uma data de compromisso e verifica se o compromisso já ficou no passado:

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

3. Verificar se o compromisso é à tarde

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

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

4. Descrever o horário e a data do compromisso

Implemente a função description() que recebe uma data de compromisso e retorna uma descrição dessa data e desse horário:

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

5. Retornar a data de aniversário

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

julia> anniversary_date()  # run during 2025
2025-09-15
Editar via GitHub O link abre em uma nova janela ou aba
Julia Exercism

Tudo pronto para começar Agendando para a beleza?

Crie sua conta no Exercism para aprender e dominar Julia com 35 conceitos128 exercícios e mentoria humana de verdade, tudo de graça.