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:
parent
4cd58262e4
commit
7dbfd15292
179 changed files with 3 additions and 0 deletions
856
BeefLibs/corlib/src/Globalization/Calendar.bf
Normal file
856
BeefLibs/corlib/src/Globalization/Calendar.bf
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
20
BeefLibs/corlib/src/Globalization/CalendarAlgorithmType.bf
Normal file
20
BeefLibs/corlib/src/Globalization/CalendarAlgorithmType.bf
Normal 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.
|
||||
|
||||
}
|
||||
}
|
505
BeefLibs/corlib/src/Globalization/CalendarData.bf
Normal file
505
BeefLibs/corlib/src/Globalization/CalendarData.bf
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
17
BeefLibs/corlib/src/Globalization/CalendarWeekRule.bf
Normal file
17
BeefLibs/corlib/src/Globalization/CalendarWeekRule.bf
Normal 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
|
||||
}
|
||||
}
|
589
BeefLibs/corlib/src/Globalization/CultureData.bf
Normal file
589
BeefLibs/corlib/src/Globalization/CultureData.bf
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
343
BeefLibs/corlib/src/Globalization/CultureInfo.bf
Normal file
343
BeefLibs/corlib/src/Globalization/CultureInfo.bf
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
1081
BeefLibs/corlib/src/Globalization/DateTimeFormat.bf
Normal file
1081
BeefLibs/corlib/src/Globalization/DateTimeFormat.bf
Normal file
File diff suppressed because it is too large
Load diff
590
BeefLibs/corlib/src/Globalization/DateTimeFormatInfo.bf
Normal file
590
BeefLibs/corlib/src/Globalization/DateTimeFormatInfo.bf
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{
|
||||
}
|
||||
}
|
38
BeefLibs/corlib/src/Globalization/DateTimeStyles.bf
Normal file
38
BeefLibs/corlib/src/Globalization/DateTimeStyles.bf
Normal 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,
|
||||
}
|
||||
}
|
56
BeefLibs/corlib/src/Globalization/DaylightTime.bf
Normal file
56
BeefLibs/corlib/src/Globalization/DaylightTime.bf
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
661
BeefLibs/corlib/src/Globalization/GregorianCalendar.bf
Normal file
661
BeefLibs/corlib/src/Globalization/GregorianCalendar.bf
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
736
BeefLibs/corlib/src/Globalization/NumberFormatInfo.bf
Normal file
736
BeefLibs/corlib/src/Globalization/NumberFormatInfo.bf
Normal 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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
66
BeefLibs/corlib/src/Globalization/NumberStyles.bf
Normal file
66
BeefLibs/corlib/src/Globalization/NumberStyles.bf
Normal 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,
|
||||
|
||||
}
|
||||
}
|
513
BeefLibs/corlib/src/Globalization/TimeSpanFormat.bf
Normal file
513
BeefLibs/corlib/src/Globalization/TimeSpanFormat.bf
Normal 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
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue