예제 #1
0
        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;
            bool saw_day_specifier = false;

            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)));
                    }

                    saw_day_specifier = true;
                    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
                    {
                        // NOTE: .NET ignores quoted 'd' and reads it as day specifier but I think
                        // that's wrong
                        result.Append(saw_day_specifier ? dfi.GetMonthGenitiveName(month) : 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());
        }