获取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 main = new ArrayList(); 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 getFridays(int startWeek, int endWeek, Calendar cal){ ArrayList fridays = new ArrayList(); 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文章对我有所帮助:

为什么2010年12月31日作为一年中的一周返回1?

了解java.util.Calendar WEEK_OF_YEAR

这是一个更简单的方法,使用精彩的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 fridays = new ArrayList<>(); while (startDate.isBefore(endDate)){ if ( startDate.getDayOfWeek() == DateTimeConstants.FRIDAY ){ fridays.add(startDate); } startDate = startDate.plusDays(1); } 

在这结束时,你将在星期五arrays周五。 简单?

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

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

首先,我不会打扰周。 将日历设置为范围的开头,并确定它是哪个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 fridaysInRange = new ArrayList(); 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会进一步浓缩。

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 ,它是一个仅限日期的值,没有时间或时区。 请参阅教程 。

首先解析输入字符串以获取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 ); 

在您自己的代码中,在输入错误的情况下尝试捕获exception。 并validationstop确实与start相同或晚。

TemporalAdjusters

java.time框架包含TemporalAdjuster接口,作为转换日期时间值的一种方式。 例如, 获取任何特定日期的下一个或同一个星期五 。 在您的开始日期, with(TemporalAdjuster adjuster)调用with(TemporalAdjuster adjuster)TemporalAdjusters类中传递with(TemporalAdjuster adjuster)的预定义实现(注意复数s )。 请参阅教程 。

 List 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-05,2010-02-02,2010-02-19,2010-02-26,2010-03-03,2010-03-03,2010-03-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-06-18,2010-06-06,2010-07-02,20 10-07-09,2010-07-16,2010-07-23,2010-07-30,2010-08-08,2010-08-08,2010-08-08,2010-08-08,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-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- 0 2-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-06,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及更高版本中。 这些类取代了麻烦的旧遗留日期时间类,如java.util.DateCalendarSimpleDateFormat

现在处于维护模式的Joda-Time项目建议迁移到java.time类。

要了解更多信息,请参阅Oracle教程 。 并搜索Stack Overflow以获取许多示例和解释。 规范是JSR 310 。

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

从哪里获取java.time类?

  • Java SE 8Java SE 9及更高版本
    • 内置。
    • 带有捆绑实现的标准Java API的一部分。
    • Java 9增加了一些小function和修复。
  • Java SE 6Java SE 7
    • 许多java.timefunction都被反向移植到ThreeTen-Backport中的 Java 6和7。
  • Android的
    • 更高版本的Android捆绑java.time类的实现。
    • 对于早期的Android, ThreeTenABP项目采用ThreeTen-Backport (如上所述)。 请参见如何使用ThreeTenABP ….

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

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

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

这里有一个基于Java-8的新流特性并使用我的库Time4J (v4.18或更高版本)的解决方案:

 String start = "01/01/2009"; String end = "12/09/2013"; ChronoFormatter 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 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 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将提供类似的解决方案(但具有独占的结束日期边界),另请参阅此增强问题 。

与Lamma日期 :

 List fridays = Dates.from(2015, 12, 1).to(2016, 1, 1).byWeek().on(DayOfWeek.FRIDAY).build(); for (Date friday: fridays) { System.out.println(friday); } 
 public static List getWeekNumberList(Date currentMonthDate) { List 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; }