Joda Time LocalTime 24:00结束

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]的表示仅优选代表时间间隔的结束...."

aro*_*oth 5

23:59:59之后,第二天00:00:00到来.因此,也许用LocalTime0, 0上的下一个日历日?

虽然因为你的开始和结束时间是包容性的,但是23:59:59真的是你想要的.这包括第23个小时的第59分钟的第59秒,并在00:00:00准确结束范围.

没有24:00(使用时LocalTime).

  • "23:59:59之后,第二天00:00:00到来." 不必要.有时在23:59:59之后23:59:60 - http://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat (2认同)

Gar*_*son 5

我们最终使用的解决方案是使用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)

令人遗憾的是,我们必须首先编写一个解决方法; 这是我能做的最好的事情.