Java Obtenga todos los días hábiles en un año en formato AAAAMMDD

8

Mi desafío del domingo es obtener y persistir días hábiles en un año en particular en un archivo CSV, etc.

Tengo el siguiente código y el problema al que me enfrento es: cómo imprimir fechas en un formato específico, es decir, AAAAMMDD, ya que el código actualmente imprime algo como Sábado 19 de enero 00:00:00 CET 2019.

Además, si puedo excluir los fines de semana y, en general, si hay una mejor manera de escribir un código mucho más corto en Java 8.

import java.io.*;
import java.util.*;
import java.text.SimpleDateFormat;

public class DatesInYear
{

    public static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");

    public static void main (String[] args) throws java.lang.Exception
    {

        Date dt = new Date();
        System.out.println(dt);

        List<Date> dates = printDates("20190101","20191231");


        Collections.reverse(dates);
        System.out.println(dates.size());
        for(Date date:dates)
        {
            SimpleDateFormat format1 = new SimpleDateFormat("yyyyMMdd");
            System.out.println(format1.format(date));

        }
    }
    public static List<Date> printDates(String fromDate, String toDate)
    {
        ArrayList<Date> dates = new ArrayList<Date>();

        try {

            Calendar fromCal = Calendar.getInstance();
            fromCal.setTime(dateFormat .parse(fromDate));

            Calendar toCal = Calendar.getInstance();
            toCal.setTime(dateFormat .parse(toDate));

            while(!fromCal.after(toCal))
            {
                dates.add(fromCal.getTime());
                fromCal.add(Calendar.DATE, 1);
            }


        } catch (Exception e) {
            System.out.println(e);
        }
        return dates;
    }
}
JavaMan
fuente
1
No solo System.out.println(date)use el dateFormatque ya hizo para formatearlo de la manera que lo necesita.
Thilo
2
String date1 = format1.format(date);a continuación, usted no hace nada con el date1. Pero estás en el camino correcto.
Federico klez Culloca
1
Calendartambién se puede usar para verificar el día de la semana.
Thilo
1
¿Cuál es tu versión de Java? 8 o 9+?
ernest_k
1
Estoy usando Java 8
JavaMan

Respuestas:

3

Aquí hay 2 tomas ligeramente diferentes de su problema:

import java.time.LocalDate;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class DatesInYear {

    public static void main(final String[] args) throws Exception {

        listWorkingDays(2020).forEach(System.out::println);
    }

    private static List<LocalDate> listWorkingDays(final int year) {

        IntStream
            .rangeClosed(1,      LocalDate.ofYearDay(year + 1, 1).minusDays(1).getDayOfYear())
            .mapToObj   (day  -> LocalDate.ofYearDay(year, day))
            .filter     (date -> date.getDayOfWeek().getValue() <= 5)
            .forEach    (System.out::println);

        return IntStream
            .rangeClosed(1,      LocalDate.ofYearDay(year + 1, 1).minusDays(1).getDayOfYear())
            .mapToObj   (day  -> LocalDate.ofYearDay(year, day))
            .filter     (date -> date.getDayOfWeek().getValue() <= 5)
            .collect    (Collectors.toList());
    }
}
Dave el danés
fuente
Gracias Dave, esto se ve muy elegante. Solo estoy preparando algunas pruebas unitarias pero parece realmente interesante. Saludos
JavaMan
¿Cuál es el propósito de la primera IntStream? Mostrará las fechas dos veces. ¿O por qué no dejas solo el primero IntStreamy cambias el tipo de retorno a vacío? Tengo curiosidad.
Sebastian I.
Como mencioné, el problema es solo 2: uno imprime y el otro regresa. JavaMan puede elegir lo que quiera. :-)
Dave The Dane
No me gusta que estas nuevas expresiones idiomáticas sean ineficaces en general, LocalDate.ofYearDay creará una nueva instancia cada vez que github.com/frohoff/jdk8u-jdk/blob/… , si pones este código en un método altamente utilizado, no será lo más eficiente.
Leo
7

Como es 2020, realmente debería estar adoptando la java.time.*API.

Si bien estoy seguro de que probablemente haya una forma realmente ordenada de obtener los días "laborables" entre fechas, he optado por el método de fuerza bruta ...

LocalDate ld = LocalDate.of(2020, Month.JANUARY, 1);
LocalDate endDate = ld.plusYears(1);

// You don't "have" to put into a list, but I like to seperate my
// code responsbilities ;)
List<LocalDate> workDays = new ArrayList<>(365);
System.out.println(endDate);
while (ld.isBefore(endDate)) {
    // This would be a good place for a delegate to determine if we want the specific day
    // as it could then take into account public holidays
    if (ld.getDayOfWeek() == DayOfWeek.SATURDAY || ld.getDayOfWeek() == DayOfWeek.SUNDAY) {
        // NOOP
    } else {
        workDays.add(ld);
    }
    ld = ld.plusDays(1);
}

Luego, simplemente puede usar a DateTimeFormatterpara formatear el LocalDateformato que desee, por ejemplo ...

DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyyMMdd");
List<String> formats = workDays.stream().map(value -> value.format(format)).collect(Collectors.toList());

for (String value : formats) {
    System.out.println(value);
}
MadProgrammer
fuente
@Eugene Entonces, es esencialmente una versión abreviada de lo que he hecho de todos modos, es bueno saberlo
MadProgrammer
más o menos, sí, finalmente lo hace LongStream.rangeClosed(0, steps).mapToObj( n -> this.plusMonths(months * n).plusDays(days * n));... Pero con respecto a su código, eso ArrayListpodría tener el tamaño de 240una estimación aproximada de 360 - 2 * 40. Además, cuando tenga un if(condition) {NO-OP} else {OP}es debe cambiarse aif(!condition){OP}
Eugene
1
Ya veo, comprensible.
Eugene
1
@Eugene Al igual que la retroalimentación 😉
MadProgrammer
7
    Set<DayOfWeek> weekend = EnumSet.of(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY);
    LocalDate.of(2019, Month.JANUARY, 1)
             .datesUntil(LocalDate.of(2020, Month.DECEMBER, 31), Period.ofDays(1))
             .filter(x -> !weekend.contains(x.getDayOfWeek()))
             .forEachOrdered(System.out::println);
Eugene
fuente
2

Una forma lúcida de mostrar todos los días de la semana en un rango de fechas utilizando Java 8 y la API moderna de fecha y hora es la siguiente:

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        List<LocalDate> dates = getDates("2019-01-01", "2019-12-31");
        for (LocalDate date : dates) {
            System.out.println(DateTimeFormatter.BASIC_ISO_DATE.format(date));
        }
    }

    public static List<LocalDate> getDates(String fromDate, String toDate) {
        LocalDate startDate = LocalDate.parse(fromDate);
        LocalDate endDate = LocalDate.parse(toDate).plusDays(1);
        long range = ChronoUnit.DAYS.between(startDate, endDate);
        return Stream.iterate(startDate, date -> date.plusDays(1)).limit(range)
                .filter(d -> !(d.getDayOfWeek() == DayOfWeek.SATURDAY || d.getDayOfWeek() == DayOfWeek.SUNDAY))
                .collect(Collectors.toList());
    }
}

Salida:

20190101
20190102
20190103
20190104
20190107
20190108
...
...
...
20191226
20191227
20191230
20191231
Arvind Kumar Avinash
fuente
1
Muy agradable. Dos cosas que cambiaría incluyen el almacenamiento ChronoUnit.DAYS.between(startDate, endDate)en una variable en lugar de volver a calcular cada vez. Además, para el código Java 9+, se puede usar en .takeWhile(endDate::isAfter)lugar de limit(). Además, puede usar la comparación de enumeración en lugar de comparar nombres de días de la semana:!(d -> d.getDayOfWeek() == DayOfWeek.SUNDAY || d.getDayOfWeek() == DayOfWeek.SUNDAY)
ernest_k
Gracias, @ernest_k por los comentarios positivos. Tu comentario significa mucho para mí. Lo mejoraré como me has sugerido.
Arvind Kumar Avinash
@ernest_k: he incorporado su primer comentario, pero dejé el segundo a los lectores para que se incorporen porque OP ha mencionado que está utilizando Java 8. Además, entendí que JVM se optimizaría en ChronoUnit.DAYS.between(startDate, endDate)lugar de volver a calcular cada vez. Necesito tu ayuda para entender si no fue correcto.
Arvind Kumar Avinash
No estoy seguro de tener el punto de hacer d.getDayOfWeek().name().equals("SATURDAY")cuándo lo d.getDayOfWeek() == DayOfWeek.SATURDAYque sería más robusto - En mi humilde opinión
MadProgrammer
1
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
    List<LocalDate> dates = getDates("2019-01-01", "2019-12-31");
    for (LocalDate date : dates) {
        System.out.println(DateTimeFormatter.BASIC_ISO_DATE.format(date));
    }
}

public static List<LocalDate> getDates(String fromDate, String toDate) {
    LocalDate startDate = LocalDate.parse(fromDate);
    LocalDate endDate = LocalDate.parse(toDate).plusDays(1);
    long range = ChronoUnit.DAYS.between(startDate, endDate);
    return Stream.iterate(startDate, date -> date.plusDays(1)).limit(range)
            .filter(d -> !(d.getDayOfWeek() == DayOfWeek.SATURDAY || d.getDayOfWeek() == DayOfWeek.SUNDAY))
            .collect(Collectors.toList());
}

}

Yasser Abdel-Maksoud
fuente
El código es hermoso. Es posible que desee agregar alguna explicación de por qué y cómo realiza la tarea.
Ole VV
-1

prueba esto:

// Usando Java 8

 DateTimeFormatter oldPattern = DateTimeFormatter
        .ofPattern("yyyy-MM-dd HH:mm:ss");
    DateTimeFormatter newPattern = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    LocalDateTime datetime = LocalDateTime.parse(input, oldPattern);
    output = datetime.format(newPattern);

    System.out.println("old format date: " + input);
    System.out.println("new format date : " + output);
Raghavendra
fuente
Buen código, pero su relación con la pregunta formulada se me escapa.
Ole VV
Acabo de dar mycode como ejemplo aquí y solo él puede seguir la forma en que solía hacerlo. pero solo él necesita tomar un nuevo formato de fecha de mi código.
Raghavendra