public static string ToString(DateTime dt, TimeSpan?utc_offset, string format, DateTimeFormatInfo dfi)
{
// the length of the format is usually a good guess of the number
// of chars in the result. Might save us a few bytes sometimes
// Add + 10 for cases like mmmm dddd
StringBuilder result = new StringBuilder(format.Length + 10);
// For some cases, the output should not use culture dependent calendar
DateTimeFormatInfo inv = DateTimeFormatInfo.InvariantInfo;
if (format == inv.RFC1123Pattern)
{
dfi = inv;
}
else if (format == inv.UniversalSortableDateTimePattern)
{
dfi = inv;
}
int i = 0;
while (i < format.Length)
{
int tokLen;
bool omitZeros = false;
char ch = format [i];
switch (ch)
{
//
// Time Formats
//
case 'h':
// hour, [1, 12]
tokLen = DateTimeUtils.CountRepeat(format, i, ch);
int hr = dt.Hour % 12;
if (hr == 0)
{
hr = 12;
}
DateTimeUtils.ZeroPad(result, hr, tokLen == 1 ? 1 : 2);
break;
case 'H':
// hour, [0, 23]
tokLen = DateTimeUtils.CountRepeat(format, i, ch);
DateTimeUtils.ZeroPad(result, dt.Hour, tokLen == 1 ? 1 : 2);
break;
case 'm':
// minute, [0, 59]
tokLen = DateTimeUtils.CountRepeat(format, i, ch);
DateTimeUtils.ZeroPad(result, dt.Minute, tokLen == 1 ? 1 : 2);
break;
case 's':
// second [0, 29]
tokLen = DateTimeUtils.CountRepeat(format, i, ch);
DateTimeUtils.ZeroPad(result, dt.Second, tokLen == 1 ? 1 : 2);
break;
case 'F':
omitZeros = true;
goto case 'f';
case 'f':
// fraction of second, to same number of
// digits as there are f's
tokLen = DateTimeUtils.CountRepeat(format, i, ch);
if (tokLen > 7)
{
throw new FormatException("Invalid Format String");
}
int dec = (int)((long)(dt.Ticks % TimeSpan.TicksPerSecond) / (long)Math.Pow(10, 7 - tokLen));
int startLen = result.Length;
DateTimeUtils.ZeroPad(result, dec, tokLen);
if (omitZeros)
{
while (result.Length > startLen && result [result.Length - 1] == '0')
{
result.Length--;
}
// when the value was 0, then trim even preceding '.' (!) It is fixed character.
if (dec == 0 && startLen > 0 && result [startLen - 1] == '.')
{
result.Length--;
}
}
break;
case 't':
// AM/PM. t == first char, tt+ == full
tokLen = DateTimeUtils.CountRepeat(format, i, ch);
string desig = dt.Hour < 12 ? dfi.AMDesignator : dfi.PMDesignator;
if (tokLen == 1)
{
if (desig.Length >= 1)
{
result.Append(desig [0]);
}
}
else
{
result.Append(desig);
}
break;
case 'z':
// timezone. t = +/-h; tt = +/-hh; ttt+=+/-hh:mm
tokLen = DateTimeUtils.CountRepeat(format, i, ch);
TimeSpan offset =
utc_offset ??
TimeZone.CurrentTimeZone.GetUtcOffset(dt);
if (offset.Ticks >= 0)
{
result.Append('+');
}
else
{
result.Append('-');
}
switch (tokLen)
{
case 1:
result.Append(Math.Abs(offset.Hours));
break;
case 2:
result.Append(Math.Abs(offset.Hours).ToString("00"));
break;
default:
result.Append(Math.Abs(offset.Hours).ToString("00"));
result.Append(':');
result.Append(Math.Abs(offset.Minutes).ToString("00"));
break;
}
break;
case 'K': // 'Z' (UTC) or zzz (Local)
tokLen = 1;
if (utc_offset != null || dt.Kind == DateTimeKind.Local)
{
offset = utc_offset ?? TimeZone.CurrentTimeZone.GetUtcOffset(dt);
if (offset.Ticks >= 0)
{
result.Append('+');
}
else
{
result.Append('-');
}
result.Append(Math.Abs(offset.Hours).ToString("00"));
result.Append(':');
result.Append(Math.Abs(offset.Minutes).ToString("00"));
}
else if (dt.Kind == DateTimeKind.Utc)
{
result.Append('Z');
}
break;
//
// Date tokens
//
case 'd':
// day. d(d?) = day of month (leading 0 if two d's)
// ddd = three leter day of week
// dddd+ full day-of-week
tokLen = DateTimeUtils.CountRepeat(format, i, ch);
if (tokLen <= 2)
{
DateTimeUtils.ZeroPad(result, dfi.Calendar.GetDayOfMonth(dt), tokLen == 1 ? 1 : 2);
}
else if (tokLen == 3)
{
result.Append(dfi.GetAbbreviatedDayName(dfi.Calendar.GetDayOfWeek(dt)));
}
else
{
result.Append(dfi.GetDayName(dfi.Calendar.GetDayOfWeek(dt)));
}
break;
case 'M':
// Month.m(m?) = month # (with leading 0 if two mm)
// mmm = 3 letter name
// mmmm+ = full name
tokLen = DateTimeUtils.CountRepeat(format, i, ch);
int month = dfi.Calendar.GetMonth(dt);
if (tokLen <= 2)
{
DateTimeUtils.ZeroPad(result, month, tokLen);
}
else if (tokLen == 3)
{
result.Append(dfi.GetAbbreviatedMonthName(month));
}
else
{
result.Append(dfi.GetMonthName(month));
}
break;
case 'y':
// Year. y(y?) = two digit year, with leading 0 if yy
// yyy+ full year with leading zeros if needed.
tokLen = DateTimeUtils.CountRepeat(format, i, ch);
if (tokLen <= 2)
{
DateTimeUtils.ZeroPad(result, dfi.Calendar.GetYear(dt) % 100, tokLen);
}
else
{
DateTimeUtils.ZeroPad(result, dfi.Calendar.GetYear(dt), tokLen);
}
break;
case 'g':
// Era name
tokLen = DateTimeUtils.CountRepeat(format, i, ch);
result.Append(dfi.GetEraName(dfi.Calendar.GetEra(dt)));
break;
//
// Other
//
case ':':
result.Append(dfi.TimeSeparator);
tokLen = 1;
break;
case '/':
result.Append(dfi.DateSeparator);
tokLen = 1;
break;
case '\'':
case '"':
tokLen = DateTimeUtils.ParseQuotedString(format, i, result);
break;
case '%':
if (i >= format.Length - 1)
{
throw new FormatException("% at end of date time string");
}
if (format [i + 1] == '%')
{
throw new FormatException("%% in date string");
}
// Look for the next char
tokLen = 1;
break;
case '\\':
// C-Style escape
if (i >= format.Length - 1)
{
throw new FormatException("\\ at end of date time string");
}
result.Append(format [i + 1]);
tokLen = 2;
break;
default:
// catch all
result.Append(ch);
tokLen = 1;
break;
}
i += tokLen;
}
return(result.ToString());
}