Java Nhận tất cả các ngày làm việc trong một năm ở định dạng YYYYMMDD


8

Thử thách chủ nhật của tôi là có được và duy trì ngày làm việc trong một năm cụ thể đối với tệp CSV, v.v.

Tôi có mã sau đây và vấn đề tôi gặp phải là: làm thế nào để in ngày theo một định dạng cụ thể, tức là YYYYMMDD vì mã hiện đang in một cái gì đó như Sat ngày 19 tháng 1 00:00:00 CET 2019.

Ngoài ra, nếu tôi có thể loại trừ cuối tuần và nói chung nếu có cách tốt hơn để viết mã ngắn hơn nhiều trong 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
Đừng chỉ System.out.println(date), sử dụng cái dateFormatmà bạn đã thực hiện để định dạng nó theo cách bạn cần.
Thilo

2
String date1 = format1.format(date);sau đó bạn không làm gì với date1. Nhưng bạn đang đi đúng hướng.
Federico klez Culloca

1
Calendarcũng có thể được sử dụng để kiểm tra ngày trong tuần.
Thilo

1
Phiên bản Java của bạn là gì? 8 hay 9+?
ernest_k

1
Tôi đang sử dụng Java 8
JavaMan

Câu trả lời:


3

Đây là 2 hơi khác nhau về vấn đề của bạn:

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

Cảm ơn Dave, điều này trông thực sự bóng bẩy. Tôi chỉ tập hợp một số bài kiểm tra đơn vị xung quanh nhưng trông thực sự thú vị. Chúc mừng
JavaMan

Mục đích của đầu tiên là IntStreamgì? Nó sẽ hiển thị ngày hai lần. Hoặc tại sao bạn không chỉ để lại cái đầu tiên IntStreamvà thay đổi kiểu trả về thành void? Tôi chỉ tò mò thôi.
Sebastian I.

Như tôi đã đề cập, chỉ có 2 vấn đề: một bản in, một bản trả về. JavaMan có thể chọn bất cứ thứ gì anh ta muốn. :-)
Dave The Dane

Tôi không thích những thành ngữ mới này nói chung là không hiệu quả, LocalDate.ofYearDay sẽ tạo một phiên bản mới mỗi lần github.com/frohoff/jdk8u-jdk/blob/ tựa , nếu bạn đặt mã này vào một phương thức sử dụng cao, nó sẽ không hiệu quả nhất.
Leo

7

Kể từ năm 2020, bạn thực sự nên nắm lấy java.time.*API.

Trong khi tôi chắc chắn có một cách thực sự gọn gàng để có được những ngày "làm việc" giữa các ngày, tôi đã dùng phương pháp vũ phu ...

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

Sau đó, bạn có thể chỉ cần sử dụng một DateTimeFormatterđịnh dạng LocalDatethành định dạng mà bạn muốn, ví dụ ...

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 Vì vậy - về cơ bản, đây là phiên bản ngắn gọn của những gì tôi đã làm - rất vui được biết
MadProgrammer

loại, vâng, cuối cùng nó LongStream.rangeClosed(0, steps).mapToObj( n -> this.plusMonths(months * n).plusDays(days * n));... Nhưng liên quan đến mã của bạn, ArrayListcó thể có kích thước của 240một ước tính sơ bộ 360 - 2 * 40. Hơn nữa khi bạn có một if(condition) {NO-OP} else {OP}nên được đổi thànhif(!condition){OP}
Eugene

1
Tôi hiểu, hiểu.
Eugene

1
@Eugene Giống như nguồn cấp dữ liệu trở lại mặc dù 😉
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

Một cách sáng suốt để hiển thị tất cả các ngày trong tuần trong phạm vi ngày bằng Java 8 và API thời gian hiện đại như sau:

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

Đầu ra:

20190101
20190102
20190103
20190104
20190107
20190108
...
...
...
20191226
20191227
20191230
20191231

1
Rất đẹp. Hai điều tôi sẽ thay đổi bao gồm lưu trữ ChronoUnit.DAYS.between(startDate, endDate)trong một biến thay vì tính toán lại mỗi lần. Ngoài ra, đối với mã Java 9+, người ta có thể sử dụng .takeWhile(endDate::isAfter)thay vì limit(). Ngoài ra, bạn có thể sử dụng so sánh enum thay vì so sánh tên ngày trong tuần:!(d -> d.getDayOfWeek() == DayOfWeek.SUNDAY || d.getDayOfWeek() == DayOfWeek.SUNDAY)
ernest_k

Cảm ơn, @ernest_k vì phản hồi tích cực. Nhận xét của bạn có ý nghĩa rất lớn với tôi. Tôi sẽ cải thiện nó như bạn đã đề xuất.
Arvind Kumar Avinash

@ernest_k - Tôi đã kết hợp nhận xét đầu tiên của bạn nhưng để lại bình luận thứ hai cho độc giả để tự kết hợp vì OP đã đề cập rằng anh ta đang sử dụng Java 8. Ngoài ra, tôi hiểu rằng JVM sẽ tối ưu hóa ChronoUnit.DAYS.between(startDate, endDate)thay vì tính toán lại mỗi lần. Tôi cần sự giúp đỡ của bạn để hiểu nếu nó không đúng.
Arvind Kumar Avinash


Không chắc chắn tôi có được quan điểm d.getDayOfWeek().name().equals("SATURDAY")khi d.getDayOfWeek() == DayOfWeek.SATURDAYnào sẽ mạnh mẽ hơn - IMHO
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());
}

}


Mã rất đẹp. Bạn có thể muốn thêm một số giải thích về lý do tại sao và làm thế nào nó hoàn thành nhiệm vụ.
Ole VV

-1

thử cái này:

// Sử dụng 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);

Mã đẹp, nhưng mối quan hệ của nó với câu hỏi được hỏi là trượt khỏi tôi?
Ole VV

Tôi chỉ đưa ra mycode làm ví dụ ở đây và chỉ cần anh ấy có thể làm theo cách tôi đã sử dụng. nhưng chỉ anh ta cần lấy định dạng ngày mới từ mã của tôi.
Raghavendra
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.