『自己构建节假日API』

作者: 谢小路 | 来源:发表于2018-11-29 22:49 被阅读16次
    RickAndMorty.png

    大家好,我叫谢伟,是一名程序员。

    之前梳理了一些内置库的学习,收到了一些评论,绝大多数评论都在直指一个问题:为什么梳理这些无关痛痒的内置库?

    好吧,看上去确实都是些简单的内置库的梳理。主要原因是为了:《后端工程师的攻略》这个系列,从零起步,教程到这个地步,看上去是需要提高难度了。后续加以改善。另外一个原因,其实是想告诉初学者,内置库的很多代码组织方式,代码的编写方式指的学习、借鉴、参考。

    这期是我之前准备的,趁着这期还是放送出来吧。

    核心很简单:懂 Go 的基本语法,会使用内置库的 time, 基本能搞到这些。

    大纲:

    前段日子项目中需要使用的国家规定的节假日,所以需要获取这些数据。其实获取这些数据的方式也很多:

    • 比如比较笨的方式:搜索引擎,手动整理
    • 使用一些免费开放的第三方节假日 API: 不稳定,虽然这些数据也不需要频繁的使用
    • 使用一些付费的第三方节假日 API:付费

    于是本着简洁的方式,编写这么一个节假日的库。

    要求:

    • 简单的功能
    • 简单的API

    1. 数据获取

    数据源需要可靠,所以需要寻找官方的通知来源。

    比如:国务院办公厅关于2018年部分节假日安排的通知

    一般的方式呢,就是网页数据抓取,解析出得到的数据。

    这是第一步,获取数据;当然,很多网站都可以找到这些信息,这里仅仅举例。

    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 china
    func 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 not
    func IsWeekDay(value string) bool {
        return !IsWorkDay(value) && !IsHoliday(value)
    }
    

    <后记>

    基于上文的理念,其实可以写很多小工具:

    比如:

    • 获取古诗词
    • 给定一个日期,判断星座
    • 给定一个身份证,判断是否有效,属于哪个地区等
    • 给定一个ip, 给出地理位置
    • 给定一个中文,给出英文或者拼音
    • 给定文字,解释其中文含义
      ...

    <完>

    相关文章

      网友评论

        本文标题:『自己构建节假日API』

        本文链接:https://www.haomeiwen.com/subject/oliqcqtx.html