求助:用Swift实现员工登录日志中空闲时段查询功能
解决Swift中找出门店空闲时段的问题
别担心,这个问题其实可以拆成几个清晰的小步骤来解决,我来一步步带你实现这个功能:
第一步:定义数据模型
首先我们需要把JSON里的员工登录记录和门店营业时间转换成Swift可以处理的数据结构。假设你的JSON结构大概是这样的:
{ "employees": [ {"id": 1, "loginTime": "2024-05-20T09:30:00", "logoutTime": "2024-05-20T12:00:00"}, {"id": 2, "loginTime": "2024-05-20T11:00:00", "logoutTime": "2024-05-20T14:30:00"} ], "storeHours": {"openTime": "2024-05-20T08:00:00", "closeTime": "2024-05-20T18:00:00"} }
我们可以定义对应的Swift结构体,同时处理日期解析:
import Foundation // 员工登录记录模型 struct EmployeeLog: Codable { let id: Int let loginTime: Date let logoutTime: Date } // 门店营业时间模型 struct StoreHours: Codable { let openTime: Date let closeTime: Date } // 自定义日期解码器,处理JSON中的日期格式 let dateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" formatter.timeZone = TimeZone.current // 根据实际需求调整时区 return formatter }() let jsonDecoder: JSONDecoder = { let decoder = JSONDecoder() decoder.dateDecodingStrategy = .formatted(dateFormatter) return decoder }()
第二步:合并所有员工的登录时段
因为多个员工的登录时段可能重叠,我们需要先把所有有人在岗的时段合并成不重叠的连续区间,这样后续找空闲时段会更简单。
实现合并逻辑的函数:
/// 合并重叠或相邻的时间区间 /// - Parameter intervals: 原始的时间区间数组(每个元素是(开始时间, 结束时间)) /// - Returns: 合并后的不重叠时间区间数组 func mergeOverlappingIntervals(_ intervals: [(start: Date, end: Date)]) -> [(start: Date, end: Date)] { guard !intervals.isEmpty else { return [] } // 先按开始时间排序 let sortedIntervals = intervals.sorted { $0.start < $1.start } var mergedIntervals = [sortedIntervals[0]] for current in sortedIntervals.dropFirst() { guard let last = mergedIntervals.last else { continue } if current.start <= last.end { // 当前区间和最后一个合并区间重叠,合并它们 let newEnd = max(last.end, current.end) mergedIntervals[mergedIntervals.count - 1] = (start: last.start, end: newEnd) } else { // 没有重叠,直接添加 mergedIntervals.append(current) } } return mergedIntervals }
第三步:计算空闲时段
有了合并后的在岗时段,我们就可以和门店营业时间对比,找出中间的空闲区间:
/// 计算门店的空闲时段 /// - Parameters: /// - employeeLogs: 所有员工的登录记录数组 /// - storeHours: 门店营业时间 /// - Returns: 空闲时段数组(每个元素是(开始时间, 结束时间)) func calculateIdlePeriods(employeeLogs: [EmployeeLog], storeHours: StoreHours) -> [(start: Date, end: Date)] { // 1. 提取所有员工的登录时段 let workIntervals = employeeLogs.map { (start: $0.loginTime, end: $0.logoutTime) } // 2. 合并重叠的在岗时段 let mergedWorkIntervals = mergeOverlappingIntervals(workIntervals) var idlePeriods = [(start: Date, end: Date)]() var currentTime = storeHours.openTime // 3. 遍历合并后的在岗时段,找出中间的空闲区间 for interval in mergedWorkIntervals { if currentTime < interval.start { // 门店开门到第一个员工登录之间的空闲 idlePeriods.append((start: currentTime, end: interval.start)) } currentTime = max(currentTime, interval.end) } // 4. 最后一个员工离岗到门店关门之间的空闲 if currentTime < storeHours.closeTime { idlePeriods.append((start: currentTime, end: storeHours.closeTime)) } return idlePeriods }
第四步:调用示例
假设你已经把JSON解析成了对应的模型,就可以这样调用:
// 示例:解析JSON数据(这里用模拟数据代替实际JSON) let sampleJson = """ { "employees": [ {"id": 1, "loginTime": "2024-05-20T09:30:00", "logoutTime": "2024-05-20T12:00:00"}, {"id": 2, "loginTime": "2024-05-20T11:00:00", "logoutTime": "2024-05-20T14:30:00"}, {"id": 3, "loginTime": "2024-05-20T15:00:00", "logoutTime": "2024-05-20T17:00:00"} ], "storeHours": {"openTime": "2024-05-20T08:00:00", "closeTime": "2024-05-20T18:00:00"} } """.data(using: .utf8)! do { // 更规范的方式是定义一个包含employees和storeHours的根结构体,这里为了简化用了动态解析 let rootObject = try JSONSerialization.jsonObject(with: sampleJson) as! [String: Any] let employeesData = try JSONSerialization.data(withJSONObject: rootObject["employees"]!) let storeHoursData = try JSONSerialization.data(withJSONObject: rootObject["storeHours"]!) let employees = try jsonDecoder.decode([EmployeeLog].self, from: employeesData) let storeHours = try jsonDecoder.decode(StoreHours.self, from: storeHoursData) let idlePeriods = calculateIdlePeriods(employeeLogs: employees, storeHours: storeHours) // 打印空闲时段 for period in idlePeriods { print("空闲时段:\(dateFormatter.string(from: period.start)) 到 \(dateFormatter.string(from: period.end))") } } catch { print("解析错误:\(error)") }
额外注意点
- 时区问题:一定要确保日期解析和处理时使用正确的时区,避免出现时间偏差。
- 边界情况:比如没有任何员工登录,那整个营业时间都是空闲时段;或者员工覆盖了整个营业时间,那没有空闲时段。上面的函数已经处理了这些情况。
- 日期有效性:可以额外添加验证,比如员工的登录时间不能晚于登出时间,不能超出门店营业时间等,让函数更健壮。
内容的提问来源于stack exchange,提问作者JohnUse
相关产品推荐
相关产品推荐

