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;
    }
}

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());
    }
}

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);
}


@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);

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

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());
}

}


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);

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.