我开源的 Access 日期选择器更新了:八种选择方式都齐了


11.png

Hi,大家好!

我的 Access 日期选择器开源项目,这次又更新了。最近,我热衷于做一些开源工具。

虽然现在Access的日期选择器已经很好用了(好像日期选择器好像微软也要更新了,就是不知道具体的时间),但是在实际业务中,单一的日期选择往往无法满足各种不同的需求。比如订单要选下单日期,报表只想选一个月份,统计要按周看,排班只需要时分秒,查询还经常需要一段起止时间。如果每一种都让用户自己输入,格式和操作又得分别处理。

所以,这次我把项目里的选择方式补齐了:日期、日期时间、年份、年月、周、独立时间、日期范围、日期时间范围,一共八种入口。

这里说的补齐,是把这八类常用需求做进同一个项目,不是说它能代替所有业务里的日历规则。比如周从哪天开始、查询结束日期算到哪里,仍然需要与业务约定一致。

项目地址先放这里:

https://github.com/miaowei2/access-datepicker

和 Access 自带的日期选择器,有什么不同?

如果只是给订单选一个日期,Access 自带的日期选择器就很合适。不需要导入模块,也不用生成额外的选择器窗体,设置好日期字段和文本框属性就能用。

这里对比的是桌面 Access 中常见的文本框内置日期选择器,具体外观以你使用的版本为准,不把将来可能更新的功能算进来。

下面先看 Access 自带的日期选择界面:

9.png

它主要解决的是「为这个输入框选一个日期」。日期/时间字段本身可以存时间,但能存时间,不等于弹出的日历里就有时、分、秒列表。这两件事要分开看。

我的项目补充的是另一类需求:有时候只要一个年份,有时候要一个月份、一整周,或者一段带时分秒的范围。把这些需求都塞进单日期输入,后面还得加自己的代码和操作规则。

对比内容Access 自带日期选择器我的日期选择器项目
选择某一天内置支持,普通日期输入更省事支持,也可以同时选择时分
只选年份或年月日历最终选的是具体日期,年份或年月需另外处理有独立年份、年月入口,不必先选某一天
选择一整周先选日期,再由业务代码换算所属周整周预览、单击选择,按项目约定的周规则回写
只选时分秒不提供专门的时分秒列表,需要另做输入界面独立时间面板,支持到秒
选择起止范围一般用两个日期输入框分别选择,再处理起止关系双月范围选择,可统一回写两个端点
界面调整使用 Access 提供的内置日历界面源码和生成窗体可按项目需要调整
接入工作量配置文本框即可,不用额外导入选择器模块需要导入对应模块、生成窗体并绑定调用

下面是我的项目,把不同选择方式放在同一个 Demo 中,方便直接试用:

比如月度销售报表,用户要选的是「2026 年 10 月」,并不是 10 月的某一天。用年月面板,输入含义就直接对应业务;用自带日期选择器也能通过取年份、月份实现,但这部分规则要自己补。

再比如查询 10 月 1 日到 10 月 19 日的订单。两个自带日期输入框当然也能做,选择器负责分别选日,业务代码负责检查开始不能晚于结束。项目里的双月范围面板,则把区间预览和两端选择放在一起处理。

因此,我不会建议把系统里所有自带日历都换掉。普通单日期字段继续用内置的;遇到年月、周、时间或范围选择,再按需接入项目里的对应模块。

10.png

不只选某一天,业务里的几种选法都有了

当前示例数据库里有一个 Demo 窗体,八个入口按日期、日期时间、年份、月份、周、时间、日期范围、时间范围的顺序排列。下载后直接打开这个窗体,就能逐个试。

这几个入口各自解决什么问题,可以先看这张表。

选择方式主要内容适合的场景
日期选年月日,不带时间生日、业务日期
日期时间选日期和时分需要记录到分钟的时间
年份独立年份网格年度报表、年度计划
年月切换年份后选择月份月度结算、按月查询
周一次选择完整的一周周统计、周计划
独立时间时、分、秒上班时间、预约时刻
日期范围选择起止日期按日期区间查询
日期时间范围两端日期加时分秒操作日志、精确时段查询

其中,年份和年月共用一个模块、一个选择器窗体;日期和日期时间也共用一个模块,通过参数决定是否显示时间。八种入口不需要八套模块。

项目继续使用纯 VBA 和 Access 原生窗体,不需要额外注册日历 OCX,也不需要 WebBrowser、网页资源或外部控件库。

对要部署到多台电脑上的 Access 项目来说,这种做法比较省事:需要哪种就导入哪种,生成对应窗体,不必为了一个日期输入框再带上一套额外组件。

选一个年份、月份或时间,不必绕回完整日历

有些输入框的业务含义,本来就不是一个完整日期。

比如年度报表,用户只想选 2026 年,让他先选到某个月某一天,最后再从日期里取年份,操作上就多绕了一步。

这次年份入口可以直接显示年份网格,翻页选年,也可以选择今年。默认写回四位年份文本,例如 2026。

年月入口则是四列三行的月份面板。先确定年份,再点月份,默认可以写成 2026-10。对于月报筛选,比先选一个具体日期再解释「只取这个月」更直接。

独立时间也单独做了。它是时、分、秒三列,可以选择到秒;调整列表时先更新预览,点「确定」或按 Enter 才写回。「现在」用于更新预览,不会直接替你提交。

不过,只选时间和修改完整日期时间不是一回事。

独立时间选择器默认回写只含时间部分的 Date 值。原值即使带有日期,确认后也不会替你保留那一天。所以它适合上班时刻之类的字段,不要直接拿来修改必须保留原日期的业务记录。





两种范围选择,确认方式不一样

日期范围使用双月日历。第一次点击选起点,移动鼠标可以预览区间,第二次点击选终点并自动确认。

可以选同一天,也可以反向选,结果会按先后整理;切换月份或年份后,还能继续选择跨月、跨年的范围,不局限于眼前显示的两个月。

日期时间范围也是双月日历,但多了两端完整的时间选择,而且精确到秒。

它不会在第二次选日后立刻提交。日期选好之后,还可以继续调整开始、结束的时分秒,最后点「确定」或按 Enter 才回写。否则刚选完两天,窗体就关了,时间反而没机会改。

下面可以对照看日期范围和日期时间范围:前者主要选起止日期,后者还需要调整两端的时分秒。

反向选择时,处理的是完整的日期时间端点,不是只把日期交换一下、把时间留在原处。同一天也可以选择不同的起止时间,确认时会再按完整日期时间排序。

范围有两种回写方式:一个文本框显示整段范围,或者两个文本框分别保存起点和终点。

如果只是让用户看,可以用一个未绑定文本框显示;如果后面要查询、比较或保存到业务表里,我更建议使用两个日期/时间字段,分别存开始值和结束值。

整段 开始 ~ 结束 是一段文本,不能塞进单个日期/时间字段里。


周选择器,先把一周的规则说清楚

周选择器不是选中某一天以后只保存那一天。鼠标移入时会预览整周,单击这周中的任意一天,就选择这一整周。

这里采用的规则是:周日到周六,包含 1 月 1 日的一周算新年第 1 周,不采用 ISO 周编号。

例如,2026-40周 对应 2026 年 9 月 27 日到 10 月 3 日。2020 年 12 月 27 日到 2021 年 1 月 2 日,则统一属于 2021-01周。

所以,不能把这个周标签直接当成其他系统里的 ISO 周。要做周报对接,先确认双方规则相同,不能只看都是「第几周」就直接拼起来。

默认回写的是 2026-40周 这样的文本。需要用日期字段保存时,也可以选择回写该周周日的 Date 值,再由它计算周六或生成显示标签。

我一般会把周起始日期作为查询依据,周标签用于展示。这样筛选跨月、跨年的记录时,不用再靠拆文本猜日期。

5.png

接到自己的 Access 窗体里

第一步:导入需要的模块

先备份自己的数据库,按 Alt + F11 打开 VBA 编辑器,通过「文件 → 导入文件」导入需要的标准模块。

需要的功能对应模块
日期、日期时间Module_DatePicker.bas
年份、年月Module_YearMonthPicker.bas
日期范围Module_DateRangePicker.bas
周Module_WeekPicker.bas
独立时间Module_TimePicker.bas
日期时间范围Module_DateTimeRangePicker.bas

只需要某一种,就按需安装,不必把六个全部导入。导入后执行「调试 → 编译」,确认没有编译错误,再继续生成窗体。

项目中的中文模块要注意编码,尤其是使用 GBK/CP936 的模块,不要随手另存成 UTF-8 再导入 VBE。也不要把普通 .bas 文件当成窗体序列化文件,用 LoadFromText 加载。

第二步:生成对应窗体

在立即窗口执行相应命令。下面每行对应一种窗体,只执行自己已导入模块对应的行;如果六个模块都装了,可以依次执行这六行:

CreateDatePickerForm
CreateYearMonthPickerForm
CreateDateRangePickerForm
CreateWeekPickerForm
CreateTimePickerForm
CreateDateTimeRangePickerForm

生成后的窗体会保存到数据库中,不需要每次启动系统都重新生成。重新执行创建命令会重建对应窗体,自己调整过布局的,要先另存备份。

选择器内部的事件通过表达式绑定到标准模块的公共函数,不需要给生成的选择器窗体再手工粘贴一份窗体代码。

第三步:绑定业务输入框

比如订单窗体上有一个 txtOrderDate 文本框,控件来源为订单日期字段,另有按钮 cmdPickOrderDate。在这个业务窗体的按钮单击事件里写:

Private Sub cmdPickOrderDate_Click()
    Dim pickedDate As Variant
    pickedDate = ShowDatePicker(Me.txtOrderDate.Value, False)    If Not IsNull(pickedDate) Then
        Me.txtOrderDate.Value = pickedDate
    End If
End Sub

第二个参数 False 表示只选日期。返回值使用 Variant,是因为用户取消或清除时可能返回 Null。上面这段代码只在取得有效日期时赋值,所以取消或清除都不会改掉原来的文本框值。

如果业务需要「清除按钮就清空原输入」,应采用支持绑定回写的接口,不能把这个返回值判断直接理解成所有调用方式都有同样效果。

范围输入可以用绑定接口处理。假设业务窗体上有 txtStart、txtEnd 两个文本框,分别绑定开始、结束日期/时间字段,再放两个演示按钮:

Private Sub cmdPickDateRange_Click()
    PickDateRangeFor Me.txtStart, Me.txtEnd
End Sub

Private Sub cmdPickDateTimeRange_Click()
    PickDateTimeRangeFor Me.txtStart, Me.txtEnd
End Sub

前一个只写日期,后一个写完整日期时间。不传格式字符串时,双框写入的是真正的 Date 值,适合绑定日期/时间字段。显示样式用文本框的「格式」属性设置,例如 yyyy-mm-dd hh:nn:ss,其中 nn 表示分钟。

一些入口还可以直接填属性表达式。例如,在名为 frmOrder 的窗体上放置未绑定文本框 txtYear,在它的「单击」事件属性里填写:

=PickYearForCtl("frmOrder","txtYear")

不必再写 txtYear_Click。如果窗体或控件改了名字,表达式里的名字也要一起改。

选得出来,还要保存和查询得对

回写值的类型,和文本框看起来是什么样,是两回事。

年份、年月、周标签,以及单框显示的范围,适合未绑定文本框或文本字段。需要保存日期时间的数据,优先使用接口默认的 Date 回写方式,不要为了显示好看,先格式化成字符串再让数据库猜。

取消和清除也有不同含义。在支持绑定回写的这些入口中,「取消」、Esc 或下拉模式点击外部,保留原值;「清除」用于写入 Null。对于必填字段,是否允许保存空值,还要由业务窗体和表规则来约束。

如果采用 Show... 模态返回值接口,取消和清除可能都返回 Null。调用者能否清空原字段,取决于自己的赋值代码,不能混同为绑定接口的行为。

最后还有查询范围。

日期范围返回的是两端日期,不含时间。如果订单表里的字段还带时分秒,结束日期是 10 月 19 日,直接用「小于等于 10 月 19 日」往往只包含当天零点,会漏掉当天后面的记录。

这种按整天筛选的情况,可以使用「字段大于等于开始日期,并且小于结束日期加一天」的半开区间。周查询同样如此,要包含周六全天,就比较到下周日之前。

但日期时间范围已经选了具体时刻,就不能照搬加一天。应按实际起止时间比较;如果目标字段存在小数秒,还要约定结束秒的包含规则。

日历把值选出来之后,这一层查询条件仍然是业务代码的责任。

下载后,可以先从 Demo 试起

项目按 Access 2010、2013、2016、2019、365,32 位与 64 位,以及 .accdb、.mdb 提供兼容说明。具体部署前,仍建议在自己的 Access 版本和数据库副本里试用,不把兼容说明当成每个环境都已经逐一验证过。

想直接看效果,就打开项目里的 DatePicker.accdb,进入 Demo 窗体。想接入已有系统,就按需导入模块、创建窗体,再把入口绑定到自己的文本框或按钮上。

建议试的时候别只点一个正常日期,也顺手试试跨月范围、跨年周、午夜 00:00:00、取消后保留原值,以及清除后的空值处理。这些操作能不能符合业务预期,比只看一张日历截图更重要。

这次更新,我想做的是让常见的日期时间输入有一套现成的选择方式:选一天、选一个月、选一周,或者选一段精确到秒的时间,都能按需要接到 Access 窗体中。

代码已经放在项目里,欢迎下载试用。遇到问题可以提交 Issue,写清使用的 Access 版本、位数、调用方式和复现步骤。

https://github.com/miaowei2/access-datepicker



技术培训

  • Access VBA 从入门到精通(线上/线下均可)

  • Access + SQL Server 企业级开发实战

  • Access 系统性能优化与架构设计

  • AI + Access 融合开发专题培训

定制开发

  • 企业 ERP / CRM / 进销存 / WMS / MES 等系统开发

  • 旧 Access 系统升级、性能优化与架构重构

  • AI 能力集成到现有 Access 业务系统

技术支持

  • 代码审查与重构建议

  • 疑难问题远程诊断

  • 一对一技术辅导