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. 使用技巧

  1. 时区敏感场景
    始终显式指定时区,避免依赖服务器默认设置:

    // 正确做法
    LocalDate userDate = LocalDate.now(userTimeZone);
    
    // 错误做法(依赖系统默认)
    LocalDate riskyDate = LocalDate.now();
    
  2. 日期范围处理
    利用TemporalAdjusters进行复杂计算:

    LocalDate firstDayOfMonth = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
    LocalDate lastBusinessDay = LocalDate.now().with(TemporalAdjusters.lastInMonth(DayOfWeek.FRIDAY));
    
  3. 格式化输出

    DateTimeFormatter formatter = DateTimeFormatter
        .ofPattern("yyyy年MM月dd日 EEEE", Locale.CHINA);
    
    String formatted = LocalDate.now().format(formatter);
    // 输出:2025年08月16日 星期六
    

5. 常见错误

错误类型 后果 解决方案
混淆LocalDateLocalDateTime 时间信息丢失 明确需求:需要时间选LocalDateTime
未处理时区差异 跨时区系统日期不一致 始终传递ZoneId参数
忽略闰年问题 2月29日计算错误 使用plusYears()代替手动计算
==比较日期 对象引用比较失效 使用isEqual()进行内容比较

6. 注意事项

  1. 不可变性
    所有修改操作返回新对象:

    LocalDate original = LocalDate.now();
    LocalDate modified = original.plusDays(10); // 新对象
    System.out.println(original == modified);   // false
    
  2. 时区边界问题
    全球日期变更线导致日期差异:

    // 当UTC时间是00:30时
    LocalDate london = LocalDate.now(ZoneId.of("Europe/London"));   // 今日
    LocalDate tokyo = LocalDate.now(ZoneId.of("Asia/Tokyo"));       // 明日
    
  3. 月末处理
    自动处理不同月份的天数差异:

    LocalDate jan31 = LocalDate.of(2025, 1, 31);
    LocalDate feb28 = jan31.plusMonths(1); // 2025-02-28(自动截断)
    

7. 最佳实践与性能优化

  1. 时区管理策略

    // 集中管理时区配置
    public class DateUtils {
        private static final ZoneId APP_TIMEZONE = ZoneId.of("Asia/Shanghai");
    
        public static LocalDate appCurrentDate() {
            return LocalDate.now(APP_TIMEZONE);
        }
    }
    
  2. 高性能循环处理
    避免在循环内重复获取当前日期:

    // 错误做法(多次系统调用)
    for (int i = 0; i < 1000; i++) {
        process(LocalDate.now()); // 性能损耗
    }
    
    // 正确做法(单次获取)
    LocalDate today = LocalDate.now();
    for (int i = 0; i < 1000; i++) {
        process(today);
    }
    
  3. 数据库交互优化
    使用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