LOG4J2-1883 replace timeMillis with Instant/MutableInstant in LogEvent; support 
formatting date times in higher precision than milliseconds; add Java 9 precise 
time source; update docs


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/e3a126ee
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/e3a126ee
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/e3a126ee

Branch: refs/heads/master
Commit: e3a126ee14830e7a67c1cd405a2b27b331c7981e
Parents: 6b31ab3
Author: rpopma <[email protected]>
Authored: Sun Jan 14 13:48:25 2018 +0900
Committer: rpopma <[email protected]>
Committed: Sun Jan 28 19:46:17 2018 +0900

----------------------------------------------------------------------
 log4j-core-java9/pom.xml                        |  11 +-
 log4j-core-java9/src/assembly/java9.xml         |   8 +-
 .../apache/logging/log4j/core/util/Clock.java   |  32 +++
 .../apache/logging/log4j/core/util/Dummy.java   |  24 --
 .../apache/logging/log4j/core/util/Instant.java |  75 ++++++
 .../logging/log4j/core/util/MutableInstant.java | 155 +++++++++++++
 .../logging/log4j/core/util/PreciseClock.java   |  36 +++
 .../logging/log4j/core/util/SystemClock.java    |  44 ++++
 .../log4j/core/util/SystemMillisClock.java      |  34 +++
 .../apache/logging/log4j/core/util/Temp.java    |  24 --
 .../logging/log4j/core/AbstractLogEvent.java    |   9 +
 .../org/apache/logging/log4j/core/LogEvent.java |  17 +-
 .../converter/InstantAttributeConverter.java    |  58 +++++
 .../logging/log4j/core/async/AsyncLogger.java   |   6 +-
 .../log4j/core/async/RingBufferLogEvent.java    |  34 ++-
 .../async/RingBufferLogEventTranslator.java     |  22 +-
 .../logging/log4j/core/impl/Log4jLogEvent.java  |  77 ++++---
 .../log4j/core/impl/MutableLogEvent.java        |  33 ++-
 .../core/impl/ReusableLogEventFactory.java      |   6 +-
 .../log4j/core/jackson/Initializers.java        |   3 +
 .../log4j/core/jackson/InstantMixIn.java        |  55 +++++
 .../log4j/core/jackson/JsonConstants.java       |   1 +
 .../log4j/core/jackson/LogEventJsonMixIn.java   |  13 +-
 .../jackson/LogEventWithContextListMixIn.java   |  13 +-
 .../log4j/core/jackson/XmlConstants.java        |   1 +
 .../core/pattern/DatePatternConverter.java      | 100 +++++---
 .../logging/log4j/core/util/ClockFactory.java   |  27 ++-
 .../log4j/core/util/DummyPreciseClock.java      |  49 ++++
 .../apache/logging/log4j/core/util/Instant.java |  72 ++++++
 .../logging/log4j/core/util/MutableInstant.java | 152 ++++++++++++
 .../logging/log4j/core/util/PreciseClock.java   |  33 +++
 .../core/util/datetime/FixedDateFormat.java     | 122 +++++++++-
 .../appender/JsonCompleteFileAppenderTest.java  |  75 +++---
 .../appender/XmlCompleteFileAppenderTest.java   | 115 ++++------
 .../core/appender/XmlFileAppenderTest.java      |  40 ++--
 .../InstantAttributeConverterTest.java          |  68 ++++++
 .../async/AsyncLoggerTimestampMessageTest.java  |   2 +-
 .../core/async/RingBufferLogEventTest.java      |  28 +--
 .../ConcurrentLoggingWithJsonLayoutTest.java    |   2 +-
 .../log4j/core/layout/JsonLayoutTest.java       |   2 +-
 .../log4j/core/layout/XmlLayoutTest.java        |   5 +-
 .../log4j/core/layout/YamlLayoutTest.java       |   2 +-
 .../core/parser/JsonLogEventParserTest.java     |   3 +-
 .../log4j/core/parser/LogEventParserTest.java   |   2 +-
 .../core/parser/XmlLogEventParserTest.java      |   6 +
 .../core/parser/YamlLogEventParserTest.java     |  10 +-
 .../core/pattern/DatePatternConverterTest.java  |  74 ++++++
 .../log4j/core/util/MutableInstantTest.java     | 230 +++++++++++++++++++
 .../core/util/datetime/FixedDateFormatTest.java |  15 ++
 .../log4j/flume/appender/FlumeEvent.java        |  10 +
 .../db/jpa/AbstractLogEventWrapperEntity.java   |  21 ++
 .../appender/db/jpa/BasicLogEventEntity.java    |  15 +-
 .../core/appender/db/jpa/JpaH2AppenderTest.java |  11 +-
 .../appender/db/jpa/JpaHsqldbAppenderTest.java  |  11 +-
 .../appender/db/jpa/LogEventEntityTest.java     |   7 +
 .../core/appender/db/jpa/TestBaseEntity.java    |   9 +
 .../src/test/resources/META-INF/persistence.xml |   2 +
 .../src/main/resources/META-INF/persistence.xml |   2 +
 src/site/xdoc/manual/layouts.xml.vm             |  50 +++-
 59 files changed, 1816 insertions(+), 347 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core-java9/pom.xml
----------------------------------------------------------------------
diff --git a/log4j-core-java9/pom.xml b/log4j-core-java9/pom.xml
index e05f30e..b46f8c9 100644
--- a/log4j-core-java9/pom.xml
+++ b/log4j-core-java9/pom.xml
@@ -33,6 +33,11 @@
     <projectDir>/core</projectDir>
   </properties>
   <dependencies>
+    <!-- Naturally, all implementations require the log4j-api JAR -->
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+    </dependency>
     <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
@@ -84,12 +89,6 @@
             </goals>
           </execution>
         </executions>
-        <configuration>
-          <source>9</source>
-          <target>9</target>
-          <release>9</release>
-          <proc>none</proc>
-        </configuration>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core-java9/src/assembly/java9.xml
----------------------------------------------------------------------
diff --git a/log4j-core-java9/src/assembly/java9.xml 
b/log4j-core-java9/src/assembly/java9.xml
index 3e59561..f8f129d 100644
--- a/log4j-core-java9/src/assembly/java9.xml
+++ b/log4j-core-java9/src/assembly/java9.xml
@@ -34,10 +34,10 @@
       <excludes>
         <exclude>module-info.class</exclude>
         <exclude>**/Dummy.class</exclude>
-        <exclude>**/spi/Provider.class</exclude>
-        <exclude>**/util/PropertySource.class</exclude>
-        <exclude>**/message/ThreadDumpMessage.class</exclude>
-        <exclude>**/message/ThreadDumpMessage$ThreadInfoFactory.class</exclude>
+        <exclude>**/util/Clock.class</exclude>
+        <exclude>**/util/Instant.class</exclude>
+        <exclude>**/util/MutableInstant.class</exclude>
+        <exclude>**/util/PreciseClock.class</exclude>
       </excludes>
     </fileSet>
     <fileSet>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Clock.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Clock.java 
b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Clock.java
new file mode 100644
index 0000000..8c961d4
--- /dev/null
+++ 
b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Clock.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.util;
+
+// This class is here to allow {@link SystemClock}, {@link SystemMillisClock}
+// to compile. It will not be copied into the log4j-core module.
+
+/**
+ * Provides the time stamp used in log events.
+ */
+public interface Clock {
+    /**
+     * Returns the time in milliseconds since the epoch.
+     *
+     * @return the time in milliseconds since the epoch
+     */
+    long currentTimeMillis();
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Dummy.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Dummy.java 
b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Dummy.java
deleted file mode 100644
index 6bffac6..0000000
--- 
a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Dummy.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.core.util;
-
-/**
- * This is a dummy class and is only here to allow module-info.java to 
compile. It will not
- * be copied into the log4j-api module.
- */
-public class Dummy {
-}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Instant.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Instant.java
 
b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Instant.java
new file mode 100644
index 0000000..cd4ac9d
--- /dev/null
+++ 
b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Instant.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.util;
+
+// This class is here to allow {@link SystemClock}, {@link SystemMillisClock}
+// to compile. It will not be copied into the log4j-core module.
+
+/**
+ * Models a point in time, suitable for event timestamps.
+ * <p>
+ * Provides methods for obtaining high precision time information similar to 
the
+ * <a 
href="https://docs.oracle.com/javase/9/docs/api/java/time/Instant.html";>Instant</a>
 class introduced in Java 8,
+ * while also supporting the legacy millisecond precision API.
+ * </p><p>
+ * Depending on the platform, time sources ({@link Clock} implementations) may 
produce high precision or millisecond
+ * precision time values. At the same time, some time value consumers (for 
example timestamp formatters) may only be
+ * able to consume time values of millisecond precision, while some others may 
require a high precision time value.
+ * </p><p>
+ * This class bridges these two time APIs.
+ * </p>
+ * @since 2.11
+ */
+public interface Instant {
+    /**
+     * Gets the number of seconds from the Java epoch of 1970-01-01T00:00:00Z.
+     * <p>
+     * The epoch second count is a simple incrementing count of seconds where 
second 0 is 1970-01-01T00:00:00Z.
+     * The nanosecond part of the day is returned by {@link 
#getNanoOfSecond()}.
+     * </p>
+     * @return the seconds from the epoch of 1970-01-01T00:00:00Z
+     */
+    long getEpochSecond();
+
+    /**
+     * Gets the number of nanoseconds, later along the time-line, from the 
start of the second.
+     * <p>
+     * The nanosecond-of-second value measures the total number of nanoseconds 
from the second returned by {@link #getEpochSecond()}.
+     * </p>
+     * @return the nanoseconds within the second, always positive, never 
exceeds {@code 999,999,999}
+     */
+    int getNanoOfSecond();
+
+    /**
+     * Gets the number of milliseconds from the Java epoch of 
1970-01-01T00:00:00Z.
+     * <p>
+     * The epoch millisecond count is a simple incrementing count of 
milliseconds where millisecond 0 is 1970-01-01T00:00:00Z.
+     * The nanosecond part of the day is returned by {@link 
#getNanoOfMillisecond()}.
+     * </p>
+     * @return the milliseconds from the epoch of 1970-01-01T00:00:00Z
+     */
+    long getEpochMillisecond();
+
+    /**
+     * Gets the number of nanoseconds, later along the time-line, from the 
start of the millisecond.
+     * <p>
+     * The nanosecond-of-millisecond value measures the total number of 
nanoseconds from the millisecond returned by {@link #getEpochMillisecond()}.
+     * </p>
+     * @return the nanoseconds within the millisecond, always positive, never 
exceeds {@code 999,999}
+     */
+    int getNanoOfMillisecond();
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/MutableInstant.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/MutableInstant.java
 
b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/MutableInstant.java
new file mode 100644
index 0000000..8960fc5
--- /dev/null
+++ 
b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/MutableInstant.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.util;
+
+import org.apache.logging.log4j.util.PerformanceSensitive;
+
+import java.io.Serializable;
+
+// This class is here to allow {@link SystemClock}, {@link SystemMillisClock}
+// to compile. It will not be copied into the log4j-core module.
+
+/**
+ * An instantaneous point on the time line, used for high-precision log event 
timestamps.
+ * Modelled on <a 
href="https://docs.oracle.com/javase/9/docs/api/index.html?java/time/class-use/Instant.html";>java.time.Instant</a>,
+ * except that this version is mutable to prevent allocating temporary objects 
that need to be garbage-collected later.
+ * <p>
+ * Instances of this class are <em>not</em> thread-safe and should not be 
shared between threads.
+ * </p>
+ *
+ * @since 2.11
+ */
+@PerformanceSensitive("allocation")
+public class MutableInstant implements Instant, Serializable {
+
+    private static final int MILLIS_PER_SECOND = 1000;
+    private static final int NANOS_PER_MILLI = 1000_000;
+    static final int NANOS_PER_SECOND = MILLIS_PER_SECOND * NANOS_PER_MILLI;
+
+    private long epochSecond;
+    private int nanoOfSecond;
+
+    @Override
+    public long getEpochSecond() {
+        return epochSecond;
+    }
+
+    @Override
+    public int getNanoOfSecond() {
+        return nanoOfSecond;
+    }
+
+    @Override
+    public long getEpochMillisecond() {
+        final int millis = nanoOfSecond / NANOS_PER_MILLI;
+        long epochMillisecond = epochSecond * MILLIS_PER_SECOND + millis;
+        return epochMillisecond;
+    }
+
+    @Override
+    public int getNanoOfMillisecond() {
+        final int millis = nanoOfSecond / NANOS_PER_MILLI;
+        int nanoOfMillisecond = nanoOfSecond - (millis * NANOS_PER_MILLI); // 
cheaper than nanoOfSecond % NANOS_PER_MILLI
+        return nanoOfMillisecond;
+    }
+
+    public void initFrom(final Instant other) {
+        this.epochSecond = other.getEpochSecond();
+        this.nanoOfSecond = other.getNanoOfSecond();
+    }
+
+    /**
+     * Updates the fields of this {@code MutableInstant} from the specified 
epoch millis.
+     * @param epochMilli the number of milliseconds from the Java epoch of 
1970-01-01T00:00:00Z
+     * @param nanoOfMillisecond the number of nanoseconds, later along the 
time-line, from the start of the millisecond
+     */
+    public void initFromEpochMilli(final long epochMilli, final int 
nanoOfMillisecond) {
+        validateNanoOfMillisecond(nanoOfMillisecond);
+        this.epochSecond = epochMilli / MILLIS_PER_SECOND;
+        this.nanoOfSecond = (int) (epochMilli - (epochSecond * 
MILLIS_PER_SECOND)) * NANOS_PER_MILLI + nanoOfMillisecond;
+    }
+
+    private void validateNanoOfMillisecond(final int nanoOfMillisecond) {
+        if (nanoOfMillisecond < 0 || nanoOfMillisecond >= NANOS_PER_MILLI) {
+            throw new IllegalArgumentException("Invalid nanoOfMillisecond " + 
nanoOfMillisecond);
+        }
+    }
+
+    public void initFrom(final Clock clock) {
+        if (clock instanceof PreciseClock) {
+            ((PreciseClock) clock).init(this);
+        } else {
+            initFromEpochMilli(clock.currentTimeMillis(), 0);
+        }
+    }
+
+    /**
+     * Updates the fields of this {@code MutableInstant} from the specified 
instant components.
+     * @param epochSecond the number of seconds from the Java epoch of 
1970-01-01T00:00:00Z
+     * @param nano the number of nanoseconds, later along the time-line, from 
the start of the second
+     */
+    public void initFromEpochSecond(final long epochSecond, final int nano) {
+        validateNanoOfSecond(nano);
+        this.epochSecond = epochSecond;
+        this.nanoOfSecond = nano;
+    }
+
+    private void validateNanoOfSecond(final int nano) {
+        if (nano < 0 || nano >= NANOS_PER_SECOND) {
+            throw new IllegalArgumentException("Invalid nanoOfSecond " + nano);
+        }
+    }
+
+    /**
+     * Updates the elements of the specified {@code long[]} result array from 
the specified instant components.
+     * @param epochSecond (input) the number of seconds from the Java epoch of 
1970-01-01T00:00:00Z
+     * @param nano (input) the number of nanoseconds, later along the 
time-line, from the start of the second
+     * @param result (output) a two-element array to store the result: the 
first element is the number of milliseconds
+     *               from the Java epoch of 1970-01-01T00:00:00Z,
+     *               the second element is the number of nanoseconds, later 
along the time-line, from the start of the millisecond
+     */
+    public static void instantToMillisAndNanos(final long epochSecond, final 
int nano, final long[] result) {
+        int millis = nano / NANOS_PER_MILLI;
+        result[0] = epochSecond * MILLIS_PER_SECOND + millis;
+        result[1] = nano - (millis * NANOS_PER_MILLI); // cheaper than 
nanoOfSecond % NANOS_PER_MILLI
+    }
+
+    @Override
+    public boolean equals(final Object object) {
+        if (object == this) {
+            return true;
+        }
+        if (!(object instanceof MutableInstant)) {
+            return false;
+        }
+        MutableInstant other = (MutableInstant) object;
+        return epochSecond == other.epochSecond && nanoOfSecond == 
other.nanoOfSecond;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+        result = 31 * result + (int) (epochSecond ^ (epochSecond >>> 32));
+        result = 31 * result + nanoOfSecond;
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "MutableInstant[epochSecond=" + epochSecond + ", nano=" + 
nanoOfSecond + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/PreciseClock.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/PreciseClock.java
 
b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/PreciseClock.java
new file mode 100644
index 0000000..3d1f314
--- /dev/null
+++ 
b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/PreciseClock.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.util;
+
+// This class is here to allow {@link SystemClock}, {@link SystemMillisClock}
+// to compile. It will not be copied into the log4j-core module.
+
+/**
+ * Extension of the {@link Clock} interface that is able to provide more 
accurate time information than milliseconds
+ * since the epoch. {@code PreciseClock} implementations are free to return 
millisecond-precision time
+ * if that is the most accurate time information available on this platform.
+ * @since 2.11
+ */
+public interface PreciseClock extends Clock {
+
+    /**
+     * Initializes the specified instant with time information as accurate as 
available on this platform.
+     * @param mutableInstant the container to be initialized with the accurate 
time information
+     * @since 2.11
+     */
+    void init(final MutableInstant mutableInstant);
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemClock.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemClock.java
 
b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemClock.java
new file mode 100644
index 0000000..a74a1fd
--- /dev/null
+++ 
b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemClock.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.util;
+
+import java.time.Instant;
+
+/**
+ * Implementation of the {@code Clock} interface that returns the system time.
+ * @since 2.11
+ */
+public final class SystemClock implements Clock, PreciseClock {
+
+    /**
+     * Returns the system time.
+     * @return the result of calling {@code System.currentTimeMillis()}
+     */
+    @Override
+    public long currentTimeMillis() {
+        return System.currentTimeMillis();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void init(MutableInstant mutableInstant) {
+        Instant instant = java.time.Clock.systemUTC().instant();
+        mutableInstant.initFromEpochSecond(instant.getEpochSecond(), 
instant.getNano());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemMillisClock.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemMillisClock.java
 
b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemMillisClock.java
new file mode 100644
index 0000000..f267320
--- /dev/null
+++ 
b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemMillisClock.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.util;
+
+/**
+ * Implementation of the {@code Clock} interface that returns the system time 
in millisecond granularity.
+ * @since 2.11
+ */
+public final class SystemMillisClock implements Clock {
+
+    /**
+     * Returns the system time.
+     * @return the result of calling {@code System.currentTimeMillis()}
+     */
+    @Override
+    public long currentTimeMillis() {
+        return System.currentTimeMillis();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Temp.java
----------------------------------------------------------------------
diff --git 
a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Temp.java 
b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Temp.java
deleted file mode 100644
index edb6d47..0000000
--- 
a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Temp.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.core.util;
-
-/**
- * Temporary class to ensure the log4j-core-java9 jar has at least one class 
(or Maven will refuse to proceed).
- * To be removed as soon as real classes are added to the log4j-core-java9 
module.
- */
-public class Temp {
-}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLogEvent.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLogEvent.java 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLogEvent.java
index 11cc071..bc7d1b4 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLogEvent.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/AbstractLogEvent.java
@@ -24,6 +24,8 @@ import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.ThreadContext.ContextStack;
 import org.apache.logging.log4j.core.impl.ThrowableProxy;
+import org.apache.logging.log4j.core.util.Instant;
+import org.apache.logging.log4j.core.util.MutableInstant;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.util.ReadOnlyStringMap;
 
@@ -35,6 +37,8 @@ public abstract class AbstractLogEvent implements LogEvent {
 
     private static final long serialVersionUID = 1L;
 
+    private MutableInstant instant = new MutableInstant();
+
     /**
      * Subclasses should implement this method to provide an immutable version.
      */
@@ -122,6 +126,11 @@ public abstract class AbstractLogEvent implements LogEvent 
{
     }
 
     @Override
+    public Instant getInstant() {
+        return instant;
+    }
+
+    @Override
     public boolean isEndOfBatch() {
         return false;
     }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java
index 41b20a7..0f72050 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java
@@ -24,6 +24,7 @@ import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.impl.ThrowableProxy;
+import org.apache.logging.log4j.core.util.Instant;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.util.ReadOnlyStringMap;
 
@@ -124,13 +125,27 @@ public interface LogEvent extends Serializable {
 
     /**
      * Gets event time in milliseconds since midnight, January 1, 1970 UTC.
+     * Use {@link #getInstant()} to get higher precision timestamp information 
if available on this platform.
      *
-     * @return milliseconds since midnight, January 1, 1970 UTC.
+     * @return the milliseconds component of this log event's {@linkplain 
#getInstant() timestamp}
      * @see java.lang.System#currentTimeMillis()
      */
     long getTimeMillis();
 
     /**
+     * Returns the timestamp when the message was logged.
+     * <p>
+     * <b>Caution</b>: if this {@code LogEvent} implementation is mutable and 
reused for multiple consecutive log messages,
+     * then the {@code Instant} object returned by this method is also mutable 
and reused.
+     * Client code should not keep a reference to the returned object but make 
a copy instead.
+     * </p>
+     *
+     * @return the {@code Instant} holding timestamp details for this log event
+     * @since 2.11
+     */
+    Instant getInstant();
+
+    /**
      * Gets the source of logging request.
      *
      * @return source of logging request, may be null.

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverter.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverter.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverter.java
new file mode 100644
index 0000000..408d972
--- /dev/null
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverter.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.appender.db.jpa.converter;
+
+import org.apache.logging.log4j.core.util.Instant;
+import org.apache.logging.log4j.core.util.MutableInstant;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.Strings;
+
+import javax.persistence.AttributeConverter;
+import javax.persistence.Converter;
+
+/**
+ * A JPA 2.1 attribute converter for {@link Instant}s in {@link 
org.apache.logging.log4j.core.LogEvent}s. This
+ * converter is capable of converting both to and from {@link String}s.
+ */
+@Converter(autoApply = false)
+public class InstantAttributeConverter implements AttributeConverter<Instant, 
String> {
+    private static final StatusLogger LOGGER = StatusLogger.getLogger();
+
+    @Override
+    public String convertToDatabaseColumn(final Instant instant) {
+        if (instant == null) {
+            return null;
+        }
+        return instant.getEpochSecond() + "," + instant.getNanoOfSecond();
+    }
+
+    @Override
+    public Instant convertToEntityAttribute(final String s) {
+        if (Strings.isEmpty(s)) {
+            return null;
+        }
+
+        int pos = s.indexOf(",");
+        long epochSecond = Long.parseLong(s.substring(0, pos));
+        int nanos = Integer.parseInt(s.substring(pos + 1, s.length()));
+
+        MutableInstant result = new MutableInstant();
+        result.initFromEpochSecond(epochSecond, nanos);
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
index 036a130..358422c 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
@@ -203,8 +203,8 @@ public class AsyncLogger extends Logger implements 
EventTranslatorVararg<RingBuf
 
                 // location (expensive to calculate)
                 calcLocationIfRequested(fqcn), //
-                CLOCK.currentTimeMillis(), //
-                nanoClock.nanoTime() //
+                CLOCK, //
+                nanoClock //
         );
     }
 
@@ -293,7 +293,7 @@ public class AsyncLogger extends Logger implements 
EventTranslatorVararg<RingBuf
                 // in the AsyncLogger#actualAsyncLog method
                 CONTEXT_DATA_INJECTOR.injectContextData(null, (StringMap) 
event.getContextData()),
                 contextStack, currentThread.getId(), threadName, 
currentThread.getPriority(), location,
-                CLOCK.currentTimeMillis(), nanoClock.nanoTime());
+                CLOCK, nanoClock);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
index b0b023b..af06e47 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
@@ -27,7 +27,7 @@ import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.impl.ContextDataFactory;
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.core.impl.ThrowableProxy;
-import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.core.util.*;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.ParameterizedMessage;
 import org.apache.logging.log4j.message.ReusableMessage;
@@ -70,7 +70,7 @@ public class RingBufferLogEvent implements LogEvent, 
ReusableMessage, CharSequen
 
     private int threadPriority;
     private long threadId;
-    private long currentTimeMillis;
+    private MutableInstant instant = new MutableInstant();
     private long nanoTime;
     private short parameterCount;
     private boolean includeLocation;
@@ -92,18 +92,18 @@ public class RingBufferLogEvent implements LogEvent, 
ReusableMessage, CharSequen
     private transient AsyncLogger asyncLogger;
 
     public void setValues(final AsyncLogger anAsyncLogger, final String 
aLoggerName, final Marker aMarker,
-            final String theFqcn, final Level aLevel, final Message msg, final 
Throwable aThrowable,
-            final StringMap mutableContextData, final ContextStack 
aContextStack, final long threadId,
-            final String threadName, final int threadPriority, final 
StackTraceElement aLocation,
-            final long aCurrentTimeMillis, final long aNanoTime) {
+                          final String theFqcn, final Level aLevel, final 
Message msg, final Throwable aThrowable,
+                          final StringMap mutableContextData, final 
ContextStack aContextStack, final long threadId,
+                          final String threadName, final int threadPriority, 
final StackTraceElement aLocation,
+                          final Clock clock, final NanoClock nanoClock) {
         this.threadPriority = threadPriority;
         this.threadId = threadId;
-        this.currentTimeMillis = aCurrentTimeMillis;
-        this.nanoTime = aNanoTime;
         this.level = aLevel;
         this.threadName = threadName;
         this.loggerName = aLoggerName;
         setMessage(msg);
+        initTime(clock);
+        this.nanoTime = nanoClock.nanoTime();
         this.thrown = aThrowable;
         this.thrownProxy = null;
         this.marker = aMarker;
@@ -114,6 +114,14 @@ public class RingBufferLogEvent implements LogEvent, 
ReusableMessage, CharSequen
         this.asyncLogger = anAsyncLogger;
     }
 
+    private void initTime(final Clock clock) {
+        if (message instanceof TimestampMessage) {
+            instant.initFromEpochMilli(((TimestampMessage) 
message).getTimestamp(), 0);
+        } else {
+            instant.initFrom(clock);
+        }
+    }
+
     @Override
     public LogEvent toImmutable() {
         return createMemento();
@@ -367,7 +375,12 @@ public class RingBufferLogEvent implements LogEvent, 
ReusableMessage, CharSequen
 
     @Override
     public long getTimeMillis() {
-        return message instanceof TimestampMessage ? ((TimestampMessage) 
message).getTimestamp() :currentTimeMillis;
+        return message instanceof TimestampMessage ? ((TimestampMessage) 
message).getTimestamp() : instant.getEpochMillisecond();
+    }
+
+    @Override
+    public Instant getInstant() {
+        return instant;
     }
 
     @Override
@@ -443,7 +456,8 @@ public class RingBufferLogEvent implements LogEvent, 
ReusableMessage, CharSequen
                 .setThreadPriority(threadPriority) //
                 .setThrown(getThrown()) // may deserialize from thrownProxy
                 .setThrownProxy(thrownProxy) // avoid unnecessarily creating 
thrownProxy
-                .setTimeMillis(currentTimeMillis);
+                .setInstant(instant) //
+        ;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java
index cb3e6ca..ec2ff1c 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java
@@ -21,6 +21,8 @@ import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.ThreadContext.ContextStack;
 import org.apache.logging.log4j.core.ContextDataInjector;
 import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
+import org.apache.logging.log4j.core.util.Clock;
+import org.apache.logging.log4j.core.util.NanoClock;
 import org.apache.logging.log4j.util.StringMap;
 import org.apache.logging.log4j.message.Message;
 
@@ -48,8 +50,8 @@ public class RingBufferLogEventTranslator implements
     private String threadName = Thread.currentThread().getName();
     private int threadPriority = Thread.currentThread().getPriority();
     private StackTraceElement location;
-    private long currentTimeMillis;
-    private long nanoTime;
+    private Clock clock;
+    private NanoClock nanoClock;
 
     // @Override
     @Override
@@ -59,7 +61,7 @@ public class RingBufferLogEventTranslator implements
                 // config properties are taken care of in the EventHandler 
thread
                 // in the AsyncLogger#actualAsyncLog method
                 injector.injectContextData(null, (StringMap) 
event.getContextData()), contextStack,
-                threadId, threadName, threadPriority, location, 
currentTimeMillis, nanoTime);
+                threadId, threadName, threadPriority, location, clock, 
nanoClock);
 
         clear(); // clear the translator
     }
@@ -77,15 +79,15 @@ public class RingBufferLogEventTranslator implements
                 null, // t
                 null, // contextStack
                 null, // location
-                0, // currentTimeMillis
-                0 // nanoTime
+                null, // clock
+                null // nanoClock
         );
     }
 
     public void setBasicValues(final AsyncLogger anAsyncLogger, final String 
aLoggerName, final Marker aMarker,
-            final String theFqcn, final Level aLevel, final Message msg, final 
Throwable aThrowable,
-            final ContextStack aContextStack, final StackTraceElement 
aLocation,
-            final long aCurrentTimeMillis, final long aNanoTime) {
+                               final String theFqcn, final Level aLevel, final 
Message msg, final Throwable aThrowable,
+                               final ContextStack aContextStack, final 
StackTraceElement aLocation,
+                               final Clock aClock, final NanoClock aNanoClock) 
{
         this.asyncLogger = anAsyncLogger;
         this.loggerName = aLoggerName;
         this.marker = aMarker;
@@ -95,8 +97,8 @@ public class RingBufferLogEventTranslator implements
         this.thrown = aThrowable;
         this.contextStack = aContextStack;
         this.location = aLocation;
-        this.currentTimeMillis = aCurrentTimeMillis;
-        this.nanoTime = aNanoTime;
+        this.clock = aClock;
+        this.nanoClock = aNanoClock;
     }
 
     public void updateThreadValues() {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
index 74ddaf6..7332531 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
@@ -29,15 +29,12 @@ import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.ContextDataInjector;
+import org.apache.logging.log4j.core.util.*;
 import org.apache.logging.log4j.util.ReadOnlyStringMap;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.async.RingBufferLogEvent;
 import org.apache.logging.log4j.core.config.LoggerConfig;
 import org.apache.logging.log4j.core.config.Property;
-import org.apache.logging.log4j.core.util.Clock;
-import org.apache.logging.log4j.core.util.ClockFactory;
-import org.apache.logging.log4j.core.util.DummyNanoClock;
-import org.apache.logging.log4j.core.util.NanoClock;
 import org.apache.logging.log4j.message.LoggerNameAwareMessage;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.ReusableMessage;
@@ -63,7 +60,7 @@ public class Log4jLogEvent implements LogEvent {
     private final Level level;
     private final String loggerName;
     private Message message;
-    private final long timeMillis;
+    private final MutableInstant instant = new MutableInstant();
     private final transient Throwable thrown;
     private ThrowableProxy thrownProxy;
     private final StringMap contextData;
@@ -86,7 +83,7 @@ public class Log4jLogEvent implements LogEvent {
         private String loggerName;
         private Message message;
         private Throwable thrown;
-        private long timeMillis = CLOCK.currentTimeMillis();
+        private MutableInstant instant = new MutableInstant();
         private ThrowableProxy thrownProxy;
         private StringMap contextData = createContextData((List<Property>) 
null);
         private ThreadContext.ContextStack contextStack = 
ThreadContext.getImmutableStack();
@@ -116,7 +113,7 @@ public class Log4jLogEvent implements LogEvent {
             this.level = other.getLevel();
             this.loggerName = other.getLoggerName();
             this.message = other.getMessage();
-            this.timeMillis = other.getTimeMillis();
+            this.instant.initFrom(other.getInstant());
             this.thrown = other.getThrown();
             this.contextStack = other.getContextStack();
             this.includeLocation = other.isIncludeLocation();
@@ -183,7 +180,12 @@ public class Log4jLogEvent implements LogEvent {
         }
 
         public Builder setTimeMillis(final long timeMillis) {
-            this.timeMillis = timeMillis;
+            this.instant.initFromEpochMilli(timeMillis, 0);
+            return this;
+        }
+
+        public Builder setInstant(final Instant instant) {
+            this.instant.initFrom(instant);
             return this;
         }
 
@@ -256,13 +258,20 @@ public class Log4jLogEvent implements LogEvent {
 
         @Override
         public Log4jLogEvent build() {
+            initTimeFields();
             final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, 
loggerFqcn, level, message, thrown,
-                    thrownProxy, contextData, contextStack, threadId, 
threadName, threadPriority, source, timeMillis,
-                    nanoTime);
+                    thrownProxy, contextData, contextStack, threadId, 
threadName, threadPriority, source,
+                    instant.getEpochMillisecond(), 
instant.getNanoOfMillisecond(), nanoTime);
             result.setIncludeLocation(includeLocation);
             result.setEndOfBatch(endOfBatch);
             return result;
         }
+
+        private void initTimeFields() {
+            if (instant.getEpochMillisecond() == 0) {
+                instant.initFrom(CLOCK);
+            }
+        }
     }
 
     /**
@@ -275,7 +284,7 @@ public class Log4jLogEvent implements LogEvent {
 
     public Log4jLogEvent() {
         this(Strings.EMPTY, null, Strings.EMPTY, null, null, (Throwable) null, 
null, null, null, 0, null,
-                0, null, CLOCK.currentTimeMillis(), nanoClock.nanoTime());
+                0, null, CLOCK.currentTimeMillis(), 0, nanoClock.nanoTime());
     }
 
     /**
@@ -285,7 +294,7 @@ public class Log4jLogEvent implements LogEvent {
    @Deprecated
    public Log4jLogEvent(final long timestamp) {
        this(Strings.EMPTY, null, Strings.EMPTY, null, null, (Throwable) null, 
null, null, null, 0, null,
-               0, null, timestamp, nanoClock.nanoTime());
+               0, null, timestamp, 0, nanoClock.nanoTime());
    }
 
    /**
@@ -325,7 +334,7 @@ public class Log4jLogEvent implements LogEvent {
            null, // LOG4J2-628 use log4j.Clock for timestamps
            // LOG4J2-744 unless TimestampMessage already has one
            message instanceof TimestampMessage ? ((TimestampMessage) 
message).getTimestamp() :
-               CLOCK.currentTimeMillis(), nanoClock.nanoTime());
+               CLOCK.currentTimeMillis(), 0, nanoClock.nanoTime());
    }
 
    /**
@@ -349,7 +358,7 @@ public class Log4jLogEvent implements LogEvent {
                         final ThreadContext.ContextStack ndc, final String 
threadName,
                         final StackTraceElement location, final long 
timestampMillis) {
        this(loggerName, marker, loggerFQCN, level, message, t, null, 
createContextData(mdc), ndc, 0,
-               threadName, 0, location, timestampMillis, nanoClock.nanoTime());
+               threadName, 0, location, timestampMillis, 0, 
nanoClock.nanoTime());
    }
 
    /**
@@ -377,7 +386,7 @@ public class Log4jLogEvent implements LogEvent {
                                             final String threadName, final 
StackTraceElement location,
                                             final long timestamp) {
         final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, 
loggerFQCN, level, message, thrown,
-                thrownProxy, createContextData(mdc), ndc, 0, threadName, 0, 
location, timestamp, nanoClock.nanoTime());
+                thrownProxy, createContextData(mdc), ndc, 0, threadName, 0, 
location, timestamp, 0, nanoClock.nanoTime());
         return result;
     }
 
@@ -397,6 +406,7 @@ public class Log4jLogEvent implements LogEvent {
      * @param threadPriority the thread priority
      * @param source The locations of the caller.
      * @param timestampMillis The timestamp of the event.
+     * @param nanoOfMillisecond the nanoseconds within the millisecond, always 
positive, never exceeds {@code 999,999}
      * @param nanoTime The value of the running Java Virtual Machine's 
high-resolution time source when the event was
      *          created.
      */
@@ -404,7 +414,7 @@ public class Log4jLogEvent implements LogEvent {
             final Message message, final Throwable thrown, final 
ThrowableProxy thrownProxy,
             final StringMap contextData, final ThreadContext.ContextStack 
contextStack, final long threadId,
             final String threadName, final int threadPriority, final 
StackTraceElement source,
-            final long timestampMillis, final long nanoTime) {
+            final long timestampMillis, final int nanoOfMillisecond, final 
long nanoTime) {
         this.loggerName = loggerName;
         this.marker = marker;
         this.loggerFqcn = loggerFQCN;
@@ -414,9 +424,10 @@ public class Log4jLogEvent implements LogEvent {
         this.thrownProxy = thrownProxy;
         this.contextData = contextData == null ? 
ContextDataFactory.createContextData() : contextData;
         this.contextStack = contextStack == null ? ThreadContext.EMPTY_STACK : 
contextStack;
-        this.timeMillis = message instanceof TimestampMessage
+        long millis = message instanceof TimestampMessage
                 ? ((TimestampMessage) message).getTimestamp()
                 : timestampMillis;
+        this.instant.initFromEpochMilli(millis, nanoOfMillisecond);
         this.threadId = threadId;
         this.threadName = threadName;
         this.threadPriority = threadPriority;
@@ -539,12 +550,20 @@ public class Log4jLogEvent implements LogEvent {
     }
 
     /**
-     * Returns the time in milliseconds from the epoch when the event occurred.
-     * @return The time the event occurred.
+     * {@inheritDoc}
      */
     @Override
     public long getTimeMillis() {
-        return timeMillis;
+        return instant.getEpochMillisecond();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @since 2.11
+     */
+    @Override
+    public Instant getInstant() {
+        return instant;
     }
 
     /**
@@ -707,7 +726,8 @@ public class Log4jLogEvent implements LogEvent {
             final Log4jLogEvent result = new Log4jLogEvent(proxy.loggerName, 
proxy.marker,
                     proxy.loggerFQCN, proxy.level, proxy.message,
                     proxy.thrown, proxy.thrownProxy, proxy.contextData, 
proxy.contextStack, proxy.threadId,
-                    proxy.threadName, proxy.threadPriority, proxy.source, 
proxy.timeMillis, proxy.nanoTime);
+                    proxy.threadName, proxy.threadPriority, proxy.source, 
proxy.timeMillis, proxy.nanoOfMillisecond,
+                    proxy.nanoTime);
             result.setEndOfBatch(proxy.isEndOfBatch);
             result.setIncludeLocation(proxy.isLocationRequired);
             return result;
@@ -759,7 +779,7 @@ public class Log4jLogEvent implements LogEvent {
         if (includeLocation != that.includeLocation) {
             return false;
         }
-        if (timeMillis != that.timeMillis) {
+        if (!instant.equals(that.instant)) {
             return false;
         }
         if (nanoTime != that.nanoTime) {
@@ -816,7 +836,7 @@ public class Log4jLogEvent implements LogEvent {
         result = 31 * result + (level != null ? level.hashCode() : 0);
         result = 31 * result + loggerName.hashCode();
         result = 31 * result + message.hashCode();
-        result = 31 * result + (int) (timeMillis ^ (timeMillis >>> 32));
+        result = 31 * result + instant.hashCode();
         result = 31 * result + (int) (nanoTime ^ (nanoTime >>> 32));
         result = 31 * result + (thrown != null ? thrown.hashCode() : 0);
         result = 31 * result + (thrownProxy != null ? thrownProxy.hashCode() : 
0);
@@ -849,6 +869,8 @@ public class Log4jLogEvent implements LogEvent {
         /** since 2.8 */
         private String messageString;
         private final long timeMillis;
+        /** since 2.11 */
+        private final int nanoOfMillisecond;
         private final transient Throwable thrown;
         private final ThrowableProxy thrownProxy;
         /** @since 2.7 */
@@ -873,7 +895,8 @@ public class Log4jLogEvent implements LogEvent {
             this.message = event.message instanceof ReusableMessage
                     ? memento((ReusableMessage) event.message)
                     : event.message;
-            this.timeMillis = event.timeMillis;
+            this.timeMillis = event.instant.getEpochMillisecond();
+            this.nanoOfMillisecond = event.instant.getNanoOfMillisecond();
             this.thrown = event.thrown;
             this.thrownProxy = event.thrownProxy;
             this.contextData = event.contextData;
@@ -897,7 +920,8 @@ public class Log4jLogEvent implements LogEvent {
             message = temp instanceof ReusableMessage
                     ? memento((ReusableMessage) temp)
                     : temp;
-            this.timeMillis = event.getTimeMillis();
+            this.timeMillis = event.getInstant().getEpochMillisecond();
+            this.nanoOfMillisecond = event.getInstant().getNanoOfMillisecond();
             this.thrown = event.getThrown();
             this.thrownProxy = event.getThrownProxy();
             this.contextData = memento(event.getContextData());
@@ -942,7 +966,7 @@ public class Log4jLogEvent implements LogEvent {
         protected Object readResolve() {
             final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, 
loggerFQCN, level, message(), thrown,
                     thrownProxy, contextData, contextStack, threadId, 
threadName, threadPriority, source, timeMillis,
-                    nanoTime);
+                    nanoOfMillisecond, nanoTime);
             result.setEndOfBatch(isEndOfBatch);
             result.setIncludeLocation(isLocationRequired);
             return result;
@@ -959,5 +983,4 @@ public class Log4jLogEvent implements LogEvent {
             return new SimpleMessage(messageString);
         }
     }
-
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
index acc31b3..ec807d3 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
@@ -26,11 +26,8 @@ import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.async.InternalAsyncUtil;
-import org.apache.logging.log4j.core.util.Constants;
-import org.apache.logging.log4j.message.Message;
-import org.apache.logging.log4j.message.ParameterizedMessage;
-import org.apache.logging.log4j.message.ReusableMessage;
-import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.core.util.*;
+import org.apache.logging.log4j.message.*;
 import org.apache.logging.log4j.util.ReadOnlyStringMap;
 import org.apache.logging.log4j.util.StackLocatorUtil;
 import org.apache.logging.log4j.util.StringBuilders;
@@ -46,7 +43,7 @@ public class MutableLogEvent implements LogEvent, 
ReusableMessage {
 
     private int threadPriority;
     private long threadId;
-    private long timeMillis;
+    private MutableInstant instant = new MutableInstant();
     private long nanoTime;
     private short parameterCount;
     private boolean includeLocation;
@@ -95,10 +92,11 @@ public class MutableLogEvent implements LogEvent, 
ReusableMessage {
         this.marker = event.getMarker();
         this.level = event.getLevel();
         this.loggerName = event.getLoggerName();
-        this.timeMillis = event.getTimeMillis();
         this.thrown = event.getThrown();
         this.thrownProxy = event.getThrownProxy();
 
+        this.instant.initFrom(event.getInstant());
+
         // NOTE: this ringbuffer event SHOULD NOT keep a reference to the 
specified
         // thread-local MutableLogEvent's context data, because then two 
threads would call
         // ReadOnlyStringMap.clear() on the same shared instance, resulting in 
data corruption.
@@ -307,13 +305,27 @@ public class MutableLogEvent implements LogEvent, 
ReusableMessage {
         this.thrown = thrown;
     }
 
+    void initTime(final Clock clock, final NanoClock nanoClock) {
+        if (message instanceof TimestampMessage) {
+            instant.initFromEpochMilli(((TimestampMessage) 
message).getTimestamp(), 0);
+        } else {
+            instant.initFrom(clock);
+        }
+        nanoTime = nanoClock.nanoTime();
+    }
+
     @Override
     public long getTimeMillis() {
-        return timeMillis;
+        return instant.getEpochMillisecond();
     }
 
     public void setTimeMillis(final long timeMillis) {
-        this.timeMillis = timeMillis;
+        this.instant.initFromEpochMilli(timeMillis, 0);
+    }
+
+    @Override
+    public Instant getInstant() {
+        return instant;
     }
 
     /**
@@ -468,7 +480,8 @@ public class MutableLogEvent implements LogEvent, 
ReusableMessage {
                 .setThreadPriority(threadPriority) //
                 .setThrown(getThrown()) // may deserialize from thrownProxy
                 .setThrownProxy(thrownProxy) // avoid unnecessarily creating 
thrownProxy
-                .setTimeMillis(timeMillis);
+                .setInstant(instant) //
+        ;
     }
 
     private Message getNonNullImmutableMessage() {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
index bef1b8d..0ecefed 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
@@ -28,7 +28,6 @@ import org.apache.logging.log4j.core.config.Property;
 import org.apache.logging.log4j.core.util.Clock;
 import org.apache.logging.log4j.core.util.ClockFactory;
 import org.apache.logging.log4j.message.Message;
-import org.apache.logging.log4j.message.TimestampMessage;
 import org.apache.logging.log4j.util.StringMap;
 
 /**
@@ -79,13 +78,10 @@ public class ReusableLogEventFactory implements 
LogEventFactory {
         result.setLoggerFqcn(fqcn);
         result.setLevel(level == null ? Level.OFF : level);
         result.setMessage(message);
+        result.initTime(CLOCK, Log4jLogEvent.getNanoClock());
         result.setThrown(t);
         result.setContextData(injector.injectContextData(properties, 
(StringMap) result.getContextData()));
         result.setContextStack(ThreadContext.getDepth() == 0 ? 
ThreadContext.EMPTY_STACK : ThreadContext.cloneStack());// mutable copy
-        result.setTimeMillis(message instanceof TimestampMessage
-                ? ((TimestampMessage) message).getTimestamp()
-                : CLOCK.currentTimeMillis());
-        result.setNanoTime(Log4jLogEvent.getNanoClock().nanoTime());
 
         if (THREAD_NAME_CACHING_STRATEGY == 
ThreadNameCachingStrategy.UNCACHED) {
             result.setThreadName(Thread.currentThread().getName()); // 
Thread.getName() allocates Objects on each call

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java
index 65c8438..18e30e2 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java
@@ -27,6 +27,7 @@ import org.apache.logging.log4j.message.ObjectMessage;
 
 import com.fasterxml.jackson.databind.Module.SetupContext;
 import com.fasterxml.jackson.databind.module.SimpleModule;
+import org.apache.logging.log4j.core.util.Instant;
 
 /**
  * Initialization utils.
@@ -47,6 +48,7 @@ class Initializers {
             // Log4j API classes: we do not want to edit those with Jackson 
annotations because the API module should not depend on Jackson.
             context.setMixInAnnotations(Marker.class, MarkerMixIn.class);
             context.setMixInAnnotations(Level.class, LevelMixIn.class);
+            context.setMixInAnnotations(Instant.class, InstantMixIn.class);
             context.setMixInAnnotations(LogEvent.class, 
LogEventWithContextListMixIn.class);
             // Log4j Core classes: we do not want to bring in Jackson at 
runtime if we do not have to.
             context.setMixInAnnotations(ExtendedStackTraceElement.class, 
ExtendedStackTraceElementMixIn.class);
@@ -68,6 +70,7 @@ class Initializers {
             // Log4j API classes: we do not want to edit those with Jackson 
annotations because the API module should not depend on Jackson.
             context.setMixInAnnotations(Marker.class, MarkerMixIn.class);
             context.setMixInAnnotations(Level.class, LevelMixIn.class);
+            context.setMixInAnnotations(Instant.class, InstantMixIn.class);
             context.setMixInAnnotations(LogEvent.class, 
LogEventJsonMixIn.class); // different ThreadContext handling
             // Log4j Core classes: we do not want to bring in Jackson at 
runtime if we do not have to.
             context.setMixInAnnotations(ExtendedStackTraceElement.class, 
ExtendedStackTraceElementMixIn.class);

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/InstantMixIn.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/InstantMixIn.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/InstantMixIn.java
new file mode 100644
index 0000000..44b9a6d
--- /dev/null
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/InstantMixIn.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.jackson;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonValue;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.core.util.Instant;
+
+/**
+ * Jackson mix-in for {@link Instant}.
+ * <p>
+ * <em>Consider this class private.</em>
+ * </p>
+ * @see Marker
+ */
+@JsonIgnoreProperties({ "epochMillisecond", "nanoOfMillisecond" })
+abstract class InstantMixIn {
+
+    @JsonCreator
+    InstantMixIn(
+            // @formatter:off
+            @JsonProperty("epochSecond") final long epochSecond,
+            @JsonProperty("nanoOfSecond") final int nanoOfSecond)
+            // @formatter:on
+    {
+        // empty
+    }
+
+    @JsonProperty("epochSecond")
+    @JacksonXmlProperty(localName = "epochSecond", isAttribute = true)
+    abstract long getEpochSecond();
+
+    @JsonProperty("nanoOfSecond")
+    @JacksonXmlProperty(localName = "nanoOfSecond", isAttribute = true)
+    abstract int getNanoOfSecond();
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java
index 8e9ed2c..bb9898d 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java
@@ -31,4 +31,5 @@ public final class JsonConstants {
     public static final String ELT_MESSAGE = "message";
     public static final String ELT_EXTENDED_STACK_TRACE = "extendedStackTrace";
     public static final String ELT_NANO_TIME = "nanoTime";
+    public static final String ELT_INSTANT = "instant";
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java
index b659e9b..6c27295 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java
@@ -21,6 +21,7 @@ import java.util.Map;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.ThreadContext.ContextStack;
+import org.apache.logging.log4j.core.util.Instant;
 import org.apache.logging.log4j.util.ReadOnlyStringMap;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.impl.ThrowableProxy;
@@ -40,7 +41,7 @@ import 
com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
 @JsonRootName(XmlConstants.ELT_EVENT)
 @JacksonXmlRootElement(namespace = XmlConstants.XML_NAMESPACE, localName = 
XmlConstants.ELT_EVENT)
 @JsonFilter("org.apache.logging.log4j.core.impl.Log4jLogEvent")
-@JsonPropertyOrder({ "timeMillis", "threadName", "level", "loggerName", 
"marker", "message", "thrown", XmlConstants.ELT_CONTEXT_MAP,
+@JsonPropertyOrder({ "timeMillis", XmlConstants.ELT_INSTANT, "threadName", 
"level", "loggerName", "marker", "message", "thrown", 
XmlConstants.ELT_CONTEXT_MAP,
         JsonConstants.ELT_CONTEXT_STACK, "loggerFQCN", "Source", "endOfBatch" 
})
 abstract class LogEventJsonMixIn implements LogEvent {
 
@@ -126,11 +127,17 @@ abstract class LogEventJsonMixIn implements LogEvent {
     @Override
     public abstract ThrowableProxy getThrownProxy();
 
-    @JsonProperty()
-    @JacksonXmlProperty(isAttribute = true)
+    @JsonIgnore // ignore from 2.11
+//    @JsonProperty()
+//    @JacksonXmlProperty(isAttribute = true)
     @Override
     public abstract long getTimeMillis();
 
+    @JsonProperty(JsonConstants.ELT_INSTANT)
+    @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = 
XmlConstants.ELT_INSTANT)
+    @Override
+    public abstract Instant getInstant();
+
     @JsonProperty()
     @JacksonXmlProperty(isAttribute = true)
     @Override

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventWithContextListMixIn.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventWithContextListMixIn.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventWithContextListMixIn.java
index 176d82d..b71fcfc 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventWithContextListMixIn.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventWithContextListMixIn.java
@@ -21,6 +21,7 @@ import java.util.Map;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.ThreadContext.ContextStack;
+import org.apache.logging.log4j.core.util.Instant;
 import org.apache.logging.log4j.util.ReadOnlyStringMap;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.impl.ThrowableProxy;
@@ -40,7 +41,7 @@ import 
com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
 @JsonRootName(XmlConstants.ELT_EVENT)
 @JacksonXmlRootElement(namespace = XmlConstants.XML_NAMESPACE, localName = 
XmlConstants.ELT_EVENT)
 @JsonFilter("org.apache.logging.log4j.core.impl.Log4jLogEvent")
-@JsonPropertyOrder({ "timeMillis", "threadName", "level", "loggerName", 
"marker", "message", "thrown", XmlConstants.ELT_CONTEXT_MAP,
+@JsonPropertyOrder({ "timeMillis", XmlConstants.ELT_INSTANT, "threadName", 
"level", "loggerName", "marker", "message", "thrown", 
XmlConstants.ELT_CONTEXT_MAP,
         JsonConstants.ELT_CONTEXT_STACK, "loggerFQCN", "Source", "endOfBatch" 
})
 abstract class LogEventWithContextListMixIn implements LogEvent {
 
@@ -125,11 +126,17 @@ abstract class LogEventWithContextListMixIn implements 
LogEvent {
     @Override
     public abstract ThrowableProxy getThrownProxy();
 
-    @JsonProperty()
-    @JacksonXmlProperty(isAttribute = true)
+    @JsonIgnore // ignore from 2.11
+//    @JsonProperty()
+//    @JacksonXmlProperty(isAttribute = true)
     @Override
     public abstract long getTimeMillis();
 
+    @JsonProperty(JsonConstants.ELT_INSTANT)
+    @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = 
XmlConstants.ELT_INSTANT)
+    @Override
+    public abstract Instant getInstant();
+
     @JsonProperty()
     @JacksonXmlProperty(isAttribute = true)
     @Override

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java
index c3b03cc..0871440 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java
@@ -27,6 +27,7 @@ public final class XmlConstants {
     public static final String ELT_EVENT = "Event";
     public static final String ELT_EXTENDED_STACK_TRACE = "ExtendedStackTrace";
     public static final String ELT_EXTENDED_STACK_TRACE_ITEM = 
"ExtendedStackTraceItem";
+    public static final String ELT_INSTANT = "Instant";
     public static final String ELT_MARKER = "Marker";
     public static final String ELT_MESSAGE = "Message";
     public static final String ELT_PARENTS = "Parents";

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java
index 732acf8..aa49ee4 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java
@@ -25,6 +25,8 @@ import java.util.concurrent.atomic.AtomicReference;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.core.util.Instant;
+import org.apache.logging.log4j.core.util.MutableInstant;
 import org.apache.logging.log4j.core.util.datetime.FastDateFormat;
 import org.apache.logging.log4j.core.util.datetime.FixedDateFormat;
 import org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat;
@@ -40,10 +42,11 @@ public final class DatePatternConverter extends 
LogEventPatternConverter impleme
 
     private abstract static class Formatter {
         long previousTime; // for ThreadLocal caching mode
+        int nanos;
 
-        abstract String format(long timeMillis);
+        abstract String format(final Instant instant);
 
-        abstract void formatToBuffer(long timeMillis, StringBuilder 
destination);
+        abstract void formatToBuffer(final Instant instant, StringBuilder 
destination);
 
         public String toPattern() {
             return null;
@@ -61,12 +64,13 @@ public final class DatePatternConverter extends 
LogEventPatternConverter impleme
         }
 
         @Override
-        String format(final long timeMillis) {
-            return fastDateFormat.format(timeMillis);
+        String format(final Instant instant) {
+            return fastDateFormat.format(instant.getEpochMillisecond());
         }
 
         @Override
-        void formatToBuffer(final long timeMillis, final StringBuilder 
destination) {
+        void formatToBuffer(final Instant instant, final StringBuilder 
destination) {
+            final long timeMillis = instant.getEpochMillisecond();
             if (previousTime != timeMillis) {
                 cachedBuffer.setLength(0);
                 fastDateFormat.format(timeMillis, cachedBuffer);
@@ -92,14 +96,18 @@ public final class DatePatternConverter extends 
LogEventPatternConverter impleme
         }
 
         @Override
-        String format(final long timeMillis) {
-            return fixedDateFormat.format(timeMillis);
+        String format(final Instant instant) {
+            return fixedDateFormat.formatInstant(instant);
         }
 
         @Override
-        void formatToBuffer(final long timeMillis, final StringBuilder 
destination) {
-            if (previousTime != timeMillis) {
-                length = fixedDateFormat.format(timeMillis, cachedBuffer, 0);
+        void formatToBuffer(final Instant instant, final StringBuilder 
destination) {
+            final long epochSecond = instant.getEpochSecond();
+            final int nanoOfSecond = instant.getNanoOfSecond();
+            if (previousTime != epochSecond && nanos != nanoOfSecond) {
+                length = fixedDateFormat.formatInstant(instant, cachedBuffer, 
0);
+                previousTime = epochSecond;
+                nanos = nanoOfSecond;
             }
             destination.append(cachedBuffer, 0, length);
         }
@@ -113,36 +121,38 @@ public final class DatePatternConverter extends 
LogEventPatternConverter impleme
     private static final class UnixFormatter extends Formatter {
 
         @Override
-        String format(final long timeMillis) {
-            return Long.toString(timeMillis / 1000);
+        String format(final Instant instant) {
+            return Long.toString(instant.getEpochSecond());
         }
 
         @Override
-        void formatToBuffer(final long timeMillis, final StringBuilder 
destination) {
-            destination.append(timeMillis / 1000); // no need for caching
+        void formatToBuffer(final Instant instant, final StringBuilder 
destination) {
+            destination.append(instant.getEpochSecond()); // no need for 
caching
         }
     }
 
     private static final class UnixMillisFormatter extends Formatter {
 
         @Override
-        String format(final long timeMillis) {
-            return Long.toString(timeMillis);
+        String format(final Instant instant) {
+            return Long.toString(instant.getEpochMillisecond());
         }
 
         @Override
-        void formatToBuffer(final long timeMillis, final StringBuilder 
destination) {
-            destination.append(timeMillis); // no need for caching
+        void formatToBuffer(final Instant instant, final StringBuilder 
destination) {
+            destination.append(instant.getEpochMillisecond()); // no need for 
caching
         }
     }
 
     private final class CachedTime {
-        public long timestampMillis;
+        public long epochSecond;
+        public int nanoOfSecond;
         public String formatted;
 
-        public CachedTime(final long timestampMillis) {
-            this.timestampMillis = timestampMillis;
-            this.formatted = formatter.format(this.timestampMillis);
+        public CachedTime(final Instant instant) {
+            this.epochSecond = instant.getEpochSecond();
+            this.nanoOfSecond = instant.getNanoOfSecond();
+            this.formatted = formatter.format(instant);
         }
     }
 
@@ -157,6 +167,7 @@ public final class DatePatternConverter extends 
LogEventPatternConverter impleme
     private static final String UNIX_MILLIS_FORMAT = "UNIX_MILLIS";
 
     private final String[] options;
+    private final ThreadLocal<MutableInstant> threadLocalMutableInstant = new 
ThreadLocal<>();
     private final ThreadLocal<Formatter> threadLocalFormatter = new 
ThreadLocal<>();
     private final AtomicReference<CachedTime> cachedTime;
     private final Formatter formatter;
@@ -170,7 +181,13 @@ public final class DatePatternConverter extends 
LogEventPatternConverter impleme
         super("Date", "date");
         this.options = options == null ? null : Arrays.copyOf(options, 
options.length);
         this.formatter = createFormatter(options);
-        cachedTime = new AtomicReference<>(new 
CachedTime(System.currentTimeMillis()));
+        cachedTime = new 
AtomicReference<>(fromEpochMillis(System.currentTimeMillis()));
+    }
+
+    private CachedTime fromEpochMillis(long epochMillis) {
+        final MutableInstant temp = new MutableInstant();
+        temp.initFromEpochMilli(epochMillis, 0);
+        return new CachedTime(temp);
     }
 
     private Formatter createFormatter(final String[] options) {
@@ -245,19 +262,38 @@ public final class DatePatternConverter extends 
LogEventPatternConverter impleme
      */
     @Override
     public void format(final LogEvent event, final StringBuilder output) {
-        format(event.getTimeMillis(), output);
+        format(event.getInstant(), output);
+    }
+
+    public void format(final long epochMilli, final StringBuilder output) {
+        MutableInstant instant = getMutableInstant();
+        instant.initFromEpochMilli(epochMilli, 0);
+        format(instant, output);
+    }
+
+    private MutableInstant getMutableInstant() {
+        if (Constants.ENABLE_THREADLOCALS) {
+            MutableInstant result = threadLocalMutableInstant.get();
+            if (result == null) {
+                result = new MutableInstant();
+                threadLocalMutableInstant.set(result);
+            }
+            return result;
+        } else {
+            return new MutableInstant();
+        }
     }
 
-    public void format(final long timestampMillis, final StringBuilder output) 
{
+    public void format(final Instant instant, final StringBuilder output) {
         if (Constants.ENABLE_THREADLOCALS) {
-            formatWithoutAllocation(timestampMillis, output);
+            formatWithoutAllocation(instant, output);
         } else {
-            formatWithoutThreadLocals(timestampMillis, output);
+            formatWithoutThreadLocals(instant, output);
         }
     }
 
-    private void formatWithoutAllocation(final long timestampMillis, final 
StringBuilder output) {
-        getThreadLocalFormatter().formatToBuffer(timestampMillis, output);
+    private void formatWithoutAllocation(final Instant instant, final 
StringBuilder output) {
+        getThreadLocalFormatter().formatToBuffer(instant, output);
     }
 
     private Formatter getThreadLocalFormatter() {
@@ -269,10 +305,10 @@ public final class DatePatternConverter extends 
LogEventPatternConverter impleme
         return result;
     }
 
-    private void formatWithoutThreadLocals(final long timestampMillis, final 
StringBuilder output) {
+    private void formatWithoutThreadLocals(final Instant instant, final 
StringBuilder output) {
         CachedTime cached = cachedTime.get();
-        if (timestampMillis != cached.timestampMillis) {
-            final CachedTime newTime = new CachedTime(timestampMillis);
+        if (instant.getEpochSecond() != cached.epochSecond || 
instant.getNanoOfSecond() != cached.nanoOfSecond) {
+            final CachedTime newTime = new CachedTime(instant);
             if (cachedTime.compareAndSet(cached, newTime)) {
                 cached = newTime;
             } else {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e3a126ee/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java
index 129f281..bd5e840 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java
@@ -18,6 +18,10 @@ package org.apache.logging.log4j.core.util;
 
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.PropertiesUtil;
+import org.apache.logging.log4j.util.Supplier;
+
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * Factory for {@code Clock} objects.
@@ -62,21 +66,24 @@ public final class ClockFactory {
         return createClock();
     }
 
+    private static Map<String, Supplier<Clock>> aliases() {
+        Map<String, Supplier<Clock>> result = new HashMap<>();
+        result.put("SystemClock",       new Supplier<Clock>() { @Override 
public Clock get() { return new SystemClock(); } });
+        result.put("CachedClock",       new Supplier<Clock>() { @Override 
public Clock get() { return CachedClock.instance(); } });
+        result.put("CoarseCachedClock", new Supplier<Clock>() { @Override 
public Clock get() { return CoarseCachedClock.instance(); } });
+        return result;
+    }
+
     private static Clock createClock() {
         final String userRequest = 
PropertiesUtil.getProperties().getStringProperty(PROPERTY_NAME);
-        if (userRequest == null || "SystemClock".equals(userRequest)) {
+        if (userRequest == null) {
             LOGGER.trace("Using default SystemClock for timestamps.");
             return new SystemClock();
         }
-        if (CachedClock.class.getName().equals(userRequest)
-                || "CachedClock".equals(userRequest)) {
-            LOGGER.trace("Using specified CachedClock for timestamps.");
-            return CachedClock.instance();
-        }
-        if (CoarseCachedClock.class.getName().equals(userRequest)
-                || "CoarseCachedClock".equals(userRequest)) {
-            LOGGER.trace("Using specified CoarseCachedClock for timestamps.");
-            return CoarseCachedClock.instance();
+        Supplier<Clock> specified = aliases().get(userRequest);
+        if (specified != null) {
+            LOGGER.trace("Using specified {} for timestamps.", userRequest);
+            return specified.get();
         }
         try {
             final Clock result = Loader.newCheckedInstanceOf(userRequest, 
Clock.class);

Reply via email to