You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Swift中如何获取指定日期范围内特定星期几的日期列表

实现方案

核心工具方法封装

首先通过Calendar系统API实现日期范围遍历、星期匹配能力,新增Date扩展如下:

import SwiftUI

extension Date {
    /// 获取指定日期间隔内,匹配指定星期几的所有日期
    /// - Parameters:
    ///   - range: 统计日期区间
    ///   - matchingWeekdays: 要匹配的星期几集合,iOS系统默认1=周日、2=周一...7=周六
    /// - Returns: 匹配的日期数组
    static func getDates(in range: ClosedRange<Date>, matchingWeekdays: Set<Int>) -> [Date] {
        let calendar = Calendar.current
        var result: [Date] = []
        var currentDate = calendar.startOfDay(for: range.lowerBound)
        let endDate = calendar.startOfDay(for: range.upperBound)
        
        while currentDate <= endDate {
            let weekday = calendar.component(.weekday, from: currentDate)
            if matchingWeekdays.contains(weekday) {
                result.append(currentDate)
            }
            currentDate = calendar.date(byAdding: .day, value: 1, to: currentDate)!
        }
        return result
    }
    
    /// 自动计算扣除固定休息日、法定节假日后的基础工作日数
    static func calculateBasicWorkDays(
        start: Date,
        end: Date,
        restWeekdays: Set<Int>,
        publicHolidays: Set<Date>
    ) -> Int {
        // 先筛掉自定义固定休息日
        let candidateDays = getDates(in: start...end, matchingWeekdays: Set(1...7).subtracting(restWeekdays))
        // 再排除法定节假日
        let validDays = candidateDays.filter { day in
            !publicHolidays.contains(Calendar.current.startOfDay(for: day))
        }
        return validDays.count
    }
}

优化后页面代码

在原有代码基础上新增日期选择、休息日配置、节假日配置模块,自动计算基础工作日数,完整代码如下:

struct ContentView: View {
    // 原有状态变量
    @State private var basicDays = ""
    @State private var lateEntry = ""
    @State private var absentDays = ""
    @State private var otHours = ""
    @State private var midNights = ""
    @State private var nightShifts = ""
    @State private var medAllowance = ""
    @State private var dayOffOTHours = ""
    @State private var pHolidayBasicHours = ""
    @State private var pHolidayOTHours = ""
    
    // 新增自动计算工作日相关状态
    @State private var startDate = Date()
    @State private var endDate = Calendar.current.date(byAdding: .month, value: 1, to: Date())!
    // 默认休息日为周日(1)、周六(7)
    @State private var restWeekdays: Set<Int> = [1,7]
    @State private var publicHolidays: Set<Date> = []
    // 临时节假日选择变量
    @State private var tempHoliday = Date()
    
    private let weekdayText = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"]
    
    var netWage: Double {
        // 原有计算逻辑保持不变
        let monthlyBasic = 1200.00
        let dailyRate = monthlyBasic / 26
        let hourlyRate = dailyRate / 8
        let otRate = hourlyRate * 1.5
        let dayOffRate = hourlyRate * 2
        let publicHolidayRate = hourlyRate * 2
        let publicHolidayOTRate = hourlyRate * 3
        
        let basicDaysAmount = dailyRate * (Double(basicDays) ?? 0)
        let lateEntryAmount = hourlyRate * (Double(lateEntry) ?? 0)
        let absentDaysAmount = dailyRate * (Double(absentDays) ?? 0)
        let midNightAmount = 10 * (Double(midNights) ?? 0)
        let nightShiftAmount = 15 * (Double(nightShifts) ?? 0)
        let dayOffOTAmount = dayOffRate * (Double(dayOffOTHours) ?? 0)
        let publicHolidayAmount = (publicHolidayRate * (Double(pHolidayBasicHours) ?? 0)) + (publicHolidayOTRate * (Double(pHolidayOTHours) ?? 0))
        
        let totalOTAmount = otRate * (Double(otHours) ?? 0)
        let holidayOTAmount = dayOffOTAmount + publicHolidayAmount
        let otAmount = totalOTAmount + holidayOTAmount
        
        let totalDeduction = lateEntryAmount + absentDaysAmount
        let allowances = midNightAmount + nightShiftAmount
        
        let totalWage = basicDaysAmount + allowances + otAmount
        let netWage = totalWage - totalDeduction
        
        return netWage
    }
    
    // 自动更新基础工作日数
    private func updateBasicDays() {
        let count = Date.calculateBasicWorkDays(
            start: startDate,
            end: endDate,
            restWeekdays: restWeekdays,
            publicHolidays: publicHolidays
        )
        basicDays = "\(count)"
    }
    
    var body: some View {
        NavigationView {
            Form {
                // 新增工作日配置分组
                Group {
                    Section(header: Text("统计周期选择")) {
                        DatePicker("起始日期", selection: $startDate, displayedComponents: .date)
                        DatePicker("结束日期", selection: $endDate, displayedComponents: .date)
                    }
                    
                    Section(header: Text("自定义固定休息日")) {
                        ForEach(1..<8) { index in
                            HStack {
                                Text(weekdayText[index-1])
                                Spacer()
                                if restWeekdays.contains(index) {
                                    Image(systemName: "checkmark")
                                        .foregroundColor(.blue)
                                }
                            }
                            .contentShape(Rectangle())
                            .onTapGesture {
                                if restWeekdays.contains(index) {
                                    restWeekdays.remove(index)
                                } else {
                                    restWeekdays.insert(index)
                                }
                                updateBasicDays()
                            }
                        }
                    }
                    
                    Section(header: Text("法定节假日配置")) {
                        DatePicker("新增节假日", selection: $tempHoliday, displayedComponents: .date)
                        Button("添加") {
                            let holiday = Calendar.current.startOfDay(for: tempHoliday)
                            publicHolidays.insert(holiday)
                            updateBasicDays()
                        }
                        ForEach(Array(publicHolidays.sorted()), id: \.self) { date in
                            HStack {
                                Text(date.formatted(date: .abbreviated, time: .omitted))
                                Spacer()
                                Button("删除") {
                                    publicHolidays.remove(date)
                                    updateBasicDays()
                                }
                                .foregroundColor(.red)
                            }
                        }
                    }
                    
                    Section(header: Text("自动计算基础工作日数")) {
                        Text(basicDays)
                            .onAppear(perform: updateBasicDays)
                            .onChange(of: startDate) { _ in updateBasicDays() }
                            .onChange(of: endDate) { _ in updateBasicDays() }
                    }
                }
                
                // 原有输入项保持不变
                Group {
                    Section(header: Text("输入迟到总时长(小时)")) {
                        TextField("", text: $lateEntry)
                            .keyboardType(.decimalPad)
                    }
                    
                    Section(header: Text("输入缺勤天数")) {
                        TextField("", text: $absentDays)
                            .keyboardType(.numberPad)
                    }
                    
                    Section(header: Text("输入平时加班总时长")) {
                        TextField("", text: $otHours)
                            .keyboardType(.numberPad)
                    }
                    
                    Section(header: Text("输入夜班(过零点)次数")) {
                        TextField("", text: $midNights)
                            .keyboardType(.numberPad)
                    }
                    
                    Section(header: Text("输入夜班总次数")) {
                        TextField("", text: $nightShifts)
                            .keyboardType(.numberPad)
                    }
                    
                    Section(header: Text("输入医疗报销金额")) {
                        TextField("", text: $medAllowance)
                            .keyboardType(.decimalPad)
                    }
                    
                    Section(header: Text("输入休息日加班总时长")) {
                        TextField("", text: $dayOffOTHours)
                            .keyboardType(.numberPad)
                    }
                    
                    Section(header: Text("输入法定节假日正常上班总时长")) {
                        TextField("", text: $pHolidayBasicHours)
                            .keyboardType(.numberPad)
                    }
                    
                    Section(header: Text("输入法定节假日加班总时长")) {
                        TextField("", text: $pHolidayOTHours)
                            .keyboardType(.numberPad)
                    }
                }

                Section(header: Text("实发工资")) {
                    Text("\(netWage, specifier: "%.2f")")
                }
            }
            .navigationBarTitle("工资计算器")
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

功能说明

  • 核心方法getDates直接返回指定日期范围内对应星期几的日期数组,满足基础需求
  • 自动计算逻辑会在修改统计周期、休息日、节假日时实时更新基础工作日数,不需要用户手动输入
  • 星期匹配规则遵循系统默认:1代表周日,2代表周一,依次到7代表周六,可根据需求自行调整顺序

内容的提问来源于stack exchange,提问作者BangaliBabu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 13:24:06