#region Apache License
|
//
|
// 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.
|
//
|
#endregion
|
|
using System;
|
using System.IO;
|
using System.Text;
|
|
namespace log4net.DateFormatter
|
{
|
/// <summary>
|
/// Formats a <see cref="DateTime"/> as <c>"HH:mm:ss,fff"</c>.
|
/// </summary>
|
/// <remarks>
|
/// <para>
|
/// Formats a <see cref="DateTime"/> in the format <c>"HH:mm:ss,fff"</c> for example, <c>"15:49:37,459"</c>.
|
/// </para>
|
/// </remarks>
|
/// <author>Nicko Cadell</author>
|
/// <author>Gert Driesen</author>
|
public class AbsoluteTimeDateFormatter : IDateFormatter
|
{
|
#region Protected Instance Methods
|
|
/// <summary>
|
/// Renders the date into a string. Format is <c>"HH:mm:ss"</c>.
|
/// </summary>
|
/// <param name="dateToFormat">The date to render into a string.</param>
|
/// <param name="buffer">The string builder to write to.</param>
|
/// <remarks>
|
/// <para>
|
/// Subclasses should override this method to render the date
|
/// into a string using a precision up to the second. This method
|
/// will be called at most once per second and the result will be
|
/// reused if it is needed again during the same second.
|
/// </para>
|
/// </remarks>
|
virtual protected void FormatDateWithoutMillis(DateTime dateToFormat, StringBuilder buffer)
|
{
|
int hour = dateToFormat.Hour;
|
if (hour < 10)
|
{
|
buffer.Append('0');
|
}
|
buffer.Append(hour);
|
buffer.Append(':');
|
|
int mins = dateToFormat.Minute;
|
if (mins < 10)
|
{
|
buffer.Append('0');
|
}
|
buffer.Append(mins);
|
buffer.Append(':');
|
|
int secs = dateToFormat.Second;
|
if (secs < 10)
|
{
|
buffer.Append('0');
|
}
|
buffer.Append(secs);
|
}
|
|
#endregion Protected Instance Methods
|
|
#region Implementation of IDateFormatter
|
|
/// <summary>
|
/// Renders the date into a string. Format is "HH:mm:ss,fff".
|
/// </summary>
|
/// <param name="dateToFormat">The date to render into a string.</param>
|
/// <param name="writer">The writer to write to.</param>
|
/// <remarks>
|
/// <para>
|
/// Uses the <see cref="FormatDateWithoutMillis"/> method to generate the
|
/// time string up to the seconds and then appends the current
|
/// milliseconds. The results from <see cref="FormatDateWithoutMillis"/> are
|
/// cached and <see cref="FormatDateWithoutMillis"/> is called at most once
|
/// per second.
|
/// </para>
|
/// <para>
|
/// Sub classes should override <see cref="FormatDateWithoutMillis"/>
|
/// rather than <see cref="FormatDate"/>.
|
/// </para>
|
/// </remarks>
|
virtual public void FormatDate(DateTime dateToFormat, TextWriter writer)
|
{
|
// Calculate the current time precise only to the second
|
long currentTimeToTheSecond = (dateToFormat.Ticks - (dateToFormat.Ticks % TimeSpan.TicksPerSecond));
|
|
// Compare this time with the stored last time
|
// If we are in the same second then append
|
// the previously calculated time string
|
if (s_lastTimeToTheSecond != currentTimeToTheSecond)
|
{
|
// lock so that only one thread can use the buffer and
|
// update the s_lastTimeToTheSecond and s_lastTimeString
|
|
// PERF: Try removing this lock and using a new StringBuilder each time
|
lock(s_lastTimeBuf)
|
{
|
if (s_lastTimeToTheSecond != currentTimeToTheSecond)
|
{
|
// We are in a new second.
|
s_lastTimeBuf.Length = 0;
|
|
// Calculate the new string for this second
|
FormatDateWithoutMillis(dateToFormat, s_lastTimeBuf);
|
|
// Render the string buffer to a string
|
string currentDateWithoutMillis = s_lastTimeBuf.ToString();
|
|
#if NET_1_1
|
// Ensure that the above string is written into the variable NOW on all threads.
|
// This is only required on multiprocessor machines with weak memeory models
|
System.Threading.Thread.MemoryBarrier();
|
#endif
|
// Store the time as a string (we only have to do this once per second)
|
s_lastTimeString = currentDateWithoutMillis;
|
s_lastTimeToTheSecond = currentTimeToTheSecond;
|
}
|
}
|
}
|
writer.Write(s_lastTimeString);
|
|
// Append the current millisecond info
|
writer.Write(',');
|
int millis = dateToFormat.Millisecond;
|
if (millis < 100)
|
{
|
writer.Write('0');
|
}
|
if (millis < 10)
|
{
|
writer.Write('0');
|
}
|
writer.Write(millis);
|
}
|
|
#endregion Implementation of IDateFormatter
|
|
#region Public Static Fields
|
|
/// <summary>
|
/// String constant used to specify AbsoluteTimeDateFormat in layouts. Current value is <b>ABSOLUTE</b>.
|
/// </summary>
|
public const string AbsoluteTimeDateFormat = "ABSOLUTE";
|
|
/// <summary>
|
/// String constant used to specify DateTimeDateFormat in layouts. Current value is <b>DATE</b>.
|
/// </summary>
|
public const string DateAndTimeDateFormat = "DATE";
|
|
/// <summary>
|
/// String constant used to specify ISO8601DateFormat in layouts. Current value is <b>ISO8601</b>.
|
/// </summary>
|
public const string Iso8601TimeDateFormat = "ISO8601";
|
|
#endregion Public Static Fields
|
|
#region Private Static Fields
|
|
/// <summary>
|
/// Last stored time with precision up to the second.
|
/// </summary>
|
private static long s_lastTimeToTheSecond = 0;
|
|
/// <summary>
|
/// Last stored time with precision up to the second, formatted
|
/// as a string.
|
/// </summary>
|
private static StringBuilder s_lastTimeBuf = new StringBuilder();
|
|
/// <summary>
|
/// Last stored time with precision up to the second, formatted
|
/// as a string.
|
/// </summary>
|
private static string s_lastTimeString;
|
|
#endregion Private Static Fields
|
}
|
}
|