mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-10 20:42:21 +02:00
590 lines
16 KiB
Beef
590 lines
16 KiB
Beef
using System.Collections.Generic;
|
|
namespace System.Globalization
|
|
{
|
|
enum MonthNameStyles {
|
|
Regular = 0x00000000,
|
|
Genitive = 0x00000001,
|
|
LeapYear = 0x00000002,
|
|
}
|
|
|
|
enum DateTimeFormatFlags {
|
|
None = 0x00000000,
|
|
UseGenitiveMonth = 0x00000001,
|
|
UseLeapYearMonth = 0x00000002,
|
|
UseSpacesInMonthNames = 0x00000004, // Has spaces or non-breaking space in the month names.
|
|
UseHebrewRule = 0x00000008, // Format/Parse using the Hebrew calendar rule.
|
|
UseSpacesInDayNames = 0x00000010, // Has spaces or non-breaking space in the day names.
|
|
UseDigitPrefixInTokens = 0x00000020, // Has token starting with numbers.
|
|
|
|
NotInitialized = -1,
|
|
}
|
|
|
|
class DateTimeFormatInfo : IFormatProvider
|
|
{
|
|
//
|
|
// Note, some fields are derived so don't really need to be serialized, but we can't mark as
|
|
// optional because Whidbey was expecting them. Post-Arrowhead we could fix that
|
|
// once Whidbey serialization is no longer necessary.
|
|
//
|
|
|
|
// cache for the invariant culture.
|
|
// invariantInfo is constant irrespective of your current culture.
|
|
private static volatile DateTimeFormatInfo invariantInfo;
|
|
|
|
// an index which points to a record in Culture Data Table.
|
|
private CultureData m_cultureData;
|
|
|
|
// The culture name used to create this DTFI.
|
|
private String m_name = null;
|
|
|
|
// The language name of the culture used to create this DTFI.
|
|
private String m_langName = null;
|
|
|
|
// CompareInfo usually used by the parser.
|
|
//private CompareInfo m_compareInfo = null;
|
|
|
|
// Culture matches current DTFI. mainly used for string comparisons during parsing.
|
|
private CultureInfo m_cultureInfo = null;
|
|
|
|
//
|
|
// Caches for various properties.
|
|
//
|
|
|
|
//
|
|
|
|
//NotImpl: Shouldn't be initialized
|
|
String amDesignator = "AM";
|
|
String pmDesignator = "PM";
|
|
String dateSeparator = "/"; // derived from short date (whidbey expects, arrowhead doesn't)
|
|
String generalShortTimePattern = null; // short date + short time (whidbey expects, arrowhead doesn't)
|
|
String generalLongTimePattern = null; // short date + long time (whidbey expects, arrowhead doesn't)
|
|
String timeSeparator = ":"; // derived from long time (whidbey expects, arrowhead doesn't)
|
|
String monthDayPattern = null;
|
|
String dateTimeOffsetPattern = null;
|
|
|
|
//
|
|
// The following are constant values.
|
|
//
|
|
const String rfc1123Pattern = "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'";
|
|
|
|
// The sortable pattern is based on ISO 8601.
|
|
const String sortableDateTimePattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss";
|
|
const String universalSortableDateTimePattern = "yyyy'-'MM'-'dd HH':'mm':'ss'Z'";
|
|
|
|
//
|
|
// The following are affected by calendar settings.
|
|
//
|
|
Calendar calendar = null;
|
|
|
|
int firstDayOfWeek = -1;
|
|
int calendarWeekRule = -1;
|
|
|
|
String fullDateTimePattern = null; // long date + long time (whidbey expects, arrowhead doesn't)
|
|
|
|
String[] abbreviatedDayNames = null;
|
|
|
|
String[] m_superShortDayNames = null;
|
|
|
|
String[] dayNames = null;
|
|
String[] abbreviatedMonthNames = null;
|
|
String[] monthNames = null;
|
|
// Cache the genitive month names that we retrieve from the data table.
|
|
String[] genitiveMonthNames = null;
|
|
|
|
// Cache the abbreviated genitive month names that we retrieve from the data table.
|
|
String[] m_genitiveAbbreviatedMonthNames = null;
|
|
|
|
// Cache the month names of a leap year that we retrieve from the data table.
|
|
String[] leapYearMonthNames = null;
|
|
|
|
// For our "patterns" arrays we have 2 variables, a string and a string[]
|
|
//
|
|
// The string[] contains the list of patterns, EXCEPT the default may not be included.
|
|
// The string contains the default pattern.
|
|
// When we initially construct our string[], we set the string to string[0]
|
|
|
|
// The "default" Date/time patterns
|
|
String longDatePattern = "dddd, MMMM d, yyyy";
|
|
String shortDatePattern = "M/d/yyyy";
|
|
String yearMonthPattern = "MMMM yyyy";
|
|
String longTimePattern = null;
|
|
String shortTimePattern = null;
|
|
|
|
// These are Whidbey-serialization compatable arrays (eg: default not included)
|
|
// "all" is a bit of a misnomer since the "default" pattern stored above isn't
|
|
// necessarily a member of the list
|
|
String[] allYearMonthPatterns = null; // This was wasn't serialized in Whidbey
|
|
String[] allShortDatePatterns = null;
|
|
String[] allLongDatePatterns = null;
|
|
String[] allShortTimePatterns = null;
|
|
String[] allLongTimePatterns = null;
|
|
|
|
// Cache the era names for this DateTimeFormatInfo instance.
|
|
String[] m_eraNames = null;
|
|
String[] m_abbrevEraNames = null;
|
|
String[] m_abbrevEnglishEraNames = null;
|
|
|
|
int[] optionalCalendars = null;
|
|
|
|
private const int DEFAULT_ALL_DATETIMES_SIZE = 132;
|
|
|
|
// CultureInfo updates this
|
|
bool m_isReadOnly=false;
|
|
|
|
// This flag gives hints about if formatting/parsing should perform special code path for things like
|
|
// genitive form or leap year month names.
|
|
DateTimeFormatFlags formatFlags = DateTimeFormatFlags.NotInitialized;
|
|
//internal static bool preferExistingTokens = InitPreferExistingTokens();
|
|
|
|
List<Object> ownedObjects = new .() ~ DeleteContainerAndItems!(_);
|
|
|
|
public this()
|
|
{
|
|
|
|
}
|
|
|
|
public ~this()
|
|
{
|
|
|
|
}
|
|
|
|
public String AllocString()
|
|
{
|
|
var str = new String();
|
|
ownedObjects.Add(str);
|
|
return str;
|
|
}
|
|
|
|
public this(CultureData cultureData, Calendar calendar)
|
|
{
|
|
this.m_cultureData = cultureData;
|
|
this.calendar = calendar;
|
|
}
|
|
|
|
public static DateTimeFormatInfo CurrentInfo
|
|
{
|
|
get
|
|
{
|
|
CultureInfo culture = CultureInfo.CurrentCulture;
|
|
if (!culture.[Friend]m_isInherited)
|
|
{
|
|
DateTimeFormatInfo info = culture.[Friend]dateTimeInfo;
|
|
if (info != null) {
|
|
return info;
|
|
}
|
|
}
|
|
return (DateTimeFormatInfo)culture.GetFormat(typeof(DateTimeFormatInfo));
|
|
}
|
|
}
|
|
|
|
public static DateTimeFormatInfo InvariantInfo {
|
|
get
|
|
{
|
|
if (invariantInfo == null)
|
|
{
|
|
DateTimeFormatInfo info = new DateTimeFormatInfo();
|
|
info.Calendar.[Friend]SetReadOnlyState(true);
|
|
info.m_isReadOnly = true;
|
|
invariantInfo = info;
|
|
}
|
|
return (invariantInfo);
|
|
}
|
|
}
|
|
|
|
public Calendar Calendar
|
|
{
|
|
get
|
|
{
|
|
return calendar;
|
|
}
|
|
}
|
|
|
|
public StringView AMDesignator
|
|
{
|
|
get
|
|
{
|
|
return amDesignator;
|
|
}
|
|
}
|
|
|
|
public StringView PMDesignator
|
|
{
|
|
get
|
|
{
|
|
return pmDesignator;
|
|
}
|
|
}
|
|
|
|
public StringView TimeSeparator
|
|
{
|
|
get
|
|
{
|
|
if (timeSeparator == null)
|
|
{
|
|
timeSeparator = this.m_cultureData.[Friend]TimeSeparator;
|
|
}
|
|
return timeSeparator;
|
|
}
|
|
}
|
|
|
|
public StringView DateSeparator
|
|
{
|
|
get
|
|
{
|
|
if (this.dateSeparator == null)
|
|
{
|
|
Runtime.NotImplemented();
|
|
//this.dateSeparator = this.m_cultureData.DateSeparator(Calendar.ID);
|
|
}
|
|
return dateSeparator;
|
|
}
|
|
}
|
|
|
|
public bool HasForceTwoDigitYears
|
|
{
|
|
get
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public DateTimeFormatFlags FormatFlags
|
|
{
|
|
get
|
|
{
|
|
if (formatFlags == DateTimeFormatFlags.NotInitialized)
|
|
{
|
|
// Build the format flags from the data in this DTFI
|
|
formatFlags = DateTimeFormatFlags.None;
|
|
/*formatFlags |= (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagGenitiveMonth(
|
|
MonthNames, internalGetGenitiveMonthNames(false), AbbreviatedMonthNames, internalGetGenitiveMonthNames(true));
|
|
formatFlags |= (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseSpaceInMonthNames(
|
|
MonthNames, internalGetGenitiveMonthNames(false), AbbreviatedMonthNames, internalGetGenitiveMonthNames(true));
|
|
formatFlags |= (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseSpaceInDayNames(DayNames, AbbreviatedDayNames);
|
|
formatFlags |= (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseHebrewCalendar((int)Calendar.ID);*/
|
|
}
|
|
return (formatFlags);
|
|
}
|
|
}
|
|
|
|
public StringView ShortDatePattern
|
|
{
|
|
get
|
|
{
|
|
// Initialize our short date pattern from the 1st array value if not set
|
|
if (this.shortDatePattern == null)
|
|
{
|
|
// Initialize our data
|
|
this.shortDatePattern = this.UnclonedShortDatePatterns[0];
|
|
}
|
|
|
|
return this.shortDatePattern;
|
|
}
|
|
}
|
|
|
|
public StringView LongDatePattern
|
|
{
|
|
get
|
|
{
|
|
// Initialize our long date pattern from the 1st array value if not set
|
|
if (this.longDatePattern == null)
|
|
{
|
|
// Initialize our data
|
|
this.longDatePattern = this.UnclonedLongDatePatterns[0];
|
|
}
|
|
|
|
return this.longDatePattern;
|
|
}
|
|
}
|
|
|
|
public StringView ShortTimePattern
|
|
{
|
|
get
|
|
{
|
|
// Initialize our short time pattern from the 1st array value if not set
|
|
if (this.shortTimePattern == null)
|
|
{
|
|
// Initialize our data
|
|
this.shortTimePattern = this.UnclonedShortTimePatterns[0];
|
|
}
|
|
return this.shortTimePattern;
|
|
}
|
|
}
|
|
|
|
public StringView FullDateTimePattern
|
|
{
|
|
get
|
|
{
|
|
if (fullDateTimePattern == null)
|
|
fullDateTimePattern = AllocString()..Append("dddd, MMMM d, yyyy h:mm:ss tt");
|
|
return fullDateTimePattern;
|
|
}
|
|
}
|
|
|
|
public StringView DateTimeOffsetPattern
|
|
{
|
|
get
|
|
{
|
|
if (dateTimeOffsetPattern == null)
|
|
dateTimeOffsetPattern = AllocString()..Append("M/d/yyyy h:mm:ss tt zzz");
|
|
return dateTimeOffsetPattern;
|
|
}
|
|
}
|
|
|
|
public StringView GeneralShortTimePattern
|
|
{
|
|
get {
|
|
if (generalShortTimePattern == null) {
|
|
generalShortTimePattern = AllocString()..AppendF("{0} {1}", ShortDatePattern, ShortTimePattern);
|
|
}
|
|
return (generalShortTimePattern);
|
|
}
|
|
}
|
|
|
|
public StringView GeneralLongTimePattern
|
|
{
|
|
get
|
|
{
|
|
if (generalLongTimePattern == null) {
|
|
generalLongTimePattern = AllocString()..AppendF("{0} {1}", ShortDatePattern, LongTimePattern);
|
|
}
|
|
return (generalLongTimePattern);
|
|
}
|
|
}
|
|
|
|
public StringView MonthDayPattern
|
|
{
|
|
get
|
|
{
|
|
if (this.monthDayPattern == null)
|
|
{
|
|
this.monthDayPattern = this.m_cultureData.[Friend]MonthDay(Calendar.ID);
|
|
}
|
|
//Contract.Assert(this.monthDayPattern != null, "DateTimeFormatInfo.MonthDayPattern, monthDayPattern != null");
|
|
return (this.monthDayPattern);
|
|
}
|
|
|
|
set {
|
|
/*if (IsReadOnly)
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
|
|
if (value == null) {
|
|
throw new ArgumentNullException("value",
|
|
Environment.GetResourceString("ArgumentNull_String"));
|
|
}
|
|
Contract.EndContractBlock();
|
|
|
|
this.monthDayPattern = value;*/
|
|
Runtime.NotImplemented();
|
|
}
|
|
}
|
|
|
|
public StringView RFC1123Pattern
|
|
{
|
|
get
|
|
{
|
|
return (rfc1123Pattern);
|
|
}
|
|
}
|
|
|
|
public StringView SortableDateTimePattern
|
|
{
|
|
get
|
|
{
|
|
return sortableDateTimePattern;
|
|
}
|
|
}
|
|
|
|
public StringView LongTimePattern
|
|
{
|
|
get
|
|
{
|
|
if (this.longTimePattern == null)
|
|
{
|
|
// Initialize our data
|
|
this.longTimePattern = this.UnclonedLongTimePatterns[0];
|
|
}
|
|
|
|
return this.longTimePattern;
|
|
}
|
|
}
|
|
|
|
public StringView UniversalSortableDateTimePattern
|
|
{
|
|
get
|
|
{
|
|
return universalSortableDateTimePattern;
|
|
}
|
|
}
|
|
|
|
public StringView YearMonthPattern
|
|
{
|
|
get
|
|
{
|
|
if (this.yearMonthPattern == null)
|
|
{
|
|
// Initialize our data
|
|
this.yearMonthPattern = this.UnclonedYearMonthPatterns[0];
|
|
}
|
|
return this.yearMonthPattern;
|
|
}
|
|
}
|
|
|
|
public void GetAbbreviatedDayName(DayOfWeek dayofweek, String outStr)
|
|
{
|
|
outStr.Append(CalendarData.[Friend]Invariant.[Friend]saAbbrevDayNames[(int)dayofweek]);
|
|
}
|
|
|
|
public void GetDayName(DayOfWeek dayofweek, String outStr)
|
|
{
|
|
outStr.Append(CalendarData.[Friend]Invariant.[Friend]saDayNames[(int)dayofweek]);
|
|
}
|
|
|
|
public void GetAbbreviatedMonthName(int month, String outStr)
|
|
{
|
|
outStr.Append(CalendarData.[Friend]Invariant.[Friend]saAbbrevMonthNames[month - 1]);
|
|
}
|
|
|
|
public void GetMonthName(int month, String outStr)
|
|
{
|
|
outStr.Append(CalendarData.[Friend]Invariant.[Friend]saMonthNames[month - 1]);
|
|
}
|
|
|
|
public void GetEraName(int era, String outStr)
|
|
{
|
|
outStr.Append(CalendarData.[Friend]Invariant.[Friend]saEraNames[era]);
|
|
}
|
|
|
|
void internalGetMonthName(int month, MonthNameStyles style, bool abbreviated, String outStr)
|
|
{
|
|
GetMonthName(month, outStr);
|
|
}
|
|
|
|
public Object GetFormat(Type formatType)
|
|
{
|
|
return (formatType == typeof(DateTimeFormatInfo)? this: null);
|
|
}
|
|
|
|
public static DateTimeFormatInfo GetInstance(IFormatProvider provider)
|
|
{
|
|
// Fast case for a regular CultureInfo
|
|
DateTimeFormatInfo info;
|
|
CultureInfo cultureProvider = provider as CultureInfo;
|
|
if (cultureProvider != null && !cultureProvider.[Friend]m_isInherited)
|
|
{
|
|
return cultureProvider.DateTimeFormat;
|
|
}
|
|
// Fast case for a DTFI;
|
|
info = provider as DateTimeFormatInfo;
|
|
if (info != null) {
|
|
return info;
|
|
}
|
|
// Wasn't cultureInfo or DTFI, do it the slower way
|
|
if (provider != null) {
|
|
info = provider.GetFormat(typeof(DateTimeFormatInfo)) as DateTimeFormatInfo;
|
|
if (info != null) {
|
|
return info;
|
|
}
|
|
}
|
|
// Couldn't get anything, just use currentInfo as fallback
|
|
return CurrentInfo;
|
|
}
|
|
|
|
private String[] UnclonedYearMonthPatterns
|
|
{
|
|
get
|
|
{
|
|
if (this.allYearMonthPatterns == null)
|
|
{
|
|
this.allYearMonthPatterns = this.m_cultureData.[Friend]YearMonths(this.Calendar.ID);
|
|
}
|
|
|
|
return this.allYearMonthPatterns;
|
|
}
|
|
}
|
|
|
|
private String [] UnclonedShortDatePatterns
|
|
{
|
|
get
|
|
{
|
|
if (allShortDatePatterns == null)
|
|
{
|
|
this.allShortDatePatterns = this.m_cultureData.[Friend]ShortDates(this.Calendar.ID);
|
|
}
|
|
|
|
return this.allShortDatePatterns;
|
|
}
|
|
}
|
|
|
|
private String[] UnclonedLongDatePatterns
|
|
{
|
|
get
|
|
{
|
|
if (allLongDatePatterns == null)
|
|
{
|
|
this.allLongDatePatterns = this.m_cultureData.[Friend]LongDates(this.Calendar.ID);
|
|
}
|
|
|
|
return this.allLongDatePatterns;
|
|
}
|
|
}
|
|
|
|
private String[] UnclonedShortTimePatterns
|
|
{
|
|
get
|
|
{
|
|
if (this.allShortTimePatterns == null)
|
|
{
|
|
this.allShortTimePatterns = this.m_cultureData.[Friend]ShortTimes;
|
|
}
|
|
|
|
return this.allShortTimePatterns;
|
|
}
|
|
}
|
|
|
|
private String[] UnclonedLongTimePatterns
|
|
{
|
|
get
|
|
{
|
|
if (this.allLongTimePatterns == null)
|
|
{
|
|
this.allLongTimePatterns = this.m_cultureData.[Friend]LongTimes;
|
|
}
|
|
|
|
return this.allLongTimePatterns;
|
|
}
|
|
}
|
|
|
|
private String m_fullTimeSpanPositivePattern ~ delete _;
|
|
String FullTimeSpanPositivePattern
|
|
{
|
|
get
|
|
{
|
|
if (m_fullTimeSpanPositivePattern == null)
|
|
{
|
|
CultureData cultureDataWithoutUserOverrides;
|
|
if (m_cultureData.[Friend]UseUserOverride)
|
|
cultureDataWithoutUserOverrides = CultureData.[Friend]GetCultureData(m_cultureData.[Friend]CultureName, false);
|
|
else
|
|
cultureDataWithoutUserOverrides = m_cultureData;
|
|
StringView decimalSeparator = scope NumberFormatInfo(cultureDataWithoutUserOverrides).NumberDecimalSeparator;
|
|
|
|
m_fullTimeSpanPositivePattern = AllocString()..Append("d':'h':'mm':'ss'");
|
|
m_fullTimeSpanPositivePattern.Append(decimalSeparator);
|
|
m_fullTimeSpanPositivePattern.Append("'FFFFFFF");
|
|
}
|
|
return m_fullTimeSpanPositivePattern;
|
|
}
|
|
}
|
|
|
|
private String m_fullTimeSpanNegativePattern ~ delete _;
|
|
String FullTimeSpanNegativePattern
|
|
{
|
|
get
|
|
{
|
|
if (m_fullTimeSpanNegativePattern == null)
|
|
m_fullTimeSpanNegativePattern = AllocString()..Append("'-'", FullTimeSpanPositivePattern);
|
|
return m_fullTimeSpanNegativePattern;
|
|
}
|
|
}
|
|
}
|
|
}
|