All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.util.DateCache Maven / Gradle / Ivy

The newest version!
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.util;

import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

/**
 * Computes String representations of Dates then caches the results so
 * that subsequent requests within the same second will be fast.
 * 

* If consecutive calls are frequently very different, then this * may be a little slower than a normal DateFormat. *

* @see DateTimeFormatter for date formatting patterns. */ public class DateCache { public static final String DEFAULT_FORMAT = "EEE MMM dd HH:mm:ss zzz yyyy"; private final String _formatString; private final DateTimeFormatter _tzFormat1; private final DateTimeFormatter _tzFormat2; private final ZoneId _zoneId; private volatile TickHolder _tickHolder; private static class TickHolder { public TickHolder(Tick t1, Tick t2) { tick1 = t1; tick2 = t2; } final Tick tick1; final Tick tick2; } public static class Tick { private final long _seconds; private final String _prefix; private final String _suffix; public Tick(long seconds, String prefix, String suffix) { _seconds = seconds; _prefix = prefix; _suffix = suffix; } public long getSeconds() { return _seconds; } public String format(long inDate) { if (_suffix == null) return _prefix; long ms = inDate % 1000; StringBuilder sb = new StringBuilder(); sb.append(_prefix); if (ms < 10) sb.append("00").append(ms); else if (ms < 100) sb.append('0').append(ms); else sb.append(ms); sb.append(_suffix); return sb.toString(); } } /** * Make a DateCache that will use a default format. * The default format generates the same results as Date.toString(). */ public DateCache() { this(DEFAULT_FORMAT); } /** * Make a DateCache that will use the given format. * * @param format the format to use */ public DateCache(String format) { this(format, null, TimeZone.getDefault()); } public DateCache(String format, Locale l) { this(format, l, TimeZone.getDefault()); } public DateCache(String format, Locale l, String tz) { this(format, l, TimeZone.getTimeZone(tz)); } public DateCache(String format, Locale l, TimeZone tz) { this(format, l, tz, true); } public DateCache(String format, Locale l, TimeZone tz, boolean subSecondPrecision) { format = format.replaceFirst("S+", "SSS"); _formatString = format; _zoneId = tz.toZoneId(); String format1 = format; String format2 = null; boolean subSecond; if (subSecondPrecision) { int msIndex = format.indexOf("SSS"); subSecond = (msIndex >= 0); if (subSecond) { format1 = format.substring(0, msIndex); format2 = format.substring(msIndex + 3); } } else { subSecond = false; format1 = format.replace("SSS", "000"); } _tzFormat1 = createFormatter(format1, l, _zoneId); _tzFormat2 = subSecond ? createFormatter(format2, l, _zoneId) : null; } private DateTimeFormatter createFormatter(String format, Locale locale, ZoneId zoneId) { if (locale == null) return DateTimeFormatter.ofPattern(format).withZone(zoneId); else return DateTimeFormatter.ofPattern(format, locale).withZone(zoneId); } public TimeZone getTimeZone() { return TimeZone.getTimeZone(_zoneId); } /** * Format a date according to our stored formatter. * If it happens to be in the same second as the last * formatNow call, then the format is reused. * * @param inDate the Date. * @return Formatted date. */ public String format(Date inDate) { return format(inDate.getTime()); } /** * Format a date according to our stored formatter. * If it happens to be in the same second as the last * formatNow call, then the format is reused. * * @param inDate the date in milliseconds since unix epoch. * @return Formatted date. */ public String format(long inDate) { return formatTick(inDate).format(inDate); } /** * Format a date according to supplied formatter. * * @param inDate the date in milliseconds since unix epoch. * @return Formatted date. */ protected String doFormat(long inDate, DateTimeFormatter formatter) { if (formatter == null) return null; return formatter.format(Instant.ofEpochMilli(inDate)); } protected Tick formatTick(long inDate) { long seconds = inDate / 1000; // Two Ticks are cached so that for monotonically increasing times to not see any jitter from multiple cores. // The ticks are kept in a volatile field, so there a small risk of inconsequential multiple recalculations TickHolder holder = _tickHolder; if (holder != null) { if (holder.tick1 != null && holder.tick1.getSeconds() == seconds) return holder.tick1; if (holder.tick2 != null && holder.tick2.getSeconds() == seconds) return holder.tick2; } String prefix = doFormat(inDate, _tzFormat1); String suffix = doFormat(inDate, _tzFormat2); Tick tick = new Tick(seconds, prefix, suffix); _tickHolder = new TickHolder(tick, (holder == null) ? null : holder.tick1); return tick; } public String getFormatString() { return _formatString; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy