JDK8之前的日期时间API
获取当前时间的时间戳,单位毫秒
java.lang.System
类。
这个方法适于计算时间差。
// 获取当前时间与UTC 1970年1月1日午夜之间以毫秒为单位的差值。
long current = System.currentTimeMillis();
System.out.println(current); // 1677388934234
获取日期时间
java.util.Date
类。
常用的就这几个方法,其它的方法基本都被废弃了。
// 获取当前日期和时间
Date date = new Date();
// 根据毫秒时间戳获取日期和时间
Date date1 = new Date(1677388934234L);
// 获取毫秒时间戳
long time = date1.getTime();
// 使用默认的格式打印时间
System.out.println(date1); // Sun Feb 26 13:22:14 CST 2023
System.out.println(time); // 1677388934234
获取时区
java.util.TimeZone
抽象类
// 列出支持的时区 id
String ids[] = TimeZone.getAvailableIDs();
for(String id: ids) {
// 这里记住几个常用的时区id即可,如北京时间使用的 Asia/Shanghai
System.out.println(id); // Africa/Abidjan ... Asia/Shanghai ...
}
// 获取系统默认时区
TimeZone defaultTimeZone = TimeZone.getDefault();
// 根据id获取时区
TimeZone shangHaiTimeZone = TimeZone.getTimeZone("Asia/Shanghai");
System.out.println(defaultTimeZone.equals(shangHaiTimeZone)); // true
// 获取要加到UTC以获得该时区标准时间的时间量(单位毫秒)。
System.out.println(shangHaiTimeZone.getRawOffset()); // 28800000,即8小时
时区的打印结果(System.out.println(defaultTimeZone);):sun.util.calendar.ZoneInfo[id=“Asia/Shanghai”,offset=28800000,dstSavings=0,useDaylight=false,transitions=19,lastRule=null]
计算本地时间当天零点的时间戳
// 一天所对应的毫秒数
private static final int ONE_DAY = 24 * 60 * 60 * 1000;
long current = System.currentTimeMillis();
// 用当前时间戳减去本地时间经过了一天内的时间数,结果单位为毫秒
long timestamp = current - (current + TimeZone.getDefault().getRawOffset()) % ONE_DAY ;
System.out.println(timestamp);
时间格式化和解析
java.text.SimpleDateFormat
类。
格式化时间
// 创建时间格式化器,关于作为构造参数的时间模式说明,可以参考SimpleDateFormat类的api文档
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();
System.out.println("本地时区:" + dateFormat.getTimeZone());
// 格式化时间
System.out.println("本地时间:" + dateFormat.format(date));
// 时间格式化器可以指定时区,从而将时间格式化成不同时区的时间
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("UTC时区:" + dateFormat.getTimeZone());
// 格式化时间
System.out.println("UTC时间:" + dateFormat.format(date));
// 输出///
本地时区:sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=19,lastRule=null]
本地时间:2023-02-26 11:26:20
UTC时区:sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
UTC时间:2023-02-26 03:26:20
解析时间
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateTime = "2023-01-02 12:04:34";
try {
Date dt = dateFormat.parse(dateTime);
System.out.println(dateFormat.format(dt)); // 2023-01-02 12:04:34
} catch (ParseException e) { // 解析时间,可能会因为时间格式不对而抛出异常
e.printStackTrace();
}
日历
java.util.Calendar
抽象类,主用用于完成日期字段之间相互操作的功能 。
// 获取当前时间的日历
Calendar c = Calendar.getInstance();
// 获取各项时间信息
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR); // 获取年份
int month = calendar.get(Calendar.MONTH) + 1; // 获取月份,注意,月份从 0 开始,即返回0表示一月份,1表示二月份...
int day = calendar.get(Calendar.DATE); // 获取月份中的天
int hour = calendar.get(Calendar.HOUR_OF_DAY); // 获取一天中的小时
int minute = calendar.get(Calendar.MINUTE); // 获取分钟
int second = calendar.get(Calendar.SECOND); // 获取秒
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); // 获取星期几,1为周日,2为周一...
// 2023-3-2 12:25:11
System.out.println(year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second);
// 设置时区,此时再获取的年月日时分秒就是设置的时区所对应的时间
TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
// Calendar calendar = Calendar.getInstance(timeZone);
calendar.setTimeZone(timeZone);
// 从一个 Calendar 对象中获取 Date 对象
Date date = calendar.getTime();
// 使用给定的 Date 设置此 Calendar 的时间
date = new Date(1677730620226L);
calendar.setTime(date);
calendar.set(Calendar.DAY_OF_MONTH, 8);
System.out.println("当前日期设置为 8 后,时间是:" + calendar.getTime());
calendar.add(Calendar.HOUR, 2);
System.out.println("当前时间加 2 小时后,时间是:" + calendar.getTime());
calendar.add(Calendar.MONTH, -2);
System.out.println("当前日期减 2 个月后,时间是:" + calendar.getTime());
注意:通过get()方法获取的各项时间信息,没有前置0。
这些接口面临的问题
• 可变性:像日期和时间这样的类应该是不可变的。
• 偏移性: Date 中的年份是从 1900 开始的,而月份都从 0 开始。
• 格式化:格式化只对 Date 有用, Calendar 则不行。
• 此外, 它们也不是线程安全的;不能处理闰秒等。
JDK8新的日期时间 API
本地日期时间
java.time.LocalDate
:本地日期
java.time.LocalTime
:本地时间
java.time.LocalDateTime
:本地日期和时间
这些对象都不带任何与时区相关的信息
// 通过静态的now()/now(ZoneId zone)方法创建当前日期/时间对象
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
LocalDateTime dateTime = LocalDateTime.now();
// 通过 of(xx, xx, xx...) 方法,根据指定的日期/时间创建对象
date = LocalDate.of(2023, 2, 1);
time = LocalTime.of(12, 15, 4);
dateTime = LocalDateTime.of(date, time);
// 通过getXXX()方法,获取年月日时分秒 星期几
System.out.println(dateTime.getYear()); // 2023
System.out.println(dateTime.getMonthValue()); // 2
System.out.println(dateTime.getMonth()); // 返回一个枚举, FEBRUARY
System.out.println(dateTime.getDayOfMonth()); // 1
System.out.println(dateTime.getDayOfYear()); // 32
System.out.println(dateTime.getDayOfWeek()); // 返回一个枚举, WEDNESDAY
System.out.println(dateTime.getHour()); // 12
System.out.println(dateTime.getMinute()); // 15
System.out.println(dateTime.getSecond()); // 4
// 使用TemporalField读取值
// int year = date.get(ChronoField.YEAR);
// 通过withXXX()方法,修改年月日时分秒为指定值,并返回新的对象
System.out.println(dateTime.withYear(2022)); // 2022-02-01T12:15:04
// 通过plusXXX()方法,将年月日时分秒加上指定值,并返回新的对象,参数可为负数
System.out.println(dateTime.plusDays(1));
System.out.println(dateTime.plusDays(-1));
// 通过minusXXX()方法,将年月日时分秒减去指定值,并返回新的对象,参数可为负数
System.out.println(dateTime.minusDays(1));
System.out.println(dateTime.minusDays(-1));
// 格式化输出,返回一个字符串
System.out.println(dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH")));
// 解析字符串,生成本地日期时间对象
LocalDateTime localDateTime = LocalDateTime.parse("2023-01-02 13", DateTimeFormatter.ofPattern("yyyy-MM-dd HH"));
// isXXX() 比较两个日期时间
System.out.println(dateTime.isBefore(dateTime));
瞬时
java.time.Instant
类。
表示时间线上的一点,而不需要任何上下文信息,例如,时区。概念上讲, 它只是简单的表示自 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC)开始的秒数。
// 静态方法,返回默认 UTC 时区的 Instant 类的对象
Instant now = Instant.now(); // 获取当前时刻的时间戳
System.out.println(now); // 直接打印,得到的是UTC时间,2023-03-02T08:35:55.119Z
// 静态方法,返回在 1970-01-01 00:00:00 基础上加上指定毫秒数之后的 Instant 类的对象
Instant instant = Instant.ofEpochMilli(1); // 通过毫秒数创建瞬时
instant = Instant.ofEpochSecond(1); // 通过秒数创建瞬时
System.out.println(instant); // 1970-01-01T00:00:01.000Z
// 获取秒级时间戳
System.out.println(now.getEpochSecond()); // 1677747902
// 获取毫秒级时间戳
System.out.println(now.toEpochMilli()); // 1677747902707
持续日期/时间
java.time.Duration
:持续时间,用于计算两个“时间”间隔,如 两个LocalTimes对象、两个LocalDateTimes对象,或者两个Instant对象之间的 duration
java.time.Period
:日期间隔,用于计算两个“日期”间隔,如两个LocalDate对象
LocalDate t1 = LocalDate.now();
LocalDate t2 = LocalDate.of(2018, 12, 31);
Period between = Period.between(t1, t2);
System.out.println(between);
System.out.println("相差的年数: "+between.getYears());
System.out.println("相差的月数: "+between.getMonths());
System.out.println("相差的天数: "+between.getDays());
System.out.println("相差的总月数: "+between.toTotalMonths());
LocalDateTime t1 = LocalDateTime.now();
LocalDateTime t2 = LocalDateTime.of(2017, 8, 29, 0, 0, 0, 0);
Duration between = Duration.between(t1, t2);
System.out.println(between);
System.out.println("相差的总天数: "+between.toDays());
System.out.println("相差的总小时数: "+between.toHours());
System.out.println("相差的总分钟数: "+between.toMinutes());
System.out.println("相差的总秒数: "+between.getSeconds());
System.out.println("相差的总毫秒数: "+between.toMillis());
System.out.println("相差的总纳秒数: "+between.toNanos());
System.out.println("不够一秒的纳秒数: "+between.getNano());
时间调整器
java.time.temporal.TemporalAdjuster
接口,java.time.temporal.TemporalAdjusters
类提供了该接口的常用实现。
TemporalAdjuster
用来对日期进行一些更加复杂的操作,比如,将日期调整到下个周日、下个工作日,或者是本月的最后一天。
LocalDate date1 = LocalDate.of(2014, 3, 18);
// 下一个星期日
LocalDate date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY)); // 2014-03-23
// 本月的最后一天
LocalDate date3 = date2.with(lastDayOfMonth()); // 2014-03-31
TemporalAdjusters
类中的工厂方法
方 法 名 | 描 述 |
---|---|
dayOfWeekInMonth | 创建一个新的日期,它的值为同一个月中每一周的第几天 |
firstDayOfMonth | 创建一个新的日期,它的值为当月的第一天 |
firstDayOfNextMonth | 创建一个新的日期,它的值为下月的第一天 |
firstDayOfNextYear | 创建一个新的日期,它的值为明年的第一天 |
firstDayOfYear | 创建一个新的日期,它的值为当年的第一天 |
firstInMonth | 创建一个新的日期,它的值为同一个月中,第一个符合星期几要求的值 |
lastDayOfMonth | 创建一个新的日期,它的值为当月的最后一天 |
lastDayOfNextMonth | 创建一个新的日期,它的值为下月的最后一天 |
lastDayOfNextYear | 创建一个新的日期,它的值为明年的最后一天 |
lastDayOfYear | 创建一个新的日期,它的值为今年的最后一天 |
lastInMonth | 创建一个新的日期,它的值为同一个月中,最后一个符合星期几要求的值 |
next/previous | 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期 |
nextOrSame/previousOrSame | 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期,如果该日期已经符合要求,直接返回该对象 |
指定时区日期时间
java.time.ZoneId
抽象类,包含时区信息;
java.time.ZonedDateTime
类,包含时区的日期时间;
ZonedDateTime t1 = ZonedDateTime.now();
System.out.println(t1); // 2023-03-02T20:55:34.279+08:00[Asia/Shanghai]
ZonedDateTime t2 = ZonedDateTime.now(ZoneId.of("America/New_York"));
System.out.println(t2); // 2023-03-02T07:55:34.280-05:00[America/New_York]
转换
// 本地日期时间转时间戳
System.out.println(LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).getEpochSecond()); // 秒级
System.out.println(LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli()); // 毫秒级