java 为 dayOfWeek 创建日期和没有特定日期的时间,即对任何星期一有效

java create date for dayOfWeek and time without a specific date, i.e. valid for any Monday

如何创建通用日期(即不附加到任何实际 yyMMdd 但类似于:

val START = LocalTime.of(startHour, startMinute)
val END = LocalTime.of(endHour, endMinute)

但是,我还想包括 dayOfWeek

我的目的是计算时间间隔的重叠,即对于两个给定的(开始、结束)时间戳,我想计算与指定工作日和时间(即营业时间)的重叠。

编辑

我不确定自定义 class 是否足够好。 我的意图是如果我有一个事件列表,例如:

id,start,end
1,2018-01-01 08:00, 2018-01-01 08:00 || opening hours 8-10, duration: 1
2,2018-01-01 10:00, 2018-01-01 12:00 || opening hours 8-10, duration: 0
3,2018-01-02 10:00, 2018-01-02 12:00 || opening hours 10-15, duration 2

验证 start-end 的时间间隔是否与另一个时间间隔(即营业时间)相交,但另一个时间间隔取决于星期几。

构建对象后(我目前可能是因为我无法以通用方式组合 dayOfWeek 和 Time)

我会使用 isBefore/isAfter 几次,然后计算重叠的持续时间。

只需使用 Java 中内置的 DayOfWeek 枚举。它提供七个预定义对象,一个对应一周中的每一天,例如 DayOfWeek.MONDAY.

我没有完全理解您的业务问题,但听起来您需要定义自己的问题 class。

public class Shift {
    DayOfWeek dayOfWeek ;
    LocalTime startTime , stopTime ;
}

添加一种将其转化为真实时刻的方法。

public ZonedDateTime startAtDate( LocalDate ld , ZoneId z ) {
    LocalDate LocalDate = ld.with( TemporalAdjustors.previousOrSame( this.dayOfWeek ) ) ;
    ZonedDateTime zdt = ZonedDateTime.of( localDate , this.startTime , z ) ;
    return zdt ;
}

您可能希望将 ThreeTen-Extra 库添加到您的项目中。它提供 class 等 IntervalLocalDateTime 等您可能会觉得有用的内容。这些 classes 提供了一堆比较方法,例如 abutsoverlaps

看起来那个库缺少 LocalTimeRange,所以可能想自己动手。也许甚至向那个项目捐赠这样一个 class。


关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

您可以直接与数据库交换 java.time 对象。使用 JDBC driver compliant with JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* classes.

从哪里获得java.time classes?

一种简单的方法是对那些 "standard" 间隔使用枚举映射。

假设使用以下方法计算重叠:

static int calculateOverlap(LocalTime expectedStartTime, LocalTime expectedEndTime, 
        LocalTime actualStartTime, LocalTime actualEndTime) {
    //calculate overlap...
}

您可以通过这种方式查找值(为简单起见,使用 Pair,您可以使用带有两个 LocalTime 字段的自定义 class):

Map<DayOfWeek, Pair<LocalTime, LocalTime>> openingHours = 
          new EnumMap<>(DayOfWeek.class);

openingHours.put(DayOfWeek.MONDAY, 
          Pair.of(LocalTime.of(8, 0), LocalTime.of(16, 0)));
openingHours.put(DayOfWeek.TUESDAY, 
          Pair.of(LocalTime.of(9, 0), LocalTime.of(17, 0)));
//...entries for other weekdays

然后使用以下方法查找:

MyEvent mondayEvent = ...

Pair<LocalTime, LocalTime> mondayHours = officialHours.get(DayOfWeek.MONDAY);
int overlap = calculateOverlap(mondayHours.getLeft(), mondayHours.getRight(),
        mondayEvent.getStart(), mondayEvent.getEnd());

我的库 Time4J (v5.0) 为您的整个业务问题提供了以下开箱即用的解决方案:

DayPartitionRule rule =
    new DayPartitionBuilder()
        .addWeekdayRule(
            Weekday.MONDAY,
            ClockInterval.between(PlainTime.of(8, 0), PlainTime.of(10, 0)))
        .addWeekdayRule(
            Weekday.TUESDAY,
            ClockInterval.between(PlainTime.of(10, 0), PlainTime.of(15, 0)))
        .build();
Map<Integer, TimestampInterval> events = new HashMap<>();
events.put(
    1,
    TimestampInterval.between(
        PlainTimestamp.of(2018, 1, 1, 8, 0),
        PlainTimestamp.of(2018, 1, 1, 9, 0)));
events.put(
    2,
    TimestampInterval.between(
        PlainTimestamp.of(2018, 1, 1, 10, 0),
        PlainTimestamp.of(2018, 1, 1, 12, 0)));
events.put(
    3,
    TimestampInterval.between(
        PlainTimestamp.of(2018, 1, 2, 10, 0),
        PlainTimestamp.of(2018, 1, 2, 12, 0)));
events.forEach(
    (id, interval) -> System.out.println(
        "Event: " + id + " => "
            + Duration.formatter(ClockUnit.class, "#h:mm").format(
                interval
                    .streamPartitioned(rule)
                    .map(i -> i.getDuration(ClockUnit.HOURS, ClockUnit.MINUTES))
                    .collect(Duration.summingUp())
                    .with(Duration.STD_CLOCK_PERIOD)
            )));

输出:

Event: 1 => 1:00

Event: 2 => 0:00

Event: 3 => 2:00

该算法使用 Time4J 的 range-package,如果您每周有多个时钟间隔或者输入间隔超过一天(这需要总结),该算法仍然可以正常工作持续时间)。

顺便说一下,我假设您的第一个间隔行“2018-01-01 08:00, 2018-01-01 08:00”包含错字,因此我已将结束时间调整为上午 9 点(预计持续时间为一小时)。