如何识别日期是否在 10 月 1 日至 5 月 31 日之间,而不管 Javascript 中的年份如何

aki*_*ila 5 javascript

所以我正在开发一个 JavaScript 应用程序,我需要计算每月消耗的公用事业费用。水电费有不同的费率

  • 冬季费率(6 月 1 日至 9 月 30 日)--> 较高费率
  • 夏季价格(10 月 1 日至 5 月 31 日)

因此,当我需要计算月份的账单时,可以说:4 月 25 日 - 5 月 22 日,那么这需要确定为夏季。
所以我需要计算计费日期是夏季还是冬季。

我正在尝试做一些以下形式的事情,但这是代码中的很多杂耍。

我如何计算给定日期是在10 月至 5 月(夏季)之间还是在6 月至 9 月(冬季)之间

注意 - 我需要忽略年份

if (
  dateFrom.getMonth() >= vendorSummerStartDate.getMonth() &&
  dateFrom.getDate() >= vendorSummerStartDate.getDate() &&
  dateTo.getMonth() <= vendorSummerEndDate.getMonth() &&
  dateTo.getDate() <= vendorSummerEndDate.getDate()
) { /*... */ }
Run Code Online (Sandbox Code Playgroud)

Dai*_*Dai -1

更新了这篇文章有一个可运行的代码片段页面,其中包含“此日期是否在可能环绕的日期范围内?” 里面的计算器:

function compare_month_and_day_only( x, y ) {
    let cmp = x.getUTCMonth() - y.getUTCMonth();
    if( cmp != 0 ) return cmp;
    cmp = x.getUTCDay() - y.getUTCDay();
    return cmp;
}

function dt_is_in_simple_range( start, end, dt ) {
    // Preconditions:
    if( end <= start ) throw new Error( "End must be after Start" );
    if( compare_month_and_day_only( start, end ) > 0 ) throw new Error( "End must be positioned after Start in a flat calendar." );
    
    const s2 = new Date( dt.getUTCFullYear(), start.getUTCMonth(), start.getUTCDay() );
    const e2 = new Date( dt.getUTCFullYear(), end.getUTCMonth(), end.getUTCDay() );
    
    return ( s2 <= dt ) && ( dt <= e2 );
}

function dt_is_in_range( start, end, dt ) {
    // Preconditions:
    if( end <= start ) throw new Error( "End must be after Start" );
    
    const range_wraps_around = compare_month_and_day_only( start, end ) > 0;
    if( range_wraps_around ) {
        // Invert the date-range - and invert the result:
        const invStart = new Date( dt.getUTCFullYear(), end.getUTCMonth(), end.getUTCDay() );
        const invEnd   = new Date( dt.getUTCFullYear(), start.getUTCMonth(), start.getUTCDay() );
        const is_in_inverted_range = dt_is_in_simple_range( invStart, invEnd, dt );
        return !is_in_inverted_range;
    }
    else {
        return dt_is_in_simple_range( start, end, dt );
    }
}

//

function updateResults() {
   
    // Most of this code is just to create dates-from-numbers as JavaScript makes this surprisingly verbose and difficult.
    const subject = document.getElementById('subjectDate').valueAsDate;
    if( !subject ) return;
    
    const startMon = document.getElementById('startDateM').valueAsNumber;
    const startDay = document.getElementById('startDateD').valueAsNumber;
    
    const endMon   = document.getElementById('endDateM'  ).valueAsNumber;
    const endDay   = document.getElementById('endDateD'  ).valueAsNumber;
    
    const year = subject.getUTCFullYear();
    
    const start    = new Date( year, startMon, startDay );
    let   end      = new Date( year, endMon  , endDay   );
    if( end < start ) {
        end = new Date( year + 1, endMon, endDay );
    }
    
    if( !start || !end || !subject ) return;
    
    let resultMessage = '';
    try {
      const result = dt_is_in_range( start, end, subject );
      resultMessage = result ? "Yes" : "No";
    }
    catch( err ) {
      resultMessage = err.message || 'Other error';
    }
    
    const li = document.createElement('li');
    
    li.textContent = ( "Is " + subject.toLocaleDateString() + " in the range " + start.toLocaleDateString() + " to " + end.toLocaleDateString() + "? " + resultMessage );
    
    document.getElementById('list').appendChild( li );

}
Run Code Online (Sandbox Code Playgroud)
<label>
  Start day
  <input type="number" id="startDateD" min="1" max="31" oninput="updateResults()" />
</label>
<label>
  Start month
  <input type="number" id="startDateM" min="1" max="12" oninput="updateResults()" />
</label>


<label>
  End day
  <input type="number" id="endDateD" min="1" max="31" oninput="updateResults()" />
</label>
<label>
  End month
  <input type="number" id="endDateM" min="1" max="12" oninput="updateResults()" />
</label>


<label>
  Subject date
  <input type="date" id="subjectDate" oninput="updateResults()" />
</label>

<ul id="list">
</ul>
Run Code Online (Sandbox Code Playgroud)


像这样的难题很容易被过度思考,但更简单的方法是简单地检查它是否是一个环绕日期范围;如果是,则为该年之后start的日期 - 该范围内的日期与不是同一年起始日期的范围相同。因此,只需将输入标准化为简单的单年范围,并在必要时反转。 endend to

在此输入图像描述

(很抱歉在这里使用snake_case,我觉得它更适合这种情况)

function compare_month_and_day_only( x, y ) {
    let cmp = x.getUTCMonth() - y.getUTCMonth();
    if( cmp != 0 ) return cmp;
    cmp = x.getUTCDay() - y.getUTCDay();
    return cmp;
}

function dt_is_in_simple_range( start, end, dt ) {
    // Preconditions:
    if( end <= start ) throw new Error( "End must be after Start" );
    if( compare_month_and_day_only( start, end ) > 0 ) throw new Error( "End must be positioned after Start in a flat calendar." );
    
    const s2 = new Date( dt.getUTCYear(), start.getUTCMonth(), start.getUTCDay() );
    const e2 = new Date( dt.getUTCYear(), end.getUTCMonth(), end.getUTCDay() );
    
    return ( s2 <= dt ) && ( dt <= e2 );
}

function dt_is_in_range( start, end, dt ) {
    // Preconditions:
    if( end <= start ) throw new Error( "End must be after Start" );
    
    const range_wraps_around = compare_month_and_day_only( start, end ) > 0;
    if( range_wraps_around ) {
        // Invert the date-range - and invert the result:
        const invStart = new Date( dt.getUTCYear(), end.getUTCMonth(), end.getUTCDay() );
        const invEnd   = new Date( dt.getUTCYear(), start.getUTCMonth(), start.getUTCDay() );
        const is_in_inverted_range = dt_is_in_simple_range( invStart, invEnd, dt );
        return !is_in_inverted_range;
    }
    else {
        return dt_is_in_simple_range( invStart, invEnd, dt );
    }
}
Run Code Online (Sandbox Code Playgroud)

提示:记录前置条件(使用运行时断言)可以更轻松地理解函数接收的数据的“形状” - 不仅像 TypeScript 中的类型,还包括值的域和范围 - 这不是你可以轻松表达的东西打字稿。

  • OP 不需要日级粒度。当数组中只有_三个_元素时,O(n) 并不是一个大问题。 (2认同)