Go代码调试:解析餐厅时间表合并时间段生成营业时间
调试Go语言餐厅时间表解析函数
我从API获取了某餐厅单日的时间表数据:
restaurantTimetable := []string { "2023-05-27T11:00:00", "2023-05-27T11:30:00", "2023-05-27T12:00:00", "2023-05-27T12:30:00", "2023-05-27T13:00:00", "2023-05-27T13:30:00", "2023-05-27T14:00:00", "2023-05-27T18:00:00", "2023-05-27T18:30:00", "2023-05-27T19:00:00", "2023-05-27T19:30:00", "2023-05-27T20:00:00", "2023-05-27T20:30:00", "2023-05-27T21:00:00", }
希望将其解析为包含营业起止时间的结构,示例输出:
[ { "open": { "time": "1100", "hours": 11, "minutes": 0, "nextDate": 0 }, "close": { "time": "1400", "hours": 14, "minutes": 0, "nextDate": 0 } }, { "open": { "time": "1800", "hours": 18, "minutes": 0, "nextDate": 0 }, "close": { "time": "2100", "hours": 21, "minutes": 0, "nextDate": 0 } } ]
我编写了如下Go语言函数,但无法得到正确结果,请求调试:
func ParseTimetable(timetable []string) ([]map[string]map[string]interface{}, error) { const layout = "2006-01-02T15:04:05" slots := make([]map[string]map[string]interface{}, 0) for i := 0; i+1 < len(timetable); i += 2 { startSlot := timetable[i] endSlot := timetable[i+1] // parse start and end times as time.Time objects startTime, err := time.Parse(layout, startSlot) if err != nil { return nil, err } endTime, err := time.Parse(layout, endSlot) if err != nil { return nil, err } startHour, startMinute, _ := startTime.Clock() endHour, endMinute, _ := endTime.Clock() slot := map[string]map[string]interface{}{ "open": { "time": fmt.Sprintf("%02d%02d", startHour, startMinute), "hours": startHour, "minutes": startMinute, "nextDate": 0, }, "close": { "time": fmt.Sprintf("%02d%02d", endHour, endMinute), "hours": endHour, "minutes": endMinute, "nextDate": 0, }, } slots = append(slots, slot) } return slots, nil }
问题分析
原函数的核心错误在于把相邻两个时间点直接当作一个营业时段的起止,但实际上输入的时间表是餐厅所有可预约的时段点(每30分钟一个),营业时段是这些连续点的整体区间——比如11:00到14:00是连续的午市时段,18:00到21:00是晚市时段,两个时段之间有4小时的断档。
原函数会生成7个错误的时段(因为14个点,每次取2个),而不是我们需要的2个完整营业时段。
修正后的函数
import ( "fmt" "time" ) func ParseTimetable(timetable []string) ([]map[string]map[string]interface{}, error) { const layout = "2006-01-02T15:04:05" const interval = 30 * time.Minute // 先把所有时间字符串解析为time.Time对象,方便后续比较 times := make([]time.Time, 0, len(timetable)) for _, s := range timetable { t, err := time.Parse(layout, s) if err != nil { return nil, err } times = append(times, t) } if len(times) == 0 { return nil, nil } slots := make([]map[string]map[string]interface{}, 0) // 记录当前营业时段的起始时间 currentOpen := times[0] for i := 1; i < len(times); i++ { // 检查当前时间和上一个时间的间隔是否为30分钟 if times[i].Sub(times[i-1]) != interval { // 间隔不符合,说明上一个时间是当前营业时段的结束 currentClose := times[i-1] slots = append(slots, buildSlot(currentOpen, currentClose)) // 更新起始时间为当前时间 currentOpen = times[i] } } // 处理最后一个营业时段 slots = append(slots, buildSlot(currentOpen, times[len(times)-1])) return slots, nil } // buildSlot 辅助函数,将起止时间转换为需要的结构 func buildSlot(openTime, closeTime time.Time) map[string]map[string]interface{} { openHour, openMinute, _ := openTime.Clock() closeHour, closeMinute, _ := closeTime.Clock() return map[string]map[string]interface{}{ "open": { "time": fmt.Sprintf("%02d%02d", openHour, openMinute), "hours": openHour, "minutes": openMinute, "nextDate": 0, }, "close": { "time": fmt.Sprintf("%02d%02d", closeHour, closeMinute), "hours": closeHour, "minutes": closeMinute, "nextDate": 0, }, } }
代码说明
- 解析所有时间:先把输入的字符串切片全部转换成
time.Time对象,便于后续计算时间间隔。 - 识别营业时段:遍历时间切片,当相邻两个时间的间隔不等于30分钟时,说明出现了营业断档,此时将上一个时间作为当前时段的结束,当前时间作为下一个时段的开始。
- 处理最后一个时段:遍历结束后,需要把最后一个未闭合的时段加入结果。
- 辅助函数解耦:用
buildSlot函数统一处理时间到目标结构的转换,让代码更清晰。
测试该函数后,会输出你需要的两个营业时段结构。
内容的提问来源于stack exchange,提问作者Mirou
相关产品推荐
相关产品推荐

