Java时间戳与日期类详解
1. 时间戳 (Timestamp)
什么是时间戳
时间戳是指从1970年1月1日00:00:00 GMT开始到现在的总毫秒数,也称为Unix时间戳。
获取时间戳的方法
// 方法1: System.currentTimeMillis() - 最常用
long timestamp1 = System.currentTimeMillis();
System.out.println("当前时间戳: " + timestamp1);
// 方法2: java.util.Date
long timestamp2 = new Date().getTime();
System.out.println("Date获取时间戳: " + timestamp2);
// 方法3: java.util.Calendar
Calendar calendar = Calendar.getInstance();
long timestamp3 = calendar.getTimeInMillis();
System.out.println("Calendar获取时间戳: " + timestamp3);
// 方法4: java.time.Instant (Java 8+)
Instant instant = Instant.now();
long timestamp4 = instant.toEpochMilli();
System.out.println("Instant获取时间戳: " + timestamp4);
时间戳与日期转换
// 时间戳转日期
long timestamp = 1698765432100L;
// 转换为java.util.Date
Date dateFromTimestamp = new Date(timestamp);
// 转换为java.time.LocalDateTime (Java 8+)
LocalDateTime localDateTime = Instant.ofEpochMilli(timestamp)
.atZone(ZoneId.systemDefault())
.toLocalDateTime();
// 日期转时间戳
Date date = new Date();
long timestampFromDate = date.getTime();
2. 传统日期类 (Java 8之前)
java.util.Date
import java.util.Date;
// 创建Date对象
Date now = new Date(); // 当前时间
Date specificDate = new Date(1698765432100L); // 指定时间戳
// 常用方法
System.out.println("当前时间: " + now);
System.out.println("时间戳: " + now.getTime());
System.out.println("比较时间: " + now.after(specificDate)); // 是否在指定时间之后
System.out.println("比较时间: " + now.before(specificDate)); // 是否在指定时间之前
// 设置时间
now.setTime(1698765432100L);
java.util.Calendar
import java.util.Calendar;
// 获取Calendar实例
Calendar calendar = Calendar.getInstance();
// 常用字段常量
System.out.println("年: " + calendar.get(Calendar.YEAR));
System.out.println("月: " + (calendar.get(Calendar.MONTH) + 1)); // 月份从0开始
System.out.println("日: " + calendar.get(Calendar.DAY_OF_MONTH));
System.out.println("时: " + calendar.get(Calendar.HOUR_OF_DAY));
System.out.println("分: " + calendar.get(Calendar.MINUTE));
System.out.println("秒: " + calendar.get(Calendar.SECOND));
// 设置日期时间
calendar.set(2023, Calendar.NOVEMBER, 1, 10, 30, 0); // 2023年11月1日 10:30:00
// 日期计算
calendar.add(Calendar.DAY_OF_MONTH, 5); // 加5天
calendar.add(Calendar.MONTH, -1); // 减1个月
// 获取Date对象
Date dateFromCalendar = calendar.getTime();
SimpleDateFormat - 日期格式化
import java.text.SimpleDateFormat;
import java.util.Date;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 日期转字符串
String dateString = sdf.format(new Date());
System.out.println("格式化日期: " + dateString);
// 字符串转日期
try {
String dateStr = "2023-11-01 10:30:00";
Date parsedDate = sdf.parse(dateStr);
System.out.println("解析后的日期: " + parsedDate);
} catch (Exception e) {
e.printStackTrace();
}
// 常用格式模式
SimpleDateFormat[] formats = {
new SimpleDateFormat("yyyy-MM-dd"), // 2023-11-01
new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"), // 2023/11/01 10:30:00
new SimpleDateFormat("yyyy年MM月dd日"), // 2023年11月01日
new SimpleDateFormat("EEE, MMM d, ''yy") // 周三, 11月 1, '23
};
3. Java 8日期时间API (java.time包)
LocalDate - 日期
import java.time.LocalDate;
import java.time.DayOfWeek;
import java.time.Month;
// 创建LocalDate
LocalDate today = LocalDate.now();
LocalDate specificDate = LocalDate.of(2023, 11, 1);
LocalDate parsedDate = LocalDate.parse("2023-11-01");
// 常用方法
System.out.println("当前日期: " + today);
System.out.println("年: " + today.getYear());
System.out.println("月: " + today.getMonth() + " (" + today.getMonthValue() + ")");
System.out.println("日: " + today.getDayOfMonth());
System.out.println("星期: " + today.getDayOfWeek());
System.out.println("是否闰年: " + today.isLeapYear());
System.out.println("当月天数: " + today.lengthOfMonth());
System.out.println("当年天数: " + today.lengthOfYear());
// 日期计算
LocalDate tomorrow = today.plusDays(1);
LocalDate nextWeek = today.plusWeeks(1);
LocalDate nextMonth = today.plusMonths(1);
LocalDate nextYear = today.plusYears(1);
LocalDate yesterday = today.minusDays(1);
// 日期比较
System.out.println("是否在今天之后: " + tomorrow.isAfter(today));
System.out.println("是否在今天之前: " + yesterday.isBefore(today));
System.out.println("是否相等: " + today.equals(today));
LocalTime - 时间
import java.time.LocalTime;
// 创建LocalTime
LocalTime now = LocalTime.now();
LocalTime specificTime = LocalTime.of(10, 30, 45); // 10:30:45
LocalTime parsedTime = LocalTime.parse("10:30:45");
// 常用方法
System.out.println("当前时间: " + now);
System.out.println("时: " + now.getHour());
System.out.println("分: " + now.getMinute());
System.out.println("秒: " + now.getSecond());
System.out.println("纳秒: " + now.getNano());
// 时间计算
LocalTime later = now.plusHours(2).plusMinutes(30);
LocalTime earlier = now.minusHours(1);
// 时间比较
System.out.println("是否在现在之后: " + later.isAfter(now));
LocalDateTime - 日期时间
import java.time.LocalDateTime;
// 创建LocalDateTime
LocalDateTime now = LocalDateTime.now();
LocalDateTime specificDateTime = LocalDateTime.of(2023, 11, 1, 10, 30, 45);
LocalDateTime parsedDateTime = LocalDateTime.parse("2023-11-01T10:30:45");
// 常用方法
System.out.println("当前日期时间: " + now);
System.out.println("年: " + now.getYear());
System.out.println("时: " + now.getHour());
// 与LocalDate和LocalTime转换
LocalDate datePart = now.toLocalDate();
LocalTime timePart = now.toLocalTime();
LocalDateTime fromDateAndTime = LocalDateTime.of(today, now);
// 日期时间计算
LocalDateTime future = now.plusDays(1).plusHours(2);
LocalDateTime past = now.minusMonths(1).minusHours(3);
Instant - 时间戳
import java.time.Instant;
// 创建Instant
Instant now = Instant.now();
Instant specificInstant = Instant.ofEpochMilli(1698765432100L);
// 常用方法
System.out.println("当前时刻: " + now);
System.out.println("时间戳(毫秒): " + now.toEpochMilli());
System.out.println("时间戳(秒): " + now.getEpochSecond());
// 时间计算
Instant later = now.plusSeconds(3600); // 加1小时
Instant earlier = now.minusSeconds(1800); // 减30分钟
DateTimeFormatter - 格式化
import java.time.format.DateTimeFormatter;
import java.time.LocalDateTime;
// 预定义格式化器
DateTimeFormatter isoFormatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
DateTimeFormatter basicFormatter = DateTimeFormatter.BASIC_ISO_DATE;
// 自定义格式化器
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
DateTimeFormatter chineseFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
// 格式化
LocalDateTime now = LocalDateTime.now();
String formatted = now.format(formatter);
System.out.println("格式化结果: " + formatted);
// 解析
LocalDateTime parsed = LocalDateTime.parse("2023-11-01 10:30:00", formatter);
System.out.println("解析结果: " + parsed);
4. 常用工具方法
日期比较和计算
import java.time.temporal.ChronoUnit;
LocalDate date1 = LocalDate.of(2023, 1, 1);
LocalDate date2 = LocalDate.of(2023, 12, 31);
// 计算日期差
long daysBetween = ChronoUnit.DAYS.between(date1, date2);
long monthsBetween = ChronoUnit.MONTHS.between(date1, date2);
long yearsBetween = ChronoUnit.YEARS.between(date1, date2);
System.out.println("相差天数: " + daysBetween);
System.out.println("相差月数: " + monthsBetween);
System.out.println("相差年数: " + yearsBetween);
时区处理
import java.time.ZoneId;
import java.time.ZonedDateTime;
// 时区日期时间
ZonedDateTime beijingTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
ZonedDateTime newYorkTime = ZonedDateTime.now(ZoneId.of("America/New_York"));
System.out.println("北京时间: " + beijingTime);
System.out.println("纽约时间: " + newYorkTime);
// 时区转换
ZonedDateTime convertedTime = beijingTime.withZoneSameInstant(ZoneId.of("UTC"));
System.out.println("UTC时间: " + convertedTime);
5. 最佳实践
- 推荐使用Java 8的日期时间API,它更清晰、线程安全且功能更强大
- 避免使用已过时的构造方法,如
Date
的年份从1900开始计算 - 注意时区问题,明确业务需求的时区
- 使用不可变对象,Java 8的日期时间类都是不可变的,更安全
- 合理选择日期类:
- 只需要日期:
LocalDate
- 只需要时间:
LocalTime
- 需要日期时间:
LocalDateTime
- 需要时间戳:
Instant
- 需要时区:
ZonedDateTime
- 只需要日期:
这些类和方法覆盖了Java中处理日期时间的常见需求,根据具体场景选择合适的类和方法即可。
日历类 - Calendar
基本使用
import java.util.Calendar;
import java.util.Date;
public class CalendarExample {
public static void main(String[] args) {
// 获取Calendar实例
Calendar calendar = Calendar.getInstance();
// 获取各个字段的值
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1; // 月份从0开始
int day = calendar.get(Calendar.DAY_OF_MONTH);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
System.out.printf("当前时间: %d年%d月%d日 %d时%d分%d秒\n",
year, month, day, hour, minute, second);
// 设置特定时间
calendar.set(2024, Calendar.JANUARY, 15, 14, 30, 0);
Date specificDate = calendar.getTime();
System.out.println("设置的特定时间: " + specificDate);
// 日期计算
calendar.add(Calendar.DAY_OF_MONTH, 7); // 加7天
System.out.println("7天后: " + calendar.getTime());
calendar.add(Calendar.MONTH, -1); // 减1个月
System.out.println("1个月前: " + calendar.getTime());
}
}
日历操作示例
import java.util.Calendar;
public class CalendarOperations {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
// 获取月份的第一天和最后一天
cal.set(Calendar.DAY_OF_MONTH, 1);
System.out.println("本月第一天: " + cal.getTime());
int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_MONTH, lastDay);
System.out.println("本月最后一天: " + cal.getTime());
// 获取星期几
String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK) - 1;
if (dayOfWeek < 0) dayOfWeek = 0;
System.out.println("今天是: " + weekDays[dayOfWeek]);
// 计算两个日期之间的天数差
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal2.add(Calendar.DAY_OF_MONTH, 10);
long diff = cal2.getTimeInMillis() - cal1.getTimeInMillis();
long days = diff / (1000 * 60 * 60 * 24);
System.out.println("相差天数: " + days);
}
}
3. 新的时间API (Java 8+)
Instant - 时间戳
import java.time.Instant;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
public class InstantExample {
public static void main(String[] args) {
// 获取当前时间戳
Instant instant = Instant.now();
System.out.println("当前时间戳: " + instant);
System.out.println("时间戳(毫秒): " + instant.toEpochMilli());
System.out.println("时间戳(秒): " + instant.getEpochSecond());
// 从时间戳创建
Instant specificInstant = Instant.ofEpochMilli(1705296000000L);
System.out.println("特定时间戳: " + specificInstant);
// 时间计算
Instant later = instant.plus(Duration.ofHours(2));
System.out.println("2小时后: " + later);
// 与LocalDateTime转换
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
System.out.println("转换为LocalDateTime: " + localDateTime);
}
}
LocalDateTime 和 ZonedDateTime
import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
public class NewDateTimeAPI {
public static void main(String[] args) {
// LocalDate, LocalTime, LocalDateTime
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
LocalDateTime dateTime = LocalDateTime.now();
System.out.println("当前日期: " + date);
System.out.println("当前时间: " + time);
System.out.println("当前日期时间: " + dateTime);
// 创建特定时间
LocalDateTime specificDateTime = LocalDateTime.of(2024, 1, 15, 14, 30, 0);
System.out.println("特定时间: " + specificDateTime);
// 时区时间
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println("上海时区时间: " + zonedDateTime);
// 格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = dateTime.format(formatter);
System.out.println("格式化时间: " + formatted);
// 解析
LocalDateTime parsed = LocalDateTime.parse("2024-01-15 14:30:00", formatter);
System.out.println("解析的时间: " + parsed);
}
}
日期计算和比较
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.time.Period;
import java.time.Duration;
public class DateTimeCalculations {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1);
LocalDate nextWeek = today.plusWeeks(1);
LocalDate nextMonth = today.plusMonths(1);
System.out.println("今天: " + today);
System.out.println("明天: " + tomorrow);
System.out.println("下周: " + nextWeek);
System.out.println("下月: " + nextMonth);
// 日期比较
System.out.println("今天在明天之前: " + today.isBefore(tomorrow));
System.out.println("今天是闰年: " + today.isLeapYear());
// 计算日期间隔
long daysBetween = ChronoUnit.DAYS.between(today, nextWeek);
System.out.println("今天到下周的天数差: " + daysBetween);
Period period = Period.between(today, nextMonth);
System.out.printf("时间间隔: %d年%d个月%d天\n",
period.getYears(), period.getMonths(), period.getDays());
// 时间间隔计算
LocalDateTime start = LocalDateTime.now();
LocalDateTime end = start.plusHours(2).plusMinutes(30);
Duration duration = Duration.between(start, end);
System.out.println("时间间隔(小时): " + duration.toHours());
System.out.println("时间间隔(分钟): " + duration.toMinutes());
}
}
4. 新旧API转换
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.Calendar;
public class APIConversion {
public static void main(String[] args) {
// Date 转 Instant
Date date = new Date();
Instant instant = date.toInstant();
System.out.println("Date -> Instant: " + instant);
// Instant 转 Date
Date fromInstant = Date.from(instant);
System.out.println("Instant -> Date: " + fromInstant);
// Calendar 转 Instant
Calendar calendar = Calendar.getInstance();
Instant fromCalendar = calendar.toInstant();
System.out.println("Calendar -> Instant: " + fromCalendar);
// LocalDateTime 转 Date
LocalDateTime localDateTime = LocalDateTime.now();
Instant localToInstant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
Date fromLocal = Date.from(localToInstant);
System.out.println("LocalDateTime -> Date: " + fromLocal);
// Date 转 LocalDateTime
LocalDateTime fromDate = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
System.out.println("Date -> LocalDateTime: " + fromDate);
}
}
总结
-
传统API (
Date
,Calendar
):- 存在于
java.util
包 - 线程不安全
- API设计不够友好
- 存在于
-
新时间API (Java 8+):
- 存在于
java.time
包 - 线程安全
- API设计更直观易用
- 推荐在新项目中使用
- 存在于