如何在两个给定日期之间获取仅包括月末最后一天为星期一的日期?

3
返回值应该是一个类似于“10/31/2016 8/31/2017”的字符串。这个函数返回了一年中所有的星期一,但我只需要每个月最后一个星期一的日期,如果它们是每个月的最后一天。
function getMondays(startYear, endYear) {
  const startDate = new Date(startYear, 0, 2)
  const endDate = new Date(endYear, 11, 32)

  var i = startDate,
  month = i.getYear(),
  mondaysOfYear = []

  while (i.getDay() !== 2) {
  i.setDate(i.getDate() + 1)
  }

  while (i.getYear() === month) {
    mondaysOfYear.push(new Date(i.getTime()))
    i.setDate(i.getDate() + 7)
  }
  return mondaysOfYear
}
getMondays(2017, 2017)

在范围内迭代月份,将日期设置为每个月的第一天,向后退一天 date.setDate(date.getDate() - 1); 并检查 date.getDay() === 2 - pawel
如果startYear是2017,你如何得到10/31/2016? - Slai
为什么 endDate = new Date(endYear, 11, 32)?那将是次年的1月1日。 - RobG
请注意,像java.util.Datejava.util.Calendarjava.text.SimpleDateFormat这样的旧日期时间类现在已经成为遗留系统,被内置于Java 8及更高版本中的java.time类所取代。请参阅Oracle的教程 - Basil Bourque
你的“10/31/2016 8/31/2017”日期示例是不正确的。在2016年和2017年,月底是星期一的情况分别为:2016-02-29、2016-10-31和2017-07-31。请参考在线日历2016年2017年 - Basil Bourque
5个回答

2

您的逻辑似乎不太合适。存在以下问题:

month = i.getYear(),

getYear 返回两位数的年份,将其分配给名为“month”的变量似乎不明智。然后:

while (i.getDay() !== 2) {
  i.setDate(i.getDate() + 1)
}

将日期递增,直到getDay返回2,即星期二。然后:

if (i.getMonth() != prevMonth) mondaysOfYear.push(prevDate);

这对我来说毫无意义。我猜你的算法是将日期设置为周一,然后加上几周,如果最后落在月末,就将其保存。但你并没有按照这种方式实现它。

一个更简单、可能更快的算法是从开始到结束获取每个月的最后一天,如果是周一,则将其推入一个数组中。有很多方法可以做到这一点,下面是其中之一。

function getMondays(startYear, endYear) {
  // Set start to 1 Jan of start year
  var start = new Date(startYear, 0);
  // Set end to 31 Dec of end year
  var end = new Date(endYear, 11,31);
  var mondays = [];
  
  do {
    // setDate to end of month 
    start.setMonth(start.getMonth() + 1, 0);

    // If it's a Monday, store it in US mm/dd/yyyy format
    if (start.getDay() == 1) {
      mondays.push(start.toLocaleString('en-us', {
        year:  'numeric',
        month: '2-digit',
        day:   '2-digit'
      }));
    }

    // Set date to start of next month
    start.setDate(start.getDate() + 1);
  } while (start <= end) 
 
  return mondays;
}

console.log( getMondays(2016,2017) );


FYI,那些非常麻烦的旧日期时间类,如java.util.Datejava.util.Calendarjava.text.SimpleDateFormat现在已经成为遗留系统,被内置于Java 8及更高版本的java.time类所取代。请参阅Oracle的教程 - Basil Bourque

1

function getMondays(startYear, endYear) {
  mondaysOfYear = []
  for (var y = startYear; y <= endYear; y++)
    for (var m = 1; m < 13; m++) {
      var d = new Date(y, m, 0);   // console.log(d.toDateString()) // "Mon Jul 31 2017"
      if (d.getDay() === 1) 
        mondaysOfYear.push(d.toLocaleDateString())
    }
  return mondaysOfYear
}

console.log(getMondays(2016, 2017).join(" "))        // "2/29/2016 10/31/2016 7/31/2017"


0

像这样吗?

-- 编辑

这里是jsfiddle的链接,以防它在stackoverflow上给出错误结果 :)

function getMondays(startYear, endYear) {
  var months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  var mondays = [];
  while(startYear <= endYear) {
    for(var i = 0; i < 12; i++) {
      var leapYear = startYear % 4 === 0 && i === 1;
      var currentDate = new Date(startYear, i, leapYear ? months[i]+1 : months[i]);
      if(currentDate.getDay() === 1)
        mondays.push(currentDate);
    }
    startYear += 1;
  }
  return mondays;
}

var mondays = getMondays(2016, 2017)
console.log(mondays)


0

这将获取所有上个月的星期一 -

function getMondays(startYear, endYear) {
  const startDate = new Date(startYear, 0, 2)
  const endDate = new Date(endYear, 11, 32)

  var i = startDate,
  month = i.getYear(),
  mondaysOfYear = []

  while (i.getDay() !== 2) {
  i.setDate(i.getDate() + 1)
  }
  var prevMonth = 0;
  var prevDate;
  while (i.getYear() === month) {
    if(i.getMonth()!= prevMonth) mondaysOfYear.push(prevDate);
    prevMonth = i.getMonth(); //Retaining the last month to compare
    prevDate = new Date(i.getTime()); //Retaining the last monday
    i.setDate(i.getDate() + 7); 
  } 
  mondaysOfYear.push(prevDate);//for December
  return mondaysOfYear
}
getMondays(2017, 2017);

过滤掉月份变化时的日期。在循环结束后,添加12月的最后一个星期一。


-1

你的问题不太清楚,但显然你想找到每个月最后一天恰好是星期一的所有情况。

java.time

现代方法使用java.time类。具体来说,LocalDate类表示仅包含日期值而不包含时间和时区的日期。此外,YearYearMonthDayOfWeek类也是如其名称所示。
与其传递简单的整数,您可以传递Year对象以实现类型安全,使您的代码更加自我说明。
Year startYear = Year.of( 2016 );
Year stopYear = Year.of( 2018 );

定义你的实用方法。

public List< LocalDate > calcMondays ( Year startYear , Year stopYear ) { … }

传递那一对对象。

List< LocalDate> dates = this.calcMondays( startYear , stopYear ) ;

我建议在定义时间跨度时始终使用半开放方法。在这种方法中,开始时间是包含的,而结束时间是不包含的。因此,2017-2019年的时间段将从2017年的第一天开始,并持续到但不包括2019年的第一天,为期2年。

获取YearMonth的开始和停止时间,表示整个月。

YearMonth startYm = YearMonth.from( startYear.atDay( 1 ) ) ;
YearMonth stopYm = YearMonth.from( stopYear.atDay( 1 ) ) ;

定义一个包含我们找到的日期的集合。

int initialCapacity = ( int ) ChronoUnit.MONTHS.between( startYear.atDay( 1 ) , stopYear.atDay( 1 ) );
List< LocalDate > lastMondays = new ArrayList<>( initialCapacity ) ;

定义我们要定位的星期几。使用DayOfWeek枚举。

DayOfWeek dow = DayOfWeek.MONDAY ; 

定义一个TemporalAdjuster,使用在TemporalAdjusters类中找到的实现。

TemporalAdjuster ta = TemporalAdjusters.lastInMonth( dow ) ;

循环遍历月份。对于每个月份,确定第一个星期一。使用在TemporalAdjusters类中找到的TemporalAdjuster实现。
YearMonth ym = startYm ;
while( ym.isBefore( stopYm ) ) {
    LocalDate firstOfMonth = ym.atDay( 1 ) ;
    LocalDate ld = firstOfMonth.with( ta ) ;
    lastMondays.add( ld ) ;  // Collect our last-monday-of-this-month. 
    // Set up the next loop.
    ym = ym.plusMonths( 1 ) ;
}

报告。

System.out.println( lastMondays ) ;

请查看在IdeOne.com上代码运行实况

[2016-01-25,2016-02-29,2016-03-28,2016-04-25,2016-05-30,2016-06-27,2016-07-25,2016-08-29,2016-09-26,2016-10-31,2016-11-28,2016-12-26,2017-01-30,2017-02-27,2017-03-27,2017-04-24,2017-05-29,2017-06-26,2017-07-31,2017-08-28,2017-09-25,2017-10-30,2017-11-27,2017-12-25]

现在让我们修改这个循环,只关注月份的最后一天是星期一的情况。

YearMonth ym = startYm;
while ( ym.isBefore( stopYm ) ) {
    LocalDate endOfMonth = ym.atEndOfMonth();
    if ( endOfMonth.getDayOfWeek().equals( dow ) ) {
        lastMondays.add( endOfMonth );  // Collect our last-monday-of-this-month.
    }
    // Set up the next loop.
    ym = ym.plusMonths( 1 );
}

请查看在IdeOne.com上运行的代码实时运行

[2016-02-29,2016-10-31,2017-07-31]

请注意这些结果与问题中给出的结果不同。我已经验证这里的结果是正确的,而问题的结果是错误的。


关于 java.time

java.time 框架是内置于 Java 8 及更高版本的。这些类取代了旧的 遗留 日期时间类,如 java.util.DateCalendarSimpleDateFormat

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

想要了解更多,请参阅 Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是 JSR 310

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

如何获取 java.time 类?

ThreeTen-Extra项目通过添加额外的类来扩展java.time。该项目是java.time可能未来增加的内容的试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuarter更多


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接