【问题标题】:Java Get All Working Days in a year in YYYYMMDD formatJava 以 YYYYMMDD 格式获取一年中的所有工作日
【发布时间】:2020-06-07 05:00:38
【问题描述】:

我周日的挑战是获取特定年份的工作日并将其保存到 CSV 等文件中。

我有以下代码,我面临的问题是:如何以特定格式打印日期,即 YYYYMMDD,因为代码当前打印的是 Sat Jan 19 00:00:00 CET 2019。

另外,如果我可以排除周末,通常是否有更好的方法可以在 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;
    }
}

【问题讨论】:

  • 不要只使用System.out.println(date),使用您已经创建的dateFormat 以您需要的方式对其进行格式化。
  • String date1 = format1.format(date); 然后你对date1 什么都不做。但你在正确的轨道上。
  • Calendar 也可用于检查星期几。
  • 你的 Java 版本是多少? 8 岁还是 9 岁以上?
  • 我使用的是 Java 8

标签: java date time java-8


【解决方案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());
}

}

【讨论】:

  • 代码很漂亮。您可能需要添加一些解释,说明它完成任务的原因和方式。
【解决方案2】:

使用 Java 8 和现代日期时间 API 在日期范围内显示所有工作日的清晰方法如下:

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

输出:

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

【讨论】:

  • 非常好。我要改变的两件事包括将ChronoUnit.DAYS.between(startDate, endDate) 存储在一个变量中,而不是每次都重新计算。此外,对于 Java 9+ 代码,可以使用 .takeWhile(endDate::isAfter) 而不是 limit()。此外,您可以使用枚举比较而不是比较工作日名称:!(d -&gt; d.getDayOfWeek() == DayOfWeek.SUNDAY || d.getDayOfWeek() == DayOfWeek.SUNDAY)
  • 感谢@ernest_k 的积极反馈。你的评论对我来说意义重大。我会按照你的建议改进它。
  • @ernest_k - 我已经合并了您的第一条评论,但将第二条评论留给读者自己合并,因为 OP 提到他正在使用 Java 8。此外,我的理解是 JVM 会优化 @ 987654328@ 而不是每次都重新计算。我需要你的帮助来了解它是否不正确。
  • 不确定我是否明白d.getDayOfWeek().name().equals("SATURDAY") 的意义,而d.getDayOfWeek() == DayOfWeek.SATURDAY 会更强大 - 恕我直言
【解决方案3】:
    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);

【讨论】:

    【解决方案4】:

    对于您的问题,这里有 2 种略有不同的看法:

    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,这看起来非常时尚。我只是在整理一些单元测试,但看起来真的很有趣。干杯
    • 第一个IntStream的目的是什么?它将显示日期两次。或者你为什么不只留下第一个 IntStream 并将返回类型更改为 void ?我只是好奇。
    • 正如我所提到的,这只是 2 个问题:一个打印,一个返回。 JavaMan 可以选择任何他想要的。 :-)
    • 我不喜欢这些新的习语一般是低效的,LocalDate.ofYearDay 每次github.com/frohoff/jdk8u-jdk/blob/… 都会创建一个新实例,如果你把这段代码放在一个高度使用的方法中,它不会是最高效。
    【解决方案5】:

    现在是 2020 年,您真的应该接受 java.time.* API。

    虽然我确信可能有一种非常巧妙的方法来获得日期之间的“工作日”,但我已经采用了蛮力方法......

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

    然后您可以简单地使用DateTimeFormatterLocalDate 格式化为您想要的格式,例如...

    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 所以 - 它本质上是我所做的事情的简写版本 - 很高兴知道
    • 有点,是的,最终它确实是LongStream.rangeClosed(0, steps).mapToObj( n -&gt; this.plusMonths(months * n).plusDays(days * n));...但是关于你的代码,ArrayList 的大小可能是240 的粗略估计360 - 2 * 40。此外,当您有 if(condition) {NO-OP} else {OP} 时,应将其更改为 if(!condition){OP}
    • 我明白了,可以理解。
    • @Eugene 喜欢反馈虽然?
    【解决方案6】:

    试试这个:

    // 使用 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);
    

    【讨论】:

    • 不错的代码,但它与所提问题的关系从我这里消失了?
    • 我只是在这里给出了我的代码作为示例,他可以按照我使用的方式进行操作。但只有他需要从我的代码中获取新的日期格式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-02
    相关资源
    最近更新 更多