基于时间片划分的提醒算法设计与实现

文章目录

    • 前言
    • 理论基础
      • 时间片概念
      • 算法核心原理
    • 提醒算法详解
      • 1. 核心数据结构定义
      • 2. 时间片计算核心算法
      • 3. 核心提醒判断逻辑
      • 4.测试用例
    • 使用场景
      • 用户通知系统
      • 系统维护提醒
      • 健康管理应用
      • 企业任务管理
    • 总结

前言

在现代软件系统中,定时提醒功能是许多业务场景的核心需求,比如任务调度、用户通知、系统维护等。传统的提醒机制往往采用固定时间间隔,容易造成重复提醒或遗漏提醒的问题。本文将介绍一种基于时间片划分的智能提醒算法,通过将时间轴划分为固定长度的时间片,确保在每个时间段内只进行一次提醒,从而提高提醒系统的精确性和用户体验。

理论基础

时间片概念

时间片(Time Slice)是计算机科学中的一个重要概念,通常指系统分配给每个程序或任务的固定时间段。在我们的提醒算法中,时间片是指根据预定义规则将连续时间轴划分为固定长度的区间,每个区间作为一个独立的提醒周期。

算法核心原理

1.时间片划分:根据配置的提醒类型(分钟、小时、天、周、月、年)和频率,将时间轴划分为固定长度的时间片
2.唯一性保证:在同一个时间片内,对同一对象只进行一次提醒
3.周期性覆盖:时间片具有周期性,当进入新的时间片时,重新开始提醒判断

提醒算法详解

1. 核心数据结构定义

/** * 基于时间片划分的提醒算法 * 根据系统配置进行时间片划分,确保每个时间段内只提醒一次 * @author senfel * @version 1.0 * @date 2025/12/25 14:08 */ public class TimeSliceReminderAlgorithm { //something }

首先定义提醒类型枚举,支持多种时间粒度:

/** * 提醒类型枚举 */ public enum ReminderType { MINUTE, HOUR, DAY, WEEK, MONTH, YEAR }

定义系统配置类,存储提醒的基本参数:

/** * 系统配置类 */ @Data @AllArgsConstructor @NoArgsConstructor public static class ReminderConfig { private ReminderType type; // 提醒类型 private int frequency; // 频率 private LocalDateTime startTime; // 开始时间 }

定义客人提醒记录类,存储提醒状态信息:

/** * 客人提醒记录 */ @Data @AllArgsConstructor @NoArgsConstructor public static class GuestReminderRecord { private String guestId; // 客人ID private boolean isReminded; // 是否已提醒 private LocalDateTime lastRemindTime; // 最后提醒时间 private ReminderConfig config; // 提醒配置 }

2. 时间片计算核心算法

时间片计算逻辑:
根据配置类型计算当前时间所属的时间片开始时间
使用整除运算 (total / frequency) * frequency 确保时间片边界正确对齐
针对不同时间类型采用相应的边界计算方法

边界处理:
周边界:确保每周从周一00:00:00开始,到周日23:59:59结束
月边界:确保每月从1号00:00:00开始,到月末23:59:59结束
年边界:确保每年从1月1号00:00:00开始,到12月31号23:59:59结束

特殊情况处理:
月末日期:处理31号在短月的特殊情况
闰年日期:处理2月29日的特殊情况
重复提醒控制:确保每个时间片内只提醒一次

获取当前时间所属的时间片起始时间:

/** * 获取当前时间所属的时间片 * @param config * @param currentTime * @author senfel * @date 2025/12/25 15:12 * @return java.time.LocalDateTime */ public static LocalDateTime getCurrentTimeSliceStart( ReminderConfig config, LocalDateTime currentTime) { LocalDateTime startTime = config.getStartTime(); ReminderType type = config.getType(); int frequency = config.getFrequency(); switch (type) { case MINUTE: long totalMinutes = ChronoUnit.MINUTES.between(startTime, currentTime); long minutesInSlice = totalMinutes / frequency * frequency; return startTime.plusMinutes(minutesInSlice); case HOUR: long totalHours = ChronoUnit.HOURS.between(startTime, currentTime); long hoursInSlice = totalHours / frequency * frequency; return startTime.plusHours(hoursInSlice); case DAY: long totalDays = ChronoUnit.DAYS.between(startTime, currentTime); long daysInSlice = totalDays / frequency * frequency; return startTime.plusDays(daysInSlice); case WEEK: // 计算从开始时间的周一到当前时间的周数 LocalDateTime startWeek = startTime.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); LocalDateTime currentWeek = currentTime.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); long totalWeeks = ChronoUnit.WEEKS.between(startWeek, currentWeek); long weeksInSlice = totalWeeks / frequency * frequency; return startWeek.plusWeeks(weeksInSlice).with(LocalTime.MIN); case MONTH: //计算从开始时间的月初到当前时间的月数 long startMonth = startTime.getYear() * 12L + startTime.getMonthValue() - 1; long currentMonth = currentTime.getYear() * 12L + currentTime.getMonthValue() - 1; long totalMonths = currentMonth - startMonth; long monthsInSlice = totalMonths / frequency * frequency; // 计算目标月份 long targetMonth = startMonth + monthsInSlice; int targetYear = (int) (targetMonth / 12); int targetMonthValue = (int) (targetMonth % 12) + 1; LocalDateTime result = LocalDateTime.of(targetYear, targetMonthValue, 1, 0, 0); // 处理月末特殊情况 if (startTime.getDayOfMonth() == startTime.toLocalDate().lengthOfMonth()) { result = result.withDayOfMonth(result.toLocalDate().lengthOfMonth()); } return result; case YEAR: // 计算从开始时间的年初到当前时间的年数 long startYear = startTime.getYear(); long currentYear = currentTime.getYear(); long totalYears = currentYear - startYear; long yearsInSlice = totalYears / frequency * frequency; LocalDateTime yearResult = LocalDateTime.of((int) (startYear + yearsInSlice), 1, 1, 1, 0, 0); // 处理闰年2月29日特殊情况 if (startTime.getMonthValue() == 2 && startTime.getDayOfMonth() == 29) { if (yearResult.toLocalDate().lengthOfMonth() < 29) { yearResult = yearResult.withDayOfMonth(28); } } return yearResult; default: throw new IllegalArgumentException("不支持的提醒类型: " + type); } }

获取当前时间片的结束时间:

/** * 获取当前时间片的结束时间 * @param config * @param currentTime * @author senfel * @date 2025/12/25 15:12 * @return java.time.LocalDateTime */ public static LocalDateTime getCurrentTimeSliceEnd( ReminderConfig config, LocalDateTime currentTime) { LocalDateTime sliceStart = getCurrentTimeSliceStart(config, currentTime); switch (config.getType()) { case MINUTE: return sliceStart.plusMinutes(config.getFrequency()).minusSeconds(1); case HOUR: return sliceStart.plusHours(config.getFrequency()).minusSeconds(1); case DAY: return sliceStart.plusDays(config.getFrequency()).minusSeconds(1); case WEEK: // 周结束于周日的23:59:59 return sliceStart.plusWeeks(config.getFrequency()) .with(TemporalAdjusters.previous(DayOfWeek.MONDAY)) .with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)) .with(LocalTime.MAX); case MONTH: // 月结束于月末的23:59:59 return sliceStart.plusMonths(config.getFrequency()) .minusDays(1) .withDayOfMonth(sliceStart.plusMonths(config.getFrequency()).minusDays(1).toLocalDate().lengthOfMonth()) .with(LocalTime.MAX); case YEAR: // 年结束于年末的23:59:59 return sliceStart.plusYears(config.getFrequency()) .minusMonths(1) .withMonth(12) .withDayOfMonth(31) .with(LocalTime.MAX); default: throw new IllegalArgumentException("不支持的提醒类型: " + config.getType()); } }

3. 核心提醒判断逻辑

判断客人是否应该在当前时间片内收到提醒:

/** * 判断客人是否应该在当前时间片内收到提醒 * 每个时间片内都可以提醒,不依赖上次提醒时间 * @param record * @param currentTime * @author senfel * @date 2025/12/25 15:11 * @return boolean */ public static boolean shouldShowReminder(GuestReminderRecord record, LocalDateTime currentTime) { // 获取当前时间片范围 LocalDateTime currentSliceStart = getCurrentTimeSliceStart(record.getConfig(), currentTime); LocalDateTime currentSliceEnd = getCurrentTimeSliceEnd(record.getConfig(), currentTime); // 检查当前时间是否在当前时间片内 boolean inCurrentSlice = currentTime.isAfter(currentSliceStart) && currentTime.isBefore(currentSliceEnd.plusSeconds(1)); // 如果在当前时间片内,检查是否已经在这个时间片内提醒过 if (inCurrentSlice) { // 检查上次提醒是否在当前时间片内 if (record.isReminded() && record.getLastRemindTime() != null) { LocalDateTime lastRemindSliceStart = getCurrentTimeSliceStart( record.getConfig(), record.getLastRemindTime()); // 如果上次提醒在当前时间片内,则不重复提醒 return !currentSliceStart.equals(lastRemindSliceStart); } // 如果未提醒过或上次提醒不在当前时间片内,则可以提醒 return true; } // 不在当前时间片内,不能提醒 return false; }

4.测试用例

/** * main * @param args * @author senfel * @date 2025/12/25 15:12 * @return void */ public static void main(String[] args) { // 创建配置 ReminderConfig config = new ReminderConfig(); config.setType(ReminderType.MINUTE); config.setFrequency(5); config.setStartTime(LocalDateTime.of(2025, 12, 21, 0, 0, 0)); // 创建客人记录 GuestReminderRecord record = new GuestReminderRecord(); record.setGuestId("guest001"); record.setReminded(true); record.setLastRemindTime(LocalDateTime.now()); record.setConfig(config); LocalDateTime currentTime = LocalDateTime.now(); //当前时间: 2026-01-07T15:11:52.442 //当前时间片开始: 2026-01-07T15:10 //当前时间片结束: 2026-01-07T15:14:59 //是否应该提醒: false System.out.println("当前时间: " + currentTime); System.out.println("当前时间片开始: " + getCurrentTimeSliceStart(config, currentTime)); System.out.println("当前时间片结束: " + getCurrentTimeSliceEnd(config, currentTime)); System.out.println("是否应该提醒: " + shouldShowReminder(record, currentTime)); }

使用场景

用户通知系统

  • 场景:电商系统中的促销提醒
  • 配置:frequency=1(每天提醒一次)
  • 优势:避免用户被重复的促销信息打扰

系统维护提醒

  • 场景:数据库备份提醒
  • 配置:frequency=1(每周提醒一次)
  • 优势:确保系统管理员不会遗漏备份任务

健康管理应用

  • 场景:服药提醒
  • 配置:frequency=4(每4小时提醒一次)
  • 优势:在规定的时间间隔内只提醒一次,避免重复打扰

企业任务管理

  • 场景:项目进度汇报
  • 配置:frequency=1(每月提醒一次)
  • 优势:确保月度汇报按时进行,同时避免重复提醒

总结

本文介绍的基于时间片划分的智能提醒算法具有以下优势:
1.精确控制:通过时间片机制,确保在指定时间段内只进行一次提醒
2.灵活配置:支持多种时间粒度和频率配置,适应不同业务场景
3.边界处理:妥善处理了月份、年份等特殊时间边界情况
4.性能优化:算法复杂度为O(1),时间计算高效
该算法在实际应用中可以有效提升用户体验,减少不必要的重复提醒,同时保证重要提醒的及时性。通过合理的时间片划分,可以在提醒频率和用户体验之间找到最佳平衡点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1125970.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

芯科科技出展CES 2026并展出如何加速互联智能的未来

专为Zephyr优化的全新Simplicity SDK助力下一代物联网简化实时操作系统部署 低功耗无线解决方案创新性领导厂商Silicon Labs&#xff08;亦称“芯科科技”&#xff0c;NASDAQ&#xff1a;SLAB&#xff09;再度出展国际消费电子展&#xff08;CES&#xff09;&#xff0c;并全面…

基于SpringBoot+Vue的网上超市设计与实现管理系统设计与实现【Java+MySQL+MyBatis完整源码】

&#x1f4a1;实话实说&#xff1a;CSDN上做毕设辅导的都是专业技术服务&#xff0c;大家都要生活&#xff0c;这个很正常。我和其他人不同的是&#xff0c;我有自己的项目库存&#xff0c;不需要找别人拿货再加价。我就是个在校研究生&#xff0c;兼职赚点饭钱贴补生活费&…

微软星标25万!AI Agents入门教程爆火,零基础也能轻松构建智能体

2025年被业界公认为“AI Agent元年”&#xff0c;这一技术已从概念验证全面迈入企业级规模化落地阶段&#xff0c;据Gartner调研数据显示&#xff0c;截至2025年4月&#xff0c;已有79%的企业开始将AI Agent融入核心工作流程&#xff0c;成为降本增效的关键引擎。就在这一技术风…

Java Web 网上点餐系统系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】

&#x1f4a1;实话实说&#xff1a;CSDN上做毕设辅导的都是专业技术服务&#xff0c;大家都要生活&#xff0c;这个很正常。我和其他人不同的是&#xff0c;我有自己的项目库存&#xff0c;不需要找别人拿货再加价。我就是个在校研究生&#xff0c;兼职赚点饭钱贴补生活费&…

SpringBoot中的DAO以及DTO、VO和Converter的介绍

DAO&#xff08;Data Access Object&#xff09;&#xff1a;数据访问对象 &#x1f4c1; 在 Spring Boot 中的现状&#xff1a; MyBatis 体系中&#xff0c;通常用 Mapper 替代 DAO 的概念。JPA&#xff08;Spring Data JPA&#xff09;中&#xff0c;Repository 接口承担 DAO…

SpringBoot+Vue 网上购物商城系统管理平台源码【适合毕设/课设/学习】Java+MySQL

&#x1f4a1;实话实说&#xff1a;CSDN上做毕设辅导的都是专业技术服务&#xff0c;大家都要生活&#xff0c;这个很正常。我和其他人不同的是&#xff0c;我有自己的项目库存&#xff0c;不需要找别人拿货再加价。我就是个在校研究生&#xff0c;兼职赚点饭钱贴补生活费&…

前后端分离甘肃非物质文化网站系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程

&#x1f4a1;实话实说&#xff1a;CSDN上做毕设辅导的都是专业技术服务&#xff0c;大家都要生活&#xff0c;这个很正常。我和其他人不同的是&#xff0c;我有自己的项目库存&#xff0c;不需要找别人拿货再加价。我就是个在校研究生&#xff0c;兼职赚点饭钱贴补生活费&…

教师工作量管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】

&#x1f4a1;实话实说&#xff1a;CSDN上做毕设辅导的都是专业技术服务&#xff0c;大家都要生活&#xff0c;这个很正常。我和其他人不同的是&#xff0c;我有自己的项目库存&#xff0c;不需要找别人拿货再加价。我就是个在校研究生&#xff0c;兼职赚点饭钱贴补生活费&…

开源问卷平台DWSurvey开发配置记录

后端目录及配置​ 后端目录​ 后端目录 . ├─ src # 工作目录 │ ├─ main │ ├─ ├─ java │ ├─ ├─ ├─ net │ ├─ ├─ ├─ ├─ diaowen │ ├─ ├─ ├─ ├─ ├─ common # 公共类目录&#xff0c;如LOGIN、SMS、Storage... │ ├─ ├─ ├─ ├…

通用语——基于实体感知的机器翻译方法,用于知识图谱上的问答

原文&#xff1a;towardsdatascience.com/lingua-franca-entity-aware-machine-translation-approach-for-question-answering-over-knowledge-e2c7e481c870?sourcecollection_archive---------12-----------------------#2024-01-29 朝着知识图谱问答系统的通用语发展 https…

【Java 开发日记】我们来说一下 synchronized 与 ReentrantLock 的

【Java 开发日记】我们来说一下 synchronized 与 ReentrantLock 的二、详细区别分析 1. 实现层面 synchronized&#xff1a; Java 关键字&#xff0c;由 JVM 底层实现&#xff08;通过 monitorenter/monitorexit 字节码指令&#xff09;。 锁信息记录在对象头的 Mark Word 中。…

引导内存分配器 Buddy 分配器的关系

引导内存分配器 Buddy 分配器的关系 在 Linux 内核启动的早期阶段&#xff0c;物理内存管理面临着一个“鸡生蛋&#xff0c;蛋生鸡”的问题&#xff1a;内核需要分配内存来初始化用于内存管理的数据结构&#xff08;如 struct page 数组&#xff09;&#xff0c;但此时完善的 B…

Buddy分配器

Buddy分配器 1. 内核在基本的伙伴分配器基础改进扩展 支持内存节点和区域&#xff0c;称为分区的伙伴分配器&#xff08;zoned buddy allocator&#xff09;。 为了预防内存碎片&#xff0c;把物理页框通过移动性分组。 针对分配单页做了性能优化&#xff0c;为了减少处理器锁的…

AI模型容器化部署实战

&#x1f493; 博客主页&#xff1a;借口的CSDN主页 ⏩ 文章专栏&#xff1a;《热点资讯》 AI模型容器化部署&#xff1a;实战指南与未来展望目录AI模型容器化部署&#xff1a;实战指南与未来展望 引言 一、容器化部署的必要性与当前挑战 为什么需要容器化&#xff1f; 现存挑战…

Slab,不连续页,buddy分配器与内存映射

Slab分配器分析 一、Slab分配器概述 1.1 Slab分配器的作用 Slab分配器是Linux内核中用于管理小对象内存分配的高效机制。它主要解决以下问题&#xff1a; 频繁分配/释放小对象的性能问题&#xff1a;内核中大量使用固定大小的对象&#xff08;如task_struct、inode、dentry等&a…

物理内存组织架构与Buddy分配器关系分析

物理内存组织架构与Buddy分配器关系分析 在Linux内核中&#xff0c;物理内存的管理是一个分层级的复杂系统。为了高效地应对不同硬件架构&#xff08;如NUMA&#xff09;和不同的内存需求&#xff08;如DMA访问限制&#xff09;&#xff0c;Linux建立了严密的物理内存组织架构…

【数据分享】2025年全国范围各城市的公交路线及站点数据(分省/分城市)

本文分享一份2025年全国范围各城市的路线及站点数据。包含&#xff1a;安徽省、澳门、北京市、重庆市、福建省、甘肃省、广东省、广西省、贵州省、海南省、河北省、河南省、黑龙江、湖北省、湖南省、吉林省、江苏省、江西省、辽宁省、内蒙古、宁夏省、青海省、山东省、山西省、…

Agent2Agent (A2A) Protocol( A2A 协议)简介、组件

Agent2Agent (A2A) Protocol&#xff08;简称 A2A 协议&#xff09;是旨在让不同 AI 代理&#xff08;agents&#xff09;之间互联互通、协作的开放标准。内容包括协议的主要组件&#xff08;building blocks&#xff09;、各组件作用&#xff0c;以及这些组件在一个典型流程中…

期货反向跟单—从小白到高手进阶历程 六十三(研究人性不是重点)

在期货反向跟单领域&#xff0c;“研究人性” 似乎成了多数团队的共识性动作。不少团队投入大量人力、物力搭建心理干预体系&#xff0c;从资金奖惩机制到每日口头引导&#xff0c;试图通过干预盘手的心理状态来优化跟单效果。然而现实往往事与愿违&#xff0c;多数团队耗费数月…

系列教程十三 | 探索阿里云 Wan 2.1:零基础入门文本生成视频教程

一.背景介绍近年来&#xff0c;人工智能内容生成&#xff08;AIGC&#xff09;在视频创作领域取得了突破性进展&#xff0c;其中文本到视频&#xff08;Text-to-Video&#xff09;生成技术因其在内容创作、广告营销和教育可视化等方面的巨大潜力而备受关注。Wan 2.1作为阿里云推…