1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-20 08:58:00 +02:00

Moving corlib files out of "System" directory into root

This commit is contained in:
Brian Fiete 2019-09-19 05:46:35 -07:00
parent 4cd58262e4
commit 7dbfd15292
179 changed files with 3 additions and 0 deletions

View file

@ -0,0 +1,856 @@
// This file contains portions of code released by Microsoft under the MIT license as part
// of an open-sourcing initiative in 2014 of the C# core libraries.
// The original source was submitted to https://github.com/Microsoft/referencesource
namespace System.Globalization {
using System;
using System.Runtime.CompilerServices;
using System.Globalization;
using System.Diagnostics.Contracts;
// This abstract class represents a calendar. A calendar reckons time in
// divisions such as weeks, months and years. The number, length and start of
// the divisions vary in each calendar.
//
// Any instant in time can be represented as an n-tuple of numeric values using
// a particular calendar. For example, the next vernal equinox occurs at (0.0, 0
// , 46, 8, 20, 3, 1999) in the Gregorian calendar. An implementation of
// Calendar can map any DateTime value to such an n-tuple and vice versa. The
// DateTimeFormat class can map between such n-tuples and a textual
// representation such as "8:46 AM [....] 20th 1999 AD".
//
// Most calendars identify a year which begins the current era. There may be any
// number of previous eras. The Calendar class identifies the eras as enumerated
// integers where the current era (CurrentEra) has the value zero.
//
// For consistency, the first unit in each interval, e.g. the first month, is
// assigned the value one.
// The calculation of hour/minute/second is moved to Calendar from GregorianCalendar,
// since most of the calendars (or all?) have the same way of calcuating hour/minute/second.
public abstract class Calendar //: ICloneable
{
// Number of 100ns (10E-7 second) ticks per time unit
internal const int64 TicksPerMillisecond = 10000;
internal const int64 TicksPerSecond = TicksPerMillisecond * 1000;
internal const int64 TicksPerMinute = TicksPerSecond * 60;
internal const int64 TicksPerHour = TicksPerMinute * 60;
internal const int64 TicksPerDay = TicksPerHour * 24;
// Number of milliseconds per time unit
internal const int MillisPerSecond = 1000;
internal const int MillisPerMinute = MillisPerSecond * 60;
internal const int MillisPerHour = MillisPerMinute * 60;
internal const int MillisPerDay = MillisPerHour * 24;
// Number of days in a non-leap year
internal const int DaysPerYear = 365;
// Number of days in 4 years
internal const int DaysPer4Years = DaysPerYear * 4 + 1;
// Number of days in 100 years
internal const int DaysPer100Years = DaysPer4Years * 25 - 1;
// Number of days in 400 years
internal const int DaysPer400Years = DaysPer100Years * 4 + 1;
// Number of days from 1/1/0001 to 1/1/10000
internal const int DaysTo10000 = DaysPer400Years * 25 - 366;
internal const int64 MaxMillis = (int64)DaysTo10000 * MillisPerDay;
//
// Calendar ID Values. This is used to get data from calendar.nlp.
// The order of calendar ID means the order of data items in the table.
//
internal const int CAL_GREGORIAN = 1 ; // Gregorian (localized) calendar
internal const int CAL_GREGORIAN_US = 2 ; // Gregorian (U.S.) calendar
internal const int CAL_JAPAN = 3 ; // Japanese Emperor Era calendar
internal const int CAL_TAIWAN = 4 ; // Taiwan Era calendar
internal const int CAL_KOREA = 5 ; // Korean Tangun Era calendar
internal const int CAL_HIJRI = 6 ; // Hijri (Arabic Lunar) calendar
internal const int CAL_THAI = 7 ; // Thai calendar
internal const int CAL_HEBREW = 8 ; // Hebrew (Lunar) calendar
internal const int CAL_GREGORIAN_ME_FRENCH = 9 ; // Gregorian Middle East French calendar
internal const int CAL_GREGORIAN_ARABIC = 10; // Gregorian Arabic calendar
internal const int CAL_GREGORIAN_XLIT_ENGLISH = 11; // Gregorian Transliterated English calendar
internal const int CAL_GREGORIAN_XLIT_FRENCH = 12;
internal const int CAL_JULIAN = 13;
internal const int CAL_JAPANESELUNISOLAR = 14;
internal const int CAL_CHINESELUNISOLAR = 15;
internal const int CAL_SAKA = 16; // reserved to match Office but not implemented in our code
internal const int CAL_LUNAR_ETO_CHN = 17; // reserved to match Office but not implemented in our code
internal const int CAL_LUNAR_ETO_KOR = 18; // reserved to match Office but not implemented in our code
internal const int CAL_LUNAR_ETO_ROKUYOU = 19; // reserved to match Office but not implemented in our code
internal const int CAL_KOREANLUNISOLAR = 20;
internal const int CAL_TAIWANLUNISOLAR = 21;
internal const int CAL_PERSIAN = 22;
internal const int CAL_UMALQURA = 23;
internal int m_currentEraValue = -1;
private bool m_isReadOnly = false;
// The minimum supported DateTime range for the calendar.
public virtual DateTime MinSupportedDateTime
{
get
{
return (DateTime.MinValue);
}
}
// The maximum supported DateTime range for the calendar.
public virtual DateTime MaxSupportedDateTime
{
get
{
return (DateTime.MaxValue);
}
}
protected this() {
//Do-nothing constructor.
}
///
// This can not be abstract, otherwise no one can create a subclass of Calendar.
//
internal virtual int ID {
get {
return (-1);
}
}
///
// Return the Base calendar ID for calendars that didn't have defined data in calendarData
//
internal virtual int BaseCalendarID
{
get { return ID; }
}
// Returns the type of the calendar.
//
public virtual CalendarAlgorithmType AlgorithmType
{
get
{
return CalendarAlgorithmType.Unknown;
}
}
////////////////////////////////////////////////////////////////////////
//
// IsReadOnly
//
// Detect if the object is readonly.
//
////////////////////////////////////////////////////////////////////////
public bool IsReadOnly
{
get { return (m_isReadOnly); }
}
////////////////////////////////////////////////////////////////////////
//
// Clone
//
// Is the implementation of IColnable.
//
////////////////////////////////////////////////////////////////////////
/*public virtual Object Clone()
{
object o = MemberwiseClone();
((Calendar) o).SetReadOnlyState(false);
return (o);
}*/
////////////////////////////////////////////////////////////////////////
//
// ReadOnly
//
// Create a cloned readonly instance or return the input one if it is
// readonly.
//
////////////////////////////////////////////////////////////////////////
public static Calendar ReadOnly(Calendar calendar)
{
/*if (calendar == null) { throw new ArgumentNullException("calendar"); }
Contract.EndContractBlock();
if (calendar.IsReadOnly) { return (calendar); }
Calendar clonedCalendar = (Calendar)(calendar.MemberwiseClone());
clonedCalendar.SetReadOnlyState(true);
return (clonedCalendar);*/
Runtime.NotImplemented();
}
internal Result<void> VerifyWritable()
{
if (m_isReadOnly)
{
//throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
return .Err;
}
return .Ok;
}
internal void SetReadOnlyState(bool readOnly)
{
m_isReadOnly = readOnly;
}
/*=================================CurrentEraValue==========================
**Action: This is used to convert CurretEra(0) to an appropriate era value.
**Returns:
**Arguments:
**Exceptions:
**Notes:
** The value is from calendar.nlp.
============================================================================*/
internal virtual int CurrentEraValue
{
get
{
// The following code assumes that the current era value can not be -1.
if (m_currentEraValue == -1) {
Contract.Assert(BaseCalendarID > 0, "[Calendar.CurrentEraValue] Expected ID > 0");
m_currentEraValue = CalendarData.GetCalendarData(BaseCalendarID).iCurrentEra;
}
return (m_currentEraValue);
}
}
// The current era for a calendar.
public const int CurrentEra = 0;
internal int twoDigitYearMax = -1;
internal static Result<void> CheckAddResult(int64 ticks, DateTime minValue, DateTime maxValue) {
if (ticks < minValue.Ticks || ticks > maxValue.Ticks) {
return .Err;
/*throw new ArgumentException(
String.Format(CultureInfo.InvariantCulture, Environment.GetResourceString("Argument_ResultCalendarRange"),
minValue, maxValue));*/
}
//Contract.EndContractBlock();
return .Ok;
}
internal Result<DateTime> Add(DateTime time, double value, int scale) {
// From ECMA CLI spec, Partition III, section 3.27:
//
// If overflow occurs converting a floating-point type to an integer, or if the floating-point value
// being converted to an integer is a NaN, the value returned is unspecified.
//
// Based upon this, this method should be performing the comparison against the double
// before attempting a cast. Otherwise, the result is undefined.
double tempMillis = (value * scale + (value >= 0 ? 0.5 : -0.5));
if (!((tempMillis > -(double)MaxMillis) && (tempMillis < (double)MaxMillis)))
{
//throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_AddValue"));
return .Err;
}
int64 millis = (int64)tempMillis;
int64 ticks = time.Ticks + millis * TicksPerMillisecond;
CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime);
return (DateTime(ticks));
}
// Returns the DateTime resulting from adding the given number of
// milliseconds to the specified DateTime. The result is computed by rounding
// the number of milliseconds given by value to the nearest integer,
// and adding that interval to the specified DateTime. The value
// argument is permitted to be negative.
//
public virtual Result<DateTime> AddMilliseconds(DateTime time, double milliseconds) {
return (Add(time, milliseconds, 1));
}
// Returns the DateTime resulting from adding a fractional number of
// days to the specified DateTime. The result is computed by rounding the
// fractional number of days given by value to the nearest
// millisecond, and adding that interval to the specified DateTime. The
// value argument is permitted to be negative.
//
public virtual Result<DateTime> AddDays(DateTime time, int days) {
return (Add(time, days, MillisPerDay));
}
// Returns the DateTime resulting from adding a fractional number of
// hours to the specified DateTime. The result is computed by rounding the
// fractional number of hours given by value to the nearest
// millisecond, and adding that interval to the specified DateTime. The
// value argument is permitted to be negative.
//
public virtual Result<DateTime> AddHours(DateTime time, int hours) {
return (Add(time, hours, MillisPerHour));
}
// Returns the DateTime resulting from adding a fractional number of
// minutes to the specified DateTime. The result is computed by rounding the
// fractional number of minutes given by value to the nearest
// millisecond, and adding that interval to the specified DateTime. The
// value argument is permitted to be negative.
//
public virtual Result<DateTime> AddMinutes(DateTime time, int minutes) {
return (Add(time, minutes, MillisPerMinute));
}
// Returns the DateTime resulting from adding the given number of
// months to the specified DateTime. The result is computed by incrementing
// (or decrementing) the year and month parts of the specified DateTime by
// value months, and, if required, adjusting the day part of the
// resulting date downwards to the last day of the resulting month in the
// resulting year. The time-of-day part of the result is the same as the
// time-of-day part of the specified DateTime.
//
// In more precise terms, considering the specified DateTime to be of the
// form y / m / d + t, where y is the
// year, m is the month, d is the day, and t is the
// time-of-day, the result is y1 / m1 / d1 + t,
// where y1 and m1 are computed by adding value months
// to y and m, and d1 is the largest value less than
// or equal to d that denotes a valid day in month m1 of year
// y1.
//
public abstract Result<DateTime> AddMonths(DateTime time, int months);
// Returns the DateTime resulting from adding a number of
// seconds to the specified DateTime. The result is computed by rounding the
// fractional number of seconds given by value to the nearest
// millisecond, and adding that interval to the specified DateTime. The
// value argument is permitted to be negative.
//
public virtual Result<DateTime> AddSeconds(DateTime time, int seconds) {
return Add(time, seconds, MillisPerSecond);
}
// Returns the DateTime resulting from adding a number of
// weeks to the specified DateTime. The
// value argument is permitted to be negative.
//
public virtual Result<DateTime> AddWeeks(DateTime time, int weeks) {
return (AddDays(time, weeks * 7));
}
// Returns the DateTime resulting from adding the given number of
// years to the specified DateTime. The result is computed by incrementing
// (or decrementing) the year part of the specified DateTime by value
// years. If the month and day of the specified DateTime is 2/29, and if the
// resulting year is not a leap year, the month and day of the resulting
// DateTime becomes 2/28. Otherwise, the month, day, and time-of-day
// parts of the result are the same as those of the specified DateTime.
//
public abstract Result<DateTime> AddYears(DateTime time, int years);
// Returns the day-of-month part of the specified DateTime. The returned
// value is an integer between 1 and 31.
//
public abstract Result<int> GetDayOfMonth(DateTime time);
// Returns the day-of-week part of the specified DateTime. The returned value
// is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
// Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
// Thursday, 5 indicates Friday, and 6 indicates Saturday.
//
public abstract Result<DayOfWeek> GetDayOfWeek(DateTime time);
// Returns the day-of-year part of the specified DateTime. The returned value
// is an integer between 1 and 366.
//
public abstract Result<int> GetDayOfYear(DateTime time);
// Returns the number of days in the month given by the year and
// month arguments.
//
public virtual Result<int> GetDaysInMonth(int year, int month)
{
return (GetDaysInMonth(year, month, CurrentEra));
}
// Returns the number of days in the month given by the year and
// month arguments for the specified era.
//
public abstract Result<int> GetDaysInMonth(int year, int month, int era);
// Returns the number of days in the year given by the year argument for the current era.
//
public virtual Result<int> GetDaysInYear(int year)
{
return (GetDaysInYear(year, CurrentEra));
}
// Returns the number of days in the year given by the year argument for the current era.
//
public abstract Result<int> GetDaysInYear(int year, int era);
// Returns the era for the specified DateTime value.
public abstract Result<int> GetEra(DateTime time);
/*=================================Eras==========================
**Action: Get the list of era values.
**Returns: The int array of the era names supported in this calendar.
** null if era is not used.
**Arguments: None.
**Exceptions: None.
============================================================================*/
public abstract int[] Eras {
get;
}
// Returns the hour part of the specified DateTime. The returned value is an
// integer between 0 and 23.
//
public virtual Result<int> GetHour(DateTime time) {
return ((int)((time.Ticks / TicksPerHour) % 24));
}
// Returns the millisecond part of the specified DateTime. The returned value
// is an integer between 0 and 999.
//
public virtual Result<double> GetMilliseconds(DateTime time) {
return (double)((time.Ticks / TicksPerMillisecond) % 1000);
}
// Returns the minute part of the specified DateTime. The returned value is
// an integer between 0 and 59.
//
public virtual Result<int> GetMinute(DateTime time) {
return ((int)((time.Ticks / TicksPerMinute) % 60));
}
// Returns the month part of the specified DateTime. The returned value is an
// integer between 1 and 12.
//
public abstract Result<int> GetMonth(DateTime time);
// Returns the number of months in the specified year in the current era.
public virtual Result<int> GetMonthsInYear(int year)
{
return (GetMonthsInYear(year, CurrentEra));
}
// Returns the number of months in the specified year and era.
public abstract Result<int> GetMonthsInYear(int year, int era);
// Returns the second part of the specified DateTime. The returned value is
// an integer between 0 and 59.
//
public virtual Result<int> GetSecond(DateTime time) {
return ((int)((time.Ticks / TicksPerSecond) % 60));
}
/*=================================GetFirstDayWeekOfYear==========================
**Action: Get the week of year using the FirstDay rule.
**Returns: the week of year.
**Arguments:
** time
** firstDayOfWeek the first day of week (0=Sunday, 1=Monday, ... 6=Saturday)
**Notes:
** The CalendarWeekRule.FirstDay rule: Week 1 begins on the first day of the year.
** Assume f is the specifed firstDayOfWeek,
** and n is the day of week for January 1 of the specified year.
** Assign offset = n - f;
** Case 1: offset = 0
** E.g.
** f=1
** weekday 0 1 2 3 4 5 6 0 1
** date 1/1
** week# 1 2
** then week of year = (GetDayOfYear(time) - 1) / 7 + 1
**
** Case 2: offset < 0
** e.g.
** n=1 f=3
** weekday 0 1 2 3 4 5 6 0
** date 1/1
** week# 1 2
** This means that the first week actually starts 5 days before 1/1.
** So week of year = (GetDayOfYear(time) + (7 + offset) - 1) / 7 + 1
** Case 3: offset > 0
** e.g.
** f=0 n=2
** weekday 0 1 2 3 4 5 6 0 1 2
** date 1/1
** week# 1 2
** This means that the first week actually starts 2 days before 1/1.
** So Week of year = (GetDayOfYear(time) + offset - 1) / 7 + 1
============================================================================*/
internal Result<int> GetFirstDayWeekOfYear(DateTime time, int firstDayOfWeek) {
int dayOfYear = Try!(GetDayOfYear(time)) - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
// Calculate the day of week for the first day of the year.
// dayOfWeek - (dayOfYear % 7) is the day of week for the first day of this year. Note that
// this value can be less than 0. It's fine since we are making it positive again in calculating offset.
int dayForJan1 = (int)Try!(GetDayOfWeek(time)) - (dayOfYear % 7);
int offset = (dayForJan1 - firstDayOfWeek + 14) % 7;
Contract.Assert(offset >= 0, "Calendar.GetFirstDayWeekOfYear(): offset >= 0");
return ((dayOfYear + offset) / 7 + 1);
}
private Result<int> GetWeekOfYearFullDays(DateTime time, int firstDayOfWeek, int fullDays) {
int dayForJan1;
int offset;
int day;
int dayOfYear = Try!(GetDayOfYear(time)) - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
//
// Calculate the number of days between the first day of year (1/1) and the first day of the week.
// This value will be a positive value from 0 ~ 6. We call this value as "offset".
//
// If offset is 0, it means that the 1/1 is the start of the first week.
// Assume the first day of the week is Monday, it will look like this:
// Sun Mon Tue Wed Thu Fri Sat
// 12/31 1/1 1/2 1/3 1/4 1/5 1/6
// +--> First week starts here.
//
// If offset is 1, it means that the first day of the week is 1 day ahead of 1/1.
// Assume the first day of the week is Monday, it will look like this:
// Sun Mon Tue Wed Thu Fri Sat
// 1/1 1/2 1/3 1/4 1/5 1/6 1/7
// +--> First week starts here.
//
// If offset is 2, it means that the first day of the week is 2 days ahead of 1/1.
// Assume the first day of the week is Monday, it will look like this:
// Sat Sun Mon Tue Wed Thu Fri Sat
// 1/1 1/2 1/3 1/4 1/5 1/6 1/7 1/8
// +--> First week starts here.
// Day of week is 0-based.
// Get the day of week for 1/1. This can be derived from the day of week of the target day.
// Note that we can get a negative value. It's ok since we are going to make it a positive value when calculating the offset.
dayForJan1 = (int)Try!(GetDayOfWeek(time)) - (dayOfYear % 7);
// Now, calculate the offset. Subtract the first day of week from the dayForJan1. And make it a positive value.
offset = (firstDayOfWeek - dayForJan1 + 14) % 7;
if (offset != 0 && offset >= fullDays)
{
//
// If the offset is greater than the value of fullDays, it means that
// the first week of the year starts on the week where Jan/1 falls on.
//
offset -= 7;
}
//
// Calculate the day of year for specified time by taking offset into account.
//
day = dayOfYear - offset;
if (day >= 0) {
//
// If the day of year value is greater than zero, get the week of year.
//
return (day/7 + 1);
}
//
// Otherwise, the specified time falls on the week of previous year.
// Call this method again by passing the last day of previous year.
//
// the last day of the previous year may "underflow" to no longer be a valid date time for
// this calendar if we just subtract so we need the subclass to provide us with
// that information
if (time <= MinSupportedDateTime.AddDays(dayOfYear))
{
return GetWeekOfYearOfMinSupportedDateTime(firstDayOfWeek, fullDays);
}
return (GetWeekOfYearFullDays(time.AddDays(-(dayOfYear + 1)), firstDayOfWeek, fullDays));
}
private Result<int> GetWeekOfYearOfMinSupportedDateTime(int firstDayOfWeek, int minimumDaysInFirstWeek)
{
int dayOfYear = Try!(GetDayOfYear(MinSupportedDateTime)) - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
int dayOfWeekOfFirstOfYear = (int)Try!(GetDayOfWeek(MinSupportedDateTime)) - dayOfYear % 7;
// Calculate the offset (how many days from the start of the year to the start of the week)
int offset = (firstDayOfWeek + 7 - dayOfWeekOfFirstOfYear) % 7;
if (offset == 0 || offset >= minimumDaysInFirstWeek)
{
// First of year falls in the first week of the year
return 1;
}
int daysInYearBeforeMinSupportedYear = DaysInYearBeforeMinSupportedYear - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
int dayOfWeekOfFirstOfPreviousYear = dayOfWeekOfFirstOfYear - 1 - (daysInYearBeforeMinSupportedYear % 7);
// starting from first day of the year, how many days do you have to go forward
// before getting to the first day of the week?
int daysInInitialPartialWeek = (firstDayOfWeek - dayOfWeekOfFirstOfPreviousYear + 14) % 7;
int day = daysInYearBeforeMinSupportedYear - daysInInitialPartialWeek;
if (daysInInitialPartialWeek >= minimumDaysInFirstWeek)
{
// If the offset is greater than the minimum Days in the first week, it means that
// First of year is part of the first week of the year even though it is only a partial week
// add another week
day += 7;
}
return (day / 7 + 1);
}
// it would be nice to make this abstract but we can't since that would break previous implementations
protected virtual int DaysInYearBeforeMinSupportedYear
{
get
{
return 365;
}
}
// Returns the week of year for the specified DateTime. The returned value is an
// integer between 1 and 53.
//
public virtual Result<int> GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
{
if ((int)firstDayOfWeek < 0 || (int)firstDayOfWeek > 6) {
/*throw new ArgumentOutOfRangeException(
"firstDayOfWeek", Environment.GetResourceString("ArgumentOutOfRange_Range",
DayOfWeek.Sunday, DayOfWeek.Saturday));*/
return .Err;
}
//Contract.EndContractBlock();
switch (rule) {
case CalendarWeekRule.FirstDay:
return (GetFirstDayWeekOfYear(time, (int)firstDayOfWeek));
case CalendarWeekRule.FirstFullWeek:
return (GetWeekOfYearFullDays(time, (int)firstDayOfWeek, 7));
case CalendarWeekRule.FirstFourDayWeek:
return (GetWeekOfYearFullDays(time, (int)firstDayOfWeek, 4));
}
/*throw new ArgumentOutOfRangeException(
"rule", Environment.GetResourceString("ArgumentOutOfRange_Range",
CalendarWeekRule.FirstDay, CalendarWeekRule.FirstFourDayWeek));*/
//return .Err;
}
// Returns the year part of the specified DateTime. The returned value is an
// integer between 1 and 9999.
//
public abstract Result<int> GetYear(DateTime time);
// Checks whether a given day in the current era is a leap day. This method returns true if
// the date is a leap day, or false if not.
//
public virtual Result<bool> IsLeapDay(int year, int month, int day)
{
return (IsLeapDay(year, month, day, CurrentEra));
}
// Checks whether a given day in the specified era is a leap day. This method returns true if
// the date is a leap day, or false if not.
//
public abstract Result<bool> IsLeapDay(int year, int month, int day, int era);
// Checks whether a given month in the current era is a leap month. This method returns true if
// month is a leap month, or false if not.
//
public virtual Result<bool> IsLeapMonth(int year, int month) {
return (IsLeapMonth(year, month, CurrentEra));
}
// Checks whether a given month in the specified era is a leap month. This method returns true if
// month is a leap month, or false if not.
//
public abstract Result<bool> IsLeapMonth(int year, int month, int era);
// Returns the leap month in a calendar year of the current era. This method returns 0
// if this calendar does not have leap month, or this year is not a leap year.
//
public virtual Result<int> GetLeapMonth(int year)
{
return (GetLeapMonth(year, CurrentEra));
}
// Returns the leap month in a calendar year of the specified era. This method returns 0
// if this calendar does not have leap month, or this year is not a leap year.
//
public virtual Result<int> GetLeapMonth(int year, int era)
{
if (!IsLeapYear(year, era))
return 0;
int monthsCount = GetMonthsInYear(year, era);
for (int month=1; month<=monthsCount; month++)
{
if (IsLeapMonth(year, month, era))
return month;
}
return 0;
}
// Checks whether a given year in the current era is a leap year. This method returns true if
// year is a leap year, or false if not.
//
public virtual Result<bool> IsLeapYear(int year)
{
return (IsLeapYear(year, CurrentEra));
}
// Checks whether a given year in the specified era is a leap year. This method returns true if
// year is a leap year, or false if not.
//
public abstract Result<bool> IsLeapYear(int year, int era);
// Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
//
public virtual DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond)
{
return (ToDateTime(year, month, day, hour, minute, second, millisecond, CurrentEra));
}
// Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
//
public abstract Result<DateTime> ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era);
internal virtual bool TryToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era, out DateTime result) {
result = DateTime.MinValue;
switch (ToDateTime(year, month, day, hour, minute, second, millisecond, era))
{
case .Ok(out result):
return true;
case .Err:
return false;
}
}
internal virtual bool IsValidYear(int year, int era) {
return (year >= GetYear(MinSupportedDateTime).Get() && year <= GetYear(MaxSupportedDateTime).Get());
}
internal virtual bool IsValidMonth(int year, int month, int era) {
return (IsValidYear(year, era) && month >= 1 && month <= GetMonthsInYear(year, era).Get());
}
internal virtual bool IsValidDay(int year, int month, int day, int era)
{
return (IsValidMonth(year, month, era) && day >= 1 && day <= GetDaysInMonth(year, month, era).Get());
}
// Returns and assigns the maximum value to represent a two digit year. This
// value is the upper boundary of a 100 year range that allows a two digit year
// to be properly translated to a four digit year. For example, if 2029 is the
// upper boundary, then a two digit value of 30 should be interpreted as 1930
// while a two digit value of 29 should be interpreted as 2029. In this example
// , the 100 year range would be from 1930-2029. See ToFourDigitYear().
public virtual int TwoDigitYearMax
{
get
{
return (twoDigitYearMax);
}
set
{
VerifyWritable();
twoDigitYearMax = value;
}
}
// Converts the year value to the appropriate century by using the
// TwoDigitYearMax property. For example, if the TwoDigitYearMax value is 2029,
// then a two digit value of 30 will get converted to 1930 while a two digit
// value of 29 will get converted to 2029.
public virtual Result<int> ToFourDigitYear(int year) {
if (year < 0) {
/*throw new ArgumentOutOfRangeException("year",
Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));*/
return .Err;
}
//Contract.EndContractBlock();
if (year < 100) {
return ((TwoDigitYearMax/100 - ( year > TwoDigitYearMax % 100 ? 1 : 0))*100 + year);
}
// If the year value is above 100, just return the year value. Don't have to do
// the TwoDigitYearMax comparison.
return (year);
}
// Return the tick count corresponding to the given hour, minute, second.
// Will check the if the parameters are valid.
internal static Result<int64> TimeToTicks(int hour, int minute, int second, int millisecond)
{
if (hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >=0 && second < 60)
{
if (millisecond < 0 || millisecond >= MillisPerSecond) {
/*throw new ArgumentOutOfRangeException(
"millisecond",
String.Format(
CultureInfo.InvariantCulture,
Environment.GetResourceString("ArgumentOutOfRange_Range"), 0, MillisPerSecond - 1));*/
return .Err;
}
return Try!(TimeSpan.TimeToTicks(hour, minute, second)) + millisecond * TicksPerMillisecond;
}
//throw new ArgumentOutOfRangeException(null, Environment.GetResourceString("ArgumentOutOfRange_BadHourMinuteSecond"));
return .Err;
}
internal static int GetSystemTwoDigitYearSetting(int CalID, int defaultYearValue)
{
// Call nativeGetTwoDigitYearMax
int twoDigitYearMax = CalendarData.nativeGetTwoDigitYearMax(CalID);
if (twoDigitYearMax < 0)
{
twoDigitYearMax = defaultYearValue;
}
return (twoDigitYearMax);
}
}
}

View file

@ -0,0 +1,20 @@
// This file contains portions of code released by Microsoft under the MIT license as part
// of an open-sourcing initiative in 2014 of the C# core libraries.
// The original source was submitted to https://github.com/Microsoft/referencesource
namespace System.Globalization {
using System;
public enum CalendarAlgorithmType
{
Unknown = 0, // This is the default value to return in the Calendar base class.
SolarCalendar = 1, // Solar-base calendar, such as GregorianCalendar, jaoaneseCalendar, JulianCalendar, etc.
// Solar calendars are based on the solar year and seasons.
LunarCalendar = 2, // Lunar-based calendar, such as Hijri and UmAlQuraCalendar.
// Lunar calendars are based on the path of the moon. The seasons are not accurately represented.
LunisolarCalendar = 3 // Lunisolar-based calendar which use leap month rule, such as HebrewCalendar and Asian Lunisolar calendars.
// Lunisolar calendars are based on the cycle of the moon, but consider the seasons as a secondary consideration,
// so they align with the seasons as well as lunar events.
}
}

View file

@ -0,0 +1,505 @@
// This file contains portions of code released by Microsoft under the MIT license as part
// of an open-sourcing initiative in 2014 of the C# core libraries.
// The original source was submitted to https://github.com/Microsoft/referencesource
namespace System.Globalization
{
using System;
using System.Runtime.CompilerServices;
using System.Diagnostics.Contracts;
using System.Diagnostics;
//
//
// List of calendar data
// Note the we cache overrides.
// Note that localized names (resource names) aren't available from here.
//
// NOTE: Calendars depend on the locale name that creates it. Only a few
// properties are available without locales using CalendarData.GetCalendar(int)
// StructLayout is needed here otherwise compiler can re-arrange the fields.
// We have to keep this in-[....] with the definition in calendardata.h
//
// WARNING WARNING WARNING
//
// WARNING: Anything changed here also needs to be updated on the native side (object.h see type CalendarDataBaseObject)
// WARNING: The type loader will rearrange class member offsets so the mscorwks!CalendarDataBaseObject
// WARNING: must be manually structured to match the true loaded class layout
//
internal class CalendarData
{
// Max calendars
internal const int MAX_CALENDARS = 23;
// Identity
internal String sNativeName ~ delete _; // Calendar Name for the locale
// Formats
internal String[] saShortDates ~ DeleteContainerAndItems!(_); // Short Data format, default first
internal String[] saYearMonths ~ DeleteContainerAndItems!(_); // Year/Month Data format, default first
internal String[] saLongDates ~ DeleteContainerAndItems!(_); // Long Data format, default first
internal String sMonthDay ~ delete _; // Month/Day format
// Calendar Parts Names
internal String[] saEraNames ~ DeleteContainerAndItems!(_); // Names of Eras
internal String[] saAbbrevEraNames ~ DeleteContainerAndItems!(_); // Abbreviated Era Names
internal String[] saAbbrevEnglishEraNames ~ DeleteContainerAndItems!(_); // Abbreviated Era Names in English
internal String[] saDayNames ~ DeleteContainerAndItems!(_); // Day Names, null to use locale data, starts on Sunday
internal String[] saAbbrevDayNames ~ DeleteContainerAndItems!(_); // Abbrev Day Names, null to use locale data, starts on Sunday
internal String[] saSuperShortDayNames ~ DeleteContainerAndItems!(_); // Super short Day of week names
internal String[] saMonthNames ~ DeleteContainerAndItems!(_); // Month Names (13)
internal String[] saAbbrevMonthNames ~ DeleteContainerAndItems!(_); // Abbrev Month Names (13)
internal String[] saMonthGenitiveNames ~ DeleteContainerAndItems!(_); // Genitive Month Names (13)
internal String[] saAbbrevMonthGenitiveNames~ DeleteContainerAndItems!(_); // Genitive Abbrev Month Names (13)
internal String[] saLeapYearMonthNames ~ DeleteContainerAndItems!(_); // Multiple strings for the month names in a leap year.
// Integers at end to make marshaller happier
internal int iTwoDigitYearMax=2029 ; // Max 2 digit year (for Y2K bug data entry)
internal int iCurrentEra=0 ; // current era # (usually 1)
// Use overrides?
internal bool bUseUserOverrides ; // True if we want user overrides.
// Static invariant for the invariant locale
internal static CalendarData Invariant ~ delete _;
// Private constructor
private this() {}
// Invariant constructor
static this()
{
// Set our default/gregorian US calendar data
// Calendar IDs are 1-based, arrays are 0 based.
CalendarData invariant = new CalendarData();
invariant.SetupDefaults();
// Calendar was built, go ahead and assign it...
Invariant = invariant;
}
void SetupDefaults()
{
// Set default data for calendar
// Note that we don't load resources since this IS NOT supposed to change (by definition)
sNativeName = new String("Gregorian Calendar"); // Calendar Name
// Year
iTwoDigitYearMax = 2029; // Max 2 digit year (for Y2K bug data entry)
iCurrentEra = 1; // Current era #
// Formats
saShortDates = AllocStrings("MM/dd/yyyy", "yyyy-MM-dd"); // short date format
saLongDates = AllocStrings("dddd, dd MMMM yyyy"); // long date format
saYearMonths = AllocStrings("yyyy MMMM"); // year month format
sMonthDay = new String("MMMM dd"); // Month day pattern
// Calendar Parts Names
saEraNames = AllocStrings("A.D."); // Era names
saAbbrevEraNames = AllocStrings("AD"); // Abbreviated Era names
saAbbrevEnglishEraNames=AllocStrings("AD"); // Abbreviated era names in English
saDayNames = AllocStrings("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday");// day names
saAbbrevDayNames = AllocStrings("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"); // abbreviated day names
saSuperShortDayNames = AllocStrings("Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"); // The super short day names
saMonthNames = AllocStrings("January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December", String.Empty); // month names
saAbbrevMonthNames = AllocStrings("Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", String.Empty); // abbreviated month names
saMonthGenitiveNames = AllocStrings(params saMonthNames); // Genitive month names (same as month names for invariant)
saAbbrevMonthGenitiveNames=AllocStrings(params saAbbrevMonthNames); // Abbreviated genitive month names (same as abbrev month names for invariant)
saLeapYearMonthNames = AllocStrings(params saMonthNames); // leap year month names are unused in Gregorian English (invariant)
bUseUserOverrides = false;
}
static String[] AllocStrings(params String[] strs)
{
String[] newStrs = new String[strs.Count];
for (var str in strs)
newStrs[@str] = new String(str);
return newStrs;
}
//
// Get a bunch of data for a calendar
//
internal this(String localeName, int calendarId, bool bUseUserOverrides)
{
String[] Clone(String[] strs)
{
var newStrs = new String[strs.Count];
for (var str in strs)
newStrs[@str] = new String(str);
return newStrs;
}
// Call nativeGetCalendarData to populate the data
this.bUseUserOverrides = bUseUserOverrides;
if (!nativeGetCalendarData(this, localeName, calendarId))
{
//Contract.Assert(false, "[CalendarData] nativeGetCalendarData call isn't expected to fail for calendar " + calendarId + " locale " +localeName);
Debug.FatalError("[CalendarData] nativeGetCalendarData call isn't expected to fail for calendar");
// Something failed, try invariant for missing parts
// This is really not good, but we don't want the callers to crash.
#unwarn
if (this.sNativeName == null) this.sNativeName = String.Empty; // Calendar Name for the locale.
// Formats
if (this.saShortDates == null) this.saShortDates = Clone(Invariant.saShortDates); // Short Data format, default first
if (this.saYearMonths == null) this.saYearMonths = Clone(Invariant.saYearMonths); // Year/Month Data format, default first
if (this.saLongDates == null) this.saLongDates = Clone(Invariant.saLongDates); // Long Data format, default first
if (this.sMonthDay == null) this.sMonthDay = Invariant.sMonthDay; // Month/Day format
// Calendar Parts Names
if (this.saEraNames == null) this.saEraNames = Invariant.saEraNames; // Names of Eras
if (this.saAbbrevEraNames == null) this.saAbbrevEraNames = Invariant.saAbbrevEraNames; // Abbreviated Era Names
if (this.saAbbrevEnglishEraNames == null) this.saAbbrevEnglishEraNames = Invariant.saAbbrevEnglishEraNames; // Abbreviated Era Names in English
if (this.saDayNames == null) this.saDayNames = Invariant.saDayNames; // Day Names, null to use locale data, starts on Sunday
if (this.saAbbrevDayNames == null) this.saAbbrevDayNames = Invariant.saAbbrevDayNames; // Abbrev Day Names, null to use locale data, starts on Sunday
if (this.saSuperShortDayNames == null) this.saSuperShortDayNames = Invariant.saSuperShortDayNames; // Super short Day of week names
if (this.saMonthNames == null) this.saMonthNames = Invariant.saMonthNames; // Month Names (13)
if (this.saAbbrevMonthNames == null) this.saAbbrevMonthNames = Invariant.saAbbrevMonthNames; // Abbrev Month Names (13)
// Genitive and Leap names can follow the fallback below
}
// Clean up the escaping of the formats
CultureData.ReescapeWin32Strings(this.saShortDates);
CultureData.ReescapeWin32Strings(this.saLongDates);
CultureData.ReescapeWin32Strings(this.saYearMonths);
CultureData.ReescapeWin32String(this.sMonthDay);
if ((CalendarId)calendarId == CalendarId.TAIWAN)
{
// for Geo----al reasons, the ----ese native name should only be returned when
// for ----ese SKU
if (CultureInfo.IsTaiwanSku)
{
// We got the month/day names from the OS (same as gregorian), but the native name is wrong
this.sNativeName = "\x4e2d\x83ef\x6c11\x570b\x66c6";
}
else
{
this.sNativeName = String.Empty;
}
}
// Check for null genitive names (in case unmanaged side skips it for non-gregorian calendars, etc)
if (this.saMonthGenitiveNames == null || String.IsNullOrEmpty(this.saMonthGenitiveNames[0]))
this.saMonthGenitiveNames = this.saMonthNames; // Genitive month names (same as month names for invariant)
if (this.saAbbrevMonthGenitiveNames == null || String.IsNullOrEmpty(this.saAbbrevMonthGenitiveNames[0]))
this.saAbbrevMonthGenitiveNames = this.saAbbrevMonthNames; // Abbreviated genitive month names (same as abbrev month names for invariant)
if (this.saLeapYearMonthNames == null || String.IsNullOrEmpty(this.saLeapYearMonthNames[0]))
this.saLeapYearMonthNames = this.saMonthNames;
InitializeEraNames(localeName, calendarId);
InitializeAbbreviatedEraNames(localeName, calendarId);
// Abbreviated English Era Names are only used for the Japanese calendar.
if (calendarId == (int)CalendarId.JAPAN)
{
//this.saAbbrevEnglishEraNames = JapaneseCalendar.EnglishEraNames();
Runtime.NotImplemented();
}
else
{
// For all others just use the an empty string (doesn't matter we'll never ask for it for other calendars)
this.saAbbrevEnglishEraNames = new String[] { "" };
}
// Japanese is the only thing with > 1 era. Its current era # is how many ever
// eras are in the array. (And the others all have 1 string in the array)
this.iCurrentEra = this.saEraNames.Count;
}
private void InitializeEraNames(String localeName, int calendarId)
{
// Note that the saEraNames only include "A.D." We don't have localized names for other calendars available from windows
switch ((CalendarId)calendarId)
{
// For Localized Gregorian we really expect the data from the OS.
case CalendarId.GREGORIAN:
// Fallback for CoreCLR < Win7 or culture.dll missing
if (this.saEraNames == null || this.saEraNames.Count == 0 || String.IsNullOrEmpty(this.saEraNames[0]))
{
DeleteContainerAndItems!(this.saEraNames);
this.saEraNames = AllocStrings("A.D.");
}
break;
// The rest of the calendars have constant data, so we'll just use that
case CalendarId.GREGORIAN_US:
case CalendarId.JULIAN:
DeleteContainerAndItems!(this.saEraNames);
this.saEraNames = AllocStrings("A.D.");
break;
case CalendarId.HEBREW:
DeleteContainerAndItems!(this.saEraNames);
this.saEraNames = AllocStrings("C.E.");
break;
case CalendarId.HIJRI:
case CalendarId.UMALQURA:
DeleteContainerAndItems!(this.saEraNames);
if (localeName == "dv-MV")
{
// Special case for Divehi
this.saEraNames = AllocStrings("\x0780\x07a8\x0796\x07b0\x0783\x07a9");
}
else
{
this.saEraNames = AllocStrings("\x0628\x0639\x062F \x0627\x0644\x0647\x062C\x0631\x0629");
}
break;
case CalendarId.GREGORIAN_ARABIC:
case CalendarId.GREGORIAN_XLIT_ENGLISH:
case CalendarId.GREGORIAN_XLIT_FRENCH:
// These are all the same:
DeleteContainerAndItems!(this.saEraNames);
this.saEraNames = AllocStrings("\x0645");
break;
case CalendarId.GREGORIAN_ME_FRENCH:
DeleteContainerAndItems!(this.saEraNames);
this.saEraNames = AllocStrings("ap. J.-C.");
break;
case CalendarId.TAIWAN:
// for Geo----al reasons, the ----ese native name should only be returned when
// for ----ese SKU
DeleteContainerAndItems!(this.saEraNames);
if (CultureInfo.IsTaiwanSku)
{
//
this.saEraNames = AllocStrings("\x4e2d\x83ef\x6c11\x570b");
}
else
{
this.saEraNames = AllocStrings(String.Empty);
}
break;
case CalendarId.KOREA:
DeleteContainerAndItems!(this.saEraNames);
this.saEraNames = AllocStrings("\xb2e8\xae30");
break;
case CalendarId.THAI:
DeleteContainerAndItems!(this.saEraNames);
this.saEraNames = AllocStrings("\x0e1e\x002e\x0e28\x002e");
break;
case CalendarId.JAPAN:
case CalendarId.JAPANESELUNISOLAR:
//this.saEraNames = JapaneseCalendar.EraNames();
Runtime.NotImplemented();
//break;
case CalendarId.PERSIAN:
if (this.saEraNames == null || this.saEraNames.Count == 0 || String.IsNullOrEmpty(this.saEraNames[0]))
{
DeleteContainerAndItems!(this.saEraNames);
this.saEraNames = AllocStrings("\x0647\x002e\x0634");
}
break;
default:
// Most calendars are just "A.D."
this.saEraNames = Invariant.saEraNames;
break;
}
}
private void InitializeAbbreviatedEraNames(StringView localeName, int calendarId)
{
// Note that the saAbbrevEraNames only include "AD" We don't have localized names for other calendars available from windows
switch ((CalendarId)calendarId)
{
// For Localized Gregorian we really expect the data from the OS.
case CalendarId.GREGORIAN:
// Fallback for CoreCLR < Win7 or culture.dll missing
if (this.saAbbrevEraNames == null || this.saAbbrevEraNames.Count == 0 || String.IsNullOrEmpty(this.saAbbrevEraNames[0]))
{
DeleteContainerAndItems!(this.saAbbrevEraNames);
this.saAbbrevEraNames = AllocStrings("AD");
}
// The rest of the calendars have constant data, so we'll just use that
case CalendarId.GREGORIAN_US:
case CalendarId.JULIAN:
DeleteContainerAndItems!(this.saAbbrevEraNames);
this.saAbbrevEraNames = AllocStrings("AD");
break;
case CalendarId.JAPAN:
case CalendarId.JAPANESELUNISOLAR:
//this.saAbbrevEraNames = JapaneseCalendar.AbbrevEraNames();
Runtime.NotImplemented();
case CalendarId.HIJRI:
case CalendarId.UMALQURA:
DeleteContainerAndItems!(this.saAbbrevEraNames);
if (localeName == "dv-MV")
{
// Special case for Divehi
this.saAbbrevEraNames = AllocStrings("\x0780\x002e");
}
else
{
this.saAbbrevEraNames = AllocStrings("\x0647\x0640");
}
break;
case CalendarId.TAIWAN:
// Get era name and abbreviate it
DeleteContainerAndItems!(this.saAbbrevEraNames);
this.saAbbrevEraNames = new String[1];
if (this.saEraNames[0].Length == 4)
{
this.saAbbrevEraNames[0] = new String(this.saEraNames[0], 2, 2);
}
else
{
this.saAbbrevEraNames[0] = new String(this.saEraNames[0]);
}
break;
case CalendarId.PERSIAN:
if (this.saAbbrevEraNames == null || this.saAbbrevEraNames.Count == 0 || String.IsNullOrEmpty(this.saAbbrevEraNames[0]))
{
DeleteContainerAndItems!(this.saAbbrevEraNames);
this.saAbbrevEraNames = AllocStrings(params this.saEraNames);
}
break;
default:
// Most calendars just use the full name
this.saAbbrevEraNames = AllocStrings(params this.saEraNames);
break;
}
}
internal static CalendarData GetCalendarData(int calendarId)
{
/*//
// Get a calendar.
// Unfortunately we depend on the locale in the OS, so we need a locale
// no matter what. So just get the appropriate calendar from the
// appropriate locale here
//
// Get a culture name
//
String culture = CalendarIdToCultureName(calendarId);
// Return our calendar
return CultureInfo.GetCultureInfo(culture).m_cultureData.GetCalendar(calendarId);*/
Runtime.FatalError();
}
//
// Helper methods
//
private static String CalendarIdToCultureName(int calendarId)
{
switch (calendarId)
{
case Calendar.CAL_GREGORIAN_US:
return "fa-IR"; // "fa-IR" Iran
case Calendar.CAL_JAPAN:
return "ja-JP"; // "ja-JP" Japan
case Calendar.CAL_TAIWAN:
return "zh-TW"; // zh-TW Taiwan
case Calendar.CAL_KOREA:
return "ko-KR"; // "ko-KR" Korea
case Calendar.CAL_HIJRI:
case Calendar.CAL_GREGORIAN_ARABIC:
case Calendar.CAL_UMALQURA:
return "ar-SA"; // "ar-SA" Saudi Arabia
case Calendar.CAL_THAI:
return "th-TH"; // "th-TH" Thailand
case Calendar.CAL_HEBREW:
return "he-IL"; // "he-IL" Israel
case Calendar.CAL_GREGORIAN_ME_FRENCH:
return "ar-DZ"; // "ar-DZ" Algeria
case Calendar.CAL_GREGORIAN_XLIT_ENGLISH:
case Calendar.CAL_GREGORIAN_XLIT_FRENCH:
return "ar-IQ"; // "ar-IQ"; Iraq
default:
// Default to gregorian en-US
break;
}
return "en-US";
}
/*internal void FixupWin7MonthDaySemicolonBug()
{
int unescapedCharacterIndex = FindUnescapedCharacter(sMonthDay, ';');
if (unescapedCharacterIndex > 0)
{
sMonthDay = sMonthDay.Substring(0, unescapedCharacterIndex);
}
}*/
private static int FindUnescapedCharacter(String s, char8 charToFind)
{
bool inComment = false;
int length = s.Length;
for (int i = 0; i < length; i++)
{
char8 c = s[i];
switch (c)
{
case '\'':
inComment = !inComment;
break;
case '\\':
i++; // escape sequence -- skip next character
break;
default:
if (!inComment && charToFind == c)
{
return i;
}
break;
}
}
return -1;
}
internal static int nativeGetTwoDigitYearMax(int calID)
{
Runtime.NotImplemented();
}
private static bool nativeGetCalendarData(CalendarData data, String localeName, int calendar)
{
data.SetupDefaults();
//NotImplemented();
return true;
}
internal static int nativeGetCalendars(String localeName, bool useUserOverride, int[] calendars)
{
Runtime.NotImplemented();
}
}
}

View file

@ -0,0 +1,17 @@
// This file contains portions of code released by Microsoft under the MIT license as part
// of an open-sourcing initiative in 2014 of the C# core libraries.
// The original source was submitted to https://github.com/Microsoft/referencesource
namespace System.Globalization
{
using System;
public enum CalendarWeekRule
{
FirstDay = 0, // Week 1 begins on the first day of the year
FirstFullWeek = 1, // Week 1 begins on first FirstDayOfWeek not before the first day of the year
FirstFourDayWeek = 2 // Week 1 begins on first FirstDayOfWeek such that FirstDayOfWeek+3 is not before the first day of the year
}
}

View file

@ -0,0 +1,589 @@
using System.Diagnostics;
using System.Collections.Generic;
// This file contains portions of code released by Microsoft under the MIT license as part
// of an open-sourcing initiative in 2014 of the C# core libraries.
// The original source was submitted to https://github.com/Microsoft/referencesource
namespace System.Globalization
{
class CultureData
{
private const uint LOCALE_NOUSEROVERRIDE = 0x80000000; // do not use user overrides
private const uint LOCALE_SLOCALIZEDDISPLAYNAME = 0x00000002; // localized name of locale, eg "German (Germany)" in UI language
private const uint LOCALE_SENGLISHDISPLAYNAME = 0x00000072; // Display name (language + country usually) in English, eg "German (Germany)"
private const uint LOCALE_SNATIVEDISPLAYNAME = 0x00000073; // Display name in native locale language, eg "Deutsch (Deutschland)
private const uint LOCALE_SLOCALIZEDLANGUAGENAME = 0x0000006f; // Language Display Name for a language, eg "German" in UI language
private const uint LOCALE_SENGLISHLANGUAGENAME = 0x00001001; // English name of language, eg "German"
private const uint LOCALE_SNATIVELANGUAGENAME = 0x00000004; // native name of language, eg "Deutsch"
private const uint LOCALE_SLOCALIZEDCOUNTRYNAME = 0x00000006; // localized name of country, eg "Germany" in UI language
private const uint LOCALE_SENGLISHCOUNTRYNAME = 0x00001002; // English name of country, eg "Germany"
private const uint LOCALE_SNATIVECOUNTRYNAME = 0x00000008; // native name of country, eg "Deutschland"
private const uint LOCALE_STIME = 0x0000001E; // time separator (derived from LOCALE_STIMEFORMAT, use that instead)
private const uint LOCALE_STIMEFORMAT = 0x00001003; // time format string
const int32 undef = -1;
// Override flag
private String sRealName ~ delete _; // Name you passed in (ie: en-US, en, or de-DE_phoneb)
private String sWindowsName ~ delete _; // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in))
// Identity
private String sName ~ delete _; // locale name (ie: en-us, NO sort info, but could be neutral)
private String sParent; // Parent name (which may be a custom locale/culture)
private String sLocalizedDisplayName; // Localized pretty name for this locale
private String sEnglishDisplayName; // English pretty name for this locale
private String sNativeDisplayName; // Native pretty name for this locale
private String sSpecificCulture ~ delete _; // The culture name to be used in CultureInfo.CreateSpecificCulture(), en-US form if neutral, sort name if sort
// Language
private String sISO639Language; // ISO 639 Language Name
private String sLocalizedLanguage; // Localized name for this language
private String sEnglishLanguage; // English name for this language
private String sNativeLanguage; // Native name of this language
// Region
private String sRegionName; // (RegionInfo)
// private int iCountry=undef ; // (user can override) ---- code (RegionInfo)
private int iGeoId = undef; // GeoId
private String sLocalizedCountry; // localized country name
private String sEnglishCountry; // english country name (RegionInfo)
private String sNativeCountry; // native country name
private String sISO3166CountryName; // ISO 3166 (RegionInfo), ie: US
// Numbers
private String sPositiveSign; // (user can override) positive sign
private String sNegativeSign; // (user can override) negative sign
private String[] saNativeDigits; // (user can override) native characters for digits 0-9
// (nfi populates these 5, don't have to be = undef)
private int32 iDigitSubstitution; // (user can override) Digit substitution 0=context, 1=none/arabic, 2=Native/national (2 seems to be unused)
private int32 iLeadingZeros; // (user can override) leading zeros 0 = no leading zeros, 1 = leading zeros
private int32 iDigits; // (user can override) number of fractional digits
private int32 iNegativeNumber; // (user can override) negative number format
private int32[] waGrouping; // (user can override) grouping of digits
private String sDecimalSeparator; // (user can override) decimal separator
private String sThousandSeparator; // (user can override) thousands separator
private String sNaN; // Not a Number
private String sPositiveInfinity; // + Infinity
private String sNegativeInfinity; // - Infinity
// Percent
private int iNegativePercent = undef; // Negative Percent (0-3)
private int iPositivePercent = undef; // Positive Percent (0-11)
private String sPercent; // Percent (%) symbol
private String sPerMille; // PerMille (‰) symbol
// Currency
private String sCurrency; // (user can override) local monetary symbol
private String sIntlMonetarySymbol; // international monetary symbol (RegionInfo)
private String sEnglishCurrency; // English name for this currency
private String sNativeCurrency; // Native name for this currency
// (nfi populates these 4, don't have to be = undef)
private int iCurrencyDigits; // (user can override) # local monetary fractional digits
private int iCurrency; // (user can override) positive currency format
private int iNegativeCurrency; // (user can override) negative currency format
private int[] waMonetaryGrouping; // (user can override) monetary grouping of digits
private String sMonetaryDecimal; // (user can override) monetary decimal separator
private String sMonetaryThousand; // (user can override) monetary thousands separator
// Misc
private int32 iMeasure = undef; // (user can override) system of measurement 0=metric, 1=US (RegionInfo)
private String sListSeparator; // (user can override) list separator
// private int iPaperSize ; // default paper size (RegionInfo)
// Time
private String sAM1159; // (user can override) AM designator
private String sPM2359; // (user can override) PM designator
private String sTimeSeparator;
private volatile String[] saLongTimes; // (user can override) time format
private volatile String[] saShortTimes; // short time format
private volatile String[] saDurationFormats; // time duration format
// Calendar specific data
private int iFirstDayOfWeek = undef; // (user can override) first day of week (gregorian really)
private int iFirstWeekOfYear = undef; // (user can override) first week of year (gregorian really)
private volatile int[] waCalendars; // all available calendar type(s). The first one is the default calendar
// Store for specific data about each calendar
private CalendarData[] calendars; // Store for specific calendar data
// Text information
private int iReadingLayout = undef; // Reading layout data
// 0 - Left to right (eg en-US)
// 1 - Right to left (eg arabic locales)
// 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
// 3 - Vertical top to bottom with columns proceeding to the right
private String sTextInfo; // Text info name to use for custom
private String sCompareInfo; // Compare info name (including sorting key) to use if custom
private String sScripts; // Typical Scripts for this locale (latn;cyrl; etc)
// The bools all need to be in one spot
private bool bUseOverrides; // use user overrides?
private bool bNeutral; // Flags for the culture (ie: neutral or not right now)
List<Object> ownedObjects = new .() ~ DeleteContainerAndItems!(_);
public this()
{
}
internal void GetNFIValues(NumberFormatInfo nfi)
{
}
public bool IsInvariantCulture
{
get
{
return true;
}
}
internal Calendar DefaultCalendar
{
get
{
/*int defaultCalId = DoGetLocaleInfoInt(LOCALE_ICALENDARTYPE);
if (defaultCalId == 0)
{
defaultCalId = this.CalendarIds[0];
}
return CultureInfo.GetCalendarInstance(defaultCalId);*/
//Runtime.NotImplemented();
// NotImplemented
return CultureInfo.GetCalendarInstance(Calendar.CAL_GREGORIAN);
}
}
internal StringView CultureName
{
get
{
switch (this.sName)
{
case "zh-CHS":
case "zh-CHT":
return this.sName;
}
return this.sRealName;
}
}
internal String[] LongTimes
{
get
{
if (this.saLongTimes == null
#if !FEATURE_CORECLR
|| UseUserOverride
#endif
)
{
/*String[] longTimes = DoEnumTimeFormats();
if (longTimes == null || longTimes.Length == 0)
{
this.saLongTimes = Invariant.saLongTimes;
}
else
{
this.saLongTimes = longTimes;
}*/
//NotImpl
saLongTimes = new String[](new .("h:mm:ss tt"));
ownedObjects.Add(saLongTimes);
ownedObjects.Add(saLongTimes[0]);
}
return this.saLongTimes;
}
}
internal String[] ShortTimes
{
get
{
if (this.saShortTimes == null
#if !FEATURE_CORECLR
|| UseUserOverride
#endif
)
{
// Try to get the short times from the OS/culture.dll
/*String[] shortTimes = DoEnumShortTimeFormats();
if (shortTimes == null || shortTimes.Length == 0)
{
//
// If we couldn't find short times, then compute them from long times
// (eg: CORECLR on < Win7 OS & fallback for missing culture.dll)
//
shortTimes = DeriveShortTimesFromLong();
}
// Found short times, use them
this.saShortTimes = shortTimes;*/
saShortTimes = new String[](new .("h:mm tt"));
ownedObjects.Add(saShortTimes);
ownedObjects.Add(saShortTimes[0]);
}
return this.saShortTimes;
}
}
internal static CultureData GetCultureData(StringView cultureName, bool useUserOverride)
{
CultureData culture = CreateCultureData(cultureName, useUserOverride);
return culture;
}
private static CultureData CreateCultureData(StringView cultureName, bool useUserOverride)
{
CultureData culture = new CultureData();
//culture.bUseOverrides = useUserOverride;
//culture.sRealName = cultureName;
// Ask native code if that one's real
if (culture.InitCultureData() == false)
{
/*#if !FEATURE_CORECLR
if (culture.InitCompatibilityCultureData() == false
&& culture.InitLegacyAlternateSortData() == false)
#endif*/
{
return null;
}
}
return culture;
}
private bool InitCultureData()
{
sWindowsName = new String("en-US");
sRealName = new String("en-US");
sSpecificCulture = new String("en-US");
sName = new String("en-US");
//NotImplemented
return true;
}
////////////////////////////////////////////////////////////////////////////
//
// Reescape a Win32 style quote string as a NLS+ style quoted string
//
// This is also the escaping style used by custom culture data files
//
// NLS+ uses \ to escape the next character, whether in a quoted string or
// not, so we always have to change \ to \\.
//
// NLS+ uses \' to escape a quote inside a quoted string so we have to change
// '' to \' (if inside a quoted string)
//
// We don't build the stringbuilder unless we find something to change
////////////////////////////////////////////////////////////////////////////
static internal void ReescapeWin32String(String inStr)
{
// If we don't have data, then don't try anything
if (inStr == null)
return;
var inStr;
bool inQuote = false;
for (int i = 0; i < inStr.Length; i++)
{
// Look for quote
if (inStr[i] == '\'')
{
// Already in quote?
if (inQuote)
{
// See another single quote. Is this '' of 'fred''s' or '''', or is it an ending quote?
if (i + 1 < inStr.Length && inStr[i + 1] == '\'')
{
// Found another ', so we have ''. Need to add \' instead.
// 1st make sure we have our stringbuilder
// Append a \' and keep going (so we don't turn off quote mode)
inStr.Insert(i, "\\");
i++;
continue;
}
// Turning off quote mode, fall through to add it
inQuote = false;
}
else
{
// Found beginning quote, fall through to add it
inQuote = true;
}
}
// Is there a single \ character?
else if (inStr[i] == '\\')
{
// Found a \, need to change it to \\
// 1st make sure we have our stringbuilder
// Append our \\ to the string & continue
inStr.Insert(i, "\\\\");
continue;
}
}
}
static internal void ReescapeWin32Strings(String[] inArray)
{
if (inArray != null)
{
for (int i = 0; i < inArray.Count; i++)
{
ReescapeWin32String(inArray[i]);
}
}
}
internal bool UseUserOverride
{
get
{
return this.bUseOverrides;
}
}
internal bool IsSupplementalCustomCulture
{
get
{
//return IsCustomCultureId(this.ILANGUAGE);
return false;
}
}
static private bool IsOsWin7OrPrior()
{
return Environment.OSVersion.Platform == PlatformID.Win32NT &&
Environment.OSVersion.Version < Version(6, 2); // Win7 is 6.1.Build.Revision so we have to check for anything less than 6.2
}
internal CalendarData GetCalendar(int calendarId)
{
Debug.Assert(calendarId > 0 && calendarId <= CalendarData.MAX_CALENDARS,
"[CultureData.GetCalendar] Expect calendarId to be in a valid range");
// arrays are 0 based, calendarIds are 1 based
int calendarIndex = calendarId - 1;
// Have to have calendars
if (calendars == null)
{
calendars = new CalendarData[CalendarData.MAX_CALENDARS];
}
// we need the following local variable to avoid returning null
// when another thread creates a new array of CalendarData (above)
// right after we insert the newly created CalendarData (below)
CalendarData calendarData = calendars[calendarIndex];
// Make sure that calendar has data
if (calendarData == null
#if !FEATURE_CORECLR
|| UseUserOverride
#endif
)
{
//Contract.Assert(this.sWindowsName != null, "[CultureData.GetCalendar] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
calendarData = new CalendarData(this.sWindowsName, calendarId, this.UseUserOverride);
/*#if !FEATURE_CORECLR
//Work around issue where Win7 data for MonthDay contains invalid two sets of data separated by semicolon
//even though MonthDay is not enumerated
if (IsOsWin7OrPrior() && !IsSupplementalCustomCulture && !IsReplacementCulture)
{
calendarData.FixupWin7MonthDaySemicolonBug();
}
#endif*/
calendars[calendarIndex] = calendarData;
}
return calendarData;
}
internal String[] ShortDates(int calendarId)
{
return GetCalendar(calendarId).saShortDates;
}
internal String[] LongDates(int calendarId)
{
return GetCalendar(calendarId).saLongDates;
}
// (user can override) date year/month format.
internal String[] YearMonths(int calendarId)
{
return GetCalendar(calendarId).saYearMonths;
}
// day names
internal String[] DayNames(int calendarId)
{
return GetCalendar(calendarId).saDayNames;
}
// abbreviated day names
internal String[] AbbreviatedDayNames(int calendarId)
{
// Get abbreviated day names for this calendar from the OS if necessary
return GetCalendar(calendarId).saAbbrevDayNames;
}
// The super short day names
internal String[] SuperShortDayNames(int calendarId)
{
return GetCalendar(calendarId).saSuperShortDayNames;
}
// month names
internal String[] MonthNames(int calendarId)
{
return GetCalendar(calendarId).saMonthNames;
}
// Genitive month names
internal String[] GenitiveMonthNames(int calendarId)
{
return GetCalendar(calendarId).saMonthGenitiveNames;
}
// month names
internal String[] AbbreviatedMonthNames(int calendarId)
{
return GetCalendar(calendarId).saAbbrevMonthNames;
}
// Genitive month names
internal String[] AbbreviatedGenitiveMonthNames(int calendarId)
{
return GetCalendar(calendarId).saAbbrevMonthGenitiveNames;
}
// Leap year month names
// Note: This only applies to Hebrew, and it basically adds a "1" to the 6th month name
// the non-leap names skip the 7th name in the normal month name array
internal String[] LeapYearMonthNames(int calendarId)
{
return GetCalendar(calendarId).saLeapYearMonthNames;
}
// month/day format (single string, no override)
internal String MonthDay(int calendarId)
{
return GetCalendar(calendarId).sMonthDay;
}
void DoGetLocaleInfo(uint lctype, String outStr)
{
DoGetLocaleInfo(this.sWindowsName, lctype, outStr);
}
void DoGetLocaleInfo(StringView localeName, uint lctype, String outStr)
{
var lctype;
// Fix lctype if we don't want overrides
if (!UseUserOverride)
{
lctype |= LOCALE_NOUSEROVERRIDE;
}
// Ask OS for data
/*String result = CultureInfo.nativeGetLocaleInfoEx(localeName, lctype);
if (result == null)
{
// Failed, just use empty string
result = String.Empty;
}
return result;*/
}
private static void GetSeparator(StringView format, StringView timeParts, String outStr)
{
/*int index = IndexOfTimePart(format, 0, timeParts);
if (index != -1)
{
// Found a time part, find out when it changes
char8 cTimePart = format[index];
do
{
index++;
} while (index < format.Length && format[index] == cTimePart);
int separatorStart = index;
// Now we need to find the end of the separator
if (separatorStart < format.Length)
{
int separatorEnd = IndexOfTimePart(format, separatorStart, timeParts);
if (separatorEnd != -1)
{
// From [separatorStart, count) is our string, except we need to unescape
return UnescapeNlsString(format, separatorStart, separatorEnd - 1);
}
}
}
return String.Empty;*/
}
static private void GetTimeSeparator(StringView format, String outStr)
{
// Time format separator (ie: : in 12:39:00)
//
// We calculate this from the provided time format
//
//
// Find the time separator so that we can pretend we know STIME.
//
GetSeparator(format, "Hhms", outStr);
}
internal String TimeSeparator
{
get
{
if (sTimeSeparator == null
#if !FEATURE_CORECLR
|| UseUserOverride
#endif
)
{
String longTimeFormat = scope String();
DoGetLocaleInfo(LOCALE_STIMEFORMAT, longTimeFormat);
ReescapeWin32String(longTimeFormat);
if (String.IsNullOrEmpty(longTimeFormat))
{
longTimeFormat = LongTimes[0];
}
// Compute STIME from time format
sTimeSeparator = new String();
GetTimeSeparator(longTimeFormat, sTimeSeparator);
}
return sTimeSeparator;
}
}
}
}

View file

@ -0,0 +1,343 @@
using System.Diagnostics.Contracts;
using System.Threading;
namespace System.Globalization
{
class CultureInfo : IFormatProvider
{
//public static readonly CultureInfo CurrentCulture = null;
public CultureData mCultureData = new CultureData() ~ delete _;
public NumberFormatInfo mNumInfo ~ delete _;
static CultureInfo sInvariantCultureInfo ~ delete _; // Volatile?
static CultureInfo sUserDefaultUICulture ~ delete _; // Volatile?
static CultureInfo sUserDefaultCulture ~ delete _; // Volatile?
public static CultureInfo mDefaultCultureInfo /*= new CultureInfo()*/ ~ delete _;
[ThreadStatic]
private static CultureInfo tlCurrentCulture;
[ThreadStatic]
private static CultureInfo tlCurrentUICulture;
String m_name ~ delete _;
internal bool m_isInherited;
DateTimeFormatInfo dateTimeInfo ~ delete _;
CultureData m_cultureData ~ delete _;
Calendar calendar ~ delete _;
bool m_isReadOnly;
// LOCALE constants of interest to us internally and privately for LCID functions
// (ie: avoid using these and use names if possible)
internal const int LOCALE_NEUTRAL = 0x0000;
private const int LOCALE_USER_DEFAULT = 0x0400;
private const int LOCALE_SYSTEM_DEFAULT = 0x0800;
internal const int LOCALE_CUSTOM_DEFAULT = 0x0c00;
internal const int LOCALE_CUSTOM_UNSPECIFIED = 0x1000;
internal const int LOCALE_INVARIANT = 0x007F;
private const int LOCALE_TRADITIONAL_SPANISH = 0x040a;
public static CultureInfo DefaultThreadCurrentCulture
{
get
{
return mDefaultCultureInfo;
}
}
public static CultureInfo UserDefaultCulture
{
get
{
return sUserDefaultCulture;
}
}
public static CultureInfo InvariantCulture
{
get
{
return sInvariantCultureInfo;
}
}
public StringView Name
{
get
{
return m_name;
}
}
public NumberFormatInfo NumberFormat
{
get
{
if (mNumInfo == null)
mNumInfo = new NumberFormatInfo(mCultureData);
return mNumInfo;
}
}
public static CultureInfo CurrentCulture
{
get
{
if (tlCurrentCulture == null)
tlCurrentCulture = CultureInfo.DefaultThreadCurrentCulture ?? CultureInfo.UserDefaultCulture;
return tlCurrentCulture;
}
set
{
Contract.Assert(value != null);
Contract.EndContractBlock();
tlCurrentCulture = value;
}
}
public static CultureInfo CurrentUICulture
{
get
{
if (tlCurrentUICulture == null)
tlCurrentUICulture = CultureInfo.DefaultThreadCurrentCulture ?? CultureInfo.UserDefaultCulture;
return tlCurrentUICulture;
}
set
{
Contract.Assert(value != null);
Contract.EndContractBlock();
tlCurrentUICulture = value;
}
}
public virtual Calendar Calendar {
get {
if (calendar == null)
{
//Contract.Assert(this.m_cultureData.CalendarIds.Length > 0, "this.m_cultureData.CalendarIds.Length > 0");
// Get the default calendar for this culture. Note that the value can be
// from registry if this is a user default culture.
Calendar newObj = this.m_cultureData.DefaultCalendar;
Interlocked.Fence();
newObj.SetReadOnlyState(m_isReadOnly);
calendar = newObj;
}
return (calendar);
}
}
public virtual DateTimeFormatInfo DateTimeFormat
{
get
{
if (dateTimeInfo == null)
{
// Change the calendar of DTFI to the specified calendar of this CultureInfo.
DateTimeFormatInfo temp = new DateTimeFormatInfo(
this.m_cultureData, this.Calendar);
temp.[Friend]m_isReadOnly = m_isReadOnly;
Interlocked.Fence();
dateTimeInfo = temp;
}
return (dateTimeInfo);
}
set {
/*if (value == null) {
throw new ArgumentNullException("value",
Environment.GetResourceString("ArgumentNull_Obj"));
}
Contract.EndContractBlock();*/
VerifyWritable();
dateTimeInfo = value;
}
}
//
// The CultureData instance that reads the data provided by our CultureData class.
//
//Using a field initializer rather than a static constructor so that the whole class can be lazy
//init.
private static readonly bool init = Init();
private static bool Init()
{
if (sInvariantCultureInfo == null)
{
CultureInfo temp = new CultureInfo("", false);
temp.m_isReadOnly = true;
sInvariantCultureInfo = temp;
}
// First we set it to Invariant in case someone needs it before we're done finding it.
// For example, if we throw an exception in InitUserDefaultCulture, we will still need an valid
// s_userDefaultCulture to be used in Thread.CurrentCulture.
sUserDefaultCulture = sUserDefaultUICulture = sInvariantCultureInfo;
sUserDefaultCulture = InitUserDefaultCulture();
sUserDefaultUICulture = InitUserDefaultUICulture();
return true;
}
static CultureInfo InitUserDefaultCulture()
{
String strDefault = scope String();
GetDefaultLocaleName(LOCALE_USER_DEFAULT, strDefault);
if (strDefault.IsEmpty)
{
GetDefaultLocaleName(LOCALE_SYSTEM_DEFAULT, strDefault);
if (strDefault.IsEmpty)
{
// If system default doesn't work, keep using the invariant
return (CultureInfo.InvariantCulture);
}
}
CultureInfo temp = GetCultureByName(strDefault, true);
temp.m_isReadOnly = true;
return (temp);
}
static CultureInfo InitUserDefaultUICulture()
{
String strDefault = scope .();
GetUserDefaultUILanguage(strDefault);
// In most of cases, UserDefaultCulture == UserDefaultUICulture, so we should use the same instance if possible.
if (strDefault == UserDefaultCulture.Name)
{
return (UserDefaultCulture);
}
CultureInfo temp = GetCultureByName( strDefault, true);
if (temp == null)
{
return (CultureInfo.InvariantCulture);
}
temp.m_isReadOnly = true;
return (temp);
}
public this(String name) : this(name, true)
{
}
public this(String name, bool useUserOverride)
{
// Get our data providing record
this.m_cultureData = CultureData.GetCultureData(name, useUserOverride);
if (this.m_cultureData == null) {
//throw new CultureNotFoundException("name", name, Environment.GetResourceString("Argument_CultureNotSupported"));
Runtime.FatalError();
}
this.m_name = new String(this.m_cultureData.CultureName);
this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
}
private void VerifyWritable()
{
Runtime.Assert(!m_isReadOnly);
}
public static this()
{
//sInvariantCultureInfo = new CultureInfo();
}
private static volatile bool s_isTaiwanSku;
private static volatile bool s_haveIsTaiwanSku;
internal static bool IsTaiwanSku
{
get
{
if (!s_haveIsTaiwanSku)
{
var language = scope String();
GetSystemDefaultUILanguage(language);
s_isTaiwanSku = (language == "zh-TW");
s_haveIsTaiwanSku = true;
}
return (bool)s_isTaiwanSku;
}
}
static bool GetSystemDefaultUILanguage(String outStr)
{
outStr.Append("EN-us");
return true;
}
public virtual Object GetFormat(Type formatType)
{
if (formatType == typeof(NumberFormatInfo))
{
return (NumberFormat);
}
if (formatType == typeof(DateTimeFormatInfo))
{
return (DateTimeFormat);
}
return (null);
}
private static void GetDefaultLocaleName(int localeType, String outName)
{
/*Contract.Assert(localeType == LOCALE_USER_DEFAULT || localeType == LOCALE_SYSTEM_DEFAULT, "[CultureInfo.GetDefaultLocaleName] localeType must be LOCALE_USER_DEFAULT or LOCALE_SYSTEM_DEFAULT");
string localeName = null;
if (InternalGetDefaultLocaleName(localeType, JitHelpers.GetStringHandleOnStack(ref localeName)))
{
return localeName;
}
return string.Empty;*/
outName.Append("EN-us");
}
// Gets a cached copy of the specified culture from an internal hashtable (or creates it
// if not found). (Named version)
public static CultureInfo GetCultureInfo(StringView name)
{
// Make sure we have a valid, non-zero length string as name
CultureInfo retval = GetCultureInfoHelper(0, name, .());
return retval;
}
private static CultureInfo GetCultureByName(String name, bool userOverride)
{
// Try to get our culture
return userOverride ? new CultureInfo(name) : CultureInfo.GetCultureInfo(name);
}
// Helper function both both overloads of GetCachedReadOnlyCulture. If lcid is 0, we use the name.
// If lcid is -1, use the altName and create one of those special SQL cultures.
internal static CultureInfo GetCultureInfoHelper(int lcid, StringView name, StringView altName)
{
return new CultureInfo();
}
private static void GetUserDefaultUILanguage(String langName)
{
//NotImplemented
}
internal static Calendar GetCalendarInstance(int calType)
{
if (calType==Calendar.CAL_GREGORIAN) {
return new GregorianCalendar();
}
Runtime.NotImplemented();
//return GetCalendarInstanceRare(calType);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,590 @@
using System.Collections.Generic;
namespace System.Globalization
{
internal enum MonthNameStyles {
Regular = 0x00000000,
Genitive = 0x00000001,
LeapYear = 0x00000002,
}
internal 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.
internal 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
internal String amDesignator = "AM";
internal String pmDesignator = "PM";
internal String dateSeparator = "/"; // derived from short date (whidbey expects, arrowhead doesn't)
internal String generalShortTimePattern = null; // short date + short time (whidbey expects, arrowhead doesn't)
internal String generalLongTimePattern = null; // short date + long time (whidbey expects, arrowhead doesn't)
internal String timeSeparator = ":"; // derived from long time (whidbey expects, arrowhead doesn't)
internal String monthDayPattern = null;
internal String dateTimeOffsetPattern = null;
//
// The following are constant values.
//
internal const String rfc1123Pattern = "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'";
// The sortable pattern is based on ISO 8601.
internal const String sortableDateTimePattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss";
internal const String universalSortableDateTimePattern = "yyyy'-'MM'-'dd HH':'mm':'ss'Z'";
//
// The following are affected by calendar settings.
//
internal Calendar calendar = null;
internal int firstDayOfWeek = -1;
internal int calendarWeekRule = -1;
internal String fullDateTimePattern = null; // long date + long time (whidbey expects, arrowhead doesn't)
internal String[] abbreviatedDayNames = null;
internal String[] m_superShortDayNames = null;
internal String[] dayNames = null;
internal String[] abbreviatedMonthNames = null;
internal String[] monthNames = null;
// Cache the genitive month names that we retrieve from the data table.
internal String[] genitiveMonthNames = null;
// Cache the abbreviated genitive month names that we retrieve from the data table.
internal String[] m_genitiveAbbreviatedMonthNames = null;
// Cache the month names of a leap year that we retrieve from the data table.
internal 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
internal String longDatePattern = "dddd, MMMM d, yyyy";
internal String shortDatePattern = "M/d/yyyy";
internal String yearMonthPattern = "MMMM yyyy";
internal String longTimePattern = null;
internal 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
private String[] allYearMonthPatterns = null; // This was wasn't serialized in Whidbey
internal String[] allShortDatePatterns = null;
internal String[] allLongDatePatterns = null;
internal String[] allShortTimePatterns = null;
internal String[] allLongTimePatterns = null;
// Cache the era names for this DateTimeFormatInfo instance.
internal String[] m_eraNames = null;
internal String[] m_abbrevEraNames = null;
internal String[] m_abbrevEnglishEraNames = null;
internal int[] optionalCalendars = null;
private const int DEFAULT_ALL_DATETIMES_SIZE = 132;
// CultureInfo updates this
internal 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.
internal 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.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.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.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.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.Invariant.saAbbrevDayNames[(int)dayofweek]);
}
public void GetDayName(DayOfWeek dayofweek, String outStr)
{
outStr.Append(CalendarData.Invariant.saDayNames[(int)dayofweek]);
}
public void GetAbbreviatedMonthName(int month, String outStr)
{
outStr.Append(CalendarData.Invariant.saAbbrevMonthNames[month - 1]);
}
public void GetMonthName(int month, String outStr)
{
outStr.Append(CalendarData.Invariant.saMonthNames[month - 1]);
}
public void GetEraName(int era, String outStr)
{
outStr.Append(CalendarData.Invariant.saEraNames[era]);
}
internal 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.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.YearMonths(this.Calendar.ID);
}
return this.allYearMonthPatterns;
}
}
private String [] UnclonedShortDatePatterns
{
get
{
if (allShortDatePatterns == null)
{
this.allShortDatePatterns = this.m_cultureData.ShortDates(this.Calendar.ID);
}
return this.allShortDatePatterns;
}
}
private String[] UnclonedLongDatePatterns
{
get
{
if (allLongDatePatterns == null)
{
this.allLongDatePatterns = this.m_cultureData.LongDates(this.Calendar.ID);
}
return this.allLongDatePatterns;
}
}
private String[] UnclonedShortTimePatterns
{
get
{
if (this.allShortTimePatterns == null)
{
this.allShortTimePatterns = this.m_cultureData.ShortTimes;
}
return this.allShortTimePatterns;
}
}
private String[] UnclonedLongTimePatterns
{
get
{
if (this.allLongTimePatterns == null)
{
this.allLongTimePatterns = this.m_cultureData.LongTimes;
}
return this.allLongTimePatterns;
}
}
private String m_fullTimeSpanPositivePattern ~ delete _;
internal String FullTimeSpanPositivePattern
{
get
{
if (m_fullTimeSpanPositivePattern == null)
{
CultureData cultureDataWithoutUserOverrides;
if (m_cultureData.UseUserOverride)
cultureDataWithoutUserOverrides = CultureData.GetCultureData(m_cultureData.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 _;
internal String FullTimeSpanNegativePattern
{
get
{
if (m_fullTimeSpanNegativePattern == null)
m_fullTimeSpanNegativePattern = AllocString()..Append("'-'", FullTimeSpanPositivePattern);
return m_fullTimeSpanNegativePattern;
}
}
}
}

View file

@ -0,0 +1,35 @@
namespace System.Globalization
{
internal enum CalendarId : uint16
{
GREGORIAN = 1 , // Gregorian (localized) calendar
GREGORIAN_US = 2 , // Gregorian (U.S.) calendar
JAPAN = 3 , // Japanese Emperor Era calendar
/* SSS_WARNINGS_OFF */ TAIWAN = 4 , // Taiwan Era calendar /* SSS_WARNINGS_ON */
KOREA = 5 , // Korean Tangun Era calendar
HIJRI = 6 , // Hijri (Arabic Lunar) calendar
THAI = 7 , // Thai calendar
HEBREW = 8 , // Hebrew (Lunar) calendar
GREGORIAN_ME_FRENCH = 9 , // Gregorian Middle East French calendar
GREGORIAN_ARABIC = 10, // Gregorian Arabic calendar
GREGORIAN_XLIT_ENGLISH = 11, // Gregorian Transliterated English calendar
GREGORIAN_XLIT_FRENCH = 12,
// Note that all calendars after this point are MANAGED ONLY for now.
JULIAN = 13,
JAPANESELUNISOLAR = 14,
CHINESELUNISOLAR = 15,
SAKA = 16, // reserved to match Office but not implemented in our code
LUNAR_ETO_CHN = 17, // reserved to match Office but not implemented in our code
LUNAR_ETO_KOR = 18, // reserved to match Office but not implemented in our code
LUNAR_ETO_ROKUYOU = 19, // reserved to match Office but not implemented in our code
KOREANLUNISOLAR = 20,
TAIWANLUNISOLAR = 21,
PERSIAN = 22,
UMALQURA = 23,
LAST_CALENDAR = 23 // Last calendar ID
}
class DateTimeFormatInfoScanner
{
}
}

View file

@ -0,0 +1,38 @@
// This file contains portions of code released by Microsoft under the MIT license as part
// of an open-sourcing initiative in 2014 of the C# core libraries.
// The original source was submitted to https://github.com/Microsoft/referencesource
namespace System.Globalization
{
public enum DateTimeStyles
{
// Bit flag indicating that leading whitespace is allowed. Character values
// 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, and 0x0020 are considered to be
// whitespace.
None = 0x00000000,
AllowLeadingWhite = 0x00000001,
AllowTrailingWhite = 0x00000002, //Bitflag indicating trailing whitespace is allowed.
AllowInnerWhite = 0x00000004,
AllowWhiteSpaces = AllowLeadingWhite | AllowInnerWhite | AllowTrailingWhite,
// When parsing a date/time string, if all year/month/day are missing, set the default date
// to 0001/1/1, instead of the current year/month/day.
NoCurrentDateDefault = 0x00000008,
// When parsing a date/time string, if a timezone specifier ("GMT","Z","+xxxx", "-xxxx" exists), we will
// ajdust the parsed time based to GMT.
AdjustToUniversal = 0x00000010,
AssumeLocal = 0x00000020,
AssumeUniversal = 0x00000040,
// Attempt to preserve whether the input is unspecified, local or UTC
RoundtripKind = 0x00000080,
}
}

View file

@ -0,0 +1,56 @@
// This file contains portions of code released by Microsoft under the MIT license as part
// of an open-sourcing initiative in 2014 of the C# core libraries.
// The original source was submitted to https://github.com/Microsoft/referencesource
namespace System.Globalization
{
using System;
// This class represents a starting/ending time for a period of daylight saving time.
public class DaylightTime
{
internal DateTime m_start;
internal DateTime m_end;
internal TimeSpan m_delta;
public this()
{
}
public this(DateTime start, DateTime end, TimeSpan delta)
{
m_start = start;
m_end = end;
m_delta = delta;
}
public void Set(DateTime start, DateTime end, TimeSpan delta)
{
m_start = start;
m_end = end;
m_delta = delta;
}
// The start date of a daylight saving period.
public DateTime Start {
get {
return m_start;
}
}
// The end date of a daylight saving period.
public DateTime End {
get {
return m_end;
}
}
// Delta to stardard offset in ticks.
public TimeSpan Delta {
get {
return m_delta;
}
}
}
}

View file

@ -0,0 +1,661 @@
// This file contains portions of code released by Microsoft under the MIT license as part
// of an open-sourcing initiative in 2014 of the C# core libraries.
// The original source was submitted to https://github.com/Microsoft/referencesource
namespace System.Globalization {
//
// N.B.:
// A lot of this code is directly from DateTime.cs. If you update that class,
// update this one as well.
// However, we still need these duplicated code because we will add era support
// in this class.
//
//
using System.Threading;
using System;
using System.Globalization;
using System.Diagnostics.Contracts;
public enum GregorianCalendarTypes
{
Localized = Calendar.CAL_GREGORIAN,
USEnglish = Calendar.CAL_GREGORIAN_US,
MiddleEastFrench = Calendar.CAL_GREGORIAN_ME_FRENCH,
Arabic = Calendar.CAL_GREGORIAN_ARABIC,
TransliteratedEnglish = Calendar.CAL_GREGORIAN_XLIT_ENGLISH,
TransliteratedFrench = Calendar.CAL_GREGORIAN_XLIT_FRENCH,
}
// This calendar recognizes two era values:
// 0 CurrentEra (AD)
// 1 BeforeCurrentEra (BC)
public class GregorianCalendar : Calendar
{
/*
A.D. = anno Domini
*/
public const int ADEra = 1;
internal const int DatePartYear = 0;
internal const int DatePartDayOfYear = 1;
internal const int DatePartMonth = 2;
internal const int DatePartDay = 3;
//
// This is the max Gregorian year can be represented by DateTime class. The limitation
// is derived from DateTime class.
//
internal const int MaxYear = 9999;
internal GregorianCalendarTypes m_type;
internal static readonly int[] DaysToMonth365 = new int[]
{
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
} ~ delete _;
internal static readonly int[] DaysToMonth366 = new int[]
{
0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366
} ~ delete _;
private static volatile Calendar s_defaultInstance;
#region Serialization
/*private void OnDeserialized(StreamingContext ctx)
{
if (m_type < GregorianCalendarTypes.Localized ||
m_type > GregorianCalendarTypes.TransliteratedFrench)
{
throw new SerializationException(
String.Format(
CultureInfo.CurrentCulture,
Environment.GetResourceString(
"Serialization_MemberOutOfRange"),
"type",
"GregorianCalendar"));
}
}*/
#endregion Serialization
public override DateTime MinSupportedDateTime
{
get
{
return (DateTime.MinValue);
}
}
public override DateTime MaxSupportedDateTime
{
get
{
return (DateTime.MaxValue);
}
}
public override CalendarAlgorithmType AlgorithmType
{
get
{
return CalendarAlgorithmType.SolarCalendar;
}
}
/*=================================GetDefaultInstance==========================
**Action: Internal method to provide a default intance of GregorianCalendar. Used by NLS+ implementation
** and other calendars.
**Returns:
**Arguments:
**Exceptions:
============================================================================*/
internal static Calendar GetDefaultInstance() {
if (s_defaultInstance == null) {
s_defaultInstance = new GregorianCalendar();
}
return (s_defaultInstance);
}
// Construct an instance of gregorian calendar.
public this() :
this(GregorianCalendarTypes.Localized)
{
}
public this(GregorianCalendarTypes type) {
if ((int)type < (int)GregorianCalendarTypes.Localized || (int)type > (int)GregorianCalendarTypes.TransliteratedFrench) {
/*throw new ArgumentOutOfRangeException(
"type",
Environment.GetResourceString("ArgumentOutOfRange_Range",
GregorianCalendarTypes.Localized, GregorianCalendarTypes.TransliteratedFrench));*/
Runtime.FatalError();
}
Contract.EndContractBlock();
this.m_type = type;
}
public virtual GregorianCalendarTypes CalendarType {
get {
return (m_type);
}
set {
VerifyWritable();
switch (value)
{
case GregorianCalendarTypes.Localized:
case GregorianCalendarTypes.USEnglish:
case GregorianCalendarTypes.MiddleEastFrench:
case GregorianCalendarTypes.Arabic:
case GregorianCalendarTypes.TransliteratedEnglish:
case GregorianCalendarTypes.TransliteratedFrench:
m_type = value;
break;
default:
Runtime.FatalError();
//throw new ArgumentOutOfRangeException("m_type", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
}
}
}
internal override int ID {
get {
// By returning different ID for different variations of GregorianCalendar,
// we can support the Transliterated Gregorian calendar.
// DateTimeFormatInfo will use this ID to get formatting information about
// the calendar.
return ((int)m_type);
}
}
// Returns a given date part of this DateTime. This method is used
// to compute the year, day-of-year, month, or day part.
internal virtual int GetDatePart(int64 ticks, int part)
{
// n = number of days since 1/1/0001
int n = (int)(ticks / TicksPerDay);
// y400 = number of whole 400-year periods since 1/1/0001
int y400 = n / DaysPer400Years;
// n = day number within 400-year period
n -= y400 * DaysPer400Years;
// y100 = number of whole 100-year periods within 400-year period
int y100 = n / DaysPer100Years;
// Last 100-year period has an extra day, so decrement result if 4
if (y100 == 4) y100 = 3;
// n = day number within 100-year period
n -= y100 * DaysPer100Years;
// y4 = number of whole 4-year periods within 100-year period
int y4 = n / DaysPer4Years;
// n = day number within 4-year period
n -= y4 * DaysPer4Years;
// y1 = number of whole years within 4-year period
int y1 = n / DaysPerYear;
// Last year has an extra day, so decrement result if 4
if (y1 == 4) y1 = 3;
// If year was requested, compute and return it
if (part == DatePartYear)
{
return (y400 * 400 + y100 * 100 + y4 * 4 + y1 + 1);
}
// n = day number within year
n -= y1 * DaysPerYear;
// If day-of-year was requested, return it
if (part == DatePartDayOfYear)
{
return (n + 1);
}
// Leap year calculation looks different from IsLeapYear since y1, y4,
// and y100 are relative to year 1, not year 0
bool leapYear = (y1 == 3 && (y4 != 24 || y100 == 3));
int[] days = leapYear? DaysToMonth366: DaysToMonth365;
// All months have less than 32 days, so n >> 5 is a good conservative
// estimate for the month
int m = n >> 5 + 1;
// m = 1-based month number
while (n >= days[m]) m++;
// If month was requested, return it
if (part == DatePartMonth) return (m);
// Return 1-based day-of-month
return (n - days[m - 1] + 1);
}
/*=================================GetAbsoluteDate==========================
**Action: Gets the absolute date for the given Gregorian date. The absolute date means
** the number of days from January 1st, 1 A.D.
**Returns: the absolute date
**Arguments:
** year the Gregorian year
** month the Gregorian month
** day the day
**Exceptions:
** ArgumentOutOfRangException if year, month, day value is valid.
**Note:
** This is an internal method used by DateToTicks() and the calculations of Hijri and Hebrew calendars.
** Number of Days in Prior Years (both common and leap years) +
** Number of Days in Prior Months of Current Year +
** Number of Days in Current Month
**
============================================================================*/
internal static Result<int64> GetAbsoluteDate(int year, int month, int day) {
if (year >= 1 && year <= MaxYear && month >= 1 && month <= 12)
{
int[] days = ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))) ? DaysToMonth366: DaysToMonth365;
if (day >= 1 && (day <= days[month] - days[month - 1])) {
int y = year - 1;
int absoluteDate = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1;
return (absoluteDate);
}
}
//throw new ArgumentOutOfRangeException(null, Environment.GetResourceString("ArgumentOutOfRange_BadYearMonthDay"));
return .Err;
}
// Returns the tick count corresponding to the given year, month, and day.
// Will check the if the parameters are valid.
internal virtual Result<int64> DateToTicks(int year, int month, int day) {
return (Try!(GetAbsoluteDate(year, month, day)) * TicksPerDay);
}
// Returns the DateTime resulting from adding the given number of
// months to the specified DateTime. The result is computed by incrementing
// (or decrementing) the year and month parts of the specified DateTime by
// value months, and, if required, adjusting the day part of the
// resulting date downwards to the last day of the resulting month in the
// resulting year. The time-of-day part of the result is the same as the
// time-of-day part of the specified DateTime.
//
// In more precise terms, considering the specified DateTime to be of the
// form y / m / d + t, where y is the
// year, m is the month, d is the day, and t is the
// time-of-day, the result is y1 / m1 / d1 + t,
// where y1 and m1 are computed by adding value months
// to y and m, and d1 is the largest value less than
// or equal to d that denotes a valid day in month m1 of year
// y1.
//
public override Result<DateTime> AddMonths(DateTime time, int months)
{
if (months < -120000 || months > 120000) {
/*throw new ArgumentOutOfRangeException(
"months",
String.Format(
CultureInfo.CurrentCulture,
Environment.GetResourceString("ArgumentOutOfRange_Range"),
-120000,
120000));*/
return .Err;
}
Contract.EndContractBlock();
int y = GetDatePart(time.Ticks, DatePartYear);
int m = GetDatePart(time.Ticks, DatePartMonth);
int d = GetDatePart(time.Ticks, DatePartDay);
int i = m - 1 + months;
if (i >= 0)
{
m = i % 12 + 1;
y = y + i / 12;
}
else
{
m = 12 + (i + 1) % 12;
y = y + (i - 11) / 12;
}
int[] daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? DaysToMonth366: DaysToMonth365;
int days = (daysArray[m] - daysArray[m - 1]);
if (d > days)
{
d = days;
}
int64 ticks = Try!(DateToTicks(y, m, d)) + time.Ticks % TicksPerDay;
Try!(Calendar.CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime));
return (DateTime(ticks));
}
// Returns the DateTime resulting from adding the given number of
// years to the specified DateTime. The result is computed by incrementing
// (or decrementing) the year part of the specified DateTime by value
// years. If the month and day of the specified DateTime is 2/29, and if the
// resulting year is not a leap year, the month and day of the resulting
// DateTime becomes 2/28. Otherwise, the month, day, and time-of-day
// parts of the result are the same as those of the specified DateTime.
//
public override Result<DateTime> AddYears(DateTime time, int years)
{
return (AddMonths(time, years * 12));
}
// Returns the day-of-month part of the specified DateTime. The returned
// value is an integer between 1 and 31.
//
public override Result<int> GetDayOfMonth(DateTime time)
{
return (GetDatePart(time.Ticks, DatePartDay));
}
// Returns the day-of-week part of the specified DateTime. The returned value
// is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
// Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
// Thursday, 5 indicates Friday, and 6 indicates Saturday.
//
public override Result<DayOfWeek> GetDayOfWeek(DateTime time)
{
return ((DayOfWeek)((int)(time.Ticks / TicksPerDay + 1) % 7));
}
// Returns the day-of-year part of the specified DateTime. The returned value
// is an integer between 1 and 366.
//
public override Result<int> GetDayOfYear(DateTime time)
{
return (GetDatePart(time.Ticks, DatePartDayOfYear));
}
// Returns the number of days in the month given by the year and
// month arguments.
//
public override Result<int> GetDaysInMonth(int year, int month, int era)
{
if (era == CurrentEra || era == ADEra) {
if (year < 1 || year > MaxYear) {
/*throw new ArgumentOutOfRangeException("year", Environment.GetResourceString("ArgumentOutOfRange_Range",
1, MaxYear));*/
return .Err;
}
if (month < 1 || month > 12) {
//throw new ArgumentOutOfRangeException("month", Environment.GetResourceString("ArgumentOutOfRange_Month"));
return .Err;
}
int[] days = ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366: DaysToMonth365);
return (days[month] - days[month - 1]);
}
//throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
return .Err;
}
// Returns the number of days in the year given by the year argument for the current era.
//
public override Result<int> GetDaysInYear(int year, int era)
{
if (era == CurrentEra || era == ADEra) {
if (year >= 1 && year <= MaxYear) {
return ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 366:365);
}
/*throw new ArgumentOutOfRangeException(
"year",
String.Format(
CultureInfo.CurrentCulture,
Environment.GetResourceString("ArgumentOutOfRange_Range"),
1,
MaxYear));*/
return .Err;
}
//throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
return .Err;
}
// Returns the era for the specified DateTime value.
public override Result<int> GetEra(DateTime time)
{
return (ADEra);
}
public override int[] Eras
{
get
{
return (new int[] {ADEra} );
}
}
// Returns the month part of the specified DateTime. The returned value is an
// integer between 1 and 12.
//
public override Result<int> GetMonth(DateTime time)
{
return (GetDatePart(time.Ticks, DatePartMonth));
}
// Returns the number of months in the specified year and era.
public override Result<int> GetMonthsInYear(int year, int era)
{
if (era == CurrentEra || era == ADEra) {
if (year >= 1 && year <= MaxYear)
{
return (12);
}
/*throw new ArgumentOutOfRangeException(
"year",
String.Format(
CultureInfo.CurrentCulture,
Environment.GetResourceString("ArgumentOutOfRange_Range"),
1,
MaxYear));*/
return .Err;
}
//throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
return .Err;
}
// Returns the year part of the specified DateTime. The returned value is an
// integer between 1 and 9999.
//
public override Result<int> GetYear(DateTime time)
{
return (GetDatePart(time.Ticks, DatePartYear));
}
// Checks whether a given day in the specified era is a leap day. This method returns true if
// the date is a leap day, or false if not.
//
public override Result<bool> IsLeapDay(int year, int month, int day, int era)
{
if (month < 1 || month > 12) {
/*throw new ArgumentOutOfRangeException("month", Environment.GetResourceString("ArgumentOutOfRange_Range",
1, 12));*/
return .Err;
}
Contract.EndContractBlock();
if (era != CurrentEra && era != ADEra)
{
//throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
return .Err;
}
if (year < 1 || year > MaxYear) {
/*throw new ArgumentOutOfRangeException(
"year",
Environment.GetResourceString("ArgumentOutOfRange_Range", 1, MaxYear));*/
return .Err;
}
if (day < 1 || day > Try!(GetDaysInMonth(year, month))) {
/*throw new ArgumentOutOfRangeException("day", Environment.GetResourceString("ArgumentOutOfRange_Range",
1, GetDaysInMonth(year, month)));*/
return .Err;
}
if (!Try!(IsLeapYear(year))) {
return (false);
}
if (month == 2 && day == 29) {
return (true);
}
return (false);
}
// Returns the leap month in a calendar year of the specified era. This method returns 0
// if this calendar does not have leap month, or this year is not a leap year.
//
public override Result<int> GetLeapMonth(int year, int era)
{
if (era != CurrentEra && era != ADEra)
{
//throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
return .Err;
}
if (year < 1 || year > MaxYear) {
/*throw new ArgumentOutOfRangeException(
"year",
String.Format(
CultureInfo.CurrentCulture,
Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, MaxYear));*/
return .Err;
}
//Contract.EndContractBlock();
return (0);
}
// Checks whether a given month in the specified era is a leap month. This method returns true if
// month is a leap month, or false if not.
//
public override Result<bool> IsLeapMonth(int year, int month, int era)
{
if (era != CurrentEra && era != ADEra) {
//throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
return .Err;
}
if (year < 1 || year > MaxYear) {
/*throw new ArgumentOutOfRangeException(
"year",
String.Format(
CultureInfo.CurrentCulture,
Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, MaxYear));*/
return .Err;
}
if (month < 1 || month > 12) {
/*throw new ArgumentOutOfRangeException("month", Environment.GetResourceString("ArgumentOutOfRange_Range",
1, 12));*/
return .Err;
}
//Contract.EndContractBlock();
return (false);
}
// Checks whether a given year in the specified era is a leap year. This method returns true if
// year is a leap year, or false if not.
//
public override Result<bool> IsLeapYear(int year, int era) {
if (era == CurrentEra || era == ADEra) {
if (year >= 1 && year <= MaxYear) {
return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
}
/*throw new ArgumentOutOfRangeException(
"year",
String.Format(
CultureInfo.CurrentCulture,
Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, MaxYear));*/
return .Err;
}
//throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
return .Err;
}
// Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
//
public override Result<DateTime> ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
{
if (era == CurrentEra || era == ADEra) {
//return new DateTime(year, month, day, hour, minute, second, millisecond);
return .Err;
}
//throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
return .Err;
}
internal override bool TryToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era, out DateTime result) {
if (era == CurrentEra || era == ADEra) {
switch (DateTime.TryCreate(year, month, day, hour, minute, second, millisecond))
{
case .Ok(out result):
return true;
case .Err:
}
}
result = DateTime.MinValue;
return false;
}
private const int DEFAULT_TWO_DIGIT_YEAR_MAX = 2029;
public override int TwoDigitYearMax
{
get {
if (twoDigitYearMax == -1) {
twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DEFAULT_TWO_DIGIT_YEAR_MAX);
}
return (twoDigitYearMax);
}
set {
VerifyWritable();
if (value < 99 || value > MaxYear) {
/*throw new ArgumentOutOfRangeException(
"year",
String.Format(
CultureInfo.CurrentCulture,
Environment.GetResourceString("ArgumentOutOfRange_Range"),
99,
MaxYear));*/
Runtime.FatalError();
}
twoDigitYearMax = value;
}
}
public override Result<int> ToFourDigitYear(int year) {
if (year < 0) {
/*throw new ArgumentOutOfRangeException("year",
Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));*/
return .Err;
}
//Contract.EndContractBlock();
if (year > MaxYear) {
/*throw new ArgumentOutOfRangeException(
"year",
String.Format(
CultureInfo.CurrentCulture,
Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, MaxYear));*/
return .Err;
}
return (base.ToFourDigitYear(year));
}
}
}

View file

@ -0,0 +1,736 @@
// This file contains portions of code released by Microsoft under the MIT license as part
// of an open-sourcing initiative in 2014 of the C# core libraries.
// The original source was submitted to https://github.com/Microsoft/referencesource
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
namespace System.Globalization {
using System.Text;
using System;
using System.Diagnostics.Contracts;
using System.Diagnostics;
using System.Threading;
//
// Property Default Description
// PositiveSign '+' Character used to indicate positive values.
// NegativeSign '-' Character used to indicate negative values.
// NumberDecimalSeparator '.' The character used as the decimal separator.
// NumberGroupSeparator ',' The character used to separate groups of
// digits to the left of the decimal point.
// NumberDecimalDigits 2 The default number of decimal places.
// NumberGroupSizes 3 The number of digits in each group to the
// left of the decimal point.
// NaNSymbol "NaN" The string used to represent NaN values.
// PositiveInfinitySymbol"Infinity" The string used to represent positive
// infinities.
// NegativeInfinitySymbol"-Infinity" The string used to represent negative
// infinities.
//
//
//
// Property Default Description
// CurrencyDecimalSeparator '.' The character used as the decimal
// separator.
// CurrencyGroupSeparator ',' The character used to separate groups
// of digits to the left of the decimal
// point.
// CurrencyDecimalDigits 2 The default number of decimal places.
// CurrencyGroupSizes 3 The number of digits in each group to
// the left of the decimal point.
// CurrencyPositivePattern 0 The format of positive values.
// CurrencyNegativePattern 0 The format of negative values.
// CurrencySymbol "$" String used as local monetary symbol.
//
struct OwnedString
{
public String mString;
public bool mOwned;
public this(String unownedString)
{
mString = unownedString;
mOwned = false;
}
public this(String str, bool owned)
{
mString = str;
mOwned = owned;
}
public void Dispose() mut
{
if (mOwned)
delete mString;
}
public void Set(StringView value) mut
{
if (!mOwned)
{
mString = new String(value);
mOwned = true;
}
else
mString.Set(value);
}
}
public class NumberFormatInfo : /*ICloneable,*/ IFormatProvider
{
// invariantInfo is constant irrespective of your current culture.
private static volatile NumberFormatInfo invariantInfo;
// READTHIS READTHIS READTHIS
// This class has an exact mapping onto a native structure defined in COMNumber.cpp
// DO NOT UPDATE THIS WITHOUT UPDATING THAT STRUCTURE. IF YOU ADD BOOL, ADD THEM AT THE END.
// ALSO MAKE SURE TO UPDATE mscorlib.h in the VM directory to check field offsets.
// READTHIS READTHIS READTHIS
internal int32[] numberGroupSizes = new int32[] {3} ~ delete _;
internal int32[] currencyGroupSizes = new int32[] {3} ~ delete _;
internal int32[] percentGroupSizes = new int32[] {3} ~ delete _;
internal OwnedString positiveSign = .("+") ~ _.Dispose();
internal OwnedString negativeSign = .("-") ~ _.Dispose();
internal OwnedString numberDecimalSeparator = .(".") ~ _.Dispose();
internal OwnedString numberGroupSeparator = .(",") ~ _.Dispose();
internal OwnedString currencyGroupSeparator = .(",") ~ _.Dispose();;
internal OwnedString currencyDecimalSeparator = .(".") ~ _.Dispose();
internal OwnedString currencySymbol = .("\u{00a4}") ~ _.Dispose(); // U+00a4 is the symbol for International Monetary Fund.
// The alternative currency symbol used in Win9x ANSI codepage, that can not roundtrip between ANSI and Unicode.
// Currently, only ja-JP and ko-KR has non-null values (which is U+005c, backslash)
// NOTE: The only legal values for this string are null and "\u005c"
internal String ansiCurrencySymbol = null;
internal OwnedString nanSymbol = .("NaN") ~ _.Dispose();
internal OwnedString positiveInfinitySymbol = .("Infinity") ~ _.Dispose();
internal OwnedString negativeInfinitySymbol = .("-Infinity") ~ _.Dispose();
internal OwnedString percentDecimalSeparator = .(".") ~ _.Dispose();
internal OwnedString percentGroupSeparator = .(",") ~ _.Dispose();
internal OwnedString percentSymbol = .("%") ~ _.Dispose();
internal OwnedString perMilleSymbol = .("\u{2030}") ~ _.Dispose();
internal String[] nativeDigits = new .[] {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"} ~ DeleteNativeDigits();
internal int32 numberDecimalDigits = 2;
internal int32 currencyDecimalDigits = 2;
internal int32 currencyPositivePattern = 0;
internal int32 currencyNegativePattern = 0;
internal int32 numberNegativePattern = 1;
internal int32 percentPositivePattern = 0;
internal int32 percentNegativePattern = 0;
internal int32 percentDecimalDigits = 2;
internal int32 digitSubstitution = 1; // DigitShapes.None
internal bool isReadOnly=false;
// Is this NumberFormatInfo for invariant culture?
internal bool m_isInvariant=false;
void DeleteNativeDigits()
{
if ((!nativeDigits.IsEmpty) && ((Object)nativeDigits[0] != "0"))
{
for (var str in nativeDigits)
delete str;
}
delete nativeDigits;
}
public this() : this(null)
{
}
static private void VerifyDecimalSeparator(String decSep, String propertyName)
{
if (decSep==null) {
/*throw new ArgumentNullException(propertyName,
Environment.GetResourceString("ArgumentNull_String"));*/
}
if (decSep.Length==0) {
/*throw new ArgumentException(Environment.GetResourceString("Argument_EmptyDecString"));*/
}
Contract.EndContractBlock();
}
static private void VerifyGroupSeparator(String groupSep, String propertyName) {
if (groupSep==null) {
/*throw new ArgumentNullException(propertyName,
Environment.GetResourceString("ArgumentNull_String"));*/
}
Contract.EndContractBlock();
}
static private void VerifyNativeDigits(String [] nativeDig, String propertyName) {
if (nativeDig==null) {
/*throw new ArgumentNullException(propertyName,
Environment.GetResourceString("ArgumentNull_Array"));*/
}
if (nativeDig.Count != 10)
{
//throw new ArgumentException(Environment.GetResourceString("Argument_InvalidNativeDigitCount"), propertyName);
}
Contract.EndContractBlock();
for(int i = 0; i < nativeDig.Count; i++)
{
if (nativeDig[i] == null)
{
/*throw new ArgumentNullException(propertyName,
Environment.GetResourceString("ArgumentNull_ArrayValue"));*/
}
if (nativeDig[i].Length != 1) {
if(nativeDig[i].Length != 2) {
// Not 1 or 2 UTF-16 code points
/*throw new ArgumentException(Environment.GetResourceString("Argument_InvalidNativeDigitValue"), propertyName);*/
}
/*else if (!char.IsSurrogatePair(nativeDig[i][0], nativeDig[i][1])) {
// 2 UTF-6 code points, but not a surrogate pair
/*throw new ArgumentException(Environment.GetResourceString("Argument_InvalidNativeDigitValue"), propertyName);*/
}*/
}
/*if (CharUnicodeInfo.GetDecimalDigitValue(nativeDig[i], 0) != i &&
CharUnicodeInfo.GetUnicodeCategory(nativeDig[i], 0) != UnicodeCategory.PrivateUse) {
// Not the appropriate digit according to the Unicode data properties
// (Digit 0 must be a 0, etc.).
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidNativeDigitValue"), propertyName);
}*/
}
}
// We aren't persisting dataItem any more (since its useless & we weren't using it),
// Ditto with m_useUserOverride. Don't use them, we use a local copy of everything.
internal this(CultureData cultureData)
{
if (cultureData != null)
{
// We directly use fields here since these data is coming from data table or Win32, so we
// don't need to verify their values (except for invalid parsing situations).
cultureData.GetNFIValues(this);
if (cultureData.IsInvariantCulture)
{
// For invariant culture
this.m_isInvariant = true;
}
}
}
private void VerifyWritable()
{
if (isReadOnly)
{
Runtime.FatalError("Read only");
//throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
}
Contract.EndContractBlock();
}
// Returns a default NumberFormatInfo that will be universally
// supported and constant irrespective of the current culture.
// Used by FromString methods.
//
/*public static NumberFormatInfo InvariantInfo {
get {
/*if (invariantInfo == null) {
// Lazy create the invariant info. This cannot be done in a .cctor because exceptions can
// be thrown out of a .cctor stack that will need this.
NumberFormatInfo nfi = new NumberFormatInfo();
nfi.m_isInvariant = true;
invariantInfo = ReadOnly(nfi);
}
return invariantInfo;*/
}
}*/
/*public static NumberFormatInfo GetInstance(IFormatProvider formatProvider)
{
// Fast case for a regular CultureInfo
/*NumberFormatInfo info;
CultureInfo cultureProvider = formatProvider as CultureInfo;
if (cultureProvider != null && !cultureProvider.m_isInherited) {
info = cultureProvider.numInfo;
if (info != null) {
return info;
}
else {
return cultureProvider.NumberFormat;
}
}
// Fast case for an NFI;
info = formatProvider as NumberFormatInfo;
if (info != null) {
return info;
}
if (formatProvider != null) {
info = formatProvider.GetFormat(typeof(NumberFormatInfo)) as NumberFormatInfo;
if (info != null) {
return info;
}
}
return CurrentInfo;*/
}*/
/*public Object Clone()
{
/*NumberFormatInfo n = (NumberFormatInfo)MemberwiseClone();
n.isReadOnly = false;
return n;*/
return null;
}*/
public int32 CurrencyDecimalDigits
{
get { return currencyDecimalDigits; }
set {
if (value < 0 || value > 99)
{
/*throw new ArgumentOutOfRangeException(
"CurrencyDecimalDigits",
String.Format(
CultureInfo.CurrentCulture,
Environment.GetResourceString("ArgumentOutOfRange_Range"),
0,
99));*/
}
Contract.EndContractBlock();
VerifyWritable();
currencyDecimalDigits = (.)value;
}
}
public String CurrencyDecimalSeparator {
get { return currencyDecimalSeparator.mString; }
set {
VerifyWritable();
VerifyDecimalSeparator(value, "CurrencyDecimalSeparator");
currencyDecimalSeparator.Set(value);
}
}
public bool IsReadOnly {
get {
return isReadOnly;
}
}
//
// Check the values of the groupSize array.
//
// Every element in the groupSize array should be between 1 and 9
// excpet the last element could be zero.
//
static internal void CheckGroupSize(String propName, int[] groupSize)
{
for (int i = 0; i < groupSize.Count; i++)
{
if (groupSize[i] < 1)
{
if (i == groupSize.Count - 1 && groupSize[i] == 0)
return;
/*throw new ArgumentException(Environment.GetResourceString("Argument_InvalidGroupSize"), propName);*/
}
else if (groupSize[i] > 9)
{
/*throw new ArgumentException(Environment.GetResourceString("Argument_InvalidGroupSize"), propName);*/
}
}
}
public Span<int32> CurrencyGroupSizes
{
get
{
//return ((int[])currencyGroupSizes.Clone());
return currencyGroupSizes;
}
set
{
VerifyWritable();
delete currencyGroupSizes;
currencyGroupSizes = new int32[value.Length];
for (int i < value.Length)
currencyGroupSizes[i] = value[i];
/*Int32[] inputSizes = (Int32[])value.Clone();
CheckGroupSize("CurrencyGroupSizes", inputSizes);
currencyGroupSizes = inputSizes;*/
}
}
public Span<int32> NumberGroupSizes
{
get
{
return numberGroupSizes;
}
set
{
VerifyWritable();
delete numberGroupSizes;
numberGroupSizes = new int32[value.Length];
for (int i < value.Length)
numberGroupSizes[i] = value[i];
}
}
public Span<int32> PercentGroupSizes
{
get
{
return percentGroupSizes;
}
set
{
VerifyWritable();
delete percentGroupSizes;
percentGroupSizes = new int32[value.Length];
for (int i < value.Length)
percentGroupSizes[i] = value[i];
}
}
public StringView CurrencyGroupSeparator {
get { return currencyGroupSeparator.mString; }
set {
VerifyWritable();
//VerifyGroupSeparator(value, "CurrencyGroupSeparator");
currencyGroupSeparator.Set(value);
}
}
public StringView CurrencySymbol {
get { return currencySymbol.mString; }
set {
VerifyWritable();
currencySymbol.Set(value);
}
}
// Returns the current culture's NumberFormatInfo. Used by Parse methods.
//
public static NumberFormatInfo CurrentInfo {
get {
/*System.Globalization.CultureInfo culture = System.Threading.Thread.CurrentThread.CurrentCulture;
if (!culture.m_isInherited) {
NumberFormatInfo info = culture.numInfo;
if (info != null) {
return info;
}
}
return ((NumberFormatInfo)culture.GetFormat(typeof(NumberFormatInfo)));*/
return CultureInfo.CurrentCulture.NumberFormat;
}
}
public StringView NaNSymbol
{
get
{
return nanSymbol.mString;
}
set {
/*if (value == null)
{
throw new ArgumentNullException("NaNSymbol",
Environment.GetResourceString("ArgumentNull_String"));
}
Contract.EndContractBlock();
VerifyWritable();*/
//Contract.Assert(value != null);
nanSymbol.Set(value);
}
}
public int CurrencyNegativePattern {
get { return currencyNegativePattern; }
set {
Debug.Assert((value >= 0) && (value <= 15));
VerifyWritable();
currencyNegativePattern = (.)value;
}
}
public int NumberNegativePattern {
get { return numberNegativePattern; }
set {
Debug.Assert((value >= 0) && (value <= 4));
VerifyWritable();
numberNegativePattern = (.)value;
}
}
public int PercentPositivePattern {
get { return percentPositivePattern; }
set {
Debug.Assert((value >= 0) && (value <= 3));
VerifyWritable();
percentPositivePattern = (.)value;
}
}
public int PercentNegativePattern {
get { return percentNegativePattern; }
set {
Debug.Assert((value >= 0) && (value <= 11));
VerifyWritable();
percentNegativePattern = (.)value;
}
}
public StringView NegativeInfinitySymbol {
get {
return negativeInfinitySymbol.mString;
}
set {
VerifyWritable();
negativeInfinitySymbol.Set(value);
}
}
public StringView NegativeSign {
get { return negativeSign.mString; }
set {
VerifyWritable();
negativeSign.Set(value);
}
}
public int32 NumberDecimalDigits {
get { return numberDecimalDigits; }
set {
Debug.Assert((value >= 0) && (value <= 99));
VerifyWritable();
numberDecimalDigits = (.)value;
}
}
public StringView NumberDecimalSeparator {
get { return numberDecimalSeparator.mString; }
set {
VerifyWritable();
numberDecimalSeparator.Set(value);
}
}
public StringView NumberGroupSeparator {
get { return numberGroupSeparator.mString; }
set {
VerifyWritable();
numberGroupSeparator.Set(value);
}
}
public int CurrencyPositivePattern {
get { return currencyPositivePattern; }
set {
Debug.Assert((value >= 0) && (value <= 3));
VerifyWritable();
currencyPositivePattern = (.)value;
}
}
public StringView PositiveInfinitySymbol {
get {
return positiveInfinitySymbol.mString;
}
set {
VerifyWritable();
positiveInfinitySymbol.Set(value);
}
}
public StringView PositiveSign {
get { return positiveSign.mString; }
set {
VerifyWritable();
positiveSign.Set(value);
}
}
public int32 PercentDecimalDigits {
get { return percentDecimalDigits; }
set {
Debug.Assert((value >= 0) && (value <= 99));
VerifyWritable();
percentDecimalDigits = (.)value;
}
}
public StringView PercentDecimalSeparator
{
get { return percentDecimalSeparator.mString; }
set {
VerifyWritable();
percentDecimalSeparator.Set(value);
}
}
public StringView PercentGroupSeparator
{
get { return percentGroupSeparator.mString; }
set {
VerifyWritable();
percentGroupSeparator.Set(value);
}
}
public StringView PercentSymbol
{
get {
return percentSymbol.mString;
}
set {
VerifyWritable();
percentSymbol.Set(value);
}
}
public StringView PerMilleSymbol {
get { return perMilleSymbol.mString; }
set {
VerifyWritable();
perMilleSymbol.Set(value);
}
}
public Span<String> NativeDigits
{
get { return nativeDigits; }
set
{
VerifyWritable();
DeleteNativeDigits();
nativeDigits = new String[value.Length];
for (int i < value.Length)
nativeDigits[i] = new String(value[i]);
}
}
/*#if !FEATURE_CORECLR
[System.Runtime.InteropServices.ComVisible(false)]
public DigitShapes DigitSubstitution
{
get { return (DigitShapes)digitSubstitution; }
set
{
VerifyWritable();
VerifyDigitSubstitution(value, "DigitSubstitution");
digitSubstitution = (int)value;
}
}
#endif // !FEATURE_CORECLR*/
public Object GetFormat(Type formatType) {
return formatType == typeof(NumberFormatInfo)? this: null;
}
public static NumberFormatInfo ReadOnly(NumberFormatInfo nfi)
{
Runtime.FatalError();
/*if (nfi == null) {
throw new ArgumentNullException("nfi");
}
Contract.EndContractBlock();
if (nfi.IsReadOnly) {
return (nfi);
}
NumberFormatInfo info = (NumberFormatInfo)(nfi.MemberwiseClone());
info.isReadOnly = true;
return info;*/
}
// private const NumberStyles InvalidNumberStyles = unchecked((NumberStyles) 0xFFFFFC00);
private const NumberStyles InvalidNumberStyles = ~(NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite
| NumberStyles.AllowLeadingSign | NumberStyles.AllowTrailingSign
| NumberStyles.AllowParentheses | NumberStyles.AllowDecimalPoint
| NumberStyles.AllowThousands | NumberStyles.AllowExponent
| NumberStyles.AllowCurrencySymbol | NumberStyles.AllowHexSpecifier);
/*internal static void ValidateParseStyleInteger(NumberStyles style) {
// Check for undefined flags
if ((style & InvalidNumberStyles) != 0) {
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidNumberStyles"), "style");
}
Contract.EndContractBlock();
if ((style & NumberStyles.AllowHexSpecifier) != 0) { // Check for hex number
if ((style & ~NumberStyles.HexNumber) != 0) {
throw new ArgumentException(Environment.GetResourceString("Arg_InvalidHexStyle"));
}
}
}
internal static void ValidateParseStyleFloatingPoint(NumberStyles style) {
// Check for undefined flags
if ((style & InvalidNumberStyles) != 0) {
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidNumberStyles"), "style");
}
Contract.EndContractBlock();
if ((style & NumberStyles.AllowHexSpecifier) != 0) { // Check for hex number
throw new ArgumentException(Environment.GetResourceString("Arg_HexStyleNotSupported"));
}
}*/
} // NumberFormatInfo
}

View file

@ -0,0 +1,66 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Enum: NumberStyles.cs
**
**
** Purpose: Contains valid formats for Numbers recognized by
** the Number class' parsing code.
**
**
===========================================================*/
namespace System.Globalization
{
using System;
public enum NumberStyles
{
// Bit flag indicating that leading whitespace is allowed. Character values
// 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, and 0x0020 are considered to be
// whitespace.
None = 0x00000000,
AllowLeadingWhite = 0x00000001,
AllowTrailingWhite = 0x00000002, //Bitflag indicating trailing whitespace is allowed.
AllowLeadingSign = 0x00000004, //Can the number start with a sign char.
//Specified by NumberFormatInfo.PositiveSign and NumberFormatInfo.NegativeSign
AllowTrailingSign = 0x00000008, //Allow the number to end with a sign char
AllowParentheses = 0x00000010, //Allow the number to be enclosed in parens
AllowDecimalPoint = 0x00000020, //Allow a decimal point
AllowThousands = 0x00000040, //Allow thousands separators (more properly, allow group separators)
AllowExponent = 0x00000080, //Allow an exponent
AllowCurrencySymbol = 0x00000100, //Allow a currency symbol.
AllowHexSpecifier = 0x00000200, //Allow specifiying hexadecimal.
//Common uses. These represent some of the most common combinations of these flags.
Integer = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign,
HexNumber = AllowLeadingWhite | AllowTrailingWhite | AllowHexSpecifier,
Number = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign | AllowTrailingSign |
AllowDecimalPoint | AllowThousands,
Float = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign |
AllowDecimalPoint | AllowExponent,
Currency = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign | AllowTrailingSign |
AllowParentheses | AllowDecimalPoint | AllowThousands | AllowCurrencySymbol,
Any = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign | AllowTrailingSign |
AllowParentheses | AllowDecimalPoint | AllowThousands | AllowCurrencySymbol | AllowExponent,
}
}

View file

@ -0,0 +1,513 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// <OWNER>[....]</OWNER>
//
namespace System.Globalization {
using System.Text;
using System;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Collections.Generic;
internal static class TimeSpanFormat
{
private static void IntToString(int n, int digits, String outStr)
{
((int32)n).[Friend]ToString(outStr, digits);
}
internal static readonly FormatLiterals PositiveInvariantFormatLiterals = TimeSpanFormat.FormatLiterals.InitInvariant(false /*isNegative*/) ~ _.Dispose();
internal static readonly FormatLiterals NegativeInvariantFormatLiterals = TimeSpanFormat.FormatLiterals.InitInvariant(true /*isNegative*/) ~ _.Dispose();
internal enum Pattern {
None = 0,
Minimum = 1,
Full = 2,
}
//
// Format
//
// Actions: Main method called from TimeSpan.ToString
//
internal static Result<void> Format(TimeSpan value, StringView format, IFormatProvider formatProvider, String outStr)
{
var format;
if (format.IsNull || format.Length == 0)
format = "c";
// standard formats
if (format.Length == 1) {
char8 f = format[0];
if (f == 'c' || f == 't' || f == 'T')
{
FormatStandard(value, true, format, Pattern.Minimum, outStr);
return .Ok;
}
if (f == 'g' || f == 'G') {
Pattern pattern;
DateTimeFormatInfo dtfi = DateTimeFormatInfo.GetInstance(formatProvider);
if ((int64)value < 0)
format = dtfi.FullTimeSpanNegativePattern;
else
format = dtfi.FullTimeSpanPositivePattern;
if (f == 'g')
pattern = Pattern.Minimum;
else
pattern = Pattern.Full;
return FormatStandard(value, false, format, pattern, outStr);
}
//throw new FormatException(Environment.GetResourceString("Format_InvalidString"));
return .Err;
}
return FormatCustomized(value, format, DateTimeFormatInfo.GetInstance(formatProvider), outStr);
}
//
// FormatStandard
//
// Actions: Format the TimeSpan instance using the specified format.
//
private static Result<void> FormatStandard(TimeSpan value, bool isInvariant, StringView format, Pattern pattern, String outStr)
{
int32 day = (int32)((int64)value / TimeSpan.TicksPerDay);
int64 time = (int64)value % TimeSpan.TicksPerDay;
if ((int64)value < 0) {
day = -day;
time = -time;
}
int hours = (int)(time / TimeSpan.TicksPerHour % 24);
int minutes = (int)(time / TimeSpan.TicksPerMinute % 60);
int seconds = (int)(time / TimeSpan.TicksPerSecond % 60);
int fraction = (int)(time % TimeSpan.TicksPerSecond);
FormatLiterals literal;
if (isInvariant) {
if ((int64)value < 0)
literal = NegativeInvariantFormatLiterals;
else
literal = PositiveInvariantFormatLiterals;
}
else {
literal = FormatLiterals();
literal.Init(format, pattern == Pattern.Full);
}
if (fraction != 0) { // truncate the partial second to the specified length
fraction = (int)((int64)fraction / (int64)Math.Pow(10, DateTimeFormat.MaxSecondsFractionDigits - literal.ff));
}
// Pattern.Full: [-]dd.hh:mm:ss.fffffff
// Pattern.Minimum: [-][d.]hh:mm:ss[.fffffff]
outStr.Append(literal.Start); // [-]
if (pattern == Pattern.Full || day != 0) { //
day.ToString(outStr); // [dd]
outStr.Append(literal.DayHourSep); // [.]
} //
IntToString(hours, literal.hh, outStr); // hh
outStr.Append(literal.HourMinuteSep); // :
IntToString(minutes, literal.mm, outStr); // mm
outStr.Append(literal.MinuteSecondSep); // :
IntToString(seconds, literal.ss, outStr); // ss
if (!isInvariant && pattern == Pattern.Minimum) {
int effectiveDigits = literal.ff;
while (effectiveDigits > 0) {
if (fraction % 10 == 0) {
fraction = fraction / 10;
effectiveDigits--;
}
else {
break;
}
}
if (effectiveDigits > 0) {
outStr.Append(literal.SecondFractionSep); // [.FFFFFFF]
(fraction).ToString(outStr, DateTimeFormat.fixedNumberFormats[effectiveDigits - 1], CultureInfo.InvariantCulture);
}
}
else if (pattern == Pattern.Full || fraction != 0) {
outStr.Append(literal.SecondFractionSep); // [.]
IntToString(fraction, literal.ff, outStr); // [fffffff]
} //
outStr.Append(literal.End); //
return .Ok;
}
//
// FormatCustomized
//
// Actions: Format the TimeSpan instance using the specified format.
//
internal static Result<void> FormatCustomized(TimeSpan value, StringView format, DateTimeFormatInfo dtfi, String result)
{
Contract.Assert(dtfi != null, "dtfi == null");
int day = (int)((int64)value / TimeSpan.TicksPerDay);
int64 time = (int64)value % TimeSpan.TicksPerDay;
if ((int64)value < 0) {
day = -day;
time = -time;
}
int hours = (int)(time / TimeSpan.TicksPerHour % 24);
int minutes = (int)(time / TimeSpan.TicksPerMinute % 60);
int seconds = (int)(time / TimeSpan.TicksPerSecond % 60);
int fraction = (int)(time % TimeSpan.TicksPerSecond);
int64 tmp = 0;
int i = 0;
int tokenLen = 0;
while (i < format.Length) {
char8 ch = format[i];
int nextChar;
switch (ch) {
case 'h':
tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
if (tokenLen > 2)
//throw new FormatException(Environment.GetResourceString("Format_InvalidString"));
return .Err;
DateTimeFormat.FormatDigits(result, hours, tokenLen);
break;
case 'm':
tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
if (tokenLen > 2)
return .Err;
//throw new FormatException(Environment.GetResourceString("Format_InvalidString"));
DateTimeFormat.FormatDigits(result, minutes, tokenLen);
break;
case 's':
tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
if (tokenLen > 2)
return .Err;
//throw new FormatException(Environment.GetResourceString("Format_InvalidString"));
DateTimeFormat.FormatDigits(result, seconds, tokenLen);
break;
case 'f':
//
// The fraction of a second in single-digit precision. The remaining digits are truncated.
//
tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
if (tokenLen > DateTimeFormat.MaxSecondsFractionDigits)
return .Err;
//throw new FormatException(Environment.GetResourceString("Format_InvalidString"));
tmp = (int64)fraction;
tmp /= (int64)Math.Pow(10, DateTimeFormat.MaxSecondsFractionDigits - tokenLen);
(tmp).ToString(result, DateTimeFormat.fixedNumberFormats[tokenLen - 1], CultureInfo.InvariantCulture);
break;
case 'F':
//
// Displays the most significant digit of the seconds fraction. Nothing is displayed if the digit is zero.
//
tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
if (tokenLen > DateTimeFormat.MaxSecondsFractionDigits)
return .Err;
//throw new FormatException(Environment.GetResourceString("Format_InvalidString"));
tmp = (int64)fraction;
tmp /= (int64)Math.Pow(10, DateTimeFormat.MaxSecondsFractionDigits - tokenLen);
int effectiveDigits = tokenLen;
while (effectiveDigits > 0) {
if (tmp % 10 == 0) {
tmp = tmp / 10;
effectiveDigits--;
}
else {
break;
}
}
if (effectiveDigits > 0) {
(tmp).ToString(result, DateTimeFormat.fixedNumberFormats[effectiveDigits - 1], CultureInfo.InvariantCulture);
}
break;
case 'd':
//
// tokenLen == 1 : Day as digits with no leading zero.
// tokenLen == 2+: Day as digits with leading zero for single-digit days.
//
tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
if (tokenLen > 8)
return .Err;
//throw new FormatException(Environment.GetResourceString("Format_InvalidString"));
DateTimeFormat.FormatDigits(result, day, tokenLen, true);
break;
case '\'':
case '\"':
//StringBuilder enquotedString = new StringBuilder();
tokenLen = DateTimeFormat.ParseQuoteString(format, i, result);
//result.Append(enquotedString);
break;
case '%':
// Optional format character.
// For example, format string "%d" will print day
// Most of the cases, "%" can be ignored.
nextChar = DateTimeFormat.ParseNextChar(format, i);
// nextChar will be -1 if we already reach the end of the format string.
// Besides, we will not allow "%%" appear in the pattern.
if (nextChar >= 0 && nextChar != (int)'%')
{
TimeSpanFormat.FormatCustomized(value, StringView((char8*)&nextChar, 1), dtfi, result);
tokenLen = 2;
}
else
{
//
// This means that '%' is at the end of the format string or
// "%%" appears in the format string.
//
//throw new FormatException(Environment.GetResourceString("Format_InvalidString"));
return .Err;
}
break;
case '\\':
// Escaped character. Can be used to insert character into the format string.
// For example, "\d" will insert the character 'd' into the string.
//
nextChar = DateTimeFormat.ParseNextChar(format, i);
if (nextChar >= 0)
{
result.Append(((char8)nextChar));
tokenLen = 2;
}
else
{
//
// This means that '\' is at the end of the formatting string.
//
//throw new FormatException(Environment.GetResourceString("Format_InvalidString"));
return .Err;
}
break;
default:
//throw new FormatException(Environment.GetResourceString("Format_InvalidString"));
return .Err;
}
i += tokenLen;
}
return .Ok;
}
internal struct FormatLiterals {
internal String Start {
get {
return literals[0];
}
}
internal String DayHourSep {
get {
return literals[1];
}
}
internal String HourMinuteSep {
get {
return literals[2];
}
}
internal String MinuteSecondSep {
get {
return literals[3];
}
}
internal String SecondFractionSep {
get {
return literals[4];
}
}
internal String End {
get {
return literals[5];
}
}
internal String AppCompatLiteral;
internal int dd;
internal int hh;
internal int mm;
internal int ss;
internal int ff;
private String[] literals;
private List<String> ownedStrs;
public void Dispose() mut
{
DeleteAndNullify!(AppCompatLiteral);
DeleteAndNullify!(literals);
if (ownedStrs != null)
{
DeleteContainerAndItems!(ownedStrs);
ownedStrs = null;
}
}
String AddOwnedStr(String str) mut
{
if (ownedStrs == null)
ownedStrs = new List<String>();
ownedStrs.Add(str);
return str;
}
/* factory method for static invariant FormatLiterals */
internal static FormatLiterals InitInvariant(bool isNegative) {
FormatLiterals x = FormatLiterals();
x.literals = new String[6];
x.literals[0] = isNegative ? "-" : String.Empty;
x.literals[1] = ".";
x.literals[2] = ":";
x.literals[3] = ":";
x.literals[4] = ".";
x.literals[5] = String.Empty;
x.AppCompatLiteral = ":."; // MinuteSecondSep+SecondFractionSep;
x.dd = 2;
x.hh = 2;
x.mm = 2;
x.ss = 2;
x.ff = DateTimeFormat.MaxSecondsFractionDigits;
return x;
}
// For the "v1" TimeSpan localized patterns, the data is simply literal field separators with
// the constants guaranteed to include DHMSF ordered greatest to least significant.
// Once the data becomes more complex than this we will need to write a proper tokenizer for
// parsing and formatting
internal void Init(StringView format, bool useInvariantFieldLengths) mut
{
literals = new String[6];
for (int i = 0; i < literals.Count; i++)
literals[i] = "";
dd = 0;
hh = 0;
mm = 0;
ss = 0;
ff = 0;
String sb = scope String();
bool inQuote = false;
char8 quote = '\'';
int field = 0;
for (int i = 0; i < format.Length; i++) {
switch (format[i]) {
case '\'':
case '\"':
if (inQuote && (quote == format[i])) {
/* we were in a quote and found a matching exit quote, so we are outside a quote now */
Contract.Assert(field >= 0 && field <= 5, "field >= 0 && field <= 5");
if (field >= 0 && field <= 5) {
literals[field] = AddOwnedStr(new String(sb));
sb.Length = 0;
inQuote = false;
}
else {
return; // how did we get here?
}
}
else if (!inQuote) {
/* we are at the start of a new quote block */
quote = format[i];
inQuote = true;
}
else {
/* we were in a quote and saw the other type of quote character, so we are still in a quote */
}
break;
case '%':
Contract.Assert(false, "Unexpected special token '%', Bug in DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern");
sb.Append(format[i]);
case '\\':
if (!inQuote) {
i++; /* skip next character that is escaped by this backslash or percent sign */
break;
}
sb.Append(format[i]);
case 'd':
if (!inQuote) {
Contract.Assert((field == 0 && sb.Length == 0) || field == 1,
"field == 0 || field == 1, Bug in DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern");
field = 1; // DayHourSep
dd++;
}
break;
case 'h':
if (!inQuote) {
Contract.Assert((field == 1 && sb.Length == 0) || field == 2,
"field == 1 || field == 2, Bug in DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern");
field = 2; // HourMinuteSep
hh++;
}
break;
case 'm':
if (!inQuote) {
Contract.Assert((field == 2 && sb.Length == 0) || field == 3,
"field == 2 || field == 3, Bug in DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern");
field = 3; // MinuteSecondSep
mm++;
}
break;
case 's':
if (!inQuote) {
Contract.Assert((field == 3 && sb.Length == 0) || field == 4,
"field == 3 || field == 4, Bug in DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern");
field = 4; // SecondFractionSep
ss++;
}
break;
case 'f':
case 'F':
if (!inQuote) {
Contract.Assert((field == 4 && sb.Length == 0) || field == 5,
"field == 4 || field == 5, Bug in DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern");
field = 5; // End
ff++;
}
break;
default:
sb.Append(format[i]);
break;
}
}
Contract.Assert(field == 5);
AppCompatLiteral = new String(MinuteSecondSep, SecondFractionSep);
Contract.Assert(0 < dd && dd < 3, "0 < dd && dd < 3, Bug in System.Globalization.DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern");
Contract.Assert(0 < hh && hh < 3, "0 < hh && hh < 3, Bug in System.Globalization.DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern");
Contract.Assert(0 < mm && mm < 3, "0 < mm && mm < 3, Bug in System.Globalization.DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern");
Contract.Assert(0 < ss && ss < 3, "0 < ss && ss < 3, Bug in System.Globalization.DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern");
Contract.Assert(0 < ff && ff < 8, "0 < ff && ff < 8, Bug in System.Globalization.DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern");
if (useInvariantFieldLengths) {
dd = 2;
hh = 2;
mm = 2;
ss = 2;
ff = DateTimeFormat.MaxSecondsFractionDigits;
}
else {
if (dd < 1 || dd > 2) dd = 2; // The DTFI property has a problem. let's try to make the best of the situation.
if (hh < 1 || hh > 2) hh = 2;
if (mm < 1 || mm > 2) mm = 2;
if (ss < 1 || ss > 2) ss = 2;
if (ff < 1 || ff > 7) ff = 7;
}
}
} //end of struct FormatLiterals
}
}