zxdsb666. 发表于 2021-10-25 22:23

一次工作日的获取技巧记录

# 一次工作日的获取技巧记录

# 前言

​        工作日的获取还是比较常见的,比如银行和跨境电商的交易,有时候在教育的行业也会有用到,由于我们不知道每一年那一天是节假日,有时候涉及调休等等又要上班比较麻烦,所以这里干脆做一次记录,以后用到的时候可以直接把表拿来做参考,希望这次的笔记能对读者有所帮助。

​        注意,本文使用的是**PostgreSql数据库**,使用其他的数据库需要略微的修改sql的内容。



# 日期表的设计

​        日期表的设计不是固定的,下面的内容其实都是供参考使用。

| **字段名称**   | **类型**   | **是否为空** | **描述**         |
| ---------------- | ------------ | ------------ | ---------------- |
| calendar_id      | varchar(255) | M            | 主键             |
| calendar_year    | varchar(10)| M            | 年               |
| calendar_month   | varchar(10)| M            | 月               |
| calendar_date    | varchar(10)| M            | 日               |
| day_of_week      | varchar(10)| M            | 自然周的第几天   |
| day_of_month   | varchar(10)| M            | 月的第几天       |
| week_of_year   | varchar(10)| M            | 年的第几个自然周 |
| month_of_year    | varchar(10)| M            | 年的第几月       |
| quarter_of_year| varchar(10)| M            | 年的第几季       |
| is_end_month   | varchar(10)| M            | 是否月末         |
| is_end_quarter   | varchar(10)| M            | 是否季末         |
| is_end_halfayear | varchar(10)| M            | 是否半年末       |
| is_end_year      | varchar(10)| M            | 是否年末         |
| operator_id      | varchar(50)| M            | 操作人ID         |
| operator_name    | varchar(50)| M            | 操作人名称       |
| operate_date   | timestamp    | M            | 操作时间         |
| res_attr1      | varchar(40)| O            | 预留字段1      |
| res_attr2      | varchar(40)| O            | 预留字段2      |
| res_attr3      | varchar(40)| O            | 预留字段3      |
| res_attr4      | varchar(40)| O            | 预留字段4      |



## 数据入库模板

​        当然还是针对PostgreSql数据库使用,下面使用了数据库入库的sql,入库之后可以看到一年的数据内容。

​        下面的`select insert`语句来讲数据入库,当然我们需要先根据上面的数据表构建相关的数据表才行

```sql
INSERT INTO sa_calendar_table(
            calendar_id,
            calendar_year,
            calendar_month,
            calendar_date,
            day_of_week,
            day_of_month,
            week_of_year,
            month_of_year,
            quarter_of_year,
            is_end_month,
            is_end_quarter,
            is_end_halfayear,
            is_end_year,
            operator_id,
            operator_name,
            operate_date,
            res_attr1,
            res_attr2,
            res_attr3,
            res_attr4,
            is_work_day
      )
      SELECT
            a.calendar_id,
            a.calender_year,
            a.calender_month,
            a.calendar_date,
            a.day_of_week,
            a.day_of_month,
            a.week_of_year,
            a.month_of_year,
            a.quarter_of_year,
            a.is_end_month,
            a.is_end_quarter,
            a.is_end_halfayear,
            a.is_end_year,
            a.operator_id,
            a.operator_name,
            a.operator_date,
            a.res_attr1,
            a.res_attr2,
            a.res_attr3,
            a.res_attr4,
            a.is_work_day
      FROM (
               SELECT
                     gen_random_uuid() as calendar_id,
                     to_char(tt.day, 'yyyy') as calender_year,
                     to_char(tt.day, 'yyyy-mm') as calender_month,
                     to_char(tt.day, 'yyyy-mm-dd') as calendar_date,
                     extract(DOW FROM tt.day) as day_of_week,
                     to_char(tt.day, 'dd') as day_of_month,
                     extract(MONTH FROM tt.day) as month_of_year,
                     extract(WEEK FROM tt.day) as week_of_year,
                     extract(QUARTER FROM tt.day) as quarter_of_year,
                     CASE WHEN tt.day = date_trunc('month',tt.day + interval'1 month') - interval '1 day' THEN 'Y' ELSE 'N' END as is_end_month,
                     CASE WHEN tt.day = date_trunc('quarter',tt.day + interval '3 month') - interval '1 day' THEN 'Y' ELSE 'N' END as is_end_quarter,
                     CASE WHEN tt.day = date_trunc('year',tt.day) + interval '6 month' - interval '1 day'THEN 'Y' ELSE 'N' END as is_end_halfayear,
                     CASE WHEN tt.day= date_trunc('year',tt.day) + interval '12 month' - interval '1 day'THEN 'Y' ELSE 'N' END as is_end_year,
                     'b8617d3d-d2c9-4a2a-93ba-5b2d8b700cb0' as operator_id,
                     'admin' as operator_name,
                     cast(CURRENT_DATE AS TIMESTAMP) as operator_date,
                     null as res_attr1,
                     null as res_attr2,
                     null as res_attr3,
                     null as res_attr4,
                     CASE WHEN extract(DOW FROM tt.day) = 6 THEN 'N' WHEN extract(DOW FROM tt.day) = 0 THEN 'N' ELSE 'Y' END as is_work_day
               FROM (
                     select generate_series(
                     (SELECT (date_trunc('year', now()) + interval '1 year' )::date as next_year_first_date) ,
                     (SELECT (SELECT (date_trunc('year', now()) + interval '2 year')::date -1 as last_year_last_date)), '1 d'
                     ) as day
                     ) as tt
             ) as a;
```



# 案例:获取几天前工作日

​        由于个人使用的经验也不是十分丰富,所以这里记录个人最近接触到的一个使用案例,下面的案例是使用`row_number()`来获取多少个日之前的工作日,根据下面的sql语句我们可以轻松完成多少个日之前的工作日,默认会按照当前的日期作为分水岭,如果在当天之前的日期,**则为负数**,如果是当前天数之后的内容,**则为正数**。

```sql
select * from
(
select - ROW_NUMBER () OVER (ORDER BY t.calendar_date desc) as add_day,t.calendar_date from sa_calendar_table t where t.calendar_year = '2021'
and t.calendar_date < cast(CURRENT_DATE as VARCHAR) and t.is_work_day = 'Y'
union
select ROW_NUMBER () OVER (ORDER BY t.calendar_date) -1 as add_day,t.calendar_date from sa_calendar_table t where t.calendar_year = '2021'
and t.calendar_date >= cast(CURRENT_DATE as VARCHAR) and t.is_work_day = 'Y'
) mm ORDER BY calendar_date
```

​        运行效果这里就不进行展示了,无非就是前一天工作日为-1,后一天工作日为+1等等的内容。







# 问题收集

​        如果出现`ERROR:function gen_random_uuid() does not exist`的代码,可以执行下面的sql语句实现。

```sql
CREATE EXTENSION pgcrypto;
```

​        如果再postgresql中会有如下的类似报错:

```sql
# SELECT gen_random_uuid();
ERROR:function gen_random_uuid() does not exist
LINE 1: select gen_random_uuid();
               ^
HINT:No function matches the given name and argument types. You might need to add explicit type casts.
# CREATE EXTENSION pgcrypto;
CREATE EXTENSION
# SELECT gen_random_uuid();
         gen_random_uuid            
--------------------------------------
19a12b49-a57a-4f1e-8e66-152be08e6165
(1 row)
```

# 总结

​        算是一次简单的总结,希望对于读者有帮助



# 写在最后

​        本次主要为一次个人的时间记录。

zch11230 发表于 2021-10-26 14:49

http://timor.tech/api/holiday/info/2021-10-26
分享个API

xhg2992 发表于 2021-10-25 22:45

支持~!{:1_921:}

大神88888888 发表于 2021-10-25 23:02

漂亮 {:1_921:}支持~!

C哥888 发表于 2021-10-26 02:04

怎么不使用MySQL

tbloy 发表于 2021-10-26 04:07

支持经验分享。不错。

我今天是大佬 发表于 2021-10-26 09:20

我觉得吧,
第一, Excel不是直接可以用了么, 相关函数, 很简单, 何必重复造轮子
第二, 买本日历,几块钱不是更使用么

ynboyinkm 发表于 2021-10-26 09:21

“阿里云”有提供有万年历API接口,可以从阿里云获取,并存于自己的数据库,这个方便一些!

zxdsb666. 发表于 2021-10-26 10:08

ynboyinkm 发表于 2021-10-26 09:21
“阿里云”有提供有万年历API接口,可以从阿里云获取,并存于自己的数据库,这个方便一些!

好建议,感谢分享

py学徒 发表于 2021-10-27 09:00

没有人用python写吗,我觉得很方便。
页: [1]
查看完整版本: 一次工作日的获取技巧记录