日期时间选择器 --- DatePickerUtils
背景
Swing 原生没有好用的日期时间选择器组件。如果想让用户选择日期,通常只能用手写文本框加格式校验,代码繁琐且体验一般。下拉选择年月日的方式也需要自己实现,维护成本高。
所以封装了一个工具类 DatePickerUtils,统一管理常用配置,一行代码搞定日期时间选择器。
项目中选择了开源库 LGoodDatePicker,功能完整、文档清晰。这个库支持日期选择、时间选择、日期时间组合选择,还内置了日期范围限制等常用功能。
二、依赖说明
本工具类基于 com.github.lgooddatepicker 库,需要在项目中引入:
Maven:
xml
<dependency>
<groupId>com.github.lgooddatepicker</groupId>
<artifactId>LGoodDatePicker</artifactId>
<version>11.2.1</version>
</dependency>
Gradle:
js
implementation 'com.github.lgooddatepicker:LGoodDatePicker:11.2.1'
同时使用了 cn.hutool.core.util.StrUtil(Hutool 工具类),可按需替换或自行实现判空逻辑。
三、核心方法一览
| 方法 | 返回类型 | 说明 |
|---|---|---|
| datePicker() | DatePicker | 日期选择器,yyyy-MM-dd,包含之前日期 |
| datePicker(boolean before) | DatePicker | 日期选择器,可控制是否包含之前日期 |
| datePicker(String pattern) | DatePicker | 日期选择器,自定义格式,包含之前日期 |
| datePicker(String pattern, boolean before) | DatePicker | 日期选择器,自定义格式,可控制是否包含之前日期 |
| hour() | DateTimePicker | 日期时间选择器,至小时,yyyy-MM-dd HH |
| minute() | DateTimePicker | 日期时间选择器,至分钟,间隔5分钟,包含之前 |
| minute(boolean before) | DateTimePicker | 日期时间选择器,至分钟,间隔5分钟,可控制是否包含之前 |
| minute(TimePickerSettings.TimeIncrement timeIncrement) | DateTimePicker | 日期时间选择器,至分钟,自定义时间间隔(5/10/15/20/30/60),包含之前 |
| minute(TimePickerSettings.TimeIncrement timeIncrement, boolean before) | DateTimePicker | 日期时间选择器,至分钟,自定义时间间隔,可控制是否包含之前 |
| minute(int interval) | DateTimePicker | 日期时间选择器,至分钟,自定义间隔(1-60),包含之前 |
| minute(int interval, boolean before) | DateTimePicker | 日期时间选择器,至分钟,自定义间隔(1-60),可控制是否包含之前 |
| second() | DateTimePicker | 日期时间选择器,至秒,间隔1秒,包含之前 |
| second(boolean before) | DateTimePicker | 日期时间选择器,至秒,间隔1秒,可控制是否包含之前 |
| second(int interval) | DateTimePicker | 日期时间选择器,至秒,自定义间隔(1-60),包含之前 |
| second(int interval, boolean before) | DateTimePicker | 日期时间选择器,至秒,自定义间隔(1-60),可控制是否包含之前 |
| getDate(DatePicker datePicker) | Date | 从 DatePicker 获取 java.util.Date 对象 |
四、源码实现
java
import cn.hutool.core.util.StrUtil;
import com.github.lgooddatepicker.components.DatePicker;
import com.github.lgooddatepicker.components.DatePickerSettings;
import com.github.lgooddatepicker.components.DateTimePicker;
import com.github.lgooddatepicker.components.TimePickerSettings;
import java.awt.*;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
/**
* 日期时间选择器工具类
* 基于 LGoodDatePicker 开源库封装
* * 使用示例:
* 1. 创建日期选择器(默认 yyyy-MM-dd):
* DatePicker datePicker = DatePickerUtils.datePicker();
* 2. 创建时间选择器(精确到分钟):
* DateTimePicker picker = DatePickerUtils.minute();
* 3. 获取 Date 类型值:
* Date date = DatePickerUtils.getDate(datePicker);
*/
public class DatePickerUtils {
/**
* 创建日期选择器(默认格式 yyyy-MM-dd,包含之前日期)
* @return 日期选择器
*/
public static DatePicker datePicker() {
return datePicker(true);
}
/**
* 创建日期选择器(可限制只能选今天及之后)
* @param before 是否包含之前的日期(true=包含,false=只能选今天及之后)
* @return 日期选择器
*/
public static DatePicker datePicker(boolean before) {
DatePicker datePicker = datePicker("yyyy-MM-dd");
if (!before) {
datePicker.getSettings().setDateRangeLimits(LocalDate.now(), null);
}
return datePicker;
}
/**
* 创建日期选择器(自定义格式)
* @param pattern 日期格式,如 "yyyy-MM-dd"
* @return 日期选择器
*/
public static DatePicker datePicker(String pattern) {
return datePicker(pattern, true);
}
/**
* 创建日期选择器(完整参数)
* @param pattern 日期格式
* @param before 是否包含之前的日期
* @return 日期选择器
*/
public static DatePicker datePicker(String pattern, boolean before) {
DatePicker datePicker = new DatePicker();
datePicker.setSettings(datePickerSettings(pattern));
if (!before) {
datePicker.getSettings().setDateRangeLimits(LocalDate.now(), null);
}
return datePicker;
}
/**
* 创建时间选择器(精确到小时)
* @return 日期时间选择器
*/
public static DateTimePicker hour() {
return picker("HH");
}
/**
* 创建时间选择器(精确到分钟,包含之前时间)
* @return 日期时间选择器
*/
public static DateTimePicker minute() {
return minute(true);
}
/**
* 创建时间选择器(精确到分钟)
* @param before 是否包含之前的日期和时间
* @return 日期时间选择器
*/
public static DateTimePicker minute(boolean before) {
DateTimePicker dateTimePicker = picker("HH:mm");
if (!before) {
dateTimePicker.datePicker.getSettings().setDateRangeLimits(LocalDate.now(), null);
}
dateTimePicker.timePicker.getSettings().generatePotentialMenuTimes(
TimePickerSettings.TimeIncrement.FiveMinutes,
before ? null : LocalTime.now(),
null
);
return dateTimePicker;
}
/**
* 创建时间选择器(精确到秒,包含之前时间)
* @return 日期时间选择器
*/
public static DateTimePicker second() {
return second(true);
}
/**
* 创建时间选择器(精确到秒)
* @param before 是否包含之前的日期和时间
* @return 日期时间选择器
*/
public static DateTimePicker second(boolean before) {
DateTimePicker dateTimePicker = picker("HH:mm:ss");
if (!before) {
dateTimePicker.datePicker.getSettings().setDateRangeLimits(LocalDate.now(), null);
}
dateTimePicker.timePicker.getSettings().generatePotentialMenuTimes(
before ? LocalTime.MIN : LocalTime.now(),
null
);
return dateTimePicker;
}
/**
* 获取 DatePicker 的值(转为 java.util.Date)
* @param datePicker 日期选择器
* @return Date 对象,未选择时返回 null
*/
public static Date getDate(DatePicker datePicker) {
if (null == datePicker) return null;
LocalDate localDate = datePicker.getDate();
if (null == localDate) return null;
return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
}
// ==================== 私有方法 ====================
/**
* 创建日期选择器配置
* @param pattern 日期格式
* @return 配置对象
*/
private static DatePickerSettings datePickerSettings(String pattern) {
pattern = StrUtil.isBlank(pattern) ? "yyyy-MM-dd" : pattern;
DatePickerSettings settings = new DatePickerSettings();
settings.setFormatForDatesCommonEra(DateTimeFormatter.ofPattern(pattern));
settings.setFormatForDatesBeforeCommonEra(DateTimeFormatter.ofPattern(pattern));
settings.setAllowKeyboardEditing(false);
Font font = new Font("Microsoft YaHei", Font.PLAIN, 14);
settings.setFontCalendarWeekdayLabels(font);
return settings;
}
/**
* 创建日期时间选择器
* @param timeFormat 时间格式(HH、HH:mm、HH:mm:ss)
* @return 日期时间选择器
*/
private static DateTimePicker picker(String timeFormat) {
DatePickerSettings dateSettings = datePickerSettings("yyyy-MM-dd");
TimePickerSettings timeSettings = new TimePickerSettings();
timeSettings.setFormatForMenuTimes(DateTimeFormatter.ofPattern(timeFormat));
timeSettings.setFormatForDisplayTime(DateTimeFormatter.ofPattern(timeFormat));
timeSettings.setAllowKeyboardEditing(false);
timeSettings.setInitialTimeToNow();
DateTimePicker picker = new DateTimePicker(dateSettings, timeSettings);
picker.datePicker.setDateToToday();
picker.timePicker.setTimeToNow();
return picker;
}
}
五、使用示例
- 5.1 基础日期选择
java
// 创建日期选择器(默认格式 yyyy-MM-dd,可选之前日期)
DatePicker datePicker = DatePickerUtils.datePicker();
// 创建日期选择器(只能选择今天及之后)
DatePicker futureDatePicker = DatePickerUtils.datePicker(false);
// 自定义日期格式
DatePicker customPicker = DatePickerUtils.datePicker("yyyy/MM/dd");
// 从 DatePicker 获取 Date 对象
Date selectedDate = DatePickerUtils.getDate(datePicker);
- 5.2 日期时间选择(至小时)
java
// 选择到小时(格式:yyyy-MM-dd HH)
DateTimePicker hourPicker = DatePickerUtils.hour();
- 5.3 日期时间选择(至分钟)
java
// 默认:间隔5分钟,可选之前日期时间
DateTimePicker minutePicker = DatePickerUtils.minute();
// 只能选今天及之后的时间,间隔5分钟
DateTimePicker futureMinutePicker = DatePickerUtils.minute(false);
// 使用预定义间隔(FiveMinutes/TenMinutes/FifteenMinutes/TwentyMinutes/ThirtyMinutes/SixtyMinutes)
DateTimePicker customIntervalPicker = DatePickerUtils.minute(TimePickerSettings.TimeIncrement.TenMinutes);
// 自定义间隔(10分钟)
DateTimePicker intervalPicker = DatePickerUtils.minute(10);
// 自定义间隔,且只能选未来时间
DateTimePicker futureIntervalPicker = DatePickerUtils.minute(15, false);
- 5.4 日期时间选择(至秒)
java
// 默认:间隔1秒,可选之前日期时间
DateTimePicker secondPicker = DatePickerUtils.second();
// 只能选未来时间,间隔1秒
DateTimePicker futureSecondPicker = DatePickerUtils.second(false);
// 自定义间隔(5秒)
DateTimePicker intervalSecondPicker = DatePickerUtils.second(5);
- 5.5 完整示例:在面板中使用
java
public class DemoPanel extends JPanel {
private DatePicker datePicker;
private DateTimePicker dateTimePicker;
private JLabel resultLabel;
public DemoPanel() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5, 5, 5, 5);
gbc.fill = GridBagConstraints.HORIZONTAL;
// 日期选择器
gbc.gridx = 0;
gbc.gridy = 0;
add(new JLabel("选择日期:"), gbc);
gbc.gridx = 1;
datePicker = DatePickerUtils.datePicker();
add(datePicker, gbc);
// 日期时间选择器
gbc.gridx = 0;
gbc.gridy = 1;
add(new JLabel("选择日期时间:"), gbc);
gbc.gridx = 1;
dateTimePicker = DatePickerUtils.minute();
add(dateTimePicker, gbc);
// 按钮
gbc.gridx = 0;
gbc.gridy = 2;
gbc.gridwidth = 2;
JButton btn = new JButton("获取结果");
btn.addActionListener(e -> {
String dateStr = datePicker.getDate() != null ? datePicker.getDate().toString() : "未选择";
String timeStr = dateTimePicker.getDateTimeStrict() != null ? dateTimePicker.getDateTimeStrict().toString() : "未选择";
resultLabel.setText("日期:" + dateStr + ",时间:" + timeStr);
});
add(btn, gbc);
// 结果展示
gbc.gridy = 3;
resultLabel = new JLabel("请选择日期时间");
add(resultLabel, gbc);
}
}
六、注意事项
- 依赖管理:需要引入 LGoodDatePicker 库,版本推荐 11.2.1 或更高
- 日期范围限制:通过 before 参数控制是否允许选择之前日期,false 表示只能选择今天及之后
- 时间间隔:分钟/秒的间隔参数范围是 1-60,超出会自动限制到边界值
- Hutool 依赖:StrUtil.isBlank() 方法可替换为 pattern == null || pattern.trim().isEmpty()
- 时区问题:getDate() 方法使用系统默认时区,如需指定时区可自行修改
- 键盘编辑:默认禁用了键盘编辑(setAllowKeyboardEditing(false)),避免用户手动输入非法格式
七、小结
DatePickerUtils 封装了 LGoodDatePicker 的常用配置,提供了简洁的工厂方法,一行代码即可创建日期或日期时间选择器。 核心优势:
- 开箱即用,无需重复配置日期格式、时间格式、时间间隔
- 支持日期范围限制(只能选未来/可选过去)
- 支持分钟/秒的自定义间隔
- 提供 DatePicker → java.util.Date 的转换方法