1. 方法定义
// 获取当前系统日期(默认时区)
public static LocalDate now()
// 获取指定时区的当前日期
public static LocalDate now(ZoneId zone)
// 通过自定义时钟获取日期(测试专用)
public static LocalDate now(Clock clock)
2. 功能说明
方法 | 作用 | 关键特性 |
---|---|---|
now() |
获取系统默认时区的当前日期 | 不包含时间信息 |
now(ZoneId zone) |
获取指定时区的当前日期 | 自动处理时区偏移 |
now(Clock clock) |
通过自定义时钟获取日期 | 用于测试和固定时间场景 |
3. 示例代码
基础使用
import java.time.LocalDate;
import java.time.ZoneId;
public class BasicUsage {
public static void main(String[] args) {
// 默认系统时区
LocalDate today = LocalDate.now();
System.out.println("系统默认日期: " + today); // 2025-08-16
// 指定时区(纽约)
LocalDate newYorkDate = LocalDate.now(ZoneId.of("America/New_York"));
System.out.println("纽约当前日期: " + newYorkDate);
}
}
日期操作
// 日期计算与比较
LocalDate today = LocalDate.now();
LocalDate nextWeek = today.plusWeeks(1);
LocalDate birthDate = LocalDate.of(1990, 5, 15);
boolean isAfter = today.isAfter(birthDate); // true
boolean isLeapYear = today.isLeapYear(); // false(2025不是闰年)
测试场景(固定时钟)
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneOffset;
public class TestScenario {
public static void main(String[] args) {
// 固定时钟(测试特定日期)
Clock fixedClock = Clock.fixed(
Instant.parse("2024-02-29T00:00:00Z"),
ZoneOffset.UTC
);
LocalDate leapDay = LocalDate.now(fixedClock);
System.out.println("测试日期: " + leapDay); // 2024-02-29
System.out.println("是否闰年: " + leapDay.isLeapYear()); // true
}
}
4. 使用技巧
时区敏感场景
始终显式指定时区,避免依赖服务器默认设置:// 正确做法 LocalDate userDate = LocalDate.now(userTimeZone); // 错误做法(依赖系统默认) LocalDate riskyDate = LocalDate.now();
日期范围处理
利用TemporalAdjusters
进行复杂计算:LocalDate firstDayOfMonth = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()); LocalDate lastBusinessDay = LocalDate.now().with(TemporalAdjusters.lastInMonth(DayOfWeek.FRIDAY));
格式化输出
DateTimeFormatter formatter = DateTimeFormatter .ofPattern("yyyy年MM月dd日 EEEE", Locale.CHINA); String formatted = LocalDate.now().format(formatter); // 输出:2025年08月16日 星期六
5. 常见错误
错误类型 | 后果 | 解决方案 |
---|---|---|
混淆LocalDate 与LocalDateTime |
时间信息丢失 | 明确需求:需要时间选LocalDateTime |
未处理时区差异 | 跨时区系统日期不一致 | 始终传递ZoneId 参数 |
忽略闰年问题 | 2月29日计算错误 | 使用plusYears() 代替手动计算 |
用== 比较日期 |
对象引用比较失效 | 使用isEqual() 进行内容比较 |
6. 注意事项
不可变性
所有修改操作返回新对象:LocalDate original = LocalDate.now(); LocalDate modified = original.plusDays(10); // 新对象 System.out.println(original == modified); // false
时区边界问题
全球日期变更线导致日期差异:// 当UTC时间是00:30时 LocalDate london = LocalDate.now(ZoneId.of("Europe/London")); // 今日 LocalDate tokyo = LocalDate.now(ZoneId.of("Asia/Tokyo")); // 明日
月末处理
自动处理不同月份的天数差异:LocalDate jan31 = LocalDate.of(2025, 1, 31); LocalDate feb28 = jan31.plusMonths(1); // 2025-02-28(自动截断)
7. 最佳实践与性能优化
时区管理策略
// 集中管理时区配置 public class DateUtils { private static final ZoneId APP_TIMEZONE = ZoneId.of("Asia/Shanghai"); public static LocalDate appCurrentDate() { return LocalDate.now(APP_TIMEZONE); } }
高性能循环处理
避免在循环内重复获取当前日期:// 错误做法(多次系统调用) for (int i = 0; i < 1000; i++) { process(LocalDate.now()); // 性能损耗 } // 正确做法(单次获取) LocalDate today = LocalDate.now(); for (int i = 0; i < 1000; i++) { process(today); }
数据库交互优化
使用java.sql.Date
无缝转换:// 保存到数据库 LocalDate localDate = LocalDate.now(); PreparedStatement stmt = conn.prepareStatement("INSERT INTO events(date) VALUES (?)"); stmt.setObject(1, localDate); // 直接使用JDBC 4.2+ // 从数据库读取 ResultSet rs = stmt.executeQuery(); LocalDate dbDate = rs.getObject("date", LocalDate.class);
总结
关键点 | 行动指南 |
---|---|
核心用途 | 处理纯日期信息(无时间、无时区) |
时区处理 | 关键场景必须显式指定ZoneId |
不可变性 | 所有修改操作返回新对象 |
性能优化 | 避免循环内重复调用now() ,缓存高频使用日期 |
错误预防 | 使用isEqual() 比较日期,plusMonths() 处理月末 |
API选择 | 需要时间用LocalDateTime ,需要时区用ZonedDateTime |