|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +categories: [Java] |
| 4 | +description: none |
| 5 | +keywords: Java |
| 6 | +--- |
| 7 | +# Java时间Instant |
| 8 | +Java Instant 是一个日期和时间相关的类,它表示时间轴上的一个点,精确到纳秒。 在 Java 8 中引入了 Instant 类,可以方便地进行时间戳的操作和转换。 |
| 9 | + |
| 10 | +## 时间戳 |
| 11 | +在JAVA8之前的版本,去获取时间戳(毫秒级别)常用的办法有两种 |
| 12 | +``` |
| 13 | +// 方法一:构建日期Date类然后调用getTime方法 |
| 14 | +Date date = new Date(); |
| 15 | +System.out.println(date.getTime()); |
| 16 | + |
| 17 | +// 方法二:使用System类静态方法获取 |
| 18 | +System.out.println(System.currentTimeMillis()); |
| 19 | +``` |
| 20 | +由于Date类大部分方法已经废弃,而且上面两种方法的时间戳只能精确到毫秒级别,所以我们有必要了解下jdk1.8推出的Instant类,该类可以将时间戳精确到纳秒级别。 |
| 21 | + |
| 22 | +## Instant类 |
| 23 | +时间点 该类对象表示的是时间线上的一点,这个时间点存在标准的UTC时间,注意这个时间并不是指北京时间或东京时间而是指世界时间。 |
| 24 | +``` |
| 25 | +// 获取当前时间 2022-09-26T03:12:58.517Z(比当地时间相差8个小时) |
| 26 | +System.out.println(Instant.now()); |
| 27 | + |
| 28 | +// 获取系统默认时间戳 2022-09-26T11:12:58.517+08:00[Asia/Shanghai] |
| 29 | +System.out.println(Instant.now().atZone(ZoneId.systemDefault())); |
| 30 | +``` |
| 31 | + |
| 32 | +在Instant时间线上存在三个重要的点位,最大点、最小点、原点也就是说小于1970-01-01的时间戳就为负数,超过1970-01-01的时间戳就为正数 |
| 33 | +``` |
| 34 | +// 时间线上最大点 +1000000000-12-31T23:59:59.999999999Z |
| 35 | +System.out.println(Instant.MAX); |
| 36 | +
|
| 37 | +// 时间线上最小点 -1000000000-01-01T00:00:00Z |
| 38 | +System.out.println(Instant.MIN); |
| 39 | +
|
| 40 | +// 时间线上原点 1970-01-01T00:00:00Z |
| 41 | +System.out.println(Instant.EPOCH); |
| 42 | +
|
| 43 | +// 输出结果为-8369623 |
| 44 | +System.out.println(Instant.parse("1969-09-26T03:06:17.323Z").getEpochSecond()); |
| 45 | +
|
| 46 | +``` |
| 47 | + |
| 48 | +## 时间表示 |
| 49 | +在Instant中采用两个字段表示时间戳 |
| 50 | +``` |
| 51 | +/** |
| 52 | + * The number of seconds from the epoch of 1970-01-01T00:00:00Z. |
| 53 | + * 该字段表示Instant时间距离原点1970-01-01T00:00:00Z的时间(单位秒) |
| 54 | + */ |
| 55 | +private final long seconds; |
| 56 | +/** |
| 57 | + * The number of nanoseconds, later along the time-line, from the seconds field. |
| 58 | + * This is always positive, and never exceeds 999,999,999. |
| 59 | + * 该字段表示Instant当前时间的纳秒数这个值不会超过999,999,999,因为1秒=1000_000_000纳秒 |
| 60 | + */ |
| 61 | +private final int nanos; |
| 62 | +
|
| 63 | +``` |
| 64 | + |
| 65 | +## Instant实例化 |
| 66 | +普通实例化分为如下几种 |
| 67 | + |
| 68 | +- 使用 now() 方法获取当前时间的 Instant 对象 |
| 69 | +``` |
| 70 | +// 获取当前时间 |
| 71 | +Instant instant = Instant.now(); |
| 72 | +``` |
| 73 | + |
| 74 | +- 通过 ofEpochSecond() 或 ofEpochMilli() 方法从时间戳创建 Instant 对象 |
| 75 | +``` |
| 76 | +// 构建毫秒级Instant对象,同样从时间1970-01-01T00:00:00Z开始计算(距离原点5000毫秒) |
| 77 | +Instant instantFromSeconds = Instant.ofEpochSecond(1684216800); |
| 78 | +Instant instantFromMillis = Instant.ofEpochMilli(1684216800000L); |
| 79 | +``` |
| 80 | + |
| 81 | +- 通过解析字符串创建 Instant 对象 |
| 82 | +``` |
| 83 | +// 字符串转Instant |
| 84 | +Instant instantFromString = Instant.parse("2022-05-16T12:34:56.789Z"); |
| 85 | +``` |
| 86 | + |
| 87 | +- 还有一种特殊的如下,可以构建纳秒级的Instant对象 |
| 88 | +``` |
| 89 | +// 构建纳秒级Instant对象,同样从时间1970-01-01T00:00:00Z开始计算 |
| 90 | +// 参数:epochSecond(秒),nanoAdjustment(纳秒) |
| 91 | +// 结果为:1970-01-01T00:00:05.000001111Z |
| 92 | +Instant instant5 = Instant.ofEpochSecond(5, 1111); |
| 93 | +``` |
| 94 | + |
| 95 | +不过我们需要注意Instant.ofEpochSecond方法的源码,如下 |
| 96 | +``` |
| 97 | +static final long NANOS_PER_SECOND = 1000_000_000L; |
| 98 | +/** |
| 99 | + * @param epochSecond 秒从1970-01-01T00:00:00Z开始计算 |
| 100 | + * @param nanoAdjustment 纳秒 |
| 101 | + */ |
| 102 | +public static Instant ofEpochSecond(long epochSecond, long nanoAdjustment) { |
| 103 | + // Math.floorDiv是除法运算,返回小于或等于商的整数 Math.floorDiv(25, 3)=8 |
| 104 | + // Math.addExact加法运算,Math.addExact(1, 2)=3 |
| 105 | + long secs = Math.addExact(epochSecond, Math.floorDiv(nanoAdjustment, NANOS_PER_SECOND)); |
| 106 | + // Math.floorMod是模运算,Math.floorMod(9, 20)=9 |
| 107 | + int nos = (int)Math.floorMod(nanoAdjustment, NANOS_PER_SECOND); |
| 108 | + return create(secs, nos); |
| 109 | +} |
| 110 | +``` |
| 111 | + |
| 112 | +可以使用 toString() 方法将 Instant 对象格式化为 ISO 8601 格式的字符串。 |
| 113 | +``` |
| 114 | +System.out.println(now.toString()); // 输出:2022-05-16T12:34:56.789Z |
| 115 | +``` |
| 116 | +## Instant获取参数 |
| 117 | +``` |
| 118 | +Instant instant = Instant.now(); |
| 119 | +// 时区相差8小时 2022-09-26T07:04:19.110Z |
| 120 | +System.out.println(instant); |
| 121 | +
|
| 122 | +System.out.println("秒:"+instant.getEpochSecond()); |
| 123 | +
|
| 124 | +System.out.println("毫秒:"+instant.toEpochMilli()); |
| 125 | +// 1毫秒 = 1000 000 纳秒 |
| 126 | +System.out.println("纳秒:"+instant.getNano()); |
| 127 | +
|
| 128 | +``` |
| 129 | + |
| 130 | +## Instant时间点比较 |
| 131 | +由于时间点位于时间线上,所以可以直接进行对比。 |
| 132 | +``` |
| 133 | +Instant instant1 = Instant.parse("2022-09-26T07:04:19.110Z"); |
| 134 | +Instant instant2 = Instant.parse("2022-09-26T07:04:19.110Z"); |
| 135 | +Instant instant3 = Instant.parse("2022-08-26T07:04:19.110Z"); |
| 136 | +
|
| 137 | +// 相等为0 |
| 138 | +System.out.println(instant1.compareTo(instant2)); |
| 139 | +// instant1大于instant3 为1 |
| 140 | +System.out.println(instant1.compareTo(instant3)); |
| 141 | +// instant1小于instant3 为-1 |
| 142 | +System.out.println(instant3.compareTo(instant1)); |
| 143 | +
|
| 144 | +// true |
| 145 | +System.out.println(instant1.isAfter(instant3)); |
| 146 | +// false |
| 147 | +System.out.println(instant1.isBefore(instant3)); |
| 148 | +
|
| 149 | +``` |
| 150 | + |
| 151 | +## Instant时间点运算 |
| 152 | +``` |
| 153 | +Instant instant1 = Instant.parse("2022-09-26T07:04:19.110Z"); |
| 154 | +
|
| 155 | +// 在instant1的基础上增加2秒,值为:2022-09-26T07:04:21.110Z |
| 156 | +System.out.println(instant1.plusSeconds(2)); |
| 157 | +
|
| 158 | +// 在instant1的基础上增加1毫秒,值为:2022-09-26T07:04:19.111Z |
| 159 | +System.out.println(instant1.plusMillis(1)); |
| 160 | +
|
| 161 | +// 在instant1的基础上增加1001纳秒,值为:2022-09-26T07:04:19.110001001Z |
| 162 | +System.out.println(instant1.plusNanos(1001)); |
| 163 | +
|
| 164 | +// 在instant1的基础上增加1秒,值为:2022-09-26T07:04:20.110Z |
| 165 | +// 该值取决于后面指定的单位,可以从ChronoUnit枚举类获取 |
| 166 | +System.out.println(instant1.plus(1, ChronoUnit.SECONDS)); |
| 167 | +
|
| 168 | +// 在instant1的基础上减去1秒,值为:2022-09-26T07:04:18.110Z |
| 169 | +// plus是增加,minus是减少,逻辑类似可以参考上面plus相关A |
| 170 | +System.out.println(instant1.minusSeconds(1)); |
| 171 | +
|
| 172 | +``` |
| 173 | +Instant时间点计算时需要注意,无论是调用plus或者minus相关API都会重新创建新对象。 |
| 174 | + |
| 175 | +## Instant 对象转换 |
| 176 | +还可以将 Instant 对象转换为其他日期时间相关类的对象,例如 LocalDateTime、ZonedDateTime 和 OffsetDateTime。 |
| 177 | +``` |
| 178 | +Instant now = Instant.now(); |
| 179 | +LocalDateTime localDateTime = LocalDateTime.ofInstant(now, ZoneId.systemDefault()); |
| 180 | +ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(now, ZoneId.of("America/New_York")); |
| 181 | +OffsetDateTime offsetDateTime = OffsetDateTime.ofInstant(now, ZoneOffset.ofHours(8)); |
| 182 | +``` |
| 183 | + |
| 184 | + |
| 185 | + |
| 186 | + |
| 187 | + |
| 188 | + |
| 189 | + |
| 190 | + |
| 191 | + |
| 192 | + |
| 193 | + |
| 194 | + |
| 195 | + |
| 196 | + |
| 197 | + |
| 198 | + |
| 199 | + |
| 200 | + |
| 201 | + |
| 202 | + |
| 203 | + |
| 204 | + |
| 205 | + |
| 206 | + |
| 207 | + |
| 208 | + |
| 209 | + |
| 210 | + |
| 211 | + |
| 212 | + |
| 213 | + |
| 214 | + |
| 215 | + |
| 216 | + |
| 217 | + |
| 218 | + |
| 219 | + |
| 220 | + |
| 221 | + |
| 222 | + |
| 223 | + |
| 224 | + |
| 225 | + |
| 226 | + |
| 227 | + |
| 228 | + |
| 229 | + |
| 230 | + |
| 231 | + |
| 232 | + |
| 233 | + |
0 commit comments