示例#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);

			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 {
						// Handles MMMM dd format
						if (!saw_day_specifier) {
							for (int ii = i + 1; ii < format.Length; ++ii) {
								ch = format [ii];
								if (ch == 'd') {
									saw_day_specifier = true;
									break;
								}

								if (ch == '\'' || ch == '"') {
									ii += ParseQuotedString (format, ii, null) - 1;
								}
							}
						}

						// 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 = 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 ();
		}