所以我正在开发一个 JavaScript 应用程序,我需要计算每月消耗的公用事业费用。水电费有不同的费率
因此,当我需要计算月份的账单时,可以说: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 中的类型,还包括值的域和范围 - 这不是你可以轻松表达的东西打字稿。
| 归档时间: |
|
| 查看次数: |
95 次 |
| 最近记录: |