工作中,经常会遇到需要根据节假日来进行排班、统计工作量等需求。由于每年的节假日安排不是固定的,所以在实现这些统计查询时,往往比较困难。

网上也有一些比较不错的WebService服务,可以用来提供对某个日期是否为节假日的查询。比如在下面这篇文章中


非常好用的节假日查询接口_yinfuyuan-CSDN博客blog.csdn.net


android 节假日接口 查询节假日接口_oracle 查询一周日期


就介绍了一个不错的查询节假日安排的服务:

接口坞www.apihubs.cn


而且,这个服务接口支持将指定区间范围内的所有日期(包括节假日)的安排以JSON格式返回,例如:


https://api.apihubs.cn/holiday/get?year=2021&month=202101api.apihubs.cn

就可以返回2021年1月份的所有日期安排,格式类似:


{"year":2021,"month":202112,"date":20211231,"yearweek":202152,"yearday":365,"lunar_year":2021,"lunar_month":202111,"lunar_date":20211128,"lunar_yearday":323,"week":5,"weekend":2,"workday":1,"holiday":10,"holiday_or":10,"holiday_overtime":10,"holiday_today":2,"holiday_legal":2,"holiday_recess":2}


其中各个参数的含义如下:


year 公历年份
month 公历月份
date 公历日期
yearweek 公历一年中的第几周,注意这里的年份是ISO-8601周编号年份,始终以周一至周日为一周。如需获取7天为一周直接使用年份中的天数除7即可。
yearday 公历一年中的第几天
lunar_year 农历年份
lunar_month 农历月份
lunar_date 农历日期
lunar_yearday 农历一年中的第几天
week 星期几
weekend 是否为周末
workday 是否为工作日(包含调休在内需要上班的日子)(1-工作日,2-非工作日)
holiday 节假日,这里使用两位数字枚举表示节假日,其中特殊数字10表示非节假日,特殊数字99表示全部节假日
holiday_or 其他节假日,枚举与节假日相同,表示同一天中的另一个节日
holiday_overtime 节假日调休
holiday_today 是否为节日当天
holiday_legal 是否为法定节假日(三倍工资)
holiday_recess 是否为假期节假日(节日是否放假)


为此,本人做了一个试验模型,将该网站提供的2021年全年日期数据下载后,导入Oracle数据库,以方便实现一些与节假日相关的查询。

一、构建数据结构

1、创建如下字典表:


-- Create table
create table COMM.CALENDAR_DICT
(
  year             NUMBER(4) not null,
  month            VARCHAR2(6) not null,
  day              VARCHAR2(8) not null,
  yearweek         VARCHAR2(6),
  yearday          NUMBER(3),
  lunar_year       NUMBER(4),
  lunar_month      VARCHAR2(6),
  lunar_date       VARCHAR2(8),
  lunar_yearday    NUMBER(3),
  week             NUMBER(2),
  weekend          NUMBER(1),
  workday          NUMBER(1),
  holiday          NUMBER(3),
  holiday_or       NUMBER(3),
  holiday_overtime NUMBER(3),
  holiday_today    NUMBER(1),
  holiday_legal    NUMBER(1),
  holiday_recess   NUMBER(1)
)
tablespace TSP_COMM
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    next 64K
    minextents 1
    maxextents unlimited
    pctincrease 0
  );
-- Add comments to the columns 
comment on column COMM.CALENDAR_DICT.year
  is '公历年份';
comment on column COMM.CALENDAR_DICT.month
  is '公历月份';
comment on column COMM.CALENDAR_DICT.day
  is '公历日期';
comment on column COMM.CALENDAR_DICT.yearweek
  is '公历一年中的第几周,注意这里的年份是ISO-8601周编号年份,始终以周一至周日为一周。如需获取7天为一周直接使用年份中的天数除7即可。';
comment on column COMM.CALENDAR_DICT.yearday
  is '公历一年中的第几天';
comment on column COMM.CALENDAR_DICT.lunar_year
  is '农历年份';
comment on column COMM.CALENDAR_DICT.lunar_month
  is '农历月份';
comment on column COMM.CALENDAR_DICT.lunar_date
  is '农历日期';
comment on column COMM.CALENDAR_DICT.lunar_yearday
  is '农历一年中的第几天';
comment on column COMM.CALENDAR_DICT.week
  is '星期';
comment on column COMM.CALENDAR_DICT.weekend
  is '是否为周末(星期六和星期日)';
comment on column COMM.CALENDAR_DICT.workday
  is '是否为工作日(包含调休在内需要上班的日子)(1-工作日,2-非工作日)';
comment on column COMM.CALENDAR_DICT.holiday
  is '节假日,这里使用两位数字枚举表示节假日,其中特殊数字10表示非节假日,特殊数字99表示全部节假日';
comment on column COMM.CALENDAR_DICT.holiday_or
  is '其他节假日,枚举与节假日相同,表示同一天中的另一个节日';
comment on column COMM.CALENDAR_DICT.holiday_overtime
  is '节假日调休';
comment on column COMM.CALENDAR_DICT.holiday_today
  is '是否为节日当天';
comment on column COMM.CALENDAR_DICT.holiday_legal
  is '是否为法定节假日(三倍工资)';
comment on column COMM.CALENDAR_DICT.holiday_recess
  is '是否为假期节假日(节日是否放假)';
-- Create/Recreate primary, unique and foreign key constraints 
alter table COMM.CALENDAR_DICT
  add constraint PK_CALENDAR_DICT primary key (DAY)
  using index 
  tablespace TSP_COMM
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
    initial 64K
    next 64K
    minextents 1
    maxextents unlimited
    pctincrease 0
  );


2、通过上面的服务网址,将2021年所有月份的日期安排的JSON格式数据下载到本地,使用PowerBuilder下的PBJSON接口,将JSON格式转换到数据窗口中,再将数据窗口中的数据插入上面的字典表。

这里,引用了大自在大神 (QQ号:781770213 QQ群:624409252) 提供的PB_Json_httpclient_crypto_ftp_20201210接口,特此鸣谢。

这样,我们就有了一张包含2021年全年日期的日历字典表,其中记录了所有2021年日期的公历、农历、节假日信息。


android 节假日接口 查询节假日接口_oracle 查询一周日期_02


二、关于节假日查询的两个例子

1、两个日期之间的工作日数量

该查询可能的用途:计算两个日期之间的工作日有多少个,以方便计算工作日平均工作量。

以下查询就演示了查询2021.01.01到2021.01.10之间有多少个工作日:


select count(*) 
from COMM.CALENDAR_DICT
where day >= to_char(to_date('20210101','YYYYMMDD'), 'YYYYMMDD')
  and day <  to_char(to_date('20210110','YYYYMMDD'), 'YYYYMMDD')
  and workday = 1
;

  COUNT(*)
----------
         5


2、返回指定日期的X个工作日以后的日期

该查询可能的用途:按照《病案管理质量控制指标(2021年版)》要求,出院患者病历应在2个工作日内完成归档,将“出院患者病历2 日归档率”作为重要的评价指标。因此需要根据病人出院日期计算出2个工作日是哪一天。

以下查询就演示了2021.01.01往后面数6个工作日对应的日期:


select max(day)
from 
     ( select day 
         from COMM.CALENDAR_DICT 
         where workday = 1 
           and day >= to_char(to_date('20210101','YYYYMMDD'), 'YYYYMMDD') 
         order by day
     )
where rownum <= 6 ;

MAX(DAY)
--------
20210111


上述举例完全可以举一反三,根据该字典表数据,实现各种涉及公历和农历节假日的数据统计分析。且该表的数据增长速度并不快,因此对数据库不会造成较大的存储压力。

后续,本人将逐步完善,用函数或者存储过程实现涉及节假日的主要查询功能,以方便其它应用调用。

(待更新)