001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.core.time; 018 019import org.apache.logging.log4j.core.util.Clock; 020import org.apache.logging.log4j.util.PerformanceSensitive; 021 022import java.io.Serializable; 023 024/** 025 * An instantaneous point on the time line, used for high-precision log event timestamps. 026 * Modeled on <a href="https://docs.oracle.com/javase/9/docs/api/?java/time/class-use/Instant.html">java.time.Instant</a>, 027 * except that this version is mutable to prevent allocating temporary objects that need to be garbage-collected later. 028 * <p> 029 * Instances of this class are <em>not</em> thread-safe and should not be shared between threads. 030 * </p> 031 * 032 * @since 2.11 033 */ 034@PerformanceSensitive("allocation") 035public class MutableInstant implements Instant, Serializable { 036 037 private static final int MILLIS_PER_SECOND = 1000; 038 private static final int NANOS_PER_MILLI = 1000_000; 039 private static final int NANOS_PER_SECOND = MILLIS_PER_SECOND * NANOS_PER_MILLI; 040 041 private long epochSecond; 042 private int nanoOfSecond; 043 044 @Override 045 public long getEpochSecond() { 046 return epochSecond; 047 } 048 049 @Override 050 public int getNanoOfSecond() { 051 return nanoOfSecond; 052 } 053 054 @Override 055 public long getEpochMillisecond() { 056 final int millis = nanoOfSecond / NANOS_PER_MILLI; 057 final long epochMillisecond = epochSecond * MILLIS_PER_SECOND + millis; 058 return epochMillisecond; 059 } 060 061 @Override 062 public int getNanoOfMillisecond() { 063 final int millis = nanoOfSecond / NANOS_PER_MILLI; 064 final int nanoOfMillisecond = nanoOfSecond - (millis * NANOS_PER_MILLI); // cheaper than nanoOfSecond % NANOS_PER_MILLI 065 return nanoOfMillisecond; 066 } 067 068 public void initFrom(final Instant other) { 069 this.epochSecond = other.getEpochSecond(); 070 this.nanoOfSecond = other.getNanoOfSecond(); 071 } 072 073 /** 074 * Updates the fields of this {@code MutableInstant} from the specified epoch millis. 075 * @param epochMilli the number of milliseconds from the Java epoch of 1970-01-01T00:00:00Z 076 * @param nanoOfMillisecond the number of nanoseconds, later along the time-line, from the start of the millisecond 077 */ 078 public void initFromEpochMilli(final long epochMilli, final int nanoOfMillisecond) { 079 validateNanoOfMillisecond(nanoOfMillisecond); 080 this.epochSecond = epochMilli / MILLIS_PER_SECOND; 081 this.nanoOfSecond = (int) (epochMilli - (epochSecond * MILLIS_PER_SECOND)) * NANOS_PER_MILLI + nanoOfMillisecond; 082 } 083 084 private void validateNanoOfMillisecond(final int nanoOfMillisecond) { 085 if (nanoOfMillisecond < 0 || nanoOfMillisecond >= NANOS_PER_MILLI) { 086 throw new IllegalArgumentException("Invalid nanoOfMillisecond " + nanoOfMillisecond); 087 } 088 } 089 090 public void initFrom(final Clock clock) { 091 if (clock instanceof PreciseClock) { 092 ((PreciseClock) clock).init(this); 093 } else { 094 initFromEpochMilli(clock.currentTimeMillis(), 0); 095 } 096 } 097 098 /** 099 * Updates the fields of this {@code MutableInstant} from the specified instant components. 100 * @param epochSecond the number of seconds from the Java epoch of 1970-01-01T00:00:00Z 101 * @param nano the number of nanoseconds, later along the time-line, from the start of the second 102 */ 103 public void initFromEpochSecond(final long epochSecond, final int nano) { 104 validateNanoOfSecond(nano); 105 this.epochSecond = epochSecond; 106 this.nanoOfSecond = nano; 107 } 108 109 private void validateNanoOfSecond(final int nano) { 110 if (nano < 0 || nano >= NANOS_PER_SECOND) { 111 throw new IllegalArgumentException("Invalid nanoOfSecond " + nano); 112 } 113 } 114 115 /** 116 * Updates the elements of the specified {@code long[]} result array from the specified instant components. 117 * @param epochSecond (input) the number of seconds from the Java epoch of 1970-01-01T00:00:00Z 118 * @param nano (input) the number of nanoseconds, later along the time-line, from the start of the second 119 * @param result (output) a two-element array to store the result: the first element is the number of milliseconds 120 * from the Java epoch of 1970-01-01T00:00:00Z, 121 * the second element is the number of nanoseconds, later along the time-line, from the start of the millisecond 122 */ 123 public static void instantToMillisAndNanos(final long epochSecond, final int nano, final long[] result) { 124 final int millis = nano / NANOS_PER_MILLI; 125 result[0] = epochSecond * MILLIS_PER_SECOND + millis; 126 result[1] = nano - (millis * NANOS_PER_MILLI); // cheaper than nanoOfSecond % NANOS_PER_MILLI 127 } 128 129 @Override 130 public boolean equals(final Object object) { 131 if (object == this) { 132 return true; 133 } 134 if (!(object instanceof MutableInstant)) { 135 return false; 136 } 137 final MutableInstant other = (MutableInstant) object; 138 return epochSecond == other.epochSecond && nanoOfSecond == other.nanoOfSecond; 139 } 140 141 @Override 142 public int hashCode() { 143 int result = 17; 144 result = 31 * result + (int) (epochSecond ^ (epochSecond >>> 32)); 145 result = 31 * result + nanoOfSecond; 146 return result; 147 } 148 149 @Override 150 public String toString() { 151 final StringBuilder sb = new StringBuilder(64); 152 formatTo(sb); 153 return sb.toString(); 154 } 155 156 @Override 157 public void formatTo(final StringBuilder buffer) { 158 buffer.append("MutableInstant[epochSecond=").append(epochSecond).append(", nano=").append(nanoOfSecond).append("]"); 159 } 160}