有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

在Java中获取日期范围内的所有星期五

我最近遇到一个任务,我必须把所有的星期五都安排在一个日期范围内。我写了一小段代码,并惊讶地看到一些奇怪的行为

下面是我的代码:

public class Friday {
    public static void main(String[]args){
        String start = "01/01/2009";
        String end = "12/09/2013";
        String[] startTokens = start.split("/");
        String[] endTokens = end.split("/");
        Calendar  startCal = new GregorianCalendar(Integer.parseInt(startTokens[2]),Integer.parseInt(startTokens[1])-1,Integer.parseInt(startTokens[0]));
        Calendar endCal = new GregorianCalendar(Integer.parseInt(endTokens[2]),Integer.parseInt(endTokens[1])-1, Integer.parseInt(endTokens[0]));

        int startYear = Integer.parseInt(startTokens[2]);
        int endYear = Integer.parseInt(endTokens[2]); 


        int startWeek = startCal.get(Calendar.WEEK_OF_YEAR);
        int endWeek = endCal.get(Calendar.WEEK_OF_YEAR);

        Calendar cal = new GregorianCalendar();
        cal.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
    //  cal.setMinimalDaysInFirstWeek(7);
        ArrayList<String> main = new ArrayList<String>();
        while(startYear <= endYear ){
               cal.set(Calendar.YEAR, startYear);
               System.out.println(cal.getMinimalDaysInFirstWeek());
                if(startYear == endYear){
                    main.addAll(getFridays(startWeek, endWeek, cal));
                }
                else{
                    main.addAll(getFridays(startWeek, 52, cal));
                    startWeek = 1;
                }
                startYear =startYear +1;
        }

        for(String s: main){
            System.err.println(s);
        }
    }
    public static ArrayList<String> getFridays(int startWeek, int endWeek, Calendar cal){
        ArrayList<String> fridays = new ArrayList<String>();
        while(startWeek <= endWeek){
            cal.set(Calendar.WEEK_OF_YEAR, startWeek);
            fridays.add(cal.getTime().toString());
            startWeek = startWeek+1;
        }
        return fridays;
    }
}

现在当我运行代码时,我注意到2011年的星期五不见了。经过一些调试和在线浏览之后,我发现Calendar.WEEK_OF_YEAR是特定于语言环境的,我必须使用setMinimalDaysInFirstWeek(7)来修复它

因此,在上面的代码中取消了相关行的注释

根据我现在的理解,一年中的第一周应该从一年中的整整一周开始

例如,2010年1月1日是星期五。但它不应该出现在结果中,因为我将它配置为治疗从1月3日开始的那一周。但现在我仍然认为1月1日是星期五

我很困惑。有人能解释为什么会这样吗

这些Stackoverflow文章对我有些帮助:

Why dec 31 2010 returns 1 as week of year?

Understanding java.util.Calendar WEEK_OF_YEAR


共 (6) 个答案

  1. # 1 楼答案

    Lamma Date一起:

    List<Date> fridays = Dates.from(2015, 12, 1).to(2016, 1, 1).byWeek().on(DayOfWeek.FRIDAY).build();
    for (Date friday: fridays) {
        System.out.println(friday);
    }
    
  2. # 2 楼答案

    此代码将打印星期五之前的所有日期

    public class Friday {
       public static void main(String[] args) throws ParseException {
         String start = "01/01/2013";
         String end = "12/01/2013";
         SimpleDateFormat dateFormat=new SimpleDateFormat("dd/MM/yyyy");
         Calendar scal=Calendar.getInstance();
         scal.setTime(dateFormat.parse(start));
         Calendar ecal=Calendar.getInstance();
         ecal.setTime(dateFormat.parse(end));
    
         ArrayList<Date> fridayDates=new ArrayList<>();
    
         while(!scal.equals(ecal)){
             scal.add(Calendar.DATE, 1);
             if(scal.get(Calendar.DAY_OF_WEEK)==Calendar.FRIDAY){
                 fridayDates.add(scal.getTime());
             }
         }
    
         System.out.println(fridayDates);
     }
    }
    
  3. # 3 楼答案

    tl;博士

    someLocalDate.with(                                      // Date-only value without time-of-day and without time zone, represented by `LocalDate` class.
        TemporalAdjusters.nextOrSame ( DayOfWeek.FRIDAY ) )  // Moving from one `LocalDate` object to another, to find the next Friday unless the starting date is already a Friday.
    )                                                        // Return a `LocalDate` object.
    

    爪哇。时间

    其他答案已经过时了。旧爪哇。util。日期/。在Java8和更高版本中,新的java.time框架取代了日历类。Joda Time library非常优秀,一直在维护,甚至受到了java的启发。时间但Joda Time团队建议转向java。只要方便,时间就到

    LocalDate

    爪哇。时间类包括^{},用于只包含日期的值,不包含一天中的时间或时区。见Tutorial

    首先解析输入字符串以获取LocalDate对象

    String inputStart = "01/01/2009";
    String inputStop = "12/09/2013";  // 258 Fridays.
    // String inputStop = "01/01/2009";  // 0 Friday.
    // String inputStop = "01/02/2009";  // 1 Friday.
    
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "MM/dd/yyyy" );
    
    LocalDate start = LocalDate.parse ( inputStart , formatter );
    LocalDate stop = LocalDate.parse ( inputStop , formatter );
    

    在您自己的代码中,如果输入错误,请尝试捕获异常。并验证stop确实与start相同或更晚

    TemporalAdjusters

    爪哇。时间框架包括^{}接口,用于转换日期时间值。例如,getting the next or same Friday表示任何特定日期。在开始日期,调用^{}并从类^{}传递TemporalAdjuster的预定义实现(注意复数形式s)。见Tutorial

    List<LocalDate> fridays = new ArrayList<> ();  // Collect each Friday found.
    LocalDate nextOrSameFriday = start.with ( TemporalAdjusters.nextOrSame ( DayOfWeek.FRIDAY ) );
    // Loop while we have a friday in hand (non-null) AND that friday is not after our stop date (isBefore or isEqual the stop date).
    while ( ( null != nextOrSameFriday ) & (  ! nextOrSameFriday.isAfter ( stop ) ) ) {
        fridays.add ( nextOrSameFriday );  //  Remember this friday.
        nextOrSameFriday = nextOrSameFriday.plusWeeks ( 1 );  // Move to the next Friday, setting up for next iteration of this loop.
    }
    

    转储到控制台

    System.out.println ( "From: " + start + " to: " + stop + " are " + fridays.size () + " Fridays: " + fridays );
    

    From: 2009-01-01 to: 2013-12-09 are 258 Fridays: [2009-01-02, 2009-01-09, 2009-01-16, 2009-01-23, 2009-01-30, 2009-02-06, 2009-02-13, 2009-02-20, 2009-02-27, 2009-03-06, 2009-03-13, 2009-03-20, 2009-03-27, 2009-04-03, 2009-04-10, 2009-04-17, 2009-04-24, 2009-05-01, 2009-05-08, 2009-05-15, 2009-05-22, 2009-05-29, 2009-06-05, 2009-06-12, 2009-06-19, 2009-06-26, 2009-07-03, 2009-07-10, 2009-07-17, 2009-07-24, 2009-07-31, 2009-08-07, 2009-08-14, 2009-08-21, 2009-08-28, 2009-09-04, 2009-09-11, 2009-09-18, 2009-09-25, 2009-10-02, 2009-10-09, 2009-10-16, 2009-10-23, 2009-10-30, 2009-11-06, 2009-11-13, 2009-11-20, 2009-11-27, 2009-12-04, 2009-12-11, 2009-12-18, 2009-12-25, 2010-01-01, 2010-01-08, 2010-01-15, 2010-01-22, 2010-01-29, 2010-02-05, 2010-02-12, 2010-02-19, 2010-02-26, 2010-03-05, 2010-03-12, 2010-03-19, 2010-03-26, 2010-04-02, 2010-04-09, 2010-04-16, 2010-04-23, 2010-04-30, 2010-05-07, 2010-05-14, 2010-05-21, 2010-05-28, 2010-06-04, 2010-06-11, 2010-06-18, 2010-06-25, 2010-07-02, 2010-07-09, 2010-07-16, 2010-07-23, 2010-07-30, 2010-08-06, 2010-08-13, 2010-08-20, 2010-08-27, 2010-09-03, 2010-09-10, 2010-09-17, 2010-09-24, 2010-10-01, 2010-10-08, 2010-10-15, 2010-10-22, 2010-10-29, 2010-11-05, 2010-11-12, 2010-11-19, 2010-11-26, 2010-12-03, 2010-12-10, 2010-12-17, 2010-12-24, 2010-12-31, 2011-01-07, 2011-01-14, 2011-01-21, 2011-01-28, 2011-02-04, 2011-02-11, 2011-02-18, 2011-02-25, 2011-03-04, 2011-03-11, 2011-03-18, 2011-03-25, 2011-04-01, 2011-04-08, 2011-04-15, 2011-04-22, 2011-04-29, 2011-05-06, 2011-05-13, 2011-05-20, 2011-05-27, 2011-06-03, 2011-06-10, 2011-06-17, 2011-06-24, 2011-07-01, 2011-07-08, 2011-07-15, 2011-07-22, 2011-07-29, 2011-08-05, 2011-08-12, 2011-08-19, 2011-08-26, 2011-09-02, 2011-09-09, 2011-09-16, 2011-09-23, 2011-09-30, 2011-10-07, 2011-10-14, 2011-10-21, 2011-10-28, 2011-11-04, 2011-11-11, 2011-11-18, 2011-11-25, 2011-12-02, 2011-12-09, 2011-12-16, 2011-12-23, 2011-12-30, 2012-01-06, 2012-01-13, 2012-01-20, 2012-01-27, 2012-02-03, 2012-02-10, 2012-02-17, 2012-02-24, 2012-03-02, 2012-03-09, 2012-03-16, 2012-03-23, 2012-03-30, 2012-04-06, 2012-04-13, 2012-04-20, 2012-04-27, 2012-05-04, 2012-05-11, 2012-05-18, 2012-05-25, 2012-06-01, 2012-06-08, 2012-06-15, 2012-06-22, 2012-06-29, 2012-07-06, 2012-07-13, 2012-07-20, 2012-07-27, 2012-08-03, 2012-08-10, 2012-08-17, 2012-08-24, 2012-08-31, 2012-09-07, 2012-09-14, 2012-09-21, 2012-09-28, 2012-10-05, 2012-10-12, 2012-10-19, 2012-10-26, 2012-11-02, 2012-11-09, 2012-11-16, 2012-11-23, 2012-11-30, 2012-12-07, 2012-12-14, 2012-12-21, 2012-12-28, 2013-01-04, 2013-01-11, 2013-01-18, 2013-01-25, 2013-02-01, 2013-02-08, 2013-02-15, 2013-02-22, 2013-03-01, 2013-03-08, 2013-03-15, 2013-03-22, 2013-03-29, 2013-04-05, 2013-04-12, 2013-04-19, 2013-04-26, 2013-05-03, 2013-05-10, 2013-05-17, 2013-05-24, 2013-05-31, 2013-06-07, 2013-06-14, 2013-06-21, 2013-06-28, 2013-07-05, 2013-07-12, 2013-07-19, 2013-07-26, 2013-08-02, 2013-08-09, 2013-08-16, 2013-08-23, 2013-08-30, 2013-09-06, 2013-09-13, 2013-09-20, 2013-09-27, 2013-10-04, 2013-10-11, 2013-10-18, 2013-10-25, 2013-11-01, 2013-11-08, 2013-11-15, 2013-11-22, 2013-11-29, 2013-12-06]


    关于java。时间

    java.time框架内置于Java8及更高版本中。这些类取代了麻烦的legacy日期时间类,如^{}^{}、&^{}

    目前位于maintenance modeJoda-Time项目建议迁移到java.time

    要了解更多信息,请参阅Oracle Tutorial。并在Stack Overflow中搜索许多示例和解释。规范是JSR 310

    使用与JDBC 4.2或更高版本兼容的JDBC driver,您可以交换java。时间对象直接与数据库连接。不需要字符串或java。sql.*上课

    在哪里可以获得java。时间课

    ThreeTen-Extra项目扩展了java。有额外课程的时间。这个项目是java未来可能增加的一个试验场。时间你可以在这里找到一些有用的类,比如^{}^{}^{}more

  4. # 4 楼答案

    这里是一个基于Java-8的新流特性的解决方案,使用my libraryTime4J(v4.18或更高版本):

    String start = "01/01/2009";
    String end = "12/09/2013";
    
    ChronoFormatter<PlainDate> f =
        ChronoFormatter.ofDatePattern("dd/MM/yyyy", PatternType.CLDR, Locale.ROOT);
    
    PlainDate startDate =
        f.parse(start).with(PlainDate.DAY_OF_WEEK.setToNextOrSame(Weekday.FRIDAY));
    PlainDate endDate = f.parse(end);
    
    Stream<PlainDate> fridays =
        DateInterval.stream(Duration.of(1, CalendarUnit.WEEKS), startDate, endDate);
    
    fridays.forEachOrdered(System.out::println);
    
    // output
    2009-01-02 
    2009-01-09 
    ... 
    2013-08-30 
    2013-09-06
    
    // other example: list of fridays in ISO-8601-format
    List<String> result =
      DateInterval.between(startDate, endDate)
        .stream(Duration.of(1, CalendarUnit.WEEKS))
        .map((date) -> date.toString()) // or maybe use dd/MM/yyyy => f.format(date)
        .collect(Collectors.toList());
    

    顺便说一句,Java-9将提供类似的解决方案(但具有唯一的结束日期边界),另请参见enhancement-issue

  5. # 5 楼答案

    首先,我不想花几个星期的时间。将日历设置为范围的开始,计算出道琼斯指数,然后递增到下一个星期五,然后简单地循环增加7天,直到到达范围的末尾

    实际上,因为你总是只向前看,所以应该是这样的:

    int daysToAdd = FridayDOW - currentDOW;
    if (daysToAdd < 0) daysToAdd += 7; 
    Date startDate = currentDate.add(Calendar.DAYS, daysToAdd);
    

    是的,就像那样

    好的,事实上,在Java 8中,它是:

    @Test
    public void canFindAllFridaysInRange(){
        start = LocalDate.of(2013, 5, 10);
        end = LocalDate.of(2013, 8,30);
    
        DayOfWeek dowOfStart = start.getDayOfWeek();
        int difference = DayOfWeek.FRIDAY.getValue() - dowOfStart.getValue();
        if (difference < 0) difference += 7;
    
        List<LocalDate> fridaysInRange = new ArrayList<LocalDate>();
    
        LocalDate currentFriday = start.plusDays(difference);
        do {
            fridaysInRange.add(currentFriday);
            currentFriday = currentFriday.plusDays(7);
        } while (currentFriday.isBefore(end));
    
        System.out.println("Fridays in range: " + fridaysInRange);
    }
    

    一定很喜欢新的约会课程!!当然,lambda会进一步浓缩这一点

  6. # 6 楼答案

    下面是一个更简单的方法,使用奇妙的http://www.joda.org/joda-time/库:

    String start = "01/01/2009";
    String end = "12/09/2013";
    DateTimeFormatter pattern = DateTimeFormat.forPattern("dd/MM/yyyy");
    DateTime startDate = pattern.parseDateTime(start);
    DateTime endDate = pattern.parseDateTime(end);
    
    List<DateTime> fridays = new ArrayList<>();
    
    while (startDate.isBefore(endDate)){
        if ( startDate.getDayOfWeek() == DateTimeConstants.FRIDAY ){
            fridays.add(startDate);
        }
        startDate = startDate.plusDays(1);
    }
    

    最后,在fridays数组中有fridays。简单

    或者,如果你想加快速度,一旦你有了一个星期五,你可以从使用天切换到使用周:

    String start = "01/01/2009";
    String end = "12/09/2013";
    DateTimeFormatter pattern = DateTimeFormat.forPattern("dd/MM/yyyy");
    DateTime startDate = pattern.parseDateTime(start);
    DateTime endDate = pattern.parseDateTime(end);
    
    List<DateTime> fridays = new ArrayList<>();
    boolean reachedAFriday = false;
    while (startDate.isBefore(endDate)){
        if ( startDate.getDayOfWeek() == DateTimeConstants.FRIDAY ){
            fridays.add(startDate);
            reachedAFriday = true;
        }
        if ( reachedAFriday ){
            startDate = startDate.plusWeeks(1);
        } else {
            startDate = startDate.plusDays(1);
        }
    }