Gar*_*son 11 java localtime jodatime intervals
我们正在创建一个日程安排应用程序,我们需要在白天代表某人的可用时间表,无论他们在哪个时区.以从约达时间的间隔,它代表了两个实例之间的绝对时间间隔的提示(开始包容性的,结束独家),我们创建了一个LocalInterval.LocalInterval由两个LocalTimes组成(开始包含,最终排他),我们甚至为Hibernate中的持久化做了一个方便的类.
例如,如果有人从下午1:00到下午5:00可用,我们将创建:
new LocalInterval(new LocalTime(13, 0), new LocalTime(17, 0));
Run Code Online (Sandbox Code Playgroud)
到目前为止一直很好 - 直到有人想在某天从晚上11点到午夜才有空.由于间隔结束是独占的,因此应该很容易表示:
new LocalInterval(new LocalTime(23, 0), new LocalTime(24, 0));
Run Code Online (Sandbox Code Playgroud)
确认!不行.这会抛出异常,因为LocalTime不能保持大于23的任何小时.
这对我来说似乎是一个设计缺陷--- Joda没有考虑到有人可能想要一个代表非包容性端点的LocalTime.
这真是令人沮丧,因为它在我们创造的非常优雅的模型中打了一个洞.
我有什么选择 - 除了分支Joda并在24小时内取出支票?(不,我不喜欢使用虚拟值的选项---比如23:59:59 ---代表24:00.)
更新:对于那些一直说不存在24:00的人,这里引用ISO 8601-2004 4.2.3注释2,3:"一个日历日[24:00]的结束与[00]重合:00]在下一个日历日的开始......"和"[hh]具有值[24]的表示仅优选代表时间间隔的结束...."
23:59:59之后,第二天00:00:00到来.因此,也许用LocalTime的0, 0上的下一个日历日?
虽然因为你的开始和结束时间是包容性的,但是23:59:59真的是你想要的.这包括第23个小时的第59分钟的第59秒,并在00:00:00准确结束范围.
没有24:00(使用时LocalTime).
我们最终使用的解决方案是使用00:00作为24:00的替身,整个班级中的逻辑和应用程序的其余部分用于解释此本地值.这是一个真正的kludge,但它是我能想到的最少侵入性和最优雅的东西.
首先,LocalTimeInterval类保留一个内部标志,表明间隔端点是否是一天中午(24:00).仅当结束时间为00:00(等于LocalTime.MIDNIGHT)时,此标志才会为true.
/**
* @return Whether the end of the day is {@link LocalTime#MIDNIGHT} and this should be considered midnight of the
* following day.
*/
public boolean isEndOfDay()
{
return isEndOfDay;
}
Run Code Online (Sandbox Code Playgroud)
默认情况下,构造函数将00:00视为开始日期,但是有一个备用构造函数用于手动创建一整天的间隔:
public LocalTimeInterval(final LocalTime start, final LocalTime end, final boolean considerMidnightEndOfDay)
{
...
this.isEndOfDay = considerMidnightEndOfDay && LocalTime.MIDNIGHT.equals(end);
}
Run Code Online (Sandbox Code Playgroud)
有一个原因,为什么这个构造函数不只是有一个开始时间和"是一天结束"标志:当与具有下拉列表的时间用户界面一起使用时,我们不知道用户是否会选择00:00(渲染为24:00),但我们知道由于下拉列表是在范围的末尾,因此在我们的用例中它表示24:00.(虽然LocalTimeInterval允许空间隔,但我们不允许在我们的应用程序中使用它们.)
重叠检查需要特殊的逻辑来处理24:00:
public boolean overlaps(final LocalTimeInterval localInterval)
{
if (localInterval.isEndOfDay())
{
if (isEndOfDay())
{
return true;
}
return getEnd().isAfter(localInterval.getStart());
}
if (isEndOfDay())
{
return localInterval.getEnd().isAfter(getStart());
}
return localInterval.getEnd().isAfter(getStart()) && localInterval.getStart().isBefore(getEnd());
}
Run Code Online (Sandbox Code Playgroud)
同样,如果isEndOfDay()返回true,则转换为绝对Interval需要在结果中添加另一天.重要的是,应用程序代码永远不会从LocalTimeInterval的开始和结束值手动构造Interval,因为结束时间可能表示结束时间:
public Interval toInterval(final ReadableInstant baseInstant)
{
final DateTime start = getStart().toDateTime(baseInstant);
DateTime end = getEnd().toDateTime(baseInstant);
if (isEndOfDay())
{
end = end.plusDays(1);
}
return new Interval(start, end);
}
Run Code Online (Sandbox Code Playgroud)
当在数据库中持久化LocalTimeInterval时,我们能够使kludge完全透明,因为Hibernate和SQL没有24:00的限制(并且实际上没有LocalTime的概念).如果isEndOfDay()返回true,则我们的PersistentLocalTimeIntervalAsTime实现存储并检索24:00的真实时间值:
...
final Time startTime = (Time) Hibernate.TIME.nullSafeGet(resultSet, names[0]);
final Time endTime = (Time) Hibernate.TIME.nullSafeGet(resultSet, names[1]);
...
final LocalTime start = new LocalTime(startTime, DateTimeZone.UTC);
if (endTime.equals(TIME_2400))
{
return new LocalTimeInterval(start, LocalTime.MIDNIGHT, true);
}
return new LocalTimeInterval(start, new LocalTime(endTime, DateTimeZone.UTC));
Run Code Online (Sandbox Code Playgroud)
和
final Time startTime = asTime(localTimeInterval.getStart());
final Time endTime = localTimeInterval.isEndOfDay() ? TIME_2400 : asTime(localTimeInterval.getEnd());
Hibernate.TIME.nullSafeSet(statement, startTime, index);
Hibernate.TIME.nullSafeSet(statement, endTime, index + 1);
Run Code Online (Sandbox Code Playgroud)
令人遗憾的是,我们必须首先编写一个解决方法; 这是我能做的最好的事情.
| 归档时间: |
|
| 查看次数: |
14269 次 |
| 最近记录: |