For this you need to define your own list of holidays. There are several APIs that provide this kind of information, such as jollyday (I have never used it, but it seems to have holidays from several countries), and several other listed this link .
If you do not want to use an API, you can have your own registry too (and in this case, it's something you'll have to do manually).
Another problem with holidays is that not everyone has fixed dates (such as Easter, Carnival, etc.), and they should be calculated according to the year. In addition, there are national, state and municipal holidays, and you should decide whether or not to include them in your list.
However, regardless of the solution you choose (use an external API, manually register, include only national holidays, etc.), you just have to save all holidays in java.util.Set
, and then check if the date is in Set
(using the contains
method), something like this:
Set<LocalDate> feriados = // feriados, ver mais abaixo como montar este Set
for (int dia = 1; dia <= anoMes.lengthOfMonth(); dia++) {
LocalDate data = anoMes.atDay(dia);
if (data.getDayOfWeek() != DayOfWeek.SATURDAY
&& data.getDayOfWeek() != DayOfWeek.SUNDAY
&& !feriados.contains(data)) {
listaDosDiasUteisDoMes.add(data);
}
}
Since DayOfWeek
is enum
, I can compare them using ==
and !=
( you do not have to use equals
).
In order to mount Set
with holidays, I suggest separating in 2 methods: one for fixed holidays (which is easier since they always fall on the same day every year) and another for mobile holidays.
I suggest you pass the year as a parameter for these methods, so you can build a list of LocalDate
, which is what you need.
// feriados que acontecem todo ano na mesma data, gerar lista para o ano especifico
public Set<LocalDate> getFeriadosFixos(int year) {
Set<LocalDate> dates = new HashSet<>();
// 7 de setembro
dates.add(LocalDate.of(year, 9, 7));
// natal
dates.add(LocalDate.of(year, 12, 25));
// ... adicione todos os outros
return dates;
}
This method does not consider holiday "amendments" (if it falls on Tuesday, then amend the second, then those two days are not useful). If you want, just check if the holiday is a Tuesday or Thursday (comparing DayOfWeek
):
// 7 de setembro
LocalDate seteSetembro = LocalDate.of(year, 9, 7);
dates.add(seteSetembro);
// se cai na terça, inclui a segunda ("emenda" de feriado)
if (seteSetembro.getDayOfWeek() == DayOfWeek.TUESDAY) {
dates.add(seteSetembro.minusDays(1));
}
// se cai na quinta, inclui a sexta ("emenda" de feriado)
if (seteSetembro.getDayOfWeek() == DayOfWeek.THURSDAY) {
dates.add(seteSetembro.plusDays(1));
}
Do this for all holidays that can be "mended."
For mobile holidays, there is a formula to calculate them (google search and you will find several websites explaining). I'll use one I found:
// calcula páscoa, carnaval, corpus christi e sexta-feira santa
public Set<LocalDate> getFeriadosMoveis(int year) {
Set<LocalDate> dates = new HashSet<>();
LocalDate pascoa;
LocalDate carnaval;
LocalDate corpusChristi;
LocalDate sextaFeiraSanta;
int a = year % 19;
int b = year / 100;
int c = year % 100;
int d = b / 4;
int e = b % 4;
int f = (b + 8) / 25;
int g = (b - f + 1) / 3;
int h = (19 * a + b - d - g + 15) % 30;
int i = c / 4;
int k = c % 4;
int l = (32 + 2 * e + 2 * i - h - k) % 7;
int m = (a + 11 * h + 22 * l) / 451;
int month = (h + l - 7 * m + 114) / 31;
int day = ((h + l - 7 * m + 114) % 31) + 1;
pascoa = LocalDate.of(year, month, day);
// Carnaval 47 dias antes da pascoa (sempre cai na terça)
carnaval = pascoa.minusDays(47);
// CorpusChristi 60 dias apos a pascoa
corpusChristi = pascoa.plusDays(60);
sextaFeiraSanta = pascoa.minusDays(2);
// pascoa cai sempre no domingo, entao nao precisaria adicionar como feriado
// dates.add(pascoa);
// carnaval: adicionar um dia antes e depois (emenda de segunda e quarta-feira de cinzas)
dates.add(carnaval);
dates.add(carnaval.minusDays(1)); // emenda a segunda-feira
dates.add(carnaval.plusDays(1)); // quarta-feira de cinzas
// corpus christi, emendar (adicionar a sexta)
dates.add(corpusChristi);
// if apenas para confirmar se é quinta-feira
if (corpusChristi.getDayOfWeek() == DayOfWeek.THURSDAY) {
dates.add(corpusChristi.plusDays(1)); // adicionar a sexta-feira
}
dates.add(sextaFeiraSanta);
return dates;
}
Please note that I also include holiday "amendments". If you do not want to, just remove the respective lines.
To create Set
with all holidays, simply use the two methods above and merge all into a single Set
:
Set<LocalDate> feriados = new HashSet<>();
feriados.addAll(getFeriadosFixos(year));
feriados.addAll(getFeriadosMoveis(year));
The parameter year
can be the year you are using ( anoMes.getYear()
), for example.
Just as an add-on, you can encapsulate the scan logic in a java.time.temporal.TemporalQuery
. The difference is that this interface works with java.time.temporal.TemporalAccessor
(instead of a specific type like LocalDate
), so the code to check the day of the week is a little different:
public class VerificaDiaUtil implements TemporalQuery<Boolean> {
private Set<LocalDate> feriados = new HashSet<>();
public VerificaDiaUtil() {
this.feriados = // constrói a lista de feriados
}
@Override
public Boolean queryFrom(TemporalAccessor temporal) {
// obter o dia da semana
DayOfWeek dow = DayOfWeek.from(temporal);
return dow != DayOfWeek.SATURDAY && dow != DayOfWeek.SUNDAY
// extrair o LocalDate e verificar se está no Set de feriados
&& !feriados.contains(LocalDate.from(temporal));
}
}
With this the class VerificaDiaUtil
is responsible for maintaining the list of holidays. If you wish, you can change the builder to receive the year as a parameter (and then it only builds the holidays that year), or else it loads the multi-year holidays at once. It's up to you.
To use this class, simply use the method query
of LocalDate
:
VerificaDiaUtil diaUtil = new VerificaDiaUtil();
for (int dia = 1; dia <= anoMes.lengthOfMonth(); dia++) {
LocalDate data = anoMes.atDay(dia);
if (data.query(diaUtil)) {
listaDosDiasUteisDoMes.add(data);
}
}
As
TemporalQuery
gets a
java.time.temporal.TemporalAccessor
, it works with other classes as well (as long as they have day, month and year - and consequently a day of the week), as
LocalDateTime
or
ZonedDateTime
.