1. 概述
在 FineReport 产品中提供了多种函数以便于满足用户在日常使用中的需求,同时拥有 公式不合法报错 的功能,本文主要介绍函数在使用过程中常见的问题及解决方案。
2. 日期函数
2.1 日期公式组合
2.1.1 往前推三个工作日
问题描述
往前推三个工作日,比如现在周五,得到周三,周六和周日也是得到周三,也就是不计算周末(无法跳过节假日)
解决方案
datedelta(today(), 0 - indexof('5552224', weekday(today())))
2.1.2 获取当年第一天
解决方案
format(CONCATENATE(CONCATENATE(year(now()),"01"),"01"),"yyyy-MM-dd")
2.1.3 获取上个月今天
解决方案
format(MONTHDELTA(now(),-1),"yyyy-MM-dd")
2.1.4 获取参数上一年的指定日期
解决方案
FORMAT(date(year($riqi)-1,month($riqi),25),"yyyy-MM-dd")
2.2 日历模板
问题描述
选择具体月份,显示对应日期和星期
解决方案
获取日期:RANGE(1, DAYSOFMONTH($月份 + "-01"))
获取日期对应的星期:SWITCH(WEEKDAY($月份 + "-" + FORMAT(A5, "00")), "1", "一", "2", "二", "3", "三", "4", "四", "5", "五", "6", "六", "0", "日")
2.3 给当前系统时间加8个小时
解决方案
format(year(today()) + "-" + month(today()) + "-" + day(today()) + " " + (HOUR(now(), "HH:mm:ss") + 8) + ":" +
MINUTE(now(), "HH:mm:ss") + ":" + SECOND(now(), "HH:mm:ss"), "yyyy-MM-dd HH:mm:ss")
2.4 today()公式的显示问题
问题描述
填报预览模式下,单元格放一个日期控件,设置格式是yyyy-MM-dd,单元格写公式today(),预览格式是正常的,编辑之后格式又变成了时间类型的。
解决方案
单元格显示内容需要在「样式」处单独设置。
2.5 TODATE()函数
2.5.1 TODATE()的起始日期
问题描述
todate(0)的返回结果是1970-01-01 08:00:00。如何更改?
解决方案
DATETONUMBER(date):返回自 1970 年 1 月 1 日 00:00:00 GMT 经过的毫秒数。时区问题,改成经纬度0的时区重启电脑。
2.5.2 TODATE()函数显示空白
问题描述
TODATE('2020/4/10', 'mm/dd/yy')单元格公式输入后预览最新的JAR显示为空白。10.0-2019.07.03版本以及之前JAR显示正常。
解决方案
最近版本改了逻辑:就是参数不匹配出错的时候返回空 ,之前参数不匹配是返回当前时间。函数的详细使用可参见:TODATE() 函数 。
2.6 week()函数
问题描述
week(today())计算在百度上4.13是第16周,使用内置的函数是15周,开始的比百度上面的晚一周。
解决方案
目前的规则师按照国际标准来的,所以目前做不了兼容。
2.7 日期控件默认值写today取到昨天
问题描述
远程设计时,日期控件写默认值today函数,不管类型选什么,都取到昨天;文本控件写today或者now都可以取到今天;linux服务器系统时间和硬件时间都是今天。
解决方案
模板请求的响应内容里搜下 date_milliseconds ,然后在前端执行浏览器 console 那边执行 new Date(上一步的值), 这个结果跟日期控件是一致的即可。
2.8 now()公式的时间不对
问题描述
本地环境是对的,远程环境不对。
原因分析
docker部署的工程,docker中镜像的系统时间存在问题。
解决方案
修改部署 FineReport 的镜像中的时间即可。
2.9 yyyy-MM格式的日期求月份差值
问题描述
start 是开始日期控件名,end 是结束日期控件名,两个日期控件格式都是 yyyy-MM。
解决方案
(year(format($end,"yyyy-MM-dd"))-year(format($start,"yyyy-MM-dd")))*12+(month(format($end,"yyyy-MM-dd"))-month(format($start,"yyyy-MM-dd")))
2.10 today+1-”08:00:00“无法识别
问题描述
使用模板参数,模板参数识别控件的值减去八个小时,today+1-”08:00:00“无法识别
解决方案
设置两个模板参数,定义公式「不要写8:00:00」
3. 数字
3.1 数字公式组合
3.1.1 判断小数位数
解决方案
假如A1是小数所在单元格,LEN(A1)-FIND(".",A1,1)
3.1.2 取绝对值最大的数组里的数据
解决方案
max(split(replace(ds1.select(1),"-",""),","))
3.1.3 获取最小值但是不包括0
解决方案
INDEXOFARRAY(SORTARRAY(GREPARRAY(C2[!0], index!= 0)),1)
3.1.4 判断是不是小数
解决方案
$$$-trunc($$$)>0
3.2 最小值
问题描述
A1:D1的单元格手填的值为23、4、65、1,可以使用min(A1:D1)获取最小值1,如果某个单元格为空,这个方法返回的值是0
解决方案
min(GREPARRAY(array(a1),len(item)!=0),GREPARRAY(array(b1),len(item)!=0),GREPARRAY(array(c1),len(item)!=0),GREPARRAY(array(d1),len(item)!=0))
3.3 find函数16位以上识别不准确
问题描述
使用ds1.find函数识别位数超过16位时,位数不准确
解决方案
所有计算类函数精度都只支持到16位
3.4 判断单元格内容是否是纯数字
解决方案
先提取字符串中的数字,然后和原字符串比较长度,长度一致返回true,代表纯数字,不一致false,代表非纯数字
len(JOINARRAY(GREPARRAY(split(A1, ""), regexp(item, "[0-9]")), "")) = len(A1)
3.5 去掉小数位后面的0
解决方案
比如数据88.98705670000,希望转换成88.9870567,使用:format("88.98705670000","#0.################")
4. 字符串
4.1 去掉真实姓名参数中的(用户名)
解决方案
left($fine_display_name, find("(", $fine_display_name) - 1)
4.2 单元格公式拼接参数和字符串,参数为空时,固定值也无法显示
问题描述
参数本身格式是数组,单元格用公式获取参数,并且拼接其他固定字符串。如果参数为空,整个单元格都会显示空白。场景如下拉复选框返回值为数组格式时,单元格内固定值预览不显示
原因分析
字符串+数组 的运算采用的映射运算,比如"AA"+数组(1,2)=数组(AA1,AA2)。
内部逻辑是:先根据与之相加的数组的长度属性把"AA"转成数组(AA,AA)然后与数组(1,2)进行映射。
这个逻辑就会导致如果数组是空数组,那么第一步字符串转数组就除了问题,因为数组长度为0,塞不进去
解决方案
参数为数组时,单元格公式改为判断, if(len($参数)==0,"",$参数)。或者用数组公式处理,将参数转换为字符串。
4.3 公式对于0开头的字符串匹配
问题描述
IF('000'=='00F','相等','不相等')公式正常结果应该是不相等,实际结果确是相等
解决方案
0是比较特殊,可以使用IF(exact("000","00F"),"相等","不相等")公式,exact()函数替代。
5. 其他问题
5.1 value函数在决策报表中无联动效果
问题描述
在决策报表中,设置一个参数,使用一个控件作为参数输入值,在其他控件、报表块、图表块中使用 value 函数 获取参数值,当输入的参数值改变时,获取值不会随之改变,即无联动效果。
解决方案
5.2 跨sheet或跨报表块使用条件过滤无效
问题描述
无论是普通报表、聚合报表还是决策报表,当涉及跨 sheet 页或跨报表块使用函数过滤时,若公式中包含了{}这种大括号的条件,则公式无效
解决方案