Trilhas
/
Java
Java
/
Exercícios
/
Clientes frequentes do salão de beleza
Clientes frequentes do salão de beleza

Clientes frequentes do salão de beleza

Exercício de aprendizagem

Introdução

Ajustadores temporais

Ao trabalhar com objetos java.time, como LocalDate, muitas vezes você precisa fazer ajustes de data mais elaborados, como encontrar a "segunda terça-feira do mês". Em vez de calcular isso manualmente, você pode usar os TemporalAdjusters.

A classe utilitária java.time.temporal.TemporalAdjusters (repare no "s" do plural) oferece métodos estáticos para muitos ajustes de data comuns. Você aplica esses ajustes com o método .with() em um objeto temporal (como LocalDate).

Note

Usar with(TemporalAdjuster) retorna uma instância nova e não atualiza a instância existente, já que os objetos java.time são imutáveis.

import java.time.LocalDate;
import java.time.Month;
import java.time.DayOfWeek;
import java.time.temporal.TemporalAdjusters;

LocalDate date = LocalDate.of(2024, Month.AUGUST, 15); // 2024-08-15 (a Thursday)

// Use a predefined adjuster: find the last day of the month
LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth());
// => 2024-08-31

Veja alguns ajustadores importantes para cálculos de agendamento:

Encontrar o enésimo dia da semana

Use dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek) para encontrar a enésima ocorrência de um dia da semana.

// Find the second Tuesday of August 2024
LocalDate secondTuesday = date.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.TUESDAY));
// => 2024-08-13

Encontrar o primeiro/último dia da semana no mês

Use firstInMonth(DayOfWeek dayOfWeek) ou lastInMonth(DayOfWeek dayOfWeek).

// Find the last Monday of August 2024
LocalDate lastMonday = date.with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY));
// => 2024-08-26

Ajustes relativos (próximo/anterior)

Ajustadores como next(), previous(), nextOrSame() e previousOrSame() encontram a próxima ocorrência ou a ocorrência anterior de um determinado dia da semana, em relação à data atual.

  • next()/previous(): excluem a data atual, caso ela corresponda.
  • nextOrSame()/previousOrSame(): incluem a data atual, caso ela corresponda.
LocalDate thursday = LocalDate.of(2024, Month.AUGUST, 15); // A Thursday

// Find the next Thursday (exclusive)
LocalDate nextThursday = thursday.with(TemporalAdjusters.next(DayOfWeek.THURSDAY));
// => 2024-08-22

// Find the next Thursday (inclusive) - returns the same date
LocalDate nextOrSameThursday = thursday.with(TemporalAdjusters.nextOrSame(DayOfWeek.THURSDAY));
// => 2024-08-15

// Find the previous Monday (exclusive)
LocalDate previousMonday = thursday.with(TemporalAdjusters.previous(DayOfWeek.MONDAY));
// => 2024-08-12

Ajustadores personalizados

TemporalAdjuster é uma interface funcional, então você pode escrever um ajustador seu como uma lambda que recebe o objeto temporal a ajustar e retorna o objeto ajustado. Ele é aplicado com .with() assim como os ajustadores predefinidos, e pode usá-los internamente.

import java.time.temporal.TemporalAdjuster;

// An adjuster that moves a weekend date to the following Monday
TemporalAdjuster skipWeekend = temporal -> {
    DayOfWeek day = DayOfWeek.from(temporal);
    if (day == DayOfWeek.SATURDAY || day == DayOfWeek.SUNDAY) {
        return temporal.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
    }
    return temporal;
};

LocalDate saturday = LocalDate.of(2024, Month.AUGUST, 17);
LocalDate monday = saturday.with(skipWeekend);
// => 2024-08-19

Usar esses ajustadores da classe TemporalAdjusters pode simplificar muito as tarefas de manipulação de datas.

Instruções

O salão de beleza em Nova York que você ajudou no exercício Booking Up For Beauty vai muito bem, e muitos dos seus clientes se tornaram clientes fixos. Em vez de marcar cada visita separadamente, um cliente fixo tem um combinado permanente: "toda segunda terça-feira", "a última sexta-feira do mês" e assim por diante. A dona do salão pediu que você fizesse um auxiliar que calcula as datas por trás desses combinados, além das datas da rotina mensal do próprio salão.

1. Encontre o horário fixo de um cliente

Implemente o método SalonCalendar.standingAppointment() que recebe um ano, um mês, uma ocorrência (1 para a primeira, 2 para a segunda, e assim por diante) e um dia da semana. Ele retorna a data daquela ocorrência do dia da semana dentro do mês:

SalonCalendar calendar = new SalonCalendar();
calendar.standingAppointment(2024, Month.AUGUST, 2, DayOfWeek.TUESDAY);
// => LocalDate.of(2024, 8, 13)

2. Encontre o horário de fim de mês de um cliente

Alguns clientes fixos preferem a última ocorrência do dia deles no mês. Implemente o método SalonCalendar.lastAppointment() que recebe um ano, um mês e um dia da semana, e retorna a data da última ocorrência desse dia da semana dentro do mês:

SalonCalendar calendar = new SalonCalendar();
calendar.lastAppointment(2024, Month.AUGUST, DayOfWeek.FRIDAY);
// => LocalDate.of(2024, 8, 30)

3. Encontre o próximo dia disponível para um cliente sem agendamento

Um cliente na recepção pede "o próximo sábado". Se o dia em que ele faz o pedido já for um sábado, ele quer dizer esse mesmo dia. Implemente o método SalonCalendar.nextAvailable() que recebe uma data e um dia da semana, e retorna a primeira data, igual ou posterior à data informada, que caia nesse dia da semana:

SalonCalendar calendar = new SalonCalendar();
calendar.nextAvailable(LocalDate.of(2024, 8, 15), DayOfWeek.SATURDAY);
// => LocalDate.of(2024, 8, 17)
calendar.nextAvailable(LocalDate.of(2024, 8, 17), DayOfWeek.SATURDAY);
// => LocalDate.of(2024, 8, 17)

4. Encontre o dia de fechamento do caixa

O salão fecha o caixa no último dia de cada mês. Só que o salão não abre nos fins de semana, então, quando o último dia do mês cai em um sábado ou em um domingo, o caixa é fechado na sexta-feira anterior. Implemente o método SalonCalendar.bookkeepingDay() que recebe um ano e um mês, e retorna o dia de fechamento do caixa daquele mês:

SalonCalendar calendar = new SalonCalendar();
calendar.bookkeepingDay(2024, Month.SEPTEMBER);
// => LocalDate.of(2024, 9, 30)
calendar.bookkeepingDay(2024, Month.AUGUST);
// => LocalDate.of(2024, 8, 30)

5. Reutilize a regra do fim de semana para o dia do pagamento

A equipe recebe no dia 15 de cada mês, com a mesma regra de fim de semana: quando o dia 15 cai em um sábado ou em um domingo, o pagamento sai na sexta-feira anterior. Em vez de escrever a regra uma segunda vez, transforme-a em um ajustador reutilizável.

Implemente o método SalonCalendar.precedingWorkday() que retorna um TemporalAdjuster que deixa um dia de semana inalterado e move um sábado ou um domingo para a sexta-feira anterior. Depois implemente o método SalonCalendar.payday(), que recebe um ano e um mês, usando esse ajustador:

SalonCalendar calendar = new SalonCalendar();
LocalDate.of(2024, 6, 15).with(calendar.precedingWorkday());
// => LocalDate.of(2024, 6, 14)
calendar.payday(2024, Month.JUNE);
// => LocalDate.of(2024, 6, 14)
calendar.payday(2024, Month.AUGUST);
// => LocalDate.of(2024, 8, 15)

Fique à vontade para voltar e usar o ajustador em bookkeepingDay() também.

Editar via GitHub O link abre em uma nova janela ou aba
Java Exercism

Tudo pronto para começar Clientes frequentes do salão de beleza?

Crie sua conta no Exercism para aprender e dominar Java com 27 conceitos159 exercícios e mentoria humana de verdade, tudo de graça.