我有一个Java方法如下:
private static boolean isDateBetweenRange(DataSet obj, MyClass dataSource, ConditionContext context) {
FilterContext fc = dataSource.getData();
LocalDate dateFieldToCheck = obj.getDate(fc.getDateField()).toInstant()
.atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate minDate = fc.getMinDateValue();
LocalDate maxDate = fc.getMaxDateValue();
if (minDate == null || maxDate == null) {
minDate = context.getStartDate().toInstant().atZone(ZoneId.systemDefault())
.toLocalDate();
maxDate = context.getEndDate().toInstant().atZone(ZoneId.systemDefault())
.toLocalDate();
}
boolean result = (dateFieldToCheck.isAfter(minDate) || dateFieldToCheck.isEqual(minDate))
&& (dateFieldToCheck.isBefore(maxDate) || dateFieldToCheck.isEqual(maxDate));
return result;
}
我想为LocalDateTime
制作相同的逻辑。如果我重载该方法,它将是LocalDateTime
完全相同的代码。
如何使用Generics或任何其他机制使方法通用以与LocalDate
和LocalDateTime
一起使用?
如何根据我的类型为context.getXXXDate()... toLocalDate()
或toLocalDateTime()
提供公共代码?
答案 0 :(得分:5)
TemporalAccessor
接口可用于执行此操作。但是,请注意TemporalAccessor
是一个高级接口,不应在低级实用程序代码之外使用。
boolean api(TemporalAccessor temporal1, TemporalAccessor temporal2) {
LocalDate date1 = LocalDate.from(temporal1);
LocalDate date2 = LocalDate.from(temporal2);
return ...;
}
此代码现在接受LocalDate
,LocalDateTime
,OffsetDateTime
和ZonedDateTime
。
正如评论中所提到的,仅在一个业务逻辑中调用ZoneId.systemDefault()
至关重要,因为价值可能会发生变化。
答案 1 :(得分:3)
嗯...... LocalDateTime
是LocalDate
和LocalTime
的不可变组合。它有方法toLocalDate()
和toLocalTime()
,您可以使用它们“分解”它。相反的情况也是如此 - 您也可以轻松创建合成 - 请参阅LocalDate.atTime(LocalTime)
。
对我来说,如果你在逻辑中考虑时间,你提取的API应该接受LocalDateTime
,这似乎很自然。在可疑情况:)中,您希望通过某些原因使用LocalDate
- 来提供此API,您可以明确使用,例如LocalDate.atStartOfDay
。这样的东西:
boolean api(LocalDate aDate, LocalDate anotherDate)
{
return this.api(aDate.atStartOfDay(), anotherDate.atStartOfDay());
}
boolean api(LocalDateTime aDateTime, LocalDateTime anotherDateTime)
{
return ...;
}
虽然看起来有点难看,但仍然能很好用,不是吗?
答案 2 :(得分:0)
您可以让您的方法获得java.time.temporal.Temporal
作为参数(或TemporalAccessor
作为suggested by @JodaStephen)。此代码适用于两者。
我必须承认,我更喜欢像@Lachezar Balev's answer所建议的那样,但无论如何,这里有另一种选择。
由于Temporal
可以是任何类型(LocalDate
,LocalDateTime
,ZonedDateTime
等),但您只需要LocalDate
和{{1我正在做以下事情:
LocalDateTime
:它需要的字段多于LocalDateTime
(小时/分钟/秒),因此如果可以创建它,则它是首选类型LocalDate
另一个细节是我也简化了你的比较:
LocalDate
相当于:
dateFieldToCheck.isAfter(minDate) || dateFieldToCheck.isEqual(minDate)
与! dateFieldToCheck.isBefore(minDate)
进行比较时进行了类似的简化:
maxDate
现在,您可以使用public boolean check(Temporal dateFieldToCheck, Temporal minDate, Temporal maxDate) {
// try to get as LocalDateTime
try {
LocalDateTime dtCheck = LocalDateTime.from(dateFieldToCheck);
LocalDateTime dtMin = LocalDateTime.from(minDate);
LocalDateTime dtMax = LocalDateTime.from(maxDate);
return (!dtCheck.isBefore(dtMin)) && (!dtCheck.isAfter(dtMax));
} catch (DateTimeException e) {
// exception: one of the Temporal objects above doesn't have all fields required by a LocalDateTime
// trying a LocaDate instead
LocalDate dCheck = LocalDate.from(dateFieldToCheck);
LocalDate dMin = LocalDate.from(minDate);
LocalDate dMax = LocalDate.from(maxDate);
return (!dCheck.isBefore(dMin)) && (!dCheck.isAfter(dMax));
}
}
和LocalDate
:
LocalDateTime
如果需要,您可以扩展代码以识别其他类型(例如check(LocalDate.of(2017, 6, 19), LocalDate.of(2017, 6, 18), LocalDate.of(2017, 6, 29)); // true
check(LocalDate.of(2017, 6, 17), LocalDate.of(2017, 6, 18), LocalDate.of(2017, 6, 29)); // false
check(LocalDateTime.of(2017, 6, 29, 9, 0), LocalDateTime.of(2017, 6, 29, 8, 0), LocalDateTime.of(2017, 6, 29, 11, 0)); // true
check(LocalDateTime.of(2017, 6, 29, 7, 0), LocalDateTime.of(2017, 6, 29, 8, 0), LocalDateTime.of(2017, 6, 29, 11, 0)); // false
)。
您还可以添加另一个参数,指示将使用的类型,如下所示:
LocalTime
因此,您可以使用public boolean check(Temporal dateFieldToCheck, Temporal minDate, Temporal maxDate, int type) {
switch (type) {
case 1:
// try to get as LocalDateTime
LocalDateTime dtCheck = LocalDateTime.from(dateFieldToCheck);
LocalDateTime dtMin = LocalDateTime.from(minDate);
LocalDateTime dtMax = LocalDateTime.from(maxDate);
return (!dtCheck.isBefore(dtMin)) && (!dtCheck.isAfter(dtMax));
case 2:
// trying a LocaDate instead
LocalDate dCheck = LocalDate.from(dateFieldToCheck);
LocalDate dMin = LocalDate.from(minDate);
LocalDate dMax = LocalDate.from(maxDate);
return (!dCheck.isBefore(dMin)) && (!dCheck.isAfter(dMax));
// ... and so on
}
// invalid type, return false?
return false;
}
调用它并强制它使用ZonedDateTime
(然后您可以调整您的代码,并使用您从{{1}获得的对象调用此方法}}):
LocalDate
此代码也适用于不同类型:
atZone(ZoneId.systemDefault())
PS:当然您可以创建ZonedDateTime z1 = obj.getDate(fc.getDateField()).toInstant().atZone(ZoneId.systemDefault());
ZonedDateTime z2 = context.getStartDate().toInstant().atZone(ZoneId.systemDefault());
ZonedDateTime z3 = context.getEndDate().toInstant().atZone(ZoneId.systemDefault());
check(z1, z2, z3, 2);
而不是ZonedDateTime z1 = ...
LocalDate d = ...
LocalDateTime dt = ...
// converts all to LocalDate
System.out.println(check(z1, dt, d, 2));
来定义类型。或使用Enum
直接指明类型:
int