For this you need to define your own list of holidays. There are several Apis that provide this type of information, such as the jollyday (never used, but seems to have the holidays of various countries), and several other listed at this link.
If you don’t want to use an API, you can have your own registration as well (and in this case, it’s something you’ll have to do manually).
Another problem with holidays is that not all holidays have fixed dates (such as Easter, Carnival, etc., which fall every year on different dates), and 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 on your list.
Anyway, regardless of the chosen solution (use an external API, manually register, include only national holidays, etc.), just keep all the holidays in one java.util.Set
, and then check if the date is on Set
(using the method contains
), sort of 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);
}
}
Like java.time.DayOfWeek
is a enum
, I can compare them using ==
and !=
(don’t need to use equals
).
To ride the Set
with the holidays, I suggest separating into 2 methods: one for the fixed holidays (which is easier, since they always fall in the same day every year) and another for the mobile holidays.
I suggest you spend the year as a parameter for these methods, so you can build a list of java.time.LocalDate
, which is what you need.
// feriados que acontecem todo ano na mesma data, gerar lista para o ano específico
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 the "amendments" of holidays (if it falls on Tuesday, amend the second, then these two days are not useful). If you want, just check if the holiday is a Tuesday or Thursday (comparing the 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 "amended".
For mobile holidays, there is a formula to calculate them (search Google and you will find several websites explaining). I will 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);
// páscoa cai sempre no domingo, entao não 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;
}
Note that I have also included the holiday "amendments". If you do not want, simply remove the respective lines.
To create the Set
with all holidays, just use the above two methods and put it all together in one Set
:
Set<LocalDate> feriados = new HashSet<>();
feriados.addAll(getFeriadosFixos(year));
feriados.addAll(getFeriadosMoveis(year));
The parameter year
may be the year you are using (anoMes.getYear()
), for example.
Just as a complement, it is possible to encapsulate the verification logic in a java.time.temporal.TemporalQuery
. The difference is that this interface works with a java.time.temporal.TemporalAccessor
(rather than a specific type like LocalDate
), then 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 that the class VerificaDiaUtil
is responsible for maintaining the holiday list. If you want, you can change the constructor to receive the year as a parameter (and then it only builds the holidays of that year), or it already carries the holidays of several years at once. At your discretion.
To use this class, just 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);
}
}
Like TemporalQuery
gets a java.time.temporal.TemporalAccessor
, it works with other classes as well (provided they have day, month and year - and consequently, a day of the week), as LocalDateTime
or ZonedDateTime
. If you pass a class that has no day of the week (like LocalTime
, for example, which only has the hours), this code will make an exception.
You plan to do this offline or have an internet connection?
– Sorack
Initially offline. But if so, I change it to online.
– ulima69