用于表示具有设定时间粒度的日历时间表的数据结构?

tom*_*ato 5 java maps data-structures

我一直在尝试考虑一种纯粹的 Java 方式来表示整个日历年的时间表。每个计划的时长为 30 分钟(半小时粒度)。

这将通过存储库方法进行抽象,例如findByDateTime()

本质上,我需要以每天 30 分钟的粒度对时间段进行建模。

我把它组合在一起的方式就像这样

public Map<Integer, Map<Integer, Programme>> enumerateMapOfMapSchedules() {

    int numberOfSlots = 48; //48 half hours in a day

    Map<Integer, Map<Integer, Programme>> dayToTimeScheduleMap = new HashMap<>();

    //create a key value map for each day of the year
    for (int i = 1; i < 366; i++) {

        Map<Integer, Programme> dayProgrammeScheduleMap = new HashMap<>();

        for (int y = 1; y < numberOfSlots; y++) {
            dayProgrammeScheduleMap.put(y, null);
        }

        dayToTimeScheduleMap.put(i, dayProgrammeScheduleMap);
    }
    //creates a map with 365 days and each day having a map of 48 schedule slots
    return dayToTimeScheduleMap;
}
Run Code Online (Sandbox Code Playgroud)

我很欣赏这个解决方案不处理或没有年份的概念,但是由于这些是用于模拟/测试的,所以我对此表示同意。

如果节目跨越两个半小时时段,它也不会处理重叠的时间表。

我的查询方法非常简单,可以查找特定计划时段中的内容。

public Programme findByDateTime(LocalDateTime dateTime) {

    int scheduleSlot = dateTime.getHour() * 2;

    //if its the after 30 minute schedule slot
    if (dateTime.getMinute() > 30) {
        scheduleSlot++;
    }

    return scheduleMap.get(dateTime.getDayOfYear()).get(scheduleSlot);
}
Run Code Online (Sandbox Code Playgroud)

然而,迭代所有数据结构以查看特定程序存在多少次。

我的问题是,有更简单的方法吗?

我尝试使用关系数据库来实现这一点,但是如果没有大量 SQL,很难轻松表示时间段。

欢迎任何建议或实施建议!

Bas*_*que 4

白天的长度各不相同

\n

日历时间表仅在时区和年份的背景下才有意义。政治家经常更改其管辖范围内的时区所使用的偏移量。这意味着白天并不总是 24 小时。夏令时 (DST)等异常情况意味着一天可能有 23 小时、25 小时或其他时间,例如 23.5 小时。

\n

从头开始,以 30 分钟为增量计数

\n

因此,如果您想要将全年分成 30 分钟的片段,则必须从特定时区的特定年份第一天的第一时刻开始,每次添加 30 分钟,直到达到新的时间段。年。

\n
ZoneId z = ZoneId.of( "America/Montreal" );\nYear year = Year.of( 2021 );\nLocalDate firstOfYear = year.atDay( 1 );\nZonedDateTime start = firstOfYear.atStartOfDay( z );\nList < ZonedDateTime > zdts = new ArrayList <>();\n\nDuration duration = Duration.ofMinutes( 30 );\nZonedDateTime zdt = start;\nwhile ( zdt.getYear() == year.getValue() )\n{\n    zdts.add( zdt );\n    // Setup the next loop.\n    zdt = zdt.plus( duration );\n}\n
Run Code Online (Sandbox Code Playgroud)\n

返回该列表的不可修改的副本。

\n
List < ZonedDateTime > slots = List.copyOf( zdts );\n
Run Code Online (Sandbox Code Playgroud)\n

运行时。请注意2021 年 3 月 14 日和 2021 年 11 月 7 日凌晨 1 点或 2 点发生的情况。

\n
\n

slot = [2021-01-01T00:00-05:00[美国/蒙特利尔]、2021-01-01T00:30-05:00[美国/蒙特利尔]、2021-01-01T01:00-05:00[美国/蒙特利尔], 2021-01-01T01:30-05:00[美国/蒙特利尔], 2021-01-01T02:00-05:00[美国/蒙特利尔],

\n

\xe2\x80\xa6

\n

2021-03-14T01:00-05:00[美国/蒙特利尔], 2021-03-14T01:30-05:00[美国/蒙特利尔], 2021-03-14T03:00-04:00[美国/蒙特利尔] ,

\n

\xe2\x80\xa6

\n

2021-11-07T00:30-04:00[美国/蒙特利尔], 2021-11-07T01:00-04:00[美国/蒙特利尔], 2021-11-07T01:30-04:00[美国/蒙特利尔] , 2021-11-07T01:00-05:00[美国/蒙特利尔], 2021-11-07T01:30-05:00[美国/蒙特利尔], 2021-11-07T02:00-05:00[美国/蒙特利尔],

\n

\xe2\x80\xa6

\n

2021-12-31T22:00-05:00[美国/蒙特利尔], 2021-12-31T22:30-05:00[美国/蒙特利尔], 2021-12-31T23:00-05:00[美国/蒙特利尔] , 2021-12-31T23:30-05:00[美国/蒙特利尔]]

\n
\n

未来的预测不可靠!

\n

但请注意:政治家经常更改区域中使用的偏移量!这种情况发生的频率比您想象的要高得多。政客们甚至更糟糕地将预警时间从几年缩短到几个月,甚至几周,就像最近在土耳其和摩洛哥看到的那样,甚至像在朝鲜看到的那样根本没有预警。

\n

因此,您无法使用上述方法可靠地预测未来。

\n

老虎机数学

\n

我想你可以用另一种方式来解决年份问题。以这种方式计算一年中的整个槽位数量。

\n
ZoneId z = ZoneId.of( "America/Montreal" );\nYear year = Year.of( 2021 );\nLocalDate firstOfYear = year.atDay( 1 );\nZonedDateTime start = firstOfYear.atStartOfDay( z );\nZonedDateTime end = start.plusYears( 1 );\n\nDuration slotLength = Duration.ofMinutes( 30 );\nlong wholeSlotsInYear = Duration.between( start , end ).dividedBy( slotLength );\n
Run Code Online (Sandbox Code Playgroud)\n

然后,您可以通过乘以持续时间并将结果添加到年初来跳转到一年中的某个点。

\n
int slotNumber = 22;\nDuration jump = slotLength.multipliedBy( slotNumber - 1 );  // Subtract one to change an ordinal number into a zero-based index. \nZonedDateTime slot22 = start.plus( jump );\n
Run Code Online (Sandbox Code Playgroud)\n

预约追踪

\n

如果您在美发沙龙或牙科诊所等处进行预约,通常的方法是跟踪年月日的特定时间。但单独跟踪时区。因此,在 Java 模型中将aLocalDateTime与单独的 a 一起使用。ZoneId在数据库表中,使用一对列,其中一个列的类型类似于 SQL 标准类型TIMESTAMP WITHOUT TIME ZONE,另一列的类型为包含时区名称的文本类型,例如America/MontrealAfrica/Tunis

\n

制定时间表时,应用区域来确定时刻。在 Java 中,这意味着将 a 应用于ZoneIdaLocalDateTime以获得 a ZonedDateTime

\n

您需要清楚一个基本概念:LocalDateTime对象并不代表某个时刻。在我们的示例中,明年 23 日的下午 3 点可能意味着日本东京的下午 3 点或美国俄亥俄州托莱多的下午 3 点,这是两个相隔几个小时的截然不同的时刻。ALocalDateTime本质上是有歧义的。因此还需要存储时区,但保持独立。

\n
LocalDateTime ldt = LocalDateTime.of( 2021 , 1 , 23 , 15 , 0 , 0 , 0 ) ;\nZoneId z = ZoneId.of( "America/Montreal" ) ;\nZonedDateTime zdt = ldt.atZone( z ) ;  // Determine a moment.\n
Run Code Online (Sandbox Code Playgroud)\n

通过提取 .txt 文件来查看 UTC 中的同一时刻Instant

\n
Instant instant = zdt.toInstant() ;\n
Run Code Online (Sandbox Code Playgroud)\n