Skip to content

日期时间API

概述

Java 8引入了新的日期时间API(java.time包),解决了旧API(Date、Calendar)的线程安全和设计问题。

LocalDate

表示日期(年月日)。

java
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class LocalDateDemo {
    public static void main(String[] args) {
        // 创建
        LocalDate today = LocalDate.now();           // 当前日期
        LocalDate date = LocalDate.of(2024, 1, 1);   // 指定日期
        LocalDate parse = LocalDate.parse("2024-01-01");  // 解析
        
        // 获取信息
        System.out.println("年: " + today.getYear());
        System.out.println("月: " + today.getMonth());
        System.out.println("月: " + today.getMonthValue());
        System.out.println("日: " + today.getDayOfMonth());
        System.out.println("星期: " + today.getDayOfWeek());
        System.out.println("年中第几天: " + today.getDayOfYear());
        
        // 计算
        LocalDate tomorrow = today.plusDays(1);
        LocalDate lastWeek = today.minusWeeks(1);
        LocalDate nextMonth = today.plusMonths(1);
        LocalDate nextYear = today.plusYears(1);
        
        // 比较
        boolean isBefore = today.isBefore(tomorrow);
        boolean isAfter = today.isAfter(lastWeek);
        boolean isLeap = today.isLeapYear();
        
        // 调整
        LocalDate firstDayOfMonth = today.withDayOfMonth(1);
        LocalDate lastDayOfMonth = today.withDayOfMonth(today.lengthOfMonth());
        
        // 格式化
        String formatted = today.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"));
        System.out.println(formatted);
    }
}

LocalTime

表示时间(时分秒)。

java
import java.time.LocalTime;

public class LocalTimeDemo {
    public static void main(String[] args) {
        // 创建
        LocalTime now = LocalTime.now();
        LocalTime time = LocalTime.of(14, 30, 0);
        LocalTime parse = LocalTime.parse("14:30:00");
        
        // 获取信息
        System.out.println("时: " + now.getHour());
        System.out.println("分: " + now.getMinute());
        System.out.println("秒: " + now.getSecond());
        System.out.println("纳秒: " + now.getNano());
        
        // 计算
        LocalTime later = now.plusHours(1);
        LocalTime earlier = now.minusMinutes(30);
        
        // 比较
        boolean isBefore = now.isBefore(later);
        
        // 常用时间
        LocalTime midnight = LocalTime.MIDNIGHT;      // 00:00
        LocalTime noon = LocalTime.NOON;              // 12:00
        LocalTime min = LocalTime.MIN;                // 00:00
        LocalTime max = LocalTime.MAX;                // 23:59:59.999999999
    }
}

LocalDateTime

表示日期和时间。

java
import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class LocalDateTimeDemo {
    public static void main(String[] args) {
        // 创建
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime dateTime = LocalDateTime.of(2024, 1, 1, 10, 30);
        LocalDateTime dateTime2 = LocalDateTime.of(LocalDate.now(), LocalTime.now());
        
        // 解析
        LocalDateTime parse = LocalDateTime.parse("2024-01-01T10:30:00");
        LocalDateTime parse2 = LocalDateTime.parse("2024-01-01 10:30:00", 
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        
        // 获取LocalDate和LocalTime
        LocalDate date = now.toLocalDate();
        LocalTime time = now.toLocalTime();
        
        // 计算
        LocalDateTime tomorrow = now.plusDays(1);
        LocalDateTime nextHour = now.plusHours(1);
        
        // 格式化
        String formatted = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        System.out.println(formatted);
    }
}

Instant

表示时间戳(机器时间)。

java
import java.time.Instant;
import java.time.Duration;

public class InstantDemo {
    public static void main(String[] args) {
        // 创建
        Instant now = Instant.now();
        Instant instant = Instant.ofEpochSecond(1000);
        Instant parse = Instant.parse("2024-01-01T00:00:00Z");
        
        // 获取时间戳
        long epochSecond = now.getEpochSecond();
        long epochMilli = now.toEpochMilli();
        
        // 计算
        Instant later = now.plusSeconds(60);
        Instant earlier = now.minusMillis(1000);
        
        // 时间差
        Duration duration = Duration.between(now, later);
        System.out.println("秒数: " + duration.getSeconds());
    }
}

Duration和Period

Duration - 时间间隔

java
import java.time.Duration;
import java.time.LocalTime;
import java.time.LocalDateTime;

public class DurationDemo {
    public static void main(String[] args) {
        LocalTime start = LocalTime.of(9, 0);
        LocalTime end = LocalTime.of(17, 0);
        
        Duration duration = Duration.between(start, end);
        
        System.out.println("小时: " + duration.toHours());      // 8
        System.out.println("分钟: " + duration.toMinutes());    // 480
        System.out.println("秒: " + duration.getSeconds());     // 28800
        
        // 创建Duration
        Duration hours = Duration.ofHours(2);
        Duration minutes = Duration.ofMinutes(30);
        Duration days = Duration.ofDays(1);
        
        // 计算
        Duration added = duration.plusHours(1);
        Duration multiplied = duration.multipliedBy(2);
    }
}

Period - 日期间隔

java
import java.time.Period;
import java.time.LocalDate;

public class PeriodDemo {
    public static void main(String[] args) {
        LocalDate start = LocalDate.of(2024, 1, 1);
        LocalDate end = LocalDate.of(2024, 12, 31);
        
        Period period = Period.between(start, end);
        
        System.out.println("年: " + period.getYears());   // 0
        System.out.println("月: " + period.getMonths());  // 11
        System.out.println("日: " + period.getDays());    // 30
        
        // 创建Period
        Period days = Period.ofDays(10);
        Period months = Period.ofMonths(6);
        Period years = Period.ofYears(1);
        Period custom = Period.of(1, 2, 3);  // 1年2月3日
    }
}

DateTimeFormatter

java
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class FormatterDemo {
    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now();
        
        // 预定义格式
        DateTimeFormatter isoDateTime = DateTimeFormatter.ISO_DATE_TIME;
        DateTimeFormatter isoDate = DateTimeFormatter.ISO_DATE;
        DateTimeFormatter isoTime = DateTimeFormatter.ISO_TIME;
        
        // 自定义格式
        DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
        
        // 格式化
        String formatted = now.format(formatter1);
        System.out.println(formatted);
        
        // 解析
        LocalDateTime parsed = LocalDateTime.parse("2024-01-01 10:30:00", formatter1);
        System.out.println(parsed);
        
        // 常用格式
        DateTimeFormatter[] formatters = {
            DateTimeFormatter.BASIC_ISO_DATE,           // 20240101
            DateTimeFormatter.ISO_LOCAL_DATE,           // 2024-01-01
            DateTimeFormatter.ISO_LOCAL_TIME,           // 10:30:00
            DateTimeFormatter.ISO_LOCAL_DATE_TIME,      // 2024-01-01T10:30:00
            DateTimeFormatter.ofPattern("yyyy/MM/dd"),  // 2024/01/01
        };
    }
}

时区处理

ZonedDateTime

java
import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

public class ZonedDateTimeDemo {
    public static void main(String[] args) {
        // 创建
        ZonedDateTime now = ZonedDateTime.now();
        ZonedDateTime specific = ZonedDateTime.of(
            2024, 1, 1, 10, 30, 0, 0,
            ZoneId.of("Asia/Shanghai")
        );
        
        // 指定时区
        ZonedDateTime tokyo = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
        ZonedDateTime newYork = ZonedDateTime.now(ZoneId.of("America/New_York"));
        
        // 时区转换
        ZonedDateTime converted = now.withZoneSameInstant(ZoneId.of("UTC"));
        
        // 获取时区信息
        ZoneId zone = now.getZone();
        System.out.println("时区: " + zone);
        
        // 可用时区
        ZoneId.getAvailableZoneIds().forEach(System.out::println);
    }
}

ZoneId

java
import java.time.ZoneId;

public class ZoneIdDemo {
    public static void main(String[] args) {
        // 系统默认时区
        ZoneId defaultZone = ZoneId.systemDefault();
        
        // 指定时区
        ZoneId shanghai = ZoneId.of("Asia/Shanghai");
        ZoneId utc = ZoneId.of("UTC");
        ZoneId offset = ZoneId.of("+08:00");
        
        // 常用时区
        String[] commonZones = {
            "Asia/Shanghai",      // 上海
            "Asia/Tokyo",         // 东京
            "America/New_York",   // 纽约
            "Europe/London",      // 伦敦
            "UTC"                 // 协调世界时
        };
    }
}

旧API转换

java
import java.time.*;
import java.util.Date;
import java.util.Calendar;

public class ConversionDemo {
    public static void main(String[] args) {
        // Date -> Instant -> LocalDateTime
        Date date = new Date();
        Instant instant = date.toInstant();
        LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        
        // LocalDateTime -> Instant -> Date
        LocalDateTime now = LocalDateTime.now();
        Instant instant2 = now.atZone(ZoneId.systemDefault()).toInstant();
        Date date2 = Date.from(instant2);
        
        // Calendar -> Instant -> ZonedDateTime
        Calendar calendar = Calendar.getInstance();
        Instant instant3 = calendar.toInstant();
        ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant3, ZoneId.systemDefault());
        
        // 时间戳转换
        long timestamp = System.currentTimeMillis();
        Instant fromTimestamp = Instant.ofEpochMilli(timestamp);
        LocalDateTime fromTimestamp2 = LocalDateTime.ofInstant(fromTimestamp, ZoneId.systemDefault());
    }
}

实战示例

计算年龄

java
public static int calculateAge(LocalDate birthDate) {
    return Period.between(birthDate, LocalDate.now()).getYears();
}

判断工作日

java
public static boolean isWorkday(LocalDate date) {
    DayOfWeek dayOfWeek = date.getDayOfWeek();
    return dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY;
}

计算两个日期之间的工作日

java
public static long countWorkdays(LocalDate start, LocalDate end) {
    return start.datesUntil(end)
        .filter(d -> !d.getDayOfWeek().equals(DayOfWeek.SATURDAY) 
                  && !d.getDayOfWeek().equals(DayOfWeek.SUNDAY))
        .count();
}

时间范围判断

java
public static boolean isInTimeRange(LocalTime time, LocalTime start, LocalTime end) {
    return !time.isBefore(start) && !time.isAfter(end);
}