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

时间:2013-12-11 19:15:33

标签: java date

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

以下是我的代码:

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

8 个答案:

答案 0 :(得分: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);
}

在这结束时,你将在星期五阵列中有星期五。简单?

或者如果你想加快速度,一旦你周五结束,你就可以从使用天数转为使用周数:

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

答案 1 :(得分:3)

首先,我不会打扰周。将日历设置为范围的开头,并确定它是哪个DOW,然后递增以到达下一个星期五,然后简单地循环添加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会进一步浓缩。

答案 2 :(得分:2)

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.

java.time

其他答案已过时。旧的java.util.Date/.Calendar类已在Java 8及更高版本的新java.time框架中取代。 Joda-Time库非常出色,继续保持,甚至启发了java.time。但是Joda-Time团队建议尽快转到java.time。

LocalDate

java.time类包含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

java.time框架包含TemporalAdjuster接口作为转换日期时间值的方法。例如,getting the next or same Friday表示任何特定日期。在开始日期,请致电with(TemporalAdjuster adjuster)并从课程TemporalAdjusters传递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 );
  

来自:2009-01-01至:2013-12-09为258周五:[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-02,2010-02-12,2010-02-19,2010-02-02,2010-03-03,2010-03-03, 2010-03-19,2010-03-26,2010-04-02,2010-04-09,2010-04-16,2010-04-23,2010-04-04,2010-05-07,2010- 05-14,2010-05-21,2010-05-28,2010-06-06,2010-06-06,2010-05-06,2010-06-06,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-10,2010-10-10,2010-10-10,2010-10-10- 29,2010-11-05,2010-11-12,2010-11-19,2010-11-26,2010-12-03,2010-12-12,2010-12-12,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-06,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,201 2-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,200 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-08,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.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和&amp; SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

使用符合JDBC driver或更高版本的JDBC 4.2,您可以直接与数据库交换 java.time 对象。不需要字符串也不需要java.sql。* classes。

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 3 :(得分:1)

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

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

答案 4 :(得分:1)

此处的解决方案基于 Java-8的新流功能并使用我的库Time4J(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 :(得分:0)

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

答案 6 :(得分:0)

public static List<Date> getWeekNumberList(Date currentMonthDate) {
    List<Date> dates = new ArrayList<>(10);
    Calendar startCalendar = Calendar.getInstance();
    startCalendar.setTime(currentMonthDate);
    startCalendar.set(Calendar.DAY_OF_MONTH,
            startCalendar.getActualMinimum(Calendar.DAY_OF_MONTH));
    Calendar endCalendar = Calendar.getInstance();
    endCalendar.setTime(currentMonthDate);
    endCalendar.set(Calendar.DAY_OF_MONTH,
            endCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));

    Date enddate = endCalendar.getTime();
    while (startCalendar.getTime().before(enddate)) {
        if (startCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) {
            Date result = startCalendar.getTime();
            dates.add(result);
            startCalendar.add(Calendar.WEEK_OF_MONTH, 1);
        } else {

            startCalendar.add(Calendar.DAY_OF_MONTH, 1);
        }
    }
    return dates;
}

答案 7 :(得分:0)

使用 Java 8+

LocalDate s= LocalDate.now();
LocalDate e= LocalDate.now().plusMonths(5);

List<LocalDate> dates2 = s.with(TemporalAdjusters.next(DayOfWeek.FRIDAY)).datesUntil(e, Period.ofWeeks(1)).collect(Collectors.toList());
dates2.forEach(x->System.out.println(x));