diff --git a/aspnet-core/LINGYUN.MicroService.Aspire.slnx b/aspnet-core/LINGYUN.MicroService.Aspire.slnx
index 166412f51..a19022d70 100644
--- a/aspnet-core/LINGYUN.MicroService.Aspire.slnx
+++ b/aspnet-core/LINGYUN.MicroService.Aspire.slnx
@@ -90,6 +90,9 @@
+
+
+
diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/FodyWeavers.xml b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN.Abp.Calendar.csproj b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN.Abp.Calendar.csproj
new file mode 100644
index 000000000..489ab7fe2
--- /dev/null
+++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN.Abp.Calendar.csproj
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+ net8.0;net9.0;net10.0
+ LINGYUN.Abp.WorkdayCalendar
+ LINGYUN.Abp.WorkdayCalendar
+ false
+ false
+ false
+ enable
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarModule.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarModule.cs
new file mode 100644
index 000000000..a52b9aadf
--- /dev/null
+++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarModule.cs
@@ -0,0 +1,9 @@
+using Volo.Abp.Modularity;
+using Volo.Abp.Timing;
+
+namespace LINGYUN.Abp.Calendar;
+
+[DependsOn(typeof(AbpTimingModule))]
+public class AbpCalendarModule : AbpModule
+{
+}
diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarOptions.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarOptions.cs
new file mode 100644
index 000000000..a4f0278d9
--- /dev/null
+++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/AbpCalendarOptions.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace LINGYUN.Abp.Calendar;
+
+public class AbpCalendarOptions
+{
+ ///
+ /// 默认工作日范围
+ /// 默认: 周一到周五
+ ///
+ public DayOfWeek[] DefaultWorkdays { get; set; }
+ ///
+ /// 是否启用工作时间限制
+ /// 默认: true
+ ///
+ public bool EnableWorkTimeRestriction { get; set; }
+ ///
+ /// 默认工作时间范围
+ /// 默认: 09:00-12:00、13:00-18:00
+ ///
+ public WorkTimeRange[] DefaultWorkTimes { get; set; }
+
+ public AbpCalendarOptions()
+ {
+ DefaultWorkdays = new[]
+ {
+ DayOfWeek.Monday,
+ DayOfWeek.Tuesday,
+ DayOfWeek.Wednesday,
+ DayOfWeek.Thursday,
+ DayOfWeek.Friday
+ };
+ EnableWorkTimeRestriction = true;
+ DefaultWorkTimes = new[]
+ {
+ new WorkTimeRange(new TimeSpan(9, 0, 0), new TimeSpan(12, 0, 0)),
+ new WorkTimeRange(new TimeSpan(13, 0, 0), new TimeSpan(18, 0, 0)),
+ };
+ }
+}
diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/IWorkdayCalendarService.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/IWorkdayCalendarService.cs
new file mode 100644
index 000000000..0e5d0c796
--- /dev/null
+++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/IWorkdayCalendarService.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.Calendar;
+
+public interface IWorkdayCalendarService
+{
+ ///
+ /// 检查指定时间是否在工作日
+ ///
+ Task IsWorkdayAsync(DateOnly date);
+ ///
+ /// 检查指定时间是否在工作时间
+ ///
+ ///
+ ///
+ Task IsInWorkTimeAsync(DateTime dateTime);
+ ///
+ /// 获取下一个工作日
+ ///
+ ///
+ ///
+ Task GetNextWorkdayAsync(DateOnly date);
+}
diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/IWorkdayCalendarStore.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/IWorkdayCalendarStore.cs
new file mode 100644
index 000000000..202239c17
--- /dev/null
+++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/IWorkdayCalendarStore.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.Calendar;
+
+public interface IWorkdayCalendarStore
+{
+ ///
+ /// 获取特殊日期
+ ///
+ /// 日期
+ ///
+ Task FindSpecialDateAsync(DateOnly date);
+ ///
+ /// 获取默认工作日历
+ ///
+ Task FindDefaultCalendarAsync();
+}
diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/NullWorkdayCalendarStore.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/NullWorkdayCalendarStore.cs
new file mode 100644
index 000000000..2ddbb9f63
--- /dev/null
+++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/NullWorkdayCalendarStore.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.Calendar;
+
+[Dependency(TryRegister = true)]
+public class NullWorkdayCalendarStore : IWorkdayCalendarStore, ISingletonDependency
+{
+ public Task FindDefaultCalendarAsync()
+ {
+ return Task.FromResult(null);
+ }
+
+ public Task FindSpecialDateAsync(DateOnly date)
+ {
+ return Task.FromResult(null);
+ }
+}
diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/SpecialDateInfo.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/SpecialDateInfo.cs
new file mode 100644
index 000000000..686a90b7e
--- /dev/null
+++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/SpecialDateInfo.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace LINGYUN.Abp.Calendar;
+///
+/// 特殊日期
+///
+public class SpecialDateInfo
+{
+ ///
+ /// 日期
+ ///
+ public DateOnly Date { get; set; }
+ ///
+ /// 特殊日期类型
+ ///
+ public SpecialDateType Type { get; set; }
+ ///
+ /// 特殊日期描述
+ ///
+ public string? Description { get; set; }
+}
diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/SpecialDateType.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/SpecialDateType.cs
new file mode 100644
index 000000000..3b034a423
--- /dev/null
+++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/SpecialDateType.cs
@@ -0,0 +1,24 @@
+using System.ComponentModel;
+
+namespace LINGYUN.Abp.Calendar;
+///
+/// 特殊日期类型
+///
+public enum SpecialDateType
+{
+ ///
+ /// 法定节假日
+ ///
+ [Description("法定节假日")]
+ Holiday = 0,
+ ///
+ /// 特殊工作日
+ ///
+ [Description("特殊工作日")]
+ SpecialWorkday = 1,
+ ///
+ /// 自定义假期
+ ///
+ [Description("自定义假期")]
+ CustomHoliday = 2
+}
diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkTimeRange.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkTimeRange.cs
new file mode 100644
index 000000000..0ec86ab9a
--- /dev/null
+++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkTimeRange.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace LINGYUN.Abp.Calendar;
+///
+/// 工作时间范围
+///
+public class WorkTimeRange
+{
+ ///
+ /// 开始时间
+ ///
+ public TimeSpan StartTime { get; set; }
+ ///
+ /// 截止时间
+ ///
+ public TimeSpan EndTime { get; set; }
+ public WorkTimeRange()
+ {
+
+ }
+
+ public WorkTimeRange(TimeSpan startTime, TimeSpan endTime)
+ {
+ StartTime = startTime;
+ EndTime = endTime;
+ }
+}
diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarInfo.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarInfo.cs
new file mode 100644
index 000000000..07ab09520
--- /dev/null
+++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarInfo.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace LINGYUN.Abp.Calendar;
+
+///
+/// 工作日历信息
+///
+public class WorkdayCalendarInfo
+{
+ ///
+ /// 日历名称
+ ///
+ public string Name { get; set; }
+ ///
+ /// 默认日历
+ ///
+ public bool IsDefault { get; set; }
+ ///
+ /// 工作日范围
+ ///
+ public DayOfWeek[] Workdays { get; set; }
+ ///
+ /// 工作时间范围
+ ///
+ public WorkTimeRange[]? WorkTimes { get; set; }
+ ///
+ /// 是否启用工作时间限制
+ ///
+ public bool EnableWorkTimeRestriction { get; set; }
+ ///
+ /// 特殊日期列表
+ ///
+ public SpecialDateInfo[]? SpecialDates { get; set; }
+}
diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarService.cs b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarService.cs
new file mode 100644
index 000000000..e63ff3150
--- /dev/null
+++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/LINGYUN/Abp/Calendar/WorkdayCalendarService.cs
@@ -0,0 +1,117 @@
+using Microsoft.Extensions.Options;
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.Calendar;
+
+public class WorkdayCalendarService : IWorkdayCalendarService, ITransientDependency
+{
+ private readonly AbpCalendarOptions _options;
+ private readonly IWorkdayCalendarStore _workdayCalendarStore;
+
+ public WorkdayCalendarService(
+ IOptions options,
+ IWorkdayCalendarStore workdayCalendarStore)
+ {
+ _options = options.Value;
+ _workdayCalendarStore = workdayCalendarStore;
+ }
+
+ public async virtual Task GetNextWorkdayAsync(DateOnly date)
+ {
+ var nextDay = date.AddDays(1);
+ // 以31天为限
+ var maxAttempts = 30;
+
+ for (var i = 0; i < maxAttempts; i++)
+ {
+ if (await IsWorkdayAsync(nextDay))
+ {
+ return nextDay;
+ }
+ nextDay = nextDay.AddDays(1);
+ }
+
+ // 如果30天内都找不到工作日,返回原日期+1天
+ return date.AddDays(1);
+ }
+
+ public async virtual Task IsWorkdayAsync(DateOnly date)
+ {
+ // 特殊工作日定义
+ var specialDate = await _workdayCalendarStore.FindSpecialDateAsync(date);
+ if (specialDate != null)
+ {
+ return specialDate.Type == SpecialDateType.SpecialWorkday;
+ }
+ // 获取默认工作日历定义
+ var calendar = await _workdayCalendarStore.FindDefaultCalendarAsync();
+ if (calendar == null)
+ {
+ // 未定义默认工作日历, 获取系统定义工作日范围
+ return _options.DefaultWorkdays.Contains(date.DayOfWeek);
+ }
+ // 特殊工作日范围
+ if (calendar.SpecialDates != null &&
+ calendar.SpecialDates.Any(x => x.Date == date && x.Type == SpecialDateType.SpecialWorkday))
+ {
+ return true;
+ }
+ // 工作日范围
+ if (!calendar.Workdays.Contains(date.DayOfWeek))
+ {
+ return false;
+ }
+
+ return false;
+ }
+
+ public async virtual Task IsInWorkTimeAsync(DateTime time)
+ {
+ var nowDate = DateOnly.FromDateTime(time);
+ // 特殊工作日定义
+ var specialDate = await _workdayCalendarStore.FindSpecialDateAsync(nowDate);
+ if (specialDate != null)
+ {
+ return specialDate.Type == SpecialDateType.SpecialWorkday;
+ }
+ // 获取默认工作日历定义
+ var calendar = await _workdayCalendarStore.FindDefaultCalendarAsync();
+ if (calendar == null)
+ {
+ // 未定义默认工作日历, 获取系统定义工作日范围
+ if (!_options.DefaultWorkdays.Contains(nowDate.DayOfWeek))
+ {
+ return false;
+ }
+ if (_options.EnableWorkTimeRestriction &&
+ !_options.DefaultWorkTimes.Any(timeRange => timeRange.StartTime >= time.TimeOfDay && timeRange.EndTime <= time.TimeOfDay))
+ {
+ return false;
+ }
+
+ return true;
+ }
+ // 特殊工作日范围
+ if (calendar.SpecialDates != null &&
+ calendar.SpecialDates.Any(x => x.Date == nowDate && x.Type == SpecialDateType.SpecialWorkday))
+ {
+ return true;
+ }
+ // 工作日范围
+ if (!calendar.Workdays.Contains(nowDate.DayOfWeek))
+ {
+ return false;
+ }
+ // 工作时间范围
+ if (calendar.EnableWorkTimeRestriction &&
+ calendar.WorkTimes != null)
+ {
+ return calendar.WorkTimes.Any(x => x.StartTime >= time.TimeOfDay && x.EndTime <= time.TimeOfDay);
+ }
+
+ return false;
+ }
+}
diff --git a/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/README.md b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/README.md
new file mode 100644
index 000000000..3bb94652b
--- /dev/null
+++ b/aspnet-core/framework/calendars/LINGYUN.Abp.Calendar/README.md
@@ -0,0 +1,15 @@
+# LINGYUN.Abp.Calendar
+
+日历模块, 定义系统日历参数, 用于特定场景.
+
+#### 注意
+
+
+## 功能特性
+
+
+## 配置使用
+
+
+## 更多信息
+