Java中日期时间操作

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()); // 毫秒级
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值