001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.core.util; 015 016import java.time.Instant; 017import java.time.OffsetDateTime; 018import java.time.ZoneId; 019import java.time.format.DateTimeFormatter; 020import java.util.concurrent.atomic.AtomicReference; 021 022/** 023 * A CAS implementation of DateTimeFormatter (previously SimpleDateFormat) which 024 * caches results for the duration of a millisecond. 025 * 026 * @author Ceki Gülcü 027 * @since 0.9.29 028 */ 029public class CachingDateFormatter { 030 031 final DateTimeFormatter dtf; 032 final ZoneId zoneId; 033 final AtomicReference<CacheTuple> atomicReference; 034 035 static class CacheTuple { 036 final long lastTimestamp; 037 final String cachedStr; 038 039 public CacheTuple(long lastTimestamp, String cachedStr) { 040 super(); 041 this.lastTimestamp = lastTimestamp; 042 this.cachedStr = cachedStr; 043 } 044 } 045 046 public CachingDateFormatter(String pattern) { 047 this(pattern, null); 048 } 049 050 public CachingDateFormatter(String pattern, ZoneId aZoneId) { 051 if (aZoneId == null) { 052 this.zoneId = ZoneId.systemDefault(); 053 } else { 054 this.zoneId = aZoneId; 055 } 056 057 dtf = DateTimeFormatter.ofPattern(pattern).withZone(this.zoneId); 058 CacheTuple cacheTuple = new CacheTuple(-1, null); 059 this.atomicReference = new AtomicReference<>(cacheTuple); 060 } 061 062 public final String format(long now) { 063 CacheTuple localCacheTuple = atomicReference.get(); 064 CacheTuple oldCacheTuple = localCacheTuple; 065 066 if (now != localCacheTuple.lastTimestamp) { 067 Instant instant = Instant.ofEpochMilli(now); 068 String result = dtf.format(instant); 069 localCacheTuple = new CacheTuple(now, result); 070 // allow a single thread to update the cache reference 071 atomicReference.compareAndSet(oldCacheTuple, localCacheTuple); 072 } 073 return localCacheTuple.cachedStr; 074 } 075 076}