据说爱因斯坦通过研究时间发现了E=MC2
向爱坦大神学习,本人希望通过研究时间能讨口饭吃
也向编程大神们学习,希望能从他们的编程思路中获得启发
时钟提供time-zone访问instant,date和time。
此类的实例用于查找当前的instant,可以使用存储的时区对其进行解释以查找当前日期和时间。因此,可以使用Clock代替System.currentTimeMillis()和TimeZone.getDefault() 。
时钟的使用是可选的。所有关键日期时间类还具有now()工厂方法,该方法在默认时区使用系统时钟。此抽象的主要目的是允许在需要时插入备用时钟。应用程序使用对象而不是静态方法来获取当前时间。这样可以简化测试。
应用程序的最佳实践是将Clock传递到需要当前时刻的任何方法中。依赖项注入框架是实现此目标的一种方法:
* public class MyBean {
* private Clock clock; // dependency inject
* ...
* public void process(LocalDate eventDate) {
* if (eventDate.isBefore(LocalDate.now(clock)) {
* ...
* }
* }
* }
这种方法允许在测试过程中使用备用时钟,例如固定时钟或偏移时钟。
系统工厂方法基于最佳可用系统时钟提供时钟。该系统时钟可以使用System.currentTimeMillis(),或者使用更高分辨率的时钟(如果有)。
从java1.8开始引入
必须谨慎实施此抽象类,以确保其他类正确运行。所有可实例化的实现都必须是最终的,不可变的且是线程安全的。
定义了主要方法以允许抛出异常。在正常使用中,不会抛出异常,但是一种可能的实现方式是从网络中的中央时间服务器获取时间。显然,在这种情况下,查找可能会失败,因此允许该方法引发异常。
从“时钟”返回的瞬间按忽略“ leap秒”的时间范围工作,如“即时”中所述。如果该实现包装了提供leap秒信息的源,则应使用一种机制来“平滑” the秒。JavaTime-Scale强制使用UTC-SLS,但是时钟实现可能会选择它们在时间上的准确性。只要它们记录了工作原理,就可以进行扩展。因此不需要实际执行UTC-SLS摆率就可以实现,也不必知道leap秒。
实现应尽可能实现Serializable,并且必须记录它们是否支持序列化。
注意:此处提供的时钟实现基于与System.currentTimeMillis()相同的基础时钟,但是精度可能会比毫秒(如果可用)还好。但是,几乎不能保证底层时钟的准确性。需要更精确时钟的应用程序必须使用其他外部时钟(例如,NTP服务器)自己实现此抽象类。
public abstract class Clock
分别是
SystemClock FixedClock OffsetClock TickClock
可以发现它们的成员变量并不相同, 从成员变量可推断它们各自的用途
Clock的成员变量都是final不可变的
/**
* Implementation of a clock that always returns the latest time from
* {@link System#currentTimeMillis()}.
*/
static final class SystemClock extends Clock implements Serializable {
SystemClock 成员变量
private static final long OFFSET_SEED =
System.currentTimeMillis()/1000 - 1024; // initial offest
static final SystemClock UTC = new SystemClock(ZoneOffset.UTC);
private final ZoneId zone;
// We don't actually need a volatile here.
// We don't care if offset is set or read concurrently by multiple
// threads - we just need a value which is 'recent enough' - in other
// words something that has been updated at least once in the last
// 2^32 secs (~136 years). And even if we by chance see an invalid
// offset, the worst that can happen is that we will get a -1 value
// from getNanoTimeAdjustment, forcing us to update the offset
// once again.
private transient long offset;
可看出SystemClock就是系统UTC+系统时区
/**
* Implementation of a clock that always returns the same instant.
* This is typically used for testing.
*/
static final class FixedClock extends Clock implements Serializable {
FixedClock成员变量
private final Instant instant;
private final ZoneId zone;
可看出FixedClock就是Instant+ZoneId(UTC时刻+时区)
/**
* Implementation of a clock that adds an offset to an underlying clock.
*/
static final class OffsetClock extends Clock implements Serializable {
OffsetClock成员变量
private final Clock baseClock;
private final Duration offset;
/**
* Implementation of a clock that adds an offset to an underlying clock.
*/
static final class TickClock extends Clock implements Serializable {
TickClock成员变量
private final Clock baseClock;
private final long tickNanos;
从getZone()和instant()方法可以得知,Clock同时具有时间和时区的属性,虽然未必是成员变量
/**
* Gets the time-zone being used to create dates and times.
*
* A clock will typically obtain the current instant and then convert that
* to a date or time using a time-zone. This method returns the time-zone used.
*
* @return the time-zone being used to interpret instants, not null
*/
public abstract ZoneId getZone();
/**
* Returns a copy of this clock with a different time-zone.
*
* A clock will typically obtain the current instant and then convert that
* to a date or time using a time-zone. This method returns a clock with
* similar properties but using a different time-zone.
*
* @param zone the time-zone to change to, not null
* @return a clock based on this clock with the specified time-zone, not null
*/
public abstract Clock withZone(ZoneId zone);
public long millis() {
return instant().toEpochMilli();
}
/**
* Gets the current instant of the clock.
*
* This returns an instant representing the current instant as defined by the clock.
*
* @return the current instant from this clock, not null
* @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
*/
public abstract Instant instant();
时间线上的瞬时点。
此类在时间轴上为单个瞬时点建模,可用于记录应用程序中的事件时间戳。
瞬时范围需要存储大于整数的数字,为实现此目的,该类存储了一个long表示纪元秒和一个int代表纳秒数,该整数始终在0到999,999,999之间。 -秒是从1970-01-01T00:00:00Z的标准Java纪元开始测量的,该纪元之后的时刻具有正值,而较早的时刻具有负值。在时间轴上比一个较小的值。
时间尺度
太阳日的长短是人类测量时间的标准方法。传统上,太阳日的长短可细分为60小时的60分钟的24小时,即第二天的86400。
现代计时基于原子钟,该原子钟精确地定义了相对于铯原子跃迁第二的SI。 SI秒的长度被定义为非常接近一天的第86400个分数。
不幸的是,随着地球旋转,一天的长度会有所不同。此外,随着时间的推移,随着地球的变慢,一天的平均长度会变长,因此,2012年太阳日的长度略长于86400 SI给定日期的实际长度和地球变慢的量是无法预测的,只能通过测量来确定.UT1时标可以捕获准确的一天长度,但仅在一天完成后的某个时间可用。
UTC时间尺度是将UT1的所有额外秒数捆绑成整秒(称为leap秒)的一种标准方法,根据地球的自转变化可以添加或删除leap秒。允许一天有86399 SI秒或86401 SI秒,以使一天与太阳对齐。
现代UTC时标于1972年引入,引入了整个leap秒的概念.1958年至1972年之间,UTC的定义很复杂,次秒级的跳跃和变化都达到了概念秒的长度。截至2012年,正在讨论再次更改UTC的定义,并可能删除leap秒或引发其他更改。
考虑到上述精确计时的复杂性,此Java API定义了自己的时间标度,即Java时间标度。
Java时间刻度将每个日历日精确划分为86400个细分,称为秒。这些秒可能与SI秒不同。它与事实上的国际民用时标紧密匹配,其定义会不时变化。
Java Time-Scale对时间线的不同段有稍微不同的定义,每个定义都基于用作民用时间基础的国际共识时间标度。每当修改或替换国际商定的时标时,都必须为其定义Java Time-Scale的新闻片段。每个细分市场都必须满足以下要求:
Java时间标度应与基础国际民用时间标度紧密匹配;
•Java时间刻度应每天中午与国际民用时间刻度完全匹配;
•Java时标应与国际民用时标有精确定义的关系。
截至2013年,Java时间范围目前分为两个部分。
对于从1972-11-03到进一步通知的这段时间(下面将讨论确切的边界),共识的国际时间范围是UTC(无跳秒)。在此部分中,Java时间刻度与UTC-SLS相同,在没有a秒的日子中与UTC相同。在具有a秒的日子中,the秒平均分布在最后1000秒内一天的时间,每天保持精确的86400秒的外观。
对于1972-11-03之前的任意段,向后任意延伸,将共识国际时间标度定义为UT1,适用于时间,这等于本初子午线(格林威治)上的(平均)太阳时间。在这一部分中,Java Time-Scale与国际共识的时间尺度相同。这两个段之间的确切边界是UT1 = UTTC在1972-11-03T00:00和1972-11-04T12:00之间的时刻。
不需要使用JSR-310 API来实现Java时标,即可提供亚秒级精度或单调或平滑进行的任何时钟。因此,不需要实际执行UTC-SLS转换或以其他方式意识到秒的实现。但是,JSR-310确实要求实现必须记录它们在定义代表当前时刻的时钟时使用的方法。有关可用时钟的详细信息,请参见“时钟”。
Java时间刻度适用于所有日期时间类,其中包括Instant,LocalDate,LocalTime,OffsetDateTime,ZonedDateTime和Duration。
这是一个基于值的类; 在Instant实例上使用标识敏感的操作(包括引用相等性(==),标识哈希码或同步)可能会产生不可预测的结果,应避免使用equals方法进行比较。
从java1.8开始引入
此类是不可变的并且是线程安全的。
Instant是一个final class , 看到final class舒服啊, 不会有各种衍生体
public final class Instant
implements Temporal, TemporalAdjuster, Comparable<Instant>, Serializable {
/**
* Constant for the 1970-01-01T00:00:00Z epoch instant.
*/
public static final Instant EPOCH = new Instant(0, 0);
可看到实例化方法new Instant(0, 0); Instant本身只保存seconds 和 nanos两个成员变量, 没有时区, 但代表UTC
/**
* The minimum supported {@code Instant}, '-1000000000-01-01T00:00Z'.
* This could be used by an application as a "far past" instant.
*
* This is one year earlier than the minimum {@code LocalDateTime}.
* This provides sufficient values to handle the range of {@code ZoneOffset}
* which affect the instant in addition to the local date-time.
* The value is also chosen such that the value of the year fits in
* an {@code int}.
*/
public static final Instant MIN = Instant.ofEpochSecond(MIN_SECOND, 0);
/**
* The maximum supported {@code Instant}, '1000000000-12-31T23:59:59.999999999Z'.
* This could be used by an application as a "far future" instant.
*
* This is one year later than the maximum {@code LocalDateTime}.
* This provides sufficient values to handle the range of {@code ZoneOffset}
* which affect the instant in addition to the local date-time.
* The value is also chosen such that the value of the year fits in
* an {@code int}.
*/
public static final Instant MAX = Instant.ofEpochSecond(MAX_SECOND, 999_999_999);
可表示1970前后十亿年
/**
* The minimum supported epoch second.
*/
private static final long MIN_SECOND = -31557014167219200L;
/**
* The maximum supported epoch second.
*/
private static final long MAX_SECOND = 31556889864403199L;
/**
* The number of seconds from the epoch of 1970-01-01T00:00:00Z.
*/
private final long seconds;
/**
* The number of nanoseconds, later along the time-line, from the seconds field.
* This is always positive, and never exceeds 999,999,999.
*/
private final int nanos;
可以看出,Instant用秒和纳秒确定时刻, 区分精度为纳秒 , 用final修饰表示不可修改, 这也是它线程安全的原因
private Instant(long epochSecond, int nanos) {
super();
this.seconds = epochSecond;
this.nanos = nanos;
}
系统时间为我国时区2021-04-08T01:29:22 执行下面代码
System.out.println(Instant.now());
结果: 2021-04-07T17:29:22.573585600Z
说明Instant的toString方法返回UTC时间 结尾Z表示UTC
public static Instant now() {
return Clock.systemUTC().instant();
}
调用了 SystemClock 的 instant() 方法
@Override
public Instant instant() {
// Take a local copy of offset. offset can be updated concurrently
// by other threads (even if we haven't made it volatile) so we will
// work with a local copy.
long localOffset = offset;
long adjustment = VM.getNanoTimeAdjustment(localOffset);
if (adjustment == -1) {
// -1 is a sentinel value returned by VM.getNanoTimeAdjustment
// when the offset it is given is too far off the current UTC
// time. In principle, this should not happen unless the
// JVM has run for more than ~136 years (not likely) or
// someone is fiddling with the system time, or the offset is
// by chance at 1ns in the future (very unlikely).
// We can easily recover from all these conditions by bringing
// back the offset in range and retry.
// bring back the offset in range. We use -1024 to make
// it more unlikely to hit the 1ns in the future condition.
localOffset = System.currentTimeMillis()/1000 - 1024;
// retry
adjustment = VM.getNanoTimeAdjustment(localOffset);
if (adjustment == -1) {
// Should not happen: we just recomputed a new offset.
// It should have fixed the issue.
throw new InternalError("Offset " + localOffset + " is not in range");
} else {
// OK - recovery succeeded. Update the offset for the
// next call...
offset = localOffset;
}
}
return Instant.ofEpochSecond(localOffset, adjustment);
}
调用了 Instant 的 ofEpochSecond(long epochSecond, long nanoAdjustment) 静态方法
public static Instant ofEpochSecond(long epochSecond, long nanoAdjustment) {
long secs = Math.addExact(epochSecond, Math.floorDiv(nanoAdjustment, NANOS_PER_SECOND));
int nos = (int)Math.floorMod(nanoAdjustment, NANOS_PER_SECOND);
return create(secs, nos);
}
调用了 Instant 的 create(long seconds, int nanoOfSecond) 私有方法
private static Instant create(long seconds, int nanoOfSecond) {
if ((seconds | nanoOfSecond) == 0) {
return EPOCH;
}
if (seconds < MIN_SECOND || seconds > MAX_SECOND) {
throw new DateTimeException("Instant exceeds minimum or maximum instant");
}
return new Instant(seconds, nanoOfSecond);
}
调用了 Instant 的 private Instant(long epochSecond, int nanos) 方法
public static Instant now(Clock clock) {
Objects.requireNonNull(clock, "clock");
return clock.instant();
}
通过 Clock 的 instant()方法获得Instant实例 , 具体怎么获得, 要看是什么Clock , 然后都是Instant自己的方法 , 最终调用 Instant 的 private Instant(long epochSecond, int nanos) 方法
now(Clock clock)是以当前时间为基础,指定时区或时差偏移,获得Instant实例
/**
* Obtains an instance of {@code Instant} from a text string such as
* {@code 2007-12-03T10:15:30.00Z}.
*
* The string must represent a valid instant in UTC and is parsed using
* {@link DateTimeFormatter#ISO_INSTANT}.
*
* @param text the text to parse, not null
* @return the parsed instant, not null
* @throws DateTimeParseException if the text cannot be parsed
*/
public static Instant parse(final CharSequence text) {
return DateTimeFormatter.ISO_INSTANT.parse(text, Instant::from);
}
使用了 DateTimeFormatter 来进行解析
过程太复杂了…
但看到 DateTimeFormatter 有个现成实例 ISO_INSTANT
私有plus核心方法:
private Instant plus(long secondsToAdd, long nanosToAdd) {
if ((secondsToAdd | nanosToAdd) == 0) {
return this;
}
long epochSec = Math.addExact(seconds, secondsToAdd);
epochSec = Math.addExact(epochSec, nanosToAdd / NANOS_PER_SECOND);
nanosToAdd = nanosToAdd % NANOS_PER_SECOND;
long nanoAdjustment = nanos + nanosToAdd; // safe int+NANOS_PER_SECOND
return ofEpochSecond(epochSec, nanoAdjustment);
}
其它plus最后都会调用这个方法, 但凡有变动都会生成新实例, 实现线程安全
@Override
public Instant plus(TemporalAmount amountToAdd) {
return (Instant) amountToAdd.addTo(this);
}
加 @Override 是因为这个方法扩展自 Temporal 的默认方法
@Override
public Instant plus(long amountToAdd, TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
switch ((ChronoUnit) unit) {
case NANOS: return plusNanos(amountToAdd);
case MICROS: return plus(amountToAdd / 1000_000, (amountToAdd % 1000_000) * 1000);
case MILLIS: return plusMillis(amountToAdd);
case SECONDS: return plusSeconds(amountToAdd);
case MINUTES: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_MINUTE));
case HOURS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_HOUR));
case HALF_DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY / 2));
case DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY));
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.addTo(this, amountToAdd);
}
public Instant plusSeconds(long secondsToAdd) {
return plus(secondsToAdd, 0);
}
public Instant plusMillis(long millisToAdd) {
return plus(millisToAdd / 1000, (millisToAdd % 1000) * 1000_000);
}
毫秒被转换为秒和纳秒
public Instant plusNanos(long nanosToAdd) {
return plus(0, nanosToAdd);
}
minus(数值)方法基本都是取负调用plus方法 但有判断过程
@Override
public Instant minus(TemporalAmount amountToSubtract) {
return (Instant) amountToSubtract.subtractFrom(this);
}
@Override
public Instant minus(long amountToSubtract, TemporalUnit unit) {
return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
}
public Instant minusSeconds(long secondsToSubtract) {
if (secondsToSubtract == Long.MIN_VALUE) {
return plusSeconds(Long.MAX_VALUE).plusSeconds(1);
}
return plusSeconds(-secondsToSubtract);
}
public Instant minusMillis(long millisToSubtract) {
if (millisToSubtract == Long.MIN_VALUE) {
return plusMillis(Long.MAX_VALUE).plusMillis(1);
}
return plusMillis(-millisToSubtract);
}
public Instant minusNanos(long nanosToSubtract) {
if (nanosToSubtract == Long.MIN_VALUE) {
return plusNanos(Long.MAX_VALUE).plusNanos(1);
}
return plusNanos(-nanosToSubtract);
}
@Override
public Instant with(TemporalAdjuster adjuster) {
return (Instant) adjuster.adjustInto(this);
}
@Override
public Instant with(TemporalField field, long newValue) {
if (field instanceof ChronoField) {
ChronoField f = (ChronoField) field;
f.checkValidValue(newValue);
switch (f) {
case MILLI_OF_SECOND: {
int nval = (int) newValue * 1000_000;
return (nval != nanos ? create(seconds, nval) : this);
}
case MICRO_OF_SECOND: {
int nval = (int) newValue * 1000;
return (nval != nanos ? create(seconds, nval) : this);
}
case NANO_OF_SECOND: return (newValue != nanos ? create(seconds, (int) newValue) : this);
case INSTANT_SECONDS: return (newValue != seconds ? create(newValue, nanos) : this);
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.adjustInto(this, newValue);
}
/**
* Gets the number of seconds from the Java epoch of 1970-01-01T00:00:00Z.
*
* The epoch second count is a simple incrementing count of seconds where
* second 0 is 1970-01-01T00:00:00Z.
* The nanosecond part is returned by {@link #getNano}.
*
* @return the seconds from the epoch of 1970-01-01T00:00:00Z
*/
public long getEpochSecond() {
return seconds;
}
/**
* Gets the number of nanoseconds, later along the time-line, from the start
* of the second.
*
* The nanosecond-of-second value measures the total number of nanoseconds from
* the second returned by {@link #getEpochSecond}.
*
* @return the nanoseconds within the second, always positive, never exceeds 999,999,999
*/
public int getNano() {
return nanos;
}
/**
* Converts this instant to the number of milliseconds from the epoch
* of 1970-01-01T00:00:00Z.
*
* If this instant represents a point on the time-line too far in the future
* or past to fit in a {@code long} milliseconds, then an exception is thrown.
*
* If this instant has greater than millisecond precision, then the conversion
* will drop any excess precision information as though the amount in nanoseconds
* was subject to integer division by one million.
*
* @return the number of milliseconds since the epoch of 1970-01-01T00:00:00Z
* @throws ArithmeticException if numeric overflow occurs
*/
public long toEpochMilli() {
if (seconds < 0 && nanos > 0) {
long millis = Math.multiplyExact(seconds+1, 1000);
long adjustment = nanos / 1000_000 - 1000;
return Math.addExact(millis, adjustment);
} else {
long millis = Math.multiplyExact(seconds, 1000);
return Math.addExact(millis, nanos / 1000_000);
}
}
@Override
public int compareTo(Instant otherInstant) {
int cmp = Long.compare(seconds, otherInstant.seconds);
if (cmp != 0) {
return cmp;
}
return nanos - otherInstant.nanos;
}
重写Object的方法 , 先比较秒, 比不出则再比较纳秒
可以看到isAfter和isBefore都是调用compareTo
public boolean isAfter(Instant otherInstant) {
return compareTo(otherInstant) > 0;
}
public boolean isBefore(Instant otherInstant) {
return compareTo(otherInstant) < 0;
}
/**
* Calculates the amount of time until another instant in terms of the specified unit.
*
* This calculates the amount of time between two {@code Instant}
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified instant.
* The result will be negative if the end is before the start.
* The calculation returns a whole number, representing the number of
* complete units between the two instants.
* The {@code Temporal} passed to this method is converted to a
* {@code Instant} using {@link #from(TemporalAccessor)}.
* For example, the amount in seconds between two dates can be calculated
* using {@code startInstant.until(endInstant, SECONDS)}.
*
* There are two equivalent ways of using this method.
* The first is to invoke this method.
* The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
*
* // these two lines are equivalent
* amount = start.until(end, SECONDS);
* amount = SECONDS.between(start, end);
*
* The choice should be made based on which makes the code more readable.
*
* The calculation is implemented in this method for {@link ChronoUnit}.
* The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
* {@code MINUTES}, {@code HOURS}, {@code HALF_DAYS} and {@code DAYS}
* are supported. Other {@code ChronoUnit} values will throw an exception.
*
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
* passing {@code this} as the first argument and the converted input temporal
* as the second argument.
*
* This instance is immutable and unaffected by this method call.
*
* @param endExclusive the end date, exclusive, which is converted to an {@code Instant}, not null
* @param unit the unit to measure the amount in, not null
* @return the amount of time between this instant and the end instant
* @throws DateTimeException if the amount cannot be calculated, or the end
* temporal cannot be converted to an {@code Instant}
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public long until(Temporal endExclusive, TemporalUnit unit) {
Instant end = Instant.from(endExclusive);
if (unit instanceof ChronoUnit) {
ChronoUnit f = (ChronoUnit) unit;
switch (f) {
case NANOS: return nanosUntil(end);
case MICROS: return nanosUntil(end) / 1000;
case MILLIS: return Math.subtractExact(end.toEpochMilli(), toEpochMilli());
case SECONDS: return secondsUntil(end);
case MINUTES: return secondsUntil(end) / SECONDS_PER_MINUTE;
case HOURS: return secondsUntil(end) / SECONDS_PER_HOUR;
case HALF_DAYS: return secondsUntil(end) / (12 * SECONDS_PER_HOUR);
case DAYS: return secondsUntil(end) / (SECONDS_PER_DAY);
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.between(this, end);
}