【问题标题】:How to get a specify date in every month in Javascript?如何在Javascript中获取每个月的指定日期?
【发布时间】:2018-03-13 20:27:44
【问题描述】:

我需要找到本月、上月和下月的具体日期。

例如,日期设置为每月 31 日,我希望得到的日期是 2018 年 2 月 28 日、2018 年 3 月 31 日和 2018 年 4 月 30 日。对于那些没有 31 的日期,它会变成前一天。

最后生成 2 个周期,2018-02-28 到 2018-03-29,2018-03-30 到 2018-04-31。 2月和31以下的月份不知道怎么处理。

var d = new Date();
var tyear = d.getFullYear(); //2018
var tmonth = d.getMonth();  //2  
new Date(2018, tmonth-1, 31);//output 2018-03-02 not what I wanted

【问题讨论】:

  • new Date(2018, 2, 31); 将是 2018-02-31,它不存在。
  • 你必须非常仔细地定义你的边缘案例几个月。 1 月 31 日 + 2 个月 = 3 月 31 日。 1 月 31 日 + 1 个月 + 1 个月 = 3 月 28 日!另一个例子:Jan31st - 1month + 1month = Jan31st,但是 Jan31st + 1month - 1month = Jan 28...玩得开心...
  • @dimwittedanimal 不,那将是 3 月 31 日,确实存在...new Date(2018, 1, 31)(您可能的意思是)将是 3 月 3 日。
  • @sheeldotme 并不是每个月的最后一天,而是用户在开始时定义的任何一天。

标签: javascript jquery date


【解决方案1】:

一个简单的算法是在原始日期的基础上增加月份,如果新日期错误,则将其设置为上个月的最后一天。保持原始日期值不变有助于,例如

/* @param {Date} start - date to start
** @param {number} count - number of months to generate dates for
** @returns {Array} monthly Dates from start for count months
*/
function getMonthlyDates(start, count) {
  var result = [];
  var temp;
  var year = start.getFullYear();
  var month = start.getMonth();
  var startDay = start.getDate();
  for (var i=0; i<count; i++) {
    temp = new Date(year, month + i, startDay);
    if (temp.getDate() != startDay) temp.setDate(0);
    result.push(temp);
  }
  return result;
}

// Start on 31 Jan in leap year
getMonthlyDates(new Date(2016,0,31), 4).forEach(d => console.log(d.toString()));
// Start on 31 Jan not in leap year
getMonthlyDates(new Date(2018,0,31), 4).forEach(d => console.log(d.toString()));

// Start on 30 Jan
getMonthlyDates(new Date(2018,0,30), 4).forEach(d => console.log(d.toString()));
// Start on 5 Jan
getMonthlyDates(new Date(2018,0,5), 4).forEach(d => console.log(d.toString()));

【讨论】:

    【解决方案2】:

    我认为您将需要一个包含 12 个数字的数组。每个数字是每个月的天数,数组中的数字按顺序排列(第一个数字是 31,因为 1 月有 31 天,第二个数字是 28 或 29 的 2 月)等。然后你会得到月份数您的输入日期并在数组中查看与月份数 +/- 1 对应的数字。

    然后,您需要根据当月的天数构造上个月和下个月的日期。

    查看 cmets 内联:

    let daysInMonths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
    
    document.getElementById("date").addEventListener("input", function(){
      console.clear();
      
      // Create new Date based on value in date picker
      var selectedDate = new Date(this.value + 'T00:00');
    
      var year = selectedDate.getYear();
    
      // Determine if it is a leap year (Feb has 29 days) and update array if so.
      if (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) {
        daysInMonths[1] = 29;
      }
    
      var selectedDateMonth = selectedDate.getMonth();
         
      // Get previous month number (if current month is January, get December)
      let prevMonth = selectedDateMonth > 0 ? selectedDateMonth - 1 : 11;
      
      let prevMonthDate = null;
      
      // If selected date is last day of month...
      if(selectedDate.getDate() === daysInMonths[selectedDateMonth]){
        // Create new date that takes the selected date and subtracts the correct amount of
        // days from it based on a lookup in the array.
        var newDate1 = new Date(selectedDate.getTime());
        prevMonthDate = 
         new Date(newDate1.setDate(selectedDate.getDate() - daysInMonths[selectedDateMonth]));
      } else {
        // Create a new date that is last month and one day earlier
        var newDate2 = new Date(selectedDate.getTime());
        prevMonthDate = 
          new Date(new Date(newDate2.setDate(selectedDate.getDate() - 1))
            .setMonth(selectedDate.getMonth() - 1));
      }
      
      // Get next month (if current month is December, get January
      let nextMonth = selectedDateMonth < 11 ? selectedDateMonth + 1 : 0;  
      
      let nextMonthDate = null;
      
      // Same idea for next month, but add instead of subtract.
      
      // If selected date is last day of month...
      if(selectedDate.getDate() === daysInMonths[selectedDateMonth]){
        var newDate3 = new Date(selectedDate.getTime());
        nextMonthDate = 
         new Date(newDate3.setDate(selectedDate.getDate() + daysInMonths[selectedDateMonth + 1]));
      } else {
        var newDate4 = new Date(selectedDate.getTime());
        nextMonthDate = new Date(new Date(newDate4.setDate(selectedDate.getDate() + 1)).setMonth(selectedDate.getMonth() + 1));
      }  
    
      console.log("Last month date: " + prevMonthDate.toLocaleDateString());
      console.log("Next month date: " + nextMonthDate.toLocaleDateString());  
    });
    &lt;p&gt;Pick a date: &lt;input type="date" id="date"&gt;&lt;/p&gt;

    【讨论】:

    • 别忘了:闰年二月的天数不同!
    • @sheeldotme 添加了闰年功能。
    • 为什么放31/03/1982,这种方法返回下一个日期01/04/1982? (仅提前 1 天)
    • 不,它返回:Last month date: 2/28/1982 Next month date: 3/31/1982,这是下一个日期的问题。
    • @Ele 对于date 字段,格式为 dd/mm/yyyy,而不是 mm/dd/yyyy
    【解决方案3】:

    使用这种方法:

    Javascript Date Object – Adding and Subtracting Months

    来自作者

    尝试前进到下个月或返回上个月时,Javascript Date() 对象存在小问题。

    例如,如果您将日期设置为 2018 年 10 月 31 日并添加了一个月,您可能会认为新日期为 2018 年 11 月 30 日,因为 11 月 31 日不存在。然而,事实并非如此。

    Javascript 会自动将您的 Date 对象提前到 12 月 1 日。此功能在大多数情况下非常有用(例如,为日期添加天数、确定一个月中的天数或是否是闰年),但不适用于添加/减去月份。我在下面汇总了一些扩展 Date() 对象的函数:nextMonth()prevMonth()

    function prevMonth() {
      var thisMonth = this.getMonth();
      this.setMonth(thisMonth - 1);
      if (this.getMonth() != thisMonth - 1 && (this.getMonth() != 11 || (thisMonth == 11 && this.getDate() == 1)))
        this.setDate(0);
    }
    
    function nextMonth() {
      var thisMonth = this.getMonth();
      this.setMonth(thisMonth + 1);
      if (this.getMonth() != thisMonth + 1 && this.getMonth() != 0)
        this.setDate(0);
    }
    
    Date.prototype.nextMonth = nextMonth;
    Date.prototype.prevMonth = prevMonth;
    
    var today = new Date(2018, 2, 31); //<----- March 31st, 2018
    
    var prevMonth = new Date(today.getTime());
    prevMonth.prevMonth();
    console.log("Previous month:", prevMonth);
    
    console.log("This month:", today)
    
    var nextMonth = new Date(today.getTime());
    nextMonth.nextMonth();
    console.log("Next month:", nextMonth);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

    • OP 说 对于那些没有 31 的日期,比它变成前一天。 如果它不是最后一天,您的答案将返回上个月和下个月的同一天月。
    • 仅仅引用别人的作品不是答案。这些方法改变了原始日期,您还没有展示如何创建一系列日期,例如 1 月 30 日、2 月 28 日、3 月 30 日、4 月 30 日等。如果您只是继续增加一个月,您将获取 3 月 28 日、4 月 28 日等。
    【解决方案4】:

    日期和时区是 JS 的一大难题,因此接受挑战。

    我分两步分解:
    - 计算上个月和下个月的天数
    - 与选定的日期进行比较并选择最小的数字

    包含测试用例

    function createUTCDate(year, month, day) {
      return new Date(Date.UTC(year, month, day));
    }
    
    function splitDate(date) {
      return {
        year: date.getUTCFullYear(),
        month: date.getUTCMonth(),
        day: date.getUTCDate()
      };
    }
    
    function numberOfDaysInMonth(year, month) {
      return new Date(year, month + 1, 0).getDate();
    }
    
    function dateNextMonth(dateObj) {
      const daysNextMonth = numberOfDaysInMonth(dateObj.year, dateObj.month + 1);
      const day = Math.min(daysNextMonth, dateObj.day);
      return createUTCDate(dateObj.year, dateObj.month + 1, day);
    }
    
    function datePreviousMonth(dateObj) {
      const daysPrevMonth = numberOfDaysInMonth(dateObj.year, dateObj.month - 1);
      const day = Math.min(daysPrevMonth, dateObj.day);
      return createUTCDate(dateObj.year, dateObj.month - 1, day);
    }
    
    const log = console.log;
    
    function print(dateString) {
      const date = new Date(dateString);
      const dateObj = splitDate(date);
      log("Previous: ", datePreviousMonth(dateObj).toISOString());
      log("Selected: ", date.toISOString());
      log("Next: ", dateNextMonth(dateObj).toISOString());
      log("--------------");
    }
    
    const testCases = [
      "2018-03-01 UTC",
      "2018-03-31 UTC",
      "2018-01-01 UTC",
      "2018-12-31 UTC"
    ];
    
    testCases.forEach(print);

    请注意,new Date(xxx + " UTC") 的 hack 不符合规范,仅用于测试目的。结果可能因浏览器而异。 您应该选择一种输入格式并相应地构建您的日期。

    【讨论】:

    • 字符串“2018-03-01 UTC”不是有效的 ISO 8601 日期字符串,因为日期没有时区。因此,解析依赖于实现(并导致至少一个当前浏览器中的日期无效)。为什么不只使用“2018-03-01”?另请注意,它将被内置解析器解析为 UTC,因此您需要使用所有 UTC 方法,否则主机时区偏移量会在看似罕见和随机的情况下引入难以发现的错误。
    【解决方案5】:

    我通过连接字符串以一种愚蠢的方式处理它

    let daysInMonths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
    let months = ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"];
    
    var target = nexttarget = lasttarget = "29"; //target day
    
    if (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) {
        daysInMonths[1] = 29;
    }
    
    function findLastDay(target, month){
        if(target > daysInMonths[month]){
            target = daysInMonths[month];
        }
        return target;
    }
    

    然后

    var d = new Date();
    var year = d.getFullYear();
    var month = d.getMonth();
    
    target = findLastDay(target, month);
    
    var this_month = year+"-"+months[month]+"-"+target;
    console.log(this_month);//2018-03-29
    
    // next month
    if(month == 11){
       nextmonth = 0;
       nextyear = year + 1;
    }else{
       nextmonth = month+1;
       nextyear = year;
    }
    
    nexttarget = findLastDay(nexttarget, nextmonth);
    
    var next_month = nextyear+"-"+months[nextmonth]+"-"+nexttarget;
    console.log(next_month);//2018-04-29
    
    //last month
    if(month == 0){
       lastmonth = 11;
       lastyear = year - 1;
    }else{
       lastmonth = month - 1;
       lastyear = year;
    }
    
    lasttarget = findLastDay(lasttarget, lastmonth);
    
    var last_month = lastyear+"-"+months[lastmonth]+"-"+lasttarget;
    console.log(last_month);//2018-02-28
    

    【讨论】:

      【解决方案6】:

      在最好的情况下,日期处理很棘手。不要自己这样做。使用Moment.js

      var target = 31;
      var today = moment().date(target).calendar();
      //  today == '03/31/2018'
      
      var nextMonth =  moment().date(target).add(1, 'month').calendar();
      // nextMonth == '04/30/2018'
      
      var lastMonth = moment().date(target).subtract(1, 'month').calendar()
      // lastMonth == '02/28/2018'
      

      【讨论】:

      • 这很好,但真的应该是一个评论,因为 OP 没有要求除了 jQuery 之外的任何库。
      • @ScottMarcus 我很想看到第一个 jQuery 答案:D
      • @Jonathan 你可以很容易地将我的香草 JS 答案转换为 jQuery,因为这个答案并不适合 jQuery。大多数代码将保持不变。
      猜你喜欢
      • 2017-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多