Date calculation in iReport

本文介绍如何在iReport中使用单行Groovy表达式完成复杂的日期计算,如获取上个月最后一天的日期,避免使用额外Java库,并保持SQL查询简洁。

The Problem

When working with JasperServer, JasperReports, and iReport it is a common problem to perform date calculations. You would usually want to calculate dates to fill parameters when calling sub reports for example. iReport expressions offer a way to do calculations in Java or Groovy. But each calculation, like the definition of a parameter value, must consist of exactly one expression. When trying to define a complex date object, describing the last day of the last month for example, most people find it very difficult, if not impossible, to do this in a single expression. I have seen different suggestions to deal with the situation. Most recommendations seem to go towards doing all date calculation in your SQL query or using an additional Java library. Both ideas help remedy the problem. Both also have drawbacks. SQL based results may force you to design the report around the date calculation, making it harder to unterstand. Additional Java libraries may increase the complexity of your development setup, since each JasperServer instance and each iReport developer needs matching versions of the library. I would like to propose another possibility, that tries to solve the problem doing simple Groovy expressions, and does not require additional libraries.

 

The Idea

The input for a report usually consists of a date. The date to run the report for. In an ideal solution the report logic calculates all other required dates internally. To do this properly you would usually depend on the Java Calendar class. It turns out however that several function calls are required to do date calculations properly using the Calendar class. Suppose we already have the date to run a report for in the parameter runDate. The following lines of code would calculate the last day of the last month.

Calendar cal = Calendar.getInstance();
cal.set($P{runDate}.getYear()+1900, $P{runDate}.getMonth(), $P{runDate}.getDate());
cal.add(Calendar.MONTH, -1);
cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));

return cal.getTime();

The problem is of course, that iReport would not allow multiple expressions and a return statement. We need to come up with a way to put all this into a single expression. Don’t worry. It can be done. Let’s do this step by step. First of all we need to convert the local variable cal into an iReport parameter. Just add a parameter of type java.util.Calendar with default value Calendar.getInstance() and ask iReport not to prompt for its value. This is what the parameter definition should look like.

Now we have a calendar object available in our expressions, that can be referenced like any other parameter using $P{cal}. We could rewrite our pseudo code now. Notice how the explicit allocation of the cal object is not necessary any more, saving us one assignment expression.

$P{cal}.set($P{runDate}.getYear()+1900,$P{runDate}.getMonth(),$P{runDate}.getDate());
$P{cal}.add(Calendar.MONTH, -1);
$P{cal}.set(Calendar.DAY_OF_MONTH, $P{cal}.getActualMaximum(Calendar.DAY_OF_MONTH));

return $P{cal}.getTime();

Now it is time to have a close look at the documentation for the Calendar class. The add and set methods we use for our calculations do not have a return type. In a boolean context, calls to add and set evaluate to false.  We can exploit this fact and put all three calls into a single expression using the logical OR operator ||.

(
 $P{cal}.set($P{runDate}.getYear()+1900, $P{runDate}.getMonth(), $P{runDate}.getDate()) ||
 $P{cal}.add(Calendar.MONTH, -1) ||
 $P{cal}.set(Calendar.DAY_OF_MONTH, $P{cal}.getActualMaximum(Calendar.DAY_OF_MONTH))
);

return $P{cal}.getTime();

We are almost there. We can use the ? operator to write the entire calculation in a single expression, also avoiding the return statement. Take a minute to read up on the ? operator if you are unsure how it works. We know for a fact that the calendar calculation expression we wrote evaluates to false, because each statement evaluates to false. So a single expression that does the calculation and returns the resulting date looks like the following.

(
 $P{cal}.set($P{runDate}.getYear()+1900, $P{runDate}.getMonth(), $P{runDate}.getDate()) ||
 $P{cal}.add(Calendar.MONTH, -1) ||
 $P{cal}.set(Calendar.DAY_OF_MONTH, $P{cal}.getActualMaximum(Calendar.DAY_OF_MONTH))
)
? null : $P{cal}.getTime()

This is it.  We are doing a multiline calculation using the Calendar class in a single expression. You should probably put an expression like this into a report variable and use the variable whenever you need it.

Conclusion

The suggested technique solves the problem of doing multiline date calculations without using external libraries, while also keeping your date calculations out of your SQL. The price to pay is getting used to a slightly inconvenient syntax. For me this is usually a small price to pay, especially since the calculations can be encapsulated in iReport variables or parameters. See the example report for details.

Example Report

You may want to download an example report created in iReport 3.7.3, which demonstrates the suggested calculation technique by defining and printing a few date variables.

 

### 解决高分辨率计算中的CFL条件违规问题 在处理高分辨率(HD)计算时,当遇到违反CFL条件的情况,通常有几种策略可以采取以确保数值稳定性并维持解的精度。 #### 使用自适应网格细化(AMR) 通过引入自适应网格细化技术,在局部区域增加空间分辨率的同时调整时间步长,使得即使在细密网格处也能满足 CFL 条件。这种方法允许更灵活的时间推进机制,从而有效应对复杂几何形状或不均匀物理现象带来的挑战[^1]。 #### 应用隐式求解器 相比于显式的有限差分方案,隐式方法能够在更大范围内稳定运行而不受严格的 CFL 限制。对于抛物型方程而言,这尤其重要,因为其影响范围覆盖整个领域内的所有节点。因此,转而采用全隐式或其他类型的半隐式算法可能是克服 CFL 局限性的理想途径之一。 #### 实施多级时间积分法(Multi-level Time Integration Methods) 利用不同层次的时间尺度特性,设计一个多阶段过程来进行数值模拟。具体来说就是在粗略级别上使用较大的Δt快速前进,而在精细级别则减小Δt以保持足够的时空解析度。这种分级处理方式有助于缓解由于过短的时间间隔所引起的效率低下问题,同时也能够较好地控制误差积累。 ```python def implicit_solver(A, b): """ A simple implementation of an iterative solver for the linear system Ax=b, which can be used as part of a fully or semi-implicit scheme. Parameters: A (numpy.ndarray): Coefficient matrix from discretization. b (numpy.ndarray): Right-hand side vector. Returns: numpy.ndarray: Solution array x that solves Ax=b approximately. """ import numpy as np n = len(b) D = np.diag(np.abs(A)) R = A - np.diag(D) x = np.zeros_like(b) max_iter = 5000 tol = 1e-10 for i in range(max_iter): x_new = (b - np.dot(R,x)) / D if np.linalg.norm(x_new-x)<tol: break x=x_new return x ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值