RickAndMorty.png
大家好,我叫谢伟,是一名程序员。
之前梳理了一些内置库的学习,收到了一些评论,绝大多数评论都在直指一个问题:为什么梳理这些无关痛痒的内置库?
好吧,看上去确实都是些简单的内置库的梳理。主要原因是为了:《后端工程师的攻略》这个系列,从零起步,教程到这个地步,看上去是需要提高难度了。后续加以改善。另外一个原因,其实是想告诉初学者,内置库的很多代码组织方式,代码的编写方式指的学习、借鉴、参考。
这期是我之前准备的,趁着这期还是放送出来吧。
核心很简单:懂 Go 的基本语法,会使用内置库的 time, 基本能搞到这些。
大纲:
前段日子项目中需要使用的国家规定的节假日,所以需要获取这些数据。其实获取这些数据的方式也很多:
比如比较笨的方式:搜索引擎,手动整理
使用一些免费开放的第三方节假日 API: 不稳定,虽然这些数据也不需要频繁的使用
使用一些付费的第三方节假日 API:付费
于是本着简洁的方式,编写这么一个节假日的库。
要求:
简单的功能
简单的API
1. 数据获取
数据源需要可靠,所以需要寻找官方的通知来源。
一般的方式呢,就是网页数据抓取,解析出得到的数据。
这是第一步,获取数据;当然,很多网站都可以找到这些信息,这里仅仅举例。
2. 定义结构体
关于节假日,我们最需要知道的是什么信息?
名称
时间安排
基于此,可以这么设计结构体:
type OneCollection struct { Start string `json:"start"` End string `json:"end"` ChName string `json:"ch_name"` EnName string `json:"en_name"` }
包括:
中文名称
英文名称
开始时间
结束时间
关于节假日名称呢,国家法定的节日是这么几个:元旦、春节、清明、端午、劳动、中秋、国庆
借鉴许多内置库的处理方式:这种固定的数据的处理,可以使用枚举类型:
const ( NewYearDay = iota SpringFestivalDay TombSweepingDay LaborDay DragonBoatFestivalDay NationalDay MidAutumnFestivalDay )var ChHolidays = [...]string{ "元旦", "春节", "清明节", "劳动节", "端午节", "中秋节", "国庆节", }var EnHolidays = [...]string{ "New Year\\'s Day", "Spring Festival", "Tomb-sweeping Day", "Labour Day", "Dragon Boat Festival", "Mid-autumn Festival", "National Day", }
中英文,获取指定偏移量上的数据即可,这种处理方式在内置库很常见:比如时间类型的时间基本单位月:一月、二月、三月等
3. 历史数据
基于上文的分析,要构建这个简单的库,要组织历史节假日,这边选取 2010年到 2019 年的数据。
// 一年type YearCollection struct { Data []OneCollection `json:"data"` }// n 年type CollectionYearHistory struct { Data [][]OneCollection `json:"data"` }// 2010 年到 2019年历史数据func FetchCollectionYearHistory() CollectionYearHistory { return CollectionYearHistory{ Data: [][]OneCollection{ holiday2019, holiday2018, holiday2017, holiday2016, holiday2015, holiday2014, holiday2013, holiday2012, holiday2011, holiday2010, }, } }
4. 构建API
选择好的命名方式
选择好的数据返回格式
- FetchAll - FetchByChName(year int, name string) - FetchByEnName(year int, name string) - FetchByMonth(year int, month int) - FetchByYear(year int) - FetchMonthHolidayCount(year int, month int) - FetchYearHolidayCount(year int) - IsHoliday - IsWeekDay - IsWorkDay
之所以这样设计, 是因为项目中经常会是这样的操作:
获取所有的历史数据
获取某年的历史数据
获取某月的历史数据
统计某年某月的放假天数
统计某年的放假天数
判断一个日期是否是节假日
判断一个日期是否是周末
判断一个日期是否是工作日
基于这些需求,构建了上文的API
以几个API 为例,详细的操作如何实现?
FetchByYear(year int): 从历史数据中获取
// FetchByYear get holidays by year in chinafunc FetchByYear(year int) []history.OneCollection { var index int nowYear, _, _ := time.Now().Date() if year > nowYear+1 { return nil } index = nowYear + 1 - year return history.FetchCollectionYearHistory().Data[index] }
FetchByMonth: 从某年的历史数据中获取
func FetchByMonth(year int, month int) []history.OneCollection { if month < 1 || month > 12 { return nil } collections := FetchByYear(year) var data []history.OneCollection for _, collection := range collections { collectionTime, _ := time.Parse("2006/01/02", collection.End) if int(collectionTime.Month()) == month { data = append(data, collection) } } return data }
IsHoliday: 历史数据中是否能击中目标
func IsHoliday(value string) bool { collectionTime, err := time.Parse("2006/01/02", value) if err != nil { return false } nowYear, _, _ := time.Now().Date() if collectionTime.Year() > nowYear+1 { return false } collections := FetchByYear(collectionTime.Year()) for _, collection := range collections { startDate, _ := getDate(collection.Start) endDate, _ := getDate(collection.End) if collectionTime.Unix() >= startDate.Unix() && collectionTime.Unix() <= endDate.Unix() { return true } } return false}
IsWeekDay: 不是节假日、也不是工作日的
// IsWeekDay: judge date is week day or notfunc IsWeekDay(value string) bool { return !IsWorkDay(value) && !IsHoliday(value) }
holidays 仅供参考
<后记>
基于上文的理念,其实可以写很多小工具:
比如:
获取古诗词
给定一个日期,判断星座
给定一个身份证,判断是否有效,属于哪个地区等
给定一个ip, 给出地理位置
给定一个中文,给出英文或者拼音
给定文字,解释其中文含义
...
作者:谢小路
链接:https://www.jianshu.com/p/aa7e7cb15994