Angular 5日期自定义:开发计算指定日期间企业工作日的算法
Got it, let's tackle this requirement step by step. Calculating business days between two dates in Angular while excluding weekends and custom holidays is a common task, and here's a solid approach to implement it:
First, we'll build a service to handle loading and checking holidays. This keeps our code organized and makes it easy to update the holiday list later.
Generate a service using Angular CLI:
ng generate service holidayIn
holiday.service.ts, we'll load our holiday array (you can store this in a JSON file or directly define it in the service). For example, if you have aholidays.jsonfile in your assets folder:import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class HolidayService { constructor(private http: HttpClient) { } getHolidays(): Observable<Date[]> { return this.http.get<string[]>('/assets/holidays.json').pipe( // Convert string dates to Date objects for consistent comparison map(holidayStrings => holidayStrings.map(dateStr => new Date(dateStr))) ); } // Helper method to check if a given date is a holiday isHoliday(date: Date, holidays: Date[]): boolean { const targetDateStr = date.toISOString().split('T')[0]; return holidays.some(holiday => holiday.toISOString().split('T')[0] === targetDateStr); } }Your
holidays.jsonwould look like this (ISO date format is recommended for consistency):[ "2024-01-01", "2024-05-27", "2024-07-04", "2024-11-28", "2024-12-25" ]
Next, we'll create a dedicated service for the core calculation. The algorithm needs to:
- Ensure the start date is always before the end date
- Iterate through each date in the range
- Skip weekends (Saturdays = 6, Sundays = 0 via
getDay()) - Skip dates that are in our holiday list
Here's the code for business-day.service.ts:
import { Injectable } from '@angular/core'; import { HolidayService } from './holiday.service'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class BusinessDayService { constructor(private holidayService: HolidayService) { } calculateBusinessDays(startDate: Date, endDate: Date): Observable<number> { // Swap dates if start is after end if (startDate > endDate) { [startDate, endDate] = [endDate, startDate]; } return this.holidayService.getHolidays().pipe( map(holidays => { let businessDayCount = 0; const currentDate = new Date(startDate); while (currentDate <= endDate) { const dayOfWeek = currentDate.getDay(); // Check if it's a weekday AND not a holiday if (dayOfWeek !== 0 && dayOfWeek !== 6 && !this.holidayService.isHoliday(currentDate, holidays)) { businessDayCount++; } // Move to next day (avoids mutating the original start date) currentDate.setDate(currentDate.getDate() + 1); } return businessDayCount; }) ); } }
Now you can integrate this logic into any component. Here's a simple calculator component example:
import { Component } from '@angular/core'; import { BusinessDayService } from './business-day.service'; @Component({ selector: 'app-business-day-calculator', template: ` <div class="calculator-container"> <div class="date-inputs"> <label>Start Date: <input type="date" [(ngModel)]="startDateStr" required> </label> <label>End Date: <input type="date" [(ngModel)]="endDateStr" required> </label> </div> <button (click)="computeBusinessDays()" [disabled]="!startDateStr || !endDateStr"> Calculate Business Days </button> <p *ngIf="result !== null" class="result"> Total Business Days: <strong>{{ result }}</strong> </p> </div> `, styles: [` .calculator-container { padding: 20px; max-width: 500px; margin: 0 auto; } .date-inputs { margin-bottom: 15px; display: flex; gap: 10px; } button { padding: 8px 16px; cursor: pointer; } .result { margin-top: 15px; font-size: 1.1rem; } `] }) export class BusinessDayCalculatorComponent { startDateStr: string = ''; endDateStr: string = ''; result: number | null = null; constructor(private businessDayService: BusinessDayService) { } computeBusinessDays() { const startDate = new Date(this.startDateStr); const endDate = new Date(this.endDateStr); this.businessDayService.calculateBusinessDays(startDate, endDate).subscribe(count => { this.result = count; }); } }
For very large date ranges (e.g., years apart), looping through each day can be slow. You can optimize it by:
- Calculating total days between the two dates
- Mathematically computing the number of weekends
- Counting only holidays that fall on weekdays (to avoid double-counting)
Here's a snippet for the optimized weekend calculation:
const totalDays = Math.floor((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24)) + 1; const fullWeeks = Math.floor(totalDays / 7); let weekendDays = fullWeeks * 2; // Add remaining weekend days from the partial week const remainingDays = totalDays % 7; for (let i = 0; i < remainingDays; i++) { const day = (startDate.getDay() + i) % 7; if (day === 0 || day === 6) weekendDays++; }
内容的提问来源于stack exchange,提问作者Marouen Abdi

