Skip to content

Instantly share code, notes, and snippets.

@alexandreaquiles
Last active October 11, 2021 00:31
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save alexandreaquiles/10300153 to your computer and use it in GitHub Desktop.
Save alexandreaquiles/10300153 to your computer and use it in GitHub Desktop.
Passado um ano ou um mês ou alguns meses de um ano, gera um mapa (Map) dos meses (YearMonth) com a lista de datas (LocalDate) que são dias úteis (segunda a sexta).
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.YearMonth;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class DiasUteis {
public static Map<YearMonth, List<LocalDate>> doAno(int ano){
return diasUteisDosMesesDoAno(mesesDoAno(ano));
}
public static List<LocalDate> doMes(int ano, Month mes) {
return doMes(YearMonth.of(ano, mes));
}
public static List<LocalDate> doMes(YearMonth mes) {
return diasUteisDosMesesDoAno(Stream.of(mes)).get(mes);
}
public static Map<YearMonth, List<LocalDate>> dosMeses(List<YearMonth> meses) {
return diasUteisDosMesesDoAno(meses.stream());
}
private static Stream<YearMonth> mesesDoAno(int ano) {
return Stream.of(Month.values()).map(month -> YearMonth.of(ano, month));
}
private static Map<YearMonth, List<LocalDate>> diasUteisDosMesesDoAno(Stream<YearMonth> mesesDoAno){
return mesesDoAno
.collect(Collectors.toMap(Function.identity(),
ym -> todosOsDiasDoMesAno(ym)
.filter(diaUtil())
.collect(Collectors.toList())));
}
private static Predicate<LocalDate> diaUtil() {
return date -> !date.getDayOfWeek().equals(DayOfWeek.SATURDAY) && !date.getDayOfWeek().equals(DayOfWeek.SUNDAY);
}
private static Stream<LocalDate> todosOsDiasDoMesAno(YearMonth yearMonth) {
return Stream.iterate(yearMonth.atDay(1), date -> date.plusDays(1)).limit(yearMonth.lengthOfMonth());
}
}
import java.time.Month;
import java.time.YearMonth;
import java.util.Arrays;
import java.util.List;
public class ProgramaDiasUteis {
public static void main(String[] args) {
System.out.println(DiasUteis.doAno(2014));
System.out.println(DiasUteis.doMes(2014, Month.APRIL));
System.out.println(DiasUteis.doMes(YearMonth.of(2014, Month.APRIL)));
List<YearMonth> abrilEMaioDe2014 = Arrays.asList(YearMonth.of(2014, Month.APRIL), YearMonth.of(2014, Month.MAY));
System.out.println(DiasUteis.dosMeses(abrilEMaioDe2014));
}
}
@alexandreaquiles
Copy link
Author

Acho interessante a chamada

.filter(diaUtil())

O método diaUtil retorna um lambda. Os parâmetros são passados na invocação (no caso, lá dentro do filter do Stream).

@alexandreaquiles
Copy link
Author

A ideia básica é gerar todos os dias válidos do mês-ano (YearMonth), usando um Stream.iterate limitado ao número de dias no mês (lengthOfMonth()). Então, só são filtrados os que são dias úteis (no caso, de Segunda a Sexta). Depois, o resultado é coletado para uma lista.

Uma implementação mais completa deveria considerar feriados.

@peas
Copy link

peas commented Apr 9, 2014

ficou BEM legal. da pra deixar clara a regra

@peas
Copy link

peas commented Apr 10, 2014

ah, falta so ler de um arquivos os feriados :)

@alexandreaquiles
Copy link
Author

Mudei de

mesesDoAno.flatMap(todosOsDiasDoMesAno())
.filter(diaUtil())
.collect(Collectors.groupingBy(LocalDate::getMonth))

para

mesesDoAno
.collect(Collectors.toMap(Function.identity(),
    ym -> todosOsDiasDoMesAno(ym)
        .filter(diaUtil())
        .collect(Collectors.toList())));

Na primeira versão, fazia um flatMap que acabava juntando a lista dos LocalDate de todos os meses.
Depois agrupava por LocalDate::getMonth, o que gerava um mapa de Month pra List<LocalDate>, perdendo a informação do ano daquele mês.

Modifiquei para, dado um Stream<YearMonth>, para todos os elementos criar um mapa do YearMonth para a lista de LocalDate. O gerador dos dias do mês, o método todosOsDiasDoMesAno, agora recebe um YearMonth como parâmetro.

@alexandreaquiles
Copy link
Author

Daria pra fazer um Map<YearMonth, List<LocalDate>> na primeira versão com:

mesesDoAno.flatMap(todosOsDiasDoMesAno())
.filter(diaUtil())
.collect(Collectors.groupingBy(date -> YearMonth.of(date.getYear(), date.getMonth())));

Não sei qual jeito é mais legível... O mais rápido entre os dois parece ser o collect toMap. Mas, na verdade, o iterativo é mais rápido.

@sjmisterm
Copy link

Dá pra fazer:

groupingBy(YearMonth::from);

@PauloCeami
Copy link

ola gente que maravilha de código... alguém poderia me ajudar numa duvida....

Como eu poderia por exemplo dividir um valor de X em 3 semanas usando a nova api de datas..

tenho um sistema de vendas em que o vendedor vende um valor X divide pro cliente dele em 3 ou 4 ou 6 semanas....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment