本篇文章将介绍时间智能函数中的 DATEADD 函数与 PARALLELPERIOD 函数。
注意,在使用时间智能函数时需要创建日期表,虽然目前的时间智能函数已经优化了很多次,许多限制都已经放开,但创建日期表仍然是一个最佳实践,能够避开许多容易出错的地方。
另外,由于时间智能函数的使用依赖于日期表,而日期表又比较特殊,因此在阅读时间智能函数系列的文章前,最好已经阅读并理解这篇前置文章:32、应用日期表时的注意事项 。
DATEADD 函数
语法:
DATEADD ( <dates>, <number_of_intervals>, <interval> )
作用:在当前计值上下文中,将可见日期按指定的间隔数向未来平移或者向过去平移,最后返回平移后的日期列表。
参数说明:
1、dates,该参数只能是对日期字段的列引用,代表将从哪个日期字段中返回指定的日期范围。
2、number_of_intervals,平移的间隔量,如果为正数,则代表向未来平移;如果为负数,则代表向过去平移;如果为0,则代表不平移,不平移时的返回结果与当前计值上下文中的可见日期一致。
3、interval,平移的周期单位,为指定的枚举值:DAY、MONTH、QUARTER、YEAR,非字符串,不需要使用双引号包括。
注意事项:
1、日期参数可以接受三种类型的输入,分别为:对日期列的引用、具有单个日期列的表,以及定义单个日期列表的布尔表达式。
2、日期参数如果是对日期列的引用,那么会触发行上下文转换。
3、DATEADD 函数还会遵循以下特殊规则:
- 规则 1:DATEADD 函数只适用于连续日期选择,否则会引发错误。
- 规则 2:DATEADD 函数返回的日期只包括那些存在于第一参数指定的日期列中的日期。
- 规则 3:当平移操作后的相应月份中不存在相应的日期时,DATEADD 函数的结果包括相应月份的最后一天,如:7月31日→6月30日。
- 规则 4:当选择中包含一个月的最后一天,且选择的跨度超过一天时,DATEADD 函数的结果包含从平移月份的对应日期到平移月份结束的所有天数。
其中,规则1的限制在2020年4月的更新中被移除了,现在可以在PowerBI中选择任意不连续的日期范围来进行平移。但是在旧版本的PowerPivot或SSAS中,该连续日期选择的规则限制可能仍然生效,这一点需要注意。
辅助理解的例子:
1、下面是 DATEADD 函数的示例表达式与结果,将把可见日期向未来平移一个月:
2、DATEADD 函数的日期参数可以接受三种输入,其中一种就是直接引用日期列,而不需要借助任何表函数,因为它等价于:
CALCULATETABLE ( DISTINCT ( '日期表'[Date] ) )
因此,如果第一参数是直接引用日期列,那么还会触发行上下文转换。
3、除了直接引用日期列,日期参数还可以接受具有单个日期列的表,以及定义单个日期列表的布尔表达式,如下图所示:
使用这两种写法时可能会出现红色波浪线的警告,这可能是智能感知功能出了Bug,语法是没问题的,忽略即可。另外,定义单列表的布尔表达式其实也是一个语法糖,它跟CALCULATE函数的布尔筛选是一样的,完整写法如下:
DATEADD('日期表'[Date]=dt"2016-3-8",-1,MONTH)
等价于:
DATEADD(FILTER(ALL('日期表'[Date]),'日期表'[Date]=dt"2016-3-8"),-1,MONTH)
需要注意的是,当第一参数不是直接引用日期列时,是不会触发行上下文转换的。
4、【规则2 – 只返回有的日期】DATEADD 函数返回的日期只包括那些存在于第一参数指定的日期列中的日期,如下图所示:
由于案例文件中的日期表的范围是从2016年1月1日至2017年12月31日,因此向过去平移一年时,2016年的日期理论上应该返回2015年的对应日期,但由于日期表中不存在2015年的日期,所以只能返回空。
5、【规则3 – 智能匹配月底日期】当平移操作后的相应月份中不存在相应的日期时,DATEADD 函数的结果包括相应月份的最后一天,如下图所示:
由于非闰年的二月份中,不会存在2/29、2/30、2/31等日期,所以3/29、3/30、3/31等日期向过去平移一个月后,将自动对应成二月份的最后一天。
另外还需要注意下矩阵的小计与总计行,由于 DATEADD 函数不会返回重复日期,所以该案例的小计与总计行中,将只返回日期为2/28的单行单列的表,而单行单列的表可以当作标量值使用,因此小计与总计行中不会报错。
6、【规则4 – 跨临界日期】当选择中包含一个月的最后一天,且选择的跨度超过一天时,DATEADD 函数的结果包含从平移月份的对应日期到平移月份结束的所有天数。如下图所示:
在矩阵明细行中,单个日期的平移并没有问题。但在小计与总计行中,可见日期包含2/27与2/28两天,虽然理论上平移后的日期应该是1/27与1/28这两天,但由于2/28还是二月份的最后一天,所以会触发跨临界日期规则,导致返回的结果持续到了平移月份的月底,即返回:1/27至1/31。
另外,由于跨临界日期规则的影响,日期表如果不连续或不完整,那么可能会带来意想不到的结果,如下图所示:
由于二月份只有2/27与2/28这两天,因此这两个日期就代表了二月份,所以将2/27与2/28这两天向过去平移一个月时,其对应的是一月份的所有日期,因此会返回日期列中存在的一月份的所有日期。
这就是为什么要求在使用时间智能函数时要创建一个标准的日期表的原因,不规范的日期表可能会带来意想不到的结果。
PARALLELPERIOD 函数
语法:
PARALLELPERIOD ( <dates>, <number_of_intervals>, <interval> )
作用:在当前计值上下文中,将可见日期按指定的间隔数向未来平移或者向过去平移,最后返回平移后所处的周期粒度级别处的完整日期范围。
参数说明:
1、dates,该参数只能是对日期字段的列引用,代表将从哪个日期字段中返回指定的日期范围。
2、number_of_intervals,平移的间隔量,如果为正数,则代表向未来平移;如果为负数,则代表向过去平移;如果为0,则代表不平移,但不平移时的返回结果也会按指定的周期粒度扩充到完整日期范围。
3、interval,平移的周期单位,为指定的枚举值:DAY、MONTH、QUARTER、YEAR,非字符串,不需要使用双引号包括。
注意事项:
1、日期参数可以接受三种类型的输入,分别为:对日期列的引用、具有单个日期列的表,以及定义单个日期列表的布尔表达式。
2、日期参数如果是对日期列的引用,那么会触发行上下文转换。
3、返回的日期只包括那些存在于第一参数指定的日期列中的日期。
辅助理解的例子:
1、PARALLELPERIOD 函数类似于 DATEADD 函数,只是 PARALLELPERIOD 函数总是返回在给定周期粒度级别处的完整日期范围,而不是 DATEADD 函数返回的部分周期。如下图所示:
2、如果用代码来表示的话,PARALLELPERIOD 函数的等价写法如下:
PARALLELPERIOD('日期表'[Date],1,MONTH)
等价于:
VAR OffsetDate = DATEADD('日期表'[Date],1,MONTH)
RETURN
DATESBETWEEN(
'日期表'[Date],
STARTOFMONTH(OffsetDate),
ENDOFMONTH(OffsetDate)
)
以上是平移周期为月份粒度时的等价写法,如果是季度或年份的,只需要更改为对应的STARTOF系列与ENDOF系列的函数即可。
总结
本篇文章主要介绍了时间智能函数中的 DATEADD 函数与 PARALLELPERIOD 函数,它们的使用频率非常高,是必须要掌握的函数。