You've already forked linux-packaging-mono
Imported Upstream version 4.3.2.467
Former-commit-id: 9c2cb47f45fa221e661ab616387c9cda183f283d
This commit is contained in:
414
external/referencesource/mscorlib/system/globalization/CalendricalCalculationsHelper.cs
vendored
Normal file
414
external/referencesource/mscorlib/system/globalization/CalendricalCalculationsHelper.cs
vendored
Normal file
@@ -0,0 +1,414 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
namespace System.Globalization
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
internal class CalendricalCalculationsHelper
|
||||
{
|
||||
const double FullCircleOfArc = 360.0; // 360.0;
|
||||
const int HalfCircleOfArc = 180;
|
||||
const double TwelveHours = 0.5; // half a day
|
||||
const double Noon2000Jan01 = 730120.5;
|
||||
internal const double MeanTropicalYearInDays = 365.242189;
|
||||
const double MeanSpeedOfSun = MeanTropicalYearInDays / FullCircleOfArc;
|
||||
const double LongitudeSpring = 0.0;
|
||||
const double TwoDegreesAfterSpring = 2.0;
|
||||
const int SecondsPerDay = 24 * 60 * 60; // 24 hours * 60 minutes * 60 seconds
|
||||
|
||||
const int DaysInUniformLengthCentury = 36525;
|
||||
const int SecondsPerMinute = 60;
|
||||
const int MinutesPerDegree = 60;
|
||||
|
||||
static long StartOf1810 = GetNumberOfDays(new DateTime(1810, 1, 1));
|
||||
static long StartOf1900Century = GetNumberOfDays(new DateTime(1900, 1, 1));
|
||||
|
||||
static double[] Coefficients1900to1987 = new double[] { -0.00002, 0.000297, 0.025184, -0.181133, 0.553040, -0.861938, 0.677066, -0.212591 };
|
||||
static double[] Coefficients1800to1899 = new double[] { -0.000009, 0.003844, 0.083563, 0.865736, 4.867575, 15.845535, 31.332267, 38.291999, 28.316289, 11.636204, 2.043794 };
|
||||
static double[] Coefficients1700to1799 = new double[] { 8.118780842, -0.005092142, 0.003336121, -0.0000266484 };
|
||||
static double[] Coefficients1620to1699 = new double[] { 196.58333, -4.0675, 0.0219167 };
|
||||
static double[] LambdaCoefficients = new double[] { 280.46645, 36000.76983, 0.0003032 };
|
||||
static double[] AnomalyCoefficients = new double[] { 357.52910, 35999.05030, -0.0001559, -0.00000048 };
|
||||
static double[] EccentricityCoefficients = new double[] { 0.016708617, -0.000042037, -0.0000001236 };
|
||||
static double[] Coefficients = new double[] { Angle(23, 26, 21.448), Angle(0, 0, -46.8150), Angle(0, 0, -0.00059), Angle(0, 0, 0.001813) };
|
||||
static double[] CoefficientsA = new double[] { 124.90, -1934.134, 0.002063 };
|
||||
static double[] CoefficientsB = new double[] { 201.11, 72001.5377, 0.00057 };
|
||||
|
||||
static double RadiansFromDegrees(double degree)
|
||||
{
|
||||
return degree * Math.PI / 180;
|
||||
}
|
||||
|
||||
static double SinOfDegree(double degree)
|
||||
{
|
||||
return Math.Sin(RadiansFromDegrees(degree));
|
||||
}
|
||||
|
||||
static double CosOfDegree(double degree)
|
||||
{
|
||||
return Math.Cos(RadiansFromDegrees(degree));
|
||||
}
|
||||
static double TanOfDegree(double degree)
|
||||
{
|
||||
return Math.Tan(RadiansFromDegrees(degree));
|
||||
}
|
||||
|
||||
public static double Angle(int degrees, int minutes, double seconds)
|
||||
{
|
||||
return ((seconds / SecondsPerMinute + minutes) / MinutesPerDegree) + degrees;
|
||||
}
|
||||
|
||||
static double Obliquity(double julianCenturies)
|
||||
{
|
||||
return PolynomialSum(Coefficients, julianCenturies);
|
||||
}
|
||||
|
||||
internal static long GetNumberOfDays(DateTime date)
|
||||
{
|
||||
return date.Ticks / GregorianCalendar.TicksPerDay;
|
||||
}
|
||||
|
||||
static int GetGregorianYear(double numberOfDays)
|
||||
{
|
||||
return new DateTime(Math.Min((long)(Math.Floor(numberOfDays) * GregorianCalendar.TicksPerDay), DateTime.MaxValue.Ticks)).Year;
|
||||
}
|
||||
|
||||
enum CorrectionAlgorithm
|
||||
{
|
||||
Default,
|
||||
Year1988to2019,
|
||||
Year1900to1987,
|
||||
Year1800to1899,
|
||||
Year1700to1799,
|
||||
Year1620to1699
|
||||
}
|
||||
|
||||
struct EphemerisCorrectionAlgorithmMap
|
||||
{
|
||||
public EphemerisCorrectionAlgorithmMap(int year, CorrectionAlgorithm algorithm)
|
||||
{
|
||||
_lowestYear = year;
|
||||
_algorithm = algorithm;
|
||||
}
|
||||
|
||||
internal int _lowestYear;
|
||||
internal CorrectionAlgorithm _algorithm;
|
||||
};
|
||||
|
||||
static EphemerisCorrectionAlgorithmMap[] EphemerisCorrectionTable = new EphemerisCorrectionAlgorithmMap[]
|
||||
{
|
||||
// lowest year that starts algorithm, algorithm to use
|
||||
new EphemerisCorrectionAlgorithmMap(2020, CorrectionAlgorithm.Default),
|
||||
new EphemerisCorrectionAlgorithmMap(1988, CorrectionAlgorithm.Year1988to2019),
|
||||
new EphemerisCorrectionAlgorithmMap(1900, CorrectionAlgorithm.Year1900to1987),
|
||||
new EphemerisCorrectionAlgorithmMap(1800, CorrectionAlgorithm.Year1800to1899),
|
||||
new EphemerisCorrectionAlgorithmMap(1700, CorrectionAlgorithm.Year1700to1799),
|
||||
new EphemerisCorrectionAlgorithmMap(1620, CorrectionAlgorithm.Year1620to1699),
|
||||
new EphemerisCorrectionAlgorithmMap(int.MinValue, CorrectionAlgorithm.Default) // default must be last
|
||||
};
|
||||
|
||||
static double Reminder(double divisor, double dividend)
|
||||
{
|
||||
double whole = Math.Floor(divisor / dividend);
|
||||
return divisor - (dividend * whole);
|
||||
}
|
||||
|
||||
static double NormalizeLongitude(double longitude)
|
||||
{
|
||||
longitude = Reminder(longitude, FullCircleOfArc);
|
||||
if (longitude < 0)
|
||||
{
|
||||
longitude += FullCircleOfArc;
|
||||
}
|
||||
return longitude;
|
||||
}
|
||||
|
||||
static public double AsDayFraction(double longitude)
|
||||
{
|
||||
return longitude / FullCircleOfArc;
|
||||
}
|
||||
|
||||
static double PolynomialSum(double[] coefficients, double indeterminate)
|
||||
{
|
||||
double sum = coefficients[0];
|
||||
double indeterminateRaised = 1;
|
||||
for (int i=1; i<coefficients.Length; i++)
|
||||
{
|
||||
indeterminateRaised *= indeterminate;
|
||||
sum += (coefficients[i] * indeterminateRaised);
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
static double CenturiesFrom1900(int gregorianYear)
|
||||
{
|
||||
long july1stOfYear = GetNumberOfDays(new DateTime(gregorianYear, 7, 1));
|
||||
return (double) (july1stOfYear - StartOf1900Century) / DaysInUniformLengthCentury;
|
||||
}
|
||||
|
||||
// the following formulas defines a polynomial function which gives us the amount that the earth is slowing down for specific year ranges
|
||||
static double DefaultEphemerisCorrection(int gregorianYear)
|
||||
{
|
||||
Contract.Assert(gregorianYear < 1620 || 2020 <= gregorianYear);
|
||||
long january1stOfYear = GetNumberOfDays(new DateTime(gregorianYear, 1, 1));
|
||||
double daysSinceStartOf1810 = january1stOfYear - StartOf1810;
|
||||
double x = TwelveHours + daysSinceStartOf1810;
|
||||
return ((Math.Pow(x, 2) / 41048480) - 15) / SecondsPerDay;
|
||||
}
|
||||
|
||||
static double EphemerisCorrection1988to2019(int gregorianYear)
|
||||
{
|
||||
Contract.Assert(1988 <= gregorianYear && gregorianYear <= 2019);
|
||||
return (double)(gregorianYear - 1933) / SecondsPerDay;
|
||||
}
|
||||
|
||||
static double EphemerisCorrection1900to1987(int gregorianYear)
|
||||
{
|
||||
Contract.Assert(1900 <= gregorianYear && gregorianYear <= 1987);
|
||||
double centuriesFrom1900 = CenturiesFrom1900(gregorianYear);
|
||||
return PolynomialSum(Coefficients1900to1987, centuriesFrom1900);
|
||||
}
|
||||
|
||||
static double EphemerisCorrection1800to1899(int gregorianYear)
|
||||
{
|
||||
Contract.Assert(1800 <= gregorianYear && gregorianYear <= 1899);
|
||||
double centuriesFrom1900 = CenturiesFrom1900(gregorianYear);
|
||||
return PolynomialSum(Coefficients1800to1899, centuriesFrom1900);
|
||||
}
|
||||
|
||||
static double EphemerisCorrection1700to1799(int gregorianYear)
|
||||
{
|
||||
Contract.Assert(1700 <= gregorianYear && gregorianYear <= 1799);
|
||||
double yearsSince1700 = gregorianYear - 1700;
|
||||
return PolynomialSum(Coefficients1700to1799, yearsSince1700) / SecondsPerDay;
|
||||
}
|
||||
|
||||
static double EphemerisCorrection1620to1699(int gregorianYear)
|
||||
{
|
||||
Contract.Assert(1620 <= gregorianYear && gregorianYear <= 1699);
|
||||
double yearsSince1600 = gregorianYear - 1600;
|
||||
return PolynomialSum(Coefficients1620to1699, yearsSince1600) / SecondsPerDay;
|
||||
}
|
||||
|
||||
// ephemeris-correction: correction to account for the slowing down of the rotation of the earth
|
||||
static double EphemerisCorrection(double time)
|
||||
{
|
||||
int year = GetGregorianYear(time);
|
||||
foreach (EphemerisCorrectionAlgorithmMap map in EphemerisCorrectionTable)
|
||||
{
|
||||
if (map._lowestYear <= year)
|
||||
{
|
||||
switch (map._algorithm)
|
||||
{
|
||||
case CorrectionAlgorithm.Default: return DefaultEphemerisCorrection(year);
|
||||
case CorrectionAlgorithm.Year1988to2019: return EphemerisCorrection1988to2019(year);
|
||||
case CorrectionAlgorithm.Year1900to1987: return EphemerisCorrection1900to1987(year);
|
||||
case CorrectionAlgorithm.Year1800to1899: return EphemerisCorrection1800to1899(year);
|
||||
case CorrectionAlgorithm.Year1700to1799: return EphemerisCorrection1700to1799(year);
|
||||
case CorrectionAlgorithm.Year1620to1699: return EphemerisCorrection1620to1699(year);
|
||||
}
|
||||
|
||||
break; // break the loop and assert eventually
|
||||
}
|
||||
}
|
||||
|
||||
Contract.Assert(false, "Not expected to come here");
|
||||
return DefaultEphemerisCorrection(year);
|
||||
}
|
||||
|
||||
static public double JulianCenturies(double moment)
|
||||
{
|
||||
double dynamicalMoment = moment + EphemerisCorrection(moment);
|
||||
return (dynamicalMoment - Noon2000Jan01) / DaysInUniformLengthCentury;
|
||||
}
|
||||
|
||||
static bool IsNegative(double value)
|
||||
{
|
||||
return Math.Sign(value) == -1;
|
||||
}
|
||||
|
||||
static double CopySign(double value, double sign)
|
||||
{
|
||||
return (IsNegative(value) == IsNegative(sign)) ? value : -value;
|
||||
}
|
||||
|
||||
// equation-of-time; approximate the difference between apparent solar time and mean solar time
|
||||
// formal definition is EOT = GHA - GMHA
|
||||
// GHA is the Greenwich Hour Angle of the apparent (actual) Sun
|
||||
// GMHA is the Greenwich Mean Hour Angle of the mean (fictitious) Sun
|
||||
// http://www.esrl.noaa.gov/gmd/grad/solcalc/
|
||||
// http://en.wikipedia.org/wiki/Equation_of_time
|
||||
static double EquationOfTime(double time)
|
||||
{
|
||||
double julianCenturies = JulianCenturies(time);
|
||||
double lambda = PolynomialSum(LambdaCoefficients, julianCenturies);
|
||||
double anomaly = PolynomialSum(AnomalyCoefficients, julianCenturies);
|
||||
double eccentricity = PolynomialSum(EccentricityCoefficients, julianCenturies);
|
||||
|
||||
double epsilon = Obliquity(julianCenturies);
|
||||
double tanHalfEpsilon = TanOfDegree(epsilon / 2);
|
||||
double y = tanHalfEpsilon * tanHalfEpsilon;
|
||||
|
||||
double dividend = ((y * SinOfDegree(2 * lambda))
|
||||
- (2 * eccentricity * SinOfDegree(anomaly))
|
||||
+ (4 * eccentricity * y * SinOfDegree(anomaly) * CosOfDegree(2 * lambda))
|
||||
- (0.5 * Math.Pow(y, 2) * SinOfDegree(4 * lambda))
|
||||
- (1.25 * Math.Pow(eccentricity, 2) * SinOfDegree(2 * anomaly)));
|
||||
double divisor = 2 * Math.PI;
|
||||
double equation = dividend / divisor;
|
||||
|
||||
// approximation of equation of time is not valid for dates that are many millennia in the past or future
|
||||
// thus limited to a half day
|
||||
return CopySign(Math.Min(Math.Abs(equation), TwelveHours), equation);
|
||||
}
|
||||
|
||||
static double AsLocalTime(double apparentMidday, double longitude)
|
||||
{
|
||||
// slightly inaccurate since equation of time takes mean time not apparent time as its argument, but the difference is negligible
|
||||
double universalTime = apparentMidday - AsDayFraction(longitude);
|
||||
return apparentMidday - EquationOfTime(universalTime);
|
||||
}
|
||||
|
||||
// midday
|
||||
static public double Midday(double date, double longitude)
|
||||
{
|
||||
return AsLocalTime(date+TwelveHours, longitude) - AsDayFraction(longitude);
|
||||
}
|
||||
|
||||
static double InitLongitude(double longitude)
|
||||
{
|
||||
return NormalizeLongitude(longitude + HalfCircleOfArc) - HalfCircleOfArc;
|
||||
}
|
||||
|
||||
// midday-in-tehran
|
||||
static public double MiddayAtPersianObservationSite(double date)
|
||||
{
|
||||
return Midday(date, InitLongitude(52.5)); // 52.5 degrees east - longitude of UTC+3:30 which defines Iranian Standard Time
|
||||
}
|
||||
|
||||
static double PeriodicTerm(double julianCenturies, int x, double y, double z)
|
||||
{
|
||||
return x * SinOfDegree(y + z * julianCenturies);
|
||||
}
|
||||
|
||||
static double SumLongSequenceOfPeriodicTerms(double julianCenturies)
|
||||
{
|
||||
double sum = 0.0;
|
||||
sum += PeriodicTerm(julianCenturies, 403406, 270.54861, 0.9287892);
|
||||
sum += PeriodicTerm(julianCenturies, 195207, 340.19128, 35999.1376958);
|
||||
sum += PeriodicTerm(julianCenturies, 119433, 63.91854, 35999.4089666);
|
||||
sum += PeriodicTerm(julianCenturies, 112392, 331.2622, 35998.7287385);
|
||||
sum += PeriodicTerm(julianCenturies, 3891, 317.843, 71998.20261);
|
||||
sum += PeriodicTerm(julianCenturies, 2819, 86.631, 71998.4403);
|
||||
sum += PeriodicTerm(julianCenturies, 1721, 240.052, 36000.35726);
|
||||
sum += PeriodicTerm(julianCenturies, 660, 310.26, 71997.4812);
|
||||
sum += PeriodicTerm(julianCenturies, 350, 247.23, 32964.4678);
|
||||
sum += PeriodicTerm(julianCenturies, 334, 260.87, -19.441);
|
||||
sum += PeriodicTerm(julianCenturies, 314, 297.82, 445267.1117);
|
||||
sum += PeriodicTerm(julianCenturies, 268, 343.14, 45036.884);
|
||||
sum += PeriodicTerm(julianCenturies, 242, 166.79, 3.1008);
|
||||
sum += PeriodicTerm(julianCenturies, 234, 81.53, 22518.4434);
|
||||
sum += PeriodicTerm(julianCenturies, 158, 3.5, -19.9739);
|
||||
sum += PeriodicTerm(julianCenturies, 132, 132.75, 65928.9345);
|
||||
sum += PeriodicTerm(julianCenturies, 129, 182.95, 9038.0293);
|
||||
sum += PeriodicTerm(julianCenturies, 114, 162.03, 3034.7684);
|
||||
sum += PeriodicTerm(julianCenturies, 99, 29.8, 33718.148);
|
||||
sum += PeriodicTerm(julianCenturies, 93, 266.4, 3034.448);
|
||||
sum += PeriodicTerm(julianCenturies, 86, 249.2, -2280.773);
|
||||
sum += PeriodicTerm(julianCenturies, 78, 157.6, 29929.992);
|
||||
sum += PeriodicTerm(julianCenturies, 72, 257.8, 31556.493);
|
||||
sum += PeriodicTerm(julianCenturies, 68, 185.1, 149.588);
|
||||
sum += PeriodicTerm(julianCenturies, 64, 69.9, 9037.75);
|
||||
sum += PeriodicTerm(julianCenturies, 46, 8.0, 107997.405);
|
||||
sum += PeriodicTerm(julianCenturies, 38, 197.1, -4444.176);
|
||||
sum += PeriodicTerm(julianCenturies, 37, 250.4, 151.771);
|
||||
sum += PeriodicTerm(julianCenturies, 32, 65.3, 67555.316);
|
||||
sum += PeriodicTerm(julianCenturies, 29, 162.7, 31556.08);
|
||||
sum += PeriodicTerm(julianCenturies, 28, 341.5, -4561.54);
|
||||
sum += PeriodicTerm(julianCenturies, 27, 291.6, 107996.706);
|
||||
sum += PeriodicTerm(julianCenturies, 27, 98.5, 1221.655);
|
||||
sum += PeriodicTerm(julianCenturies, 25, 146.7, 62894.167);
|
||||
sum += PeriodicTerm(julianCenturies, 24, 110.0, 31437.369);
|
||||
sum += PeriodicTerm(julianCenturies, 21, 5.2, 14578.298);
|
||||
sum += PeriodicTerm(julianCenturies, 21, 342.6, -31931.757);
|
||||
sum += PeriodicTerm(julianCenturies, 20, 230.9, 34777.243);
|
||||
sum += PeriodicTerm(julianCenturies, 18, 256.1, 1221.999);
|
||||
sum += PeriodicTerm(julianCenturies, 17, 45.3, 62894.511);
|
||||
sum += PeriodicTerm(julianCenturies, 14, 242.9, -4442.039);
|
||||
sum += PeriodicTerm(julianCenturies, 13, 115.2, 107997.909);
|
||||
sum += PeriodicTerm(julianCenturies, 13, 151.8, 119.066);
|
||||
sum += PeriodicTerm(julianCenturies, 13, 285.3, 16859.071);
|
||||
sum += PeriodicTerm(julianCenturies, 12, 53.3, -4.578);
|
||||
sum += PeriodicTerm(julianCenturies, 10, 126.6, 26895.292);
|
||||
sum += PeriodicTerm(julianCenturies, 10, 205.7, -39.127);
|
||||
sum += PeriodicTerm(julianCenturies, 10, 85.9, 12297.536);
|
||||
sum += PeriodicTerm(julianCenturies, 10, 146.1, 90073.778);
|
||||
return sum;
|
||||
}
|
||||
|
||||
static double Aberration(double julianCenturies)
|
||||
{
|
||||
return (0.0000974 * CosOfDegree(177.63 + (35999.01848 * julianCenturies))) - 0.005575;
|
||||
}
|
||||
|
||||
static double Nutation(double julianCenturies)
|
||||
{
|
||||
double a = PolynomialSum(CoefficientsA, julianCenturies);
|
||||
double b = PolynomialSum(CoefficientsB, julianCenturies);
|
||||
return (-0.004778 * SinOfDegree(a)) - (0.0003667 * SinOfDegree(b));
|
||||
}
|
||||
|
||||
static public double Compute(double time)
|
||||
{
|
||||
double julianCenturies = JulianCenturies(time);
|
||||
double lambda = 282.7771834
|
||||
+ (36000.76953744 * julianCenturies)
|
||||
+ (0.000005729577951308232 * SumLongSequenceOfPeriodicTerms(julianCenturies));
|
||||
|
||||
double longitude = lambda + Aberration(julianCenturies) + Nutation(julianCenturies);
|
||||
return InitLongitude(longitude);
|
||||
}
|
||||
|
||||
static public double AsSeason(double longitude)
|
||||
{
|
||||
return (longitude < 0) ? (longitude + FullCircleOfArc) : longitude;
|
||||
}
|
||||
|
||||
static double EstimatePrior(double longitude, double time)
|
||||
{
|
||||
double timeSunLastAtLongitude = time - (MeanSpeedOfSun * AsSeason(InitLongitude(Compute(time) - longitude)));
|
||||
double longitudeErrorDelta = InitLongitude(Compute(timeSunLastAtLongitude) - longitude);
|
||||
return Math.Min(time, timeSunLastAtLongitude - (MeanSpeedOfSun * longitudeErrorDelta));
|
||||
}
|
||||
|
||||
// persian-new-year-on-or-before
|
||||
// number of days is the absolute date. The absolute date is the number of days from January 1st, 1 A.D.
|
||||
// 1/1/0001 is absolute date 1.
|
||||
internal static long PersianNewYearOnOrBefore(long numberOfDays)
|
||||
{
|
||||
double date = (double) numberOfDays;
|
||||
|
||||
double approx = EstimatePrior(LongitudeSpring, MiddayAtPersianObservationSite(date));
|
||||
long lowerBoundNewYearDay = (long) Math.Floor(approx) - 1;
|
||||
long upperBoundNewYearDay = lowerBoundNewYearDay + 3; // estimate is generally within a day of the actual occurrance (at the limits, the error expands, since the calculations rely on the mean tropical year which changes...)
|
||||
long day = lowerBoundNewYearDay;
|
||||
for (; day != upperBoundNewYearDay; ++day)
|
||||
{
|
||||
double midday = MiddayAtPersianObservationSite((double) day);
|
||||
double l = Compute(midday);
|
||||
if ((LongitudeSpring <= l) && (l <= TwoDegreesAfterSpring))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
Contract.Assert(day != upperBoundNewYearDay);
|
||||
|
||||
return day - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,12 +12,16 @@ namespace System.Globalization {
|
||||
// Notes about PersianCalendar
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
// Modern Persian calendar is a solar observation based calendar. Each new year begins on the day when the vernal equinox occurs before noon.
|
||||
// The epoch is the date of the vernal equinox prior to the epoch of the Islamic calendar ([....] 19, 622 Julian or [....] 22, 622 Gregorian)
|
||||
|
||||
// There is no Persian year 0. Ordinary years have 365 days. Leap years have 366 days with the last month (Esfand) gaining the extra day.
|
||||
/*
|
||||
** Calendar support range:
|
||||
** Calendar Minimum Maximum
|
||||
** ========== ========== ==========
|
||||
** Gregorian 0622/03/21 9999/12/31
|
||||
** Persian 0001/01/01 9378/10/10
|
||||
** Gregorian 0622/03/22 9999/12/31
|
||||
** Persian 0001/01/01 9378/10/13
|
||||
*/
|
||||
|
||||
[Serializable]
|
||||
@@ -26,35 +30,24 @@ namespace System.Globalization {
|
||||
|
||||
public static readonly int PersianEra = 1;
|
||||
|
||||
internal const int DateCycle = 33;
|
||||
internal static long PersianEpoch = new DateTime(622, 3, 22).Ticks / GregorianCalendar.TicksPerDay;
|
||||
const int ApproximateHalfYear = 180;
|
||||
|
||||
internal const int DatePartYear = 0;
|
||||
internal const int DatePartDayOfYear = 1;
|
||||
internal const int DatePartMonth = 2;
|
||||
internal const int DatePartDay = 3;
|
||||
internal const int MonthsPerYear = 12;
|
||||
|
||||
internal static int[] DaysToMonth = {0,31,62,93,124,155,186,216,246,276,306,336};
|
||||
//Leap years, if Y%33 is 1,5,9,13,17,22,26,30
|
||||
internal static int[] LeapYears33 = {0,1,0,0,0, // 0 [1] 2 3 4
|
||||
1,0,0,0,1, // [5] 6 7 8 [9]
|
||||
0,0,0,1,0, // 10 11 12 [13] 14
|
||||
0,0,1,0,0, // 15 16 [17] 18 19
|
||||
0,0,1,0,0, // 20 21 [22] 23 24
|
||||
0,1,0,0,0, // 25 [26] 27 28 29
|
||||
1,0,0}; //[30] 31 32
|
||||
internal static int[] DaysToMonth = { 0, 31, 62, 93, 124, 155, 186, 216, 246, 276, 306, 336, 366 };
|
||||
|
||||
internal const int LeapYearsPerCycle = 8;
|
||||
internal const long GregorianOffset = 226894; //GregorianCalendar.GetAbsoluteDate(622, 3, 21);
|
||||
internal const long DaysPerCycle = DateCycle * 365 + LeapYearsPerCycle;
|
||||
|
||||
//internal static Calendar m_defaultInstance;
|
||||
|
||||
// DateTime.MaxValue = Persian calendar (year:9378, month: 10, day: 10).
|
||||
internal const int MaxCalendarYear = 9378;
|
||||
internal const int MaxCalendarMonth = 10;
|
||||
internal const int MaxCalendarDay = 10;
|
||||
// Persian calendar (year: 1, month: 1, day:1 ) = Gregorian (year: 622, month: 3, day: 21)
|
||||
internal const int MaxCalendarDay = 13;
|
||||
|
||||
// Persian calendar (year: 1, month: 1, day:1 ) = Gregorian (year: 622, month: 3, day: 22)
|
||||
// This is the minimal Gregorian date that we support in the PersianCalendar.
|
||||
internal static DateTime minDate = new DateTime(622, 3, 21);
|
||||
internal static DateTime minDate = new DateTime(622, 3, 22);
|
||||
internal static DateTime maxDate = DateTime.MaxValue;
|
||||
|
||||
/*=================================GetDefaultInstance==========================
|
||||
@@ -120,6 +113,7 @@ namespace System.Globalization {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*=================================GetAbsoluteDatePersian==========================
|
||||
**Action: Gets the Absolute date for the given Persian date. The absolute date means
|
||||
** the number of days from January 1st, 1 A.D.
|
||||
@@ -131,57 +125,15 @@ namespace System.Globalization {
|
||||
long GetAbsoluteDatePersian(int year, int month, int day) {
|
||||
if (year >= 1 && year <= MaxCalendarYear && month >= 1 && month <= 12)
|
||||
{
|
||||
return DaysUpToPersianYear(year) + DaysToMonth[month-1] + day - 1;
|
||||
int ordinalDay = DaysInPreviousMonths(month) + day - 1; // day is one based, make 0 based since this will be the number of days we add to beginning of year below
|
||||
int approximateDaysFromEpochForYearStart = (int)(CalendricalCalculationsHelper.MeanTropicalYearInDays * (year - 1));
|
||||
long yearStart = CalendricalCalculationsHelper.PersianNewYearOnOrBefore(PersianEpoch + approximateDaysFromEpochForYearStart + ApproximateHalfYear);
|
||||
yearStart += ordinalDay;
|
||||
return yearStart;
|
||||
}
|
||||
throw new ArgumentOutOfRangeException(null, Environment.GetResourceString("ArgumentOutOfRange_BadYearMonthDay"));
|
||||
}
|
||||
|
||||
/*=================================DaysUpToPersianYear==========================
|
||||
**Action: Gets the total number of days (absolute date) up to the given Persian Year.
|
||||
** The absolute date means the number of days from January 1st, 1 A.D.
|
||||
**Returns: Gets the total number of days (absolute date) up to the given Persian Year.
|
||||
**Arguments: PersianYear year value in Persian calendar.
|
||||
**Exceptions: None
|
||||
**Notes:
|
||||
============================================================================*/
|
||||
|
||||
long DaysUpToPersianYear(int PersianYear) {
|
||||
|
||||
long NumDays; // number of absolute days
|
||||
int NumCycles; // number of 33 year cycles
|
||||
int NumYearsLeft; // number of years into 33 year cycle
|
||||
|
||||
//
|
||||
// Compute the number of 33 years cycles.
|
||||
//
|
||||
NumCycles = (PersianYear - 1) / DateCycle;
|
||||
|
||||
//
|
||||
// Compute the number of years left. This is the number of years
|
||||
// into the 33 year cycle for the given year.
|
||||
//
|
||||
NumYearsLeft = (PersianYear-1) % DateCycle;
|
||||
|
||||
//
|
||||
// Compute the number of absolute days up to the given year.
|
||||
//
|
||||
NumDays = NumCycles * DaysPerCycle + GregorianOffset;
|
||||
while (NumYearsLeft > 0) {
|
||||
NumDays += 365;
|
||||
// Common year is 365 days, and leap year is 366 days.
|
||||
if(IsLeapYear(NumYearsLeft, CurrentEra)) {
|
||||
NumDays++;
|
||||
}
|
||||
NumYearsLeft--;
|
||||
}
|
||||
|
||||
//
|
||||
// Return the number of absolute days.
|
||||
//
|
||||
return (NumDays);
|
||||
}
|
||||
|
||||
|
||||
static internal void CheckTicksRange(long ticks) {
|
||||
if (ticks < minDate.Ticks || ticks > maxDate.Ticks) {
|
||||
throw new ArgumentOutOfRangeException(
|
||||
@@ -232,23 +184,32 @@ namespace System.Globalization {
|
||||
}
|
||||
}
|
||||
|
||||
static int MonthFromOrdinalDay(int ordinalDay)
|
||||
{
|
||||
Contract.Assert(ordinalDay <= 366);
|
||||
int index = 0;
|
||||
while (ordinalDay > DaysToMonth[index])
|
||||
index++;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static int DaysInPreviousMonths(int month)
|
||||
{
|
||||
Contract.Assert(1 <= month && month <= 12);
|
||||
--month; // months are one based but for calculations use 0 based
|
||||
return DaysToMonth[month];
|
||||
}
|
||||
|
||||
/*=================================GetDatePart==========================
|
||||
**Action: Returns a given date part of this <i>DateTime</i>. This method is used
|
||||
** to compute the year, day-of-year, month, or day part.
|
||||
**Returns:
|
||||
**Arguments:
|
||||
**Exceptions: ArgumentException if part is incorrect.
|
||||
**Notes:
|
||||
** First, we get the absolute date (the number of days from January 1st, 1 A.C) for the given ticks.
|
||||
** Use the formula (((AbsoluteDate - 226894) * 33) / (33 * 365 + 8)) + 1, we can a rough value for the Persian year.
|
||||
** In order to get the exact Persian year, we compare the exact absolute date for PersianYear and (PersianYear + 1).
|
||||
** From here, we can get the correct Persian year.
|
||||
============================================================================*/
|
||||
|
||||
internal int GetDatePart(long ticks, int part) {
|
||||
int PersianYear; // Persian year
|
||||
int PersianMonth; // Persian month
|
||||
int PersianDay; // Persian day
|
||||
long NumDays; // The calculation buffer in number of days.
|
||||
|
||||
CheckTicksRange(ticks);
|
||||
@@ -259,59 +220,51 @@ namespace System.Globalization {
|
||||
//
|
||||
NumDays = ticks / GregorianCalendar.TicksPerDay + 1;
|
||||
|
||||
|
||||
//
|
||||
// Calculate the appromixate Persian Year from this magic formula.
|
||||
// Calculate the appromixate Persian Year.
|
||||
//
|
||||
PersianYear = (int)(((NumDays - GregorianOffset) * DateCycle) / DaysPerCycle) + 1;
|
||||
|
||||
long daysToPersianYear = DaysUpToPersianYear(PersianYear); // The absoulte date for PersianYear
|
||||
long daysOfPersianYear = GetDaysInYear(PersianYear, CurrentEra); // The number of days for (PersianYear+1) year.
|
||||
long yearStart = CalendricalCalculationsHelper.PersianNewYearOnOrBefore(NumDays);
|
||||
int y = (int)(Math.Floor(((yearStart - PersianEpoch) / CalendricalCalculationsHelper.MeanTropicalYearInDays) + 0.5)) + 1;
|
||||
Contract.Assert(y >= 1);
|
||||
|
||||
if (NumDays < daysToPersianYear) {
|
||||
daysToPersianYear -= daysOfPersianYear;
|
||||
PersianYear--;
|
||||
} else if (NumDays == daysToPersianYear) {
|
||||
PersianYear--;
|
||||
daysToPersianYear -= GetDaysInYear(PersianYear, CurrentEra);
|
||||
} else {
|
||||
if (NumDays > daysToPersianYear + daysOfPersianYear) {
|
||||
daysToPersianYear += daysOfPersianYear;
|
||||
PersianYear++;
|
||||
}
|
||||
}
|
||||
if (part == DatePartYear) {
|
||||
return (PersianYear);
|
||||
if (part == DatePartYear)
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate the Persian Month.
|
||||
//
|
||||
|
||||
NumDays -= daysToPersianYear;
|
||||
int ordinalDay = (int)(NumDays - CalendricalCalculationsHelper.GetNumberOfDays(this.ToDateTime(y, 1, 1, 0, 0, 0, 0, 1)));
|
||||
|
||||
if (part == DatePartDayOfYear) {
|
||||
return ((int)NumDays);
|
||||
}
|
||||
|
||||
PersianMonth = 0;
|
||||
while ((PersianMonth < 12) && (NumDays > DaysToMonth[PersianMonth]))
|
||||
if (part == DatePartDayOfYear)
|
||||
{
|
||||
PersianMonth++;
|
||||
return ordinalDay;
|
||||
}
|
||||
|
||||
if (part == DatePartMonth) {
|
||||
return (PersianMonth);
|
||||
int m = MonthFromOrdinalDay(ordinalDay);
|
||||
Contract.Assert(ordinalDay >= 1);
|
||||
Contract.Assert(m >= 1 && m <= 12);
|
||||
if (part == DatePartMonth)
|
||||
{
|
||||
return m;
|
||||
}
|
||||
|
||||
int d = ordinalDay - DaysInPreviousMonths(m);
|
||||
Contract.Assert(1 <= d);
|
||||
Contract.Assert(d <= 31);
|
||||
|
||||
//
|
||||
// Calculate the Persian Day.
|
||||
//
|
||||
PersianDay = (int)(NumDays - DaysToMonth[PersianMonth-1]);
|
||||
|
||||
if (part == DatePartDay) {
|
||||
return (PersianDay);
|
||||
if (part == DatePartDay)
|
||||
{
|
||||
return (d);
|
||||
}
|
||||
|
||||
// Incorrect part value.
|
||||
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_DateTimeParsing"));
|
||||
}
|
||||
@@ -422,18 +375,18 @@ namespace System.Globalization {
|
||||
return MaxCalendarDay;
|
||||
}
|
||||
|
||||
if (month == 12) {
|
||||
// For the 12th month, leap year has 30 days, and common year has 29 days.
|
||||
return (IsLeapYear(year, CurrentEra) ? 30 : 29);
|
||||
int daysInMonth = DaysToMonth[month] - DaysToMonth[month - 1];
|
||||
if ((month == MonthsPerYear) && !IsLeapYear(year))
|
||||
{
|
||||
Contract.Assert(daysInMonth == 30);
|
||||
--daysInMonth;
|
||||
}
|
||||
// Other months first 6 months are 31 and the reset are 30 days.
|
||||
return ((month > 6) ? 30 : 31);
|
||||
return daysInMonth;
|
||||
}
|
||||
|
||||
// Returns the number of days in the year given by the year argument for the current era.
|
||||
//
|
||||
|
||||
|
||||
public override int GetDaysInYear(int year, int era) {
|
||||
CheckYearRange(year, era);
|
||||
if (year==MaxCalendarYear) {
|
||||
@@ -533,10 +486,15 @@ namespace System.Globalization {
|
||||
// year is a leap year, or false if not.
|
||||
//
|
||||
|
||||
|
||||
public override bool IsLeapYear(int year, int era) {
|
||||
CheckYearRange(year, era);
|
||||
return (LeapYears33[year%DateCycle]==1);
|
||||
|
||||
if (year == MaxCalendarYear)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (GetAbsoluteDatePersian(year + 1, 1, 1) - GetAbsoluteDatePersian(year, 1, 1)) == 366;
|
||||
}
|
||||
|
||||
// Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
|
||||
@@ -568,8 +526,6 @@ namespace System.Globalization {
|
||||
|
||||
private const int DEFAULT_TWO_DIGIT_YEAR_MAX = 1410;
|
||||
|
||||
|
||||
|
||||
public override int TwoDigitYearMax {
|
||||
get {
|
||||
if (twoDigitYearMax == -1) {
|
||||
|
||||
@@ -33,5 +33,9 @@ namespace System.Globalization {
|
||||
SegmentSeparator = 16,
|
||||
Whitespace = 17,
|
||||
OtherNeutrals = 18,
|
||||
LeftToRightIsolate = 19,
|
||||
RightToLeftIsolate = 20,
|
||||
FirstStrongIsolate = 21,
|
||||
PopDirectionIsolate = 22,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,6 +270,14 @@ namespace System.Globalization
|
||||
case CalendarId.JAPANESELUNISOLAR:
|
||||
this.saEraNames = JapaneseCalendar.EraNames();
|
||||
break;
|
||||
|
||||
case CalendarId.PERSIAN:
|
||||
if (this.saEraNames == null || this.saEraNames.Length == 0 || String.IsNullOrEmpty(this.saEraNames[0]))
|
||||
{
|
||||
this.saEraNames = new String[] { "\x0647\x002e\x0634" };
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Most calendars are just "A.D."
|
||||
this.saEraNames = Invariant.saEraNames;
|
||||
@@ -324,6 +332,14 @@ namespace System.Globalization
|
||||
this.saAbbrevEraNames[0] = this.saEraNames[0];
|
||||
}
|
||||
break;
|
||||
|
||||
case CalendarId.PERSIAN:
|
||||
if (this.saAbbrevEraNames == null || this.saAbbrevEraNames.Length == 0 || String.IsNullOrEmpty(this.saAbbrevEraNames[0]))
|
||||
{
|
||||
this.saAbbrevEraNames = this.saEraNames;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Most calendars just use the full name
|
||||
this.saAbbrevEraNames = this.saEraNames;
|
||||
|
||||
@@ -157,6 +157,22 @@ namespace System.Globalization {
|
||||
return(value);
|
||||
}
|
||||
|
||||
unsafe private static double EndianSwap(double value)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian) {
|
||||
byte *ptr = (byte *) &value;
|
||||
double res;
|
||||
byte *buf = (byte *) &res;
|
||||
ushort t = sizeof(double) - 1;
|
||||
|
||||
for (ushort i = 0; i < sizeof(double); i++)
|
||||
buf[t-i] = ptr[i];
|
||||
|
||||
return(res);
|
||||
} else
|
||||
return(value);
|
||||
}
|
||||
|
||||
|
||||
//We need to allocate the underlying table that provides us with the information that we
|
||||
//use. We allocate this once in the class initializer and then we don't need to worry
|
||||
@@ -322,7 +338,7 @@ namespace System.Globalization {
|
||||
}
|
||||
return (((double*)s_pNumericValues)[pBytePtr[(ch & 0x000f)]]);
|
||||
#else
|
||||
return (((double*)s_pNumericValues)[pBytePtr[(ch & 0x000f)]]);
|
||||
return EndianSwap(((double*)s_pNumericValues)[pBytePtr[(ch & 0x000f)]]);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ namespace System.Globalization {
|
||||
this.m_name = culture.m_name;
|
||||
this.m_sortName = culture.SortName;
|
||||
|
||||
#if !FEATURE_CORECLR && !MONO
|
||||
#if !MONO
|
||||
IntPtr handleOrigin;
|
||||
this.m_dataHandle = InternalInitSortHandle(m_sortName, out handleOrigin);
|
||||
this.m_handleOrigin = handleOrigin;
|
||||
@@ -283,7 +283,7 @@ namespace System.Globalization {
|
||||
ci = CultureInfo.GetCultureInfo(m_name);
|
||||
}
|
||||
this.m_sortName = ci.SortName;
|
||||
#if !FEATURE_CORECLR && !MONO
|
||||
#if !MONO
|
||||
IntPtr handleOrigin;
|
||||
this.m_dataHandle = InternalInitSortHandle(m_sortName, out handleOrigin);
|
||||
this.m_handleOrigin = handleOrigin;
|
||||
@@ -1228,6 +1228,35 @@ namespace System.Globalization {
|
||||
return (this.Name.GetHashCode());
|
||||
}
|
||||
|
||||
//
|
||||
// return hash value for the string according to the input CompareOptions
|
||||
//
|
||||
|
||||
public virtual int GetHashCode(string source, CompareOptions options)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException("source");
|
||||
}
|
||||
|
||||
if (options == CompareOptions.Ordinal)
|
||||
{
|
||||
return source.GetHashCode();
|
||||
}
|
||||
|
||||
if (options == CompareOptions.OrdinalIgnoreCase)
|
||||
{
|
||||
return TextInfo.GetHashCodeOrdinalIgnoreCase(source);
|
||||
}
|
||||
|
||||
//
|
||||
// GetHashCodeOfString does more parameters validation. basically will throw when
|
||||
// having Ordinal, OrdinalIgnoreCase and StringSort
|
||||
//
|
||||
|
||||
return GetHashCodeOfString(source, options, false, 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// GetHashCodeOfString
|
||||
@@ -1313,13 +1342,14 @@ namespace System.Globalization {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !FEATURE_CORECLR && !MONO
|
||||
#if !MONO
|
||||
[System.Security.SecuritySafeCritical]
|
||||
internal static IntPtr InternalInitSortHandle(String localeName, out IntPtr handleOrigin)
|
||||
{
|
||||
return NativeInternalInitSortHandle(localeName, out handleOrigin);
|
||||
}
|
||||
|
||||
#if !FEATURE_CORECLR
|
||||
private const int SORT_VERSION_WHIDBEY = 0x00001000;
|
||||
private const int SORT_VERSION_V4 = 0x00060101;
|
||||
|
||||
@@ -1373,13 +1403,13 @@ namespace System.Globalization {
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
private static extern uint InternalGetSortVersion();
|
||||
|
||||
#endif
|
||||
[System.Security.SecurityCritical]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
private static extern IntPtr NativeInternalInitSortHandle(String localeName, out IntPtr handleOrigin);
|
||||
#endif
|
||||
#if !MONO
|
||||
|
||||
// Get a locale sensitive sort hash code from native code -- COMNlsInfo::InternalGetGlobalizedHashCode
|
||||
[System.Security.SecurityCritical] // auto-generated
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
|
||||
@@ -1 +1 @@
|
||||
e47323b947c0dc56d8a2cb9929c5a7bcf274ffff
|
||||
b128980d0536918623b94ff41d56db064e5cc04b
|
||||
@@ -155,7 +155,7 @@ namespace System.Globalization {
|
||||
private static volatile Hashtable s_LcidCachedCultures;
|
||||
private static volatile Hashtable s_NameCachedCultures;
|
||||
|
||||
#if !FEATURE_CORECLR
|
||||
#if FEATURE_APPX
|
||||
// When running under AppX, we use this to get some information about the language list
|
||||
[SecurityCritical]
|
||||
private static volatile WindowsRuntimeResourceManagerBase s_WindowsRuntimeResourceManager;
|
||||
@@ -245,7 +245,7 @@ namespace System.Globalization {
|
||||
return (temp);
|
||||
}
|
||||
|
||||
#if !FEATURE_CORECLR
|
||||
#if FEATURE_APPX
|
||||
[SecuritySafeCritical]
|
||||
internal static CultureInfo GetCultureInfoForUserPreferredLanguageInAppX()
|
||||
{
|
||||
@@ -291,6 +291,28 @@ namespace System.Globalization {
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
internal static bool SetCultureInfoForUserPreferredLanguageInAppX(CultureInfo ci)
|
||||
{
|
||||
// If running within a compilation process (mscorsvw.exe, for example), it is illegal to
|
||||
// load any non-mscorlib assembly for execution. Since WindowsRuntimeResourceManager lives
|
||||
// in System.Runtime.WindowsRuntime, caller will need to fall back to default Win32 value,
|
||||
// which should be fine because we should only ever need to access FX resources during NGEN.
|
||||
// FX resources are always loaded from satellite assemblies - even in AppX processes (see the
|
||||
// comments in code:System.Resources.ResourceManager.SetAppXConfiguration for more details).
|
||||
if (AppDomain.IsAppXNGen)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s_WindowsRuntimeResourceManager == null)
|
||||
{
|
||||
s_WindowsRuntimeResourceManager = ResourceManager.GetWinRTResourceManager();
|
||||
}
|
||||
|
||||
return s_WindowsRuntimeResourceManager.SetGlobalResourceContextDefaultCulture(ci);
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -300,9 +322,6 @@ namespace System.Globalization {
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#if !FEATURE_CORECLR
|
||||
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
||||
#endif
|
||||
public CultureInfo(String name) : this(name, true) {
|
||||
}
|
||||
|
||||
@@ -673,12 +692,49 @@ namespace System.Globalization {
|
||||
|
||||
public static CultureInfo CurrentCulture
|
||||
{
|
||||
#if !FEATURE_CORECLR
|
||||
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
||||
#endif
|
||||
get {
|
||||
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
||||
|
||||
#if !FEATURE_CORECLR
|
||||
return Thread.CurrentThread.CurrentCulture;
|
||||
#else
|
||||
// In the case of CoreCLR, Thread.m_CurrentCulture and
|
||||
// Thread.m_CurrentUICulture are thread static so as not to let
|
||||
// CultureInfo objects leak across AppDomain boundaries. The
|
||||
// fact that these fields are thread static introduces overhead
|
||||
// in accessing them (through Thread.CurrentCulture). There is
|
||||
// also overhead in accessing Thread.CurrentThread. In this
|
||||
// case, we can avoid the overhead of Thread.CurrentThread
|
||||
// because these fields are thread static, and so do not
|
||||
// require a Thread instance to be accessed.
|
||||
#if FEATURE_APPX
|
||||
if(AppDomain.IsAppXModel()) {
|
||||
CultureInfo culture = GetCultureInfoForUserPreferredLanguageInAppX();
|
||||
if (culture != null)
|
||||
return culture;
|
||||
}
|
||||
#endif
|
||||
return Thread.m_CurrentCulture ??
|
||||
s_DefaultThreadCurrentCulture ??
|
||||
s_userDefaultCulture ??
|
||||
UserDefaultCulture;
|
||||
#endif
|
||||
}
|
||||
|
||||
set {
|
||||
#if FEATURE_APPX
|
||||
if (value == null) {
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
|
||||
if (AppDomain.IsAppXModel()) {
|
||||
if (SetCultureInfoForUserPreferredLanguageInAppX(value)) {
|
||||
// successfully set the culture, otherwise fallback to legacy path
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Thread.CurrentThread.CurrentCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -734,12 +790,49 @@ namespace System.Globalization {
|
||||
|
||||
|
||||
public static CultureInfo CurrentUICulture {
|
||||
#if !FEATURE_CORECLR
|
||||
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
||||
#endif
|
||||
get {
|
||||
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
||||
|
||||
#if !FEATURE_CORECLR
|
||||
return Thread.CurrentThread.CurrentUICulture;
|
||||
#else
|
||||
// In the case of CoreCLR, Thread.m_CurrentCulture and
|
||||
// Thread.m_CurrentUICulture are thread static so as not to let
|
||||
// CultureInfo objects leak across AppDomain boundaries. The
|
||||
// fact that these fields are thread static introduces overhead
|
||||
// in accessing them (through Thread.CurrentCulture). There is
|
||||
// also overhead in accessing Thread.CurrentThread. In this
|
||||
// case, we can avoid the overhead of Thread.CurrentThread
|
||||
// because these fields are thread static, and so do not
|
||||
// require a Thread instance to be accessed.
|
||||
#if FEATURE_APPX
|
||||
if(AppDomain.IsAppXModel()) {
|
||||
CultureInfo culture = GetCultureInfoForUserPreferredLanguageInAppX();
|
||||
if (culture != null)
|
||||
return culture;
|
||||
}
|
||||
#endif
|
||||
return Thread.m_CurrentUICulture ??
|
||||
s_DefaultThreadCurrentUICulture ??
|
||||
s_userDefaultUICulture ??
|
||||
UserDefaultUICulture;
|
||||
#endif
|
||||
}
|
||||
|
||||
set {
|
||||
#if FEATURE_APPX
|
||||
if (value == null) {
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
|
||||
if (AppDomain.IsAppXModel()) {
|
||||
if (SetCultureInfoForUserPreferredLanguageInAppX(value)) {
|
||||
// successfully set the culture, otherwise fallback to legacy path
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Thread.CurrentThread.CurrentUICulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -844,9 +937,6 @@ namespace System.Globalization {
|
||||
|
||||
public static CultureInfo InvariantCulture {
|
||||
[Pure]
|
||||
#if !FEATURE_CORECLR
|
||||
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
||||
#endif
|
||||
get {
|
||||
Contract.Ensures(Contract.Result<CultureInfo>() != null);
|
||||
return (s_InvariantCultureInfo);
|
||||
@@ -907,9 +997,6 @@ namespace System.Globalization {
|
||||
|
||||
#if FEATURE_USE_LCID
|
||||
public virtual int LCID {
|
||||
#if !FEATURE_CORECLR
|
||||
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
||||
#endif
|
||||
get {
|
||||
return (this.m_cultureData.ILANGUAGE);
|
||||
}
|
||||
@@ -1231,9 +1318,6 @@ namespace System.Globalization {
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !FEATURE_CORECLR
|
||||
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
||||
#endif
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (this.Name.GetHashCode() + this.CompareInfo.GetHashCode());
|
||||
@@ -1421,7 +1505,6 @@ namespace System.Globalization {
|
||||
return (new HebrewCalendar());
|
||||
case Calendar.CAL_UMALQURA:
|
||||
return (new UmAlQuraCalendar());
|
||||
#if !FEATURE_ONLY_CORE_CALENDARS
|
||||
case Calendar.CAL_PERSIAN:
|
||||
return (new PersianCalendar());
|
||||
case Calendar.CAL_CHINESELUNISOLAR:
|
||||
@@ -1432,7 +1515,6 @@ namespace System.Globalization {
|
||||
return (new KoreanLunisolarCalendar());
|
||||
case Calendar.CAL_TAIWANLUNISOLAR:
|
||||
return (new TaiwanLunisolarCalendar());
|
||||
#endif // !FEATURE_ONLY_CORE_CALENDARS
|
||||
}
|
||||
return (new GregorianCalendar());
|
||||
}
|
||||
|
||||
@@ -931,6 +931,7 @@ namespace System {
|
||||
case Calendar.CAL_HEBREW:
|
||||
case Calendar.CAL_JULIAN:
|
||||
case Calendar.CAL_UMALQURA:
|
||||
case Calendar.CAL_PERSIAN:
|
||||
timeOnlySpecialCase = true;
|
||||
dtfi = DateTimeFormatInfo.InvariantInfo;
|
||||
break;
|
||||
|
||||
@@ -1 +1 @@
|
||||
3db9a4bafdb7398647430f25ef9f145d369259ca
|
||||
da422367d637dc6a26c15d3e0a8941355ac41088
|
||||
@@ -86,10 +86,8 @@ namespace System.Globalization {
|
||||
// init.
|
||||
static internal volatile EraInfo[] japaneseEraInfo;
|
||||
|
||||
#if !__APPLE__
|
||||
private const string c_japaneseErasHive = @"System\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras";
|
||||
private const string c_japaneseErasHivePermissionList = @"HKEY_LOCAL_MACHINE\" + c_japaneseErasHive;
|
||||
#endif
|
||||
|
||||
//
|
||||
// Read our era info
|
||||
@@ -119,11 +117,9 @@ namespace System.Globalization {
|
||||
// See if we need to build it
|
||||
if (japaneseEraInfo == null)
|
||||
{
|
||||
#if !__APPLE__
|
||||
|
||||
// See if we have any eras from the registry
|
||||
japaneseEraInfo = GetErasFromRegistry();
|
||||
#endif
|
||||
|
||||
// See if we have to use the built-in eras
|
||||
if (japaneseEraInfo == null)
|
||||
{
|
||||
@@ -147,7 +143,6 @@ namespace System.Globalization {
|
||||
return japaneseEraInfo;
|
||||
}
|
||||
|
||||
#if !__APPLE__
|
||||
//
|
||||
// GetErasFromRegistry()
|
||||
//
|
||||
@@ -172,7 +167,7 @@ namespace System.Globalization {
|
||||
// Look in the registry key and see if we can find any ranges
|
||||
int iFoundEras = 0;
|
||||
EraInfo[] registryEraRanges = null;
|
||||
|
||||
#if !MONO
|
||||
try
|
||||
{
|
||||
// Need to access registry
|
||||
@@ -254,7 +249,7 @@ namespace System.Globalization {
|
||||
registryEraRanges[i].maxEraYear = registryEraRanges[i-1].yearOffset + 1 - registryEraRanges[i].yearOffset;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
// Return our ranges
|
||||
return registryEraRanges;
|
||||
}
|
||||
@@ -337,7 +332,6 @@ namespace System.Globalization {
|
||||
return new EraInfo( 0, year, month, day, year - 1, 1, 0,
|
||||
names[0], names[1], names[3]);
|
||||
}
|
||||
#endif // !__APPLE__
|
||||
|
||||
internal static volatile Calendar s_defaultInstance;
|
||||
internal GregorianCalendarHelper helper;
|
||||
|
||||
@@ -74,12 +74,6 @@ namespace System.Globalization {
|
||||
|
||||
Contract.EndContractBlock();
|
||||
|
||||
#if FEATURE_CORECLR
|
||||
//
|
||||
// For CoreCLR we only want the region names that are full culture names
|
||||
//
|
||||
this.m_cultureData = CultureData.GetCultureData(name,true);
|
||||
#else
|
||||
//
|
||||
// First try it as an entire culture. We must have user override as true here so
|
||||
// that we can pick up custom cultures *before* built-in ones (if they want to
|
||||
@@ -87,7 +81,7 @@ namespace System.Globalization {
|
||||
//
|
||||
this.m_cultureData = CultureData.GetCultureDataForRegion(name,true);
|
||||
// this.m_name = name.ToUpper(CultureInfo.InvariantCulture);
|
||||
#endif // FEATURE_CORECLR
|
||||
|
||||
if (this.m_cultureData == null)
|
||||
throw new ArgumentException(
|
||||
String.Format(
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace System.Globalization {
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics.Contracts;
|
||||
/* SSS_DROP_BEGIN */ /* SSS_WARNINGS_OFF */
|
||||
/*=================================TaiwanCalendar==========================
|
||||
/*
|
||||
|
||||
**
|
||||
** Taiwan calendar is based on the Gregorian calendar. And the year is an offset to Gregorian calendar.
|
||||
** That is,
|
||||
@@ -21,7 +21,7 @@ namespace System.Globalization {
|
||||
** Gregorian 1912/01/01 9999/12/31
|
||||
** Taiwan 01/01/01 8088/12/31
|
||||
============================================================================*/
|
||||
/* SSS_WARNINGS_ON */ /* SSS_DROP_END */
|
||||
|
||||
|
||||
[System.Runtime.InteropServices.ComVisible(true)]
|
||||
[Serializable] public class TaiwanCalendar: Calendar {
|
||||
|
||||
@@ -249,14 +249,8 @@ namespace System.Globalization {
|
||||
[ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
|
||||
internal static unsafe int CompareOrdinalIgnoreCase(String str1, String str2)
|
||||
{
|
||||
#if __APPLE__
|
||||
// ToUpper (invariant) here before going to the PAL since Mac OS 10.4 does this step
|
||||
// wrong (CFCompareString uses the current OS locale and does not let you specify a specific locale)
|
||||
return String.CompareOrdinal(str1.ToUpper(CultureInfo.InvariantCulture), str2.ToUpper(CultureInfo.InvariantCulture));
|
||||
#else
|
||||
// Compare the whole string and ignore case.
|
||||
return InternalCompareStringOrdinalIgnoreCase(str1, 0, str2, 0, str1.Length, str2.Length);
|
||||
#endif
|
||||
}
|
||||
|
||||
// This function doesn't check arguments. Please do check in the caller.
|
||||
@@ -268,13 +262,7 @@ namespace System.Globalization {
|
||||
{
|
||||
Contract.Assert(strA.Length >= indexA + lengthA, "[TextInfo.CompareOrdinalIgnoreCaseEx] Caller should've validated strA.Length >= indexA + lengthA");
|
||||
Contract.Assert(strB.Length >= indexB + lengthB, "[TextInfo.CompareOrdinalIgnoreCaseEx] Caller should've validated strB.Length >= indexB + lengthB");
|
||||
#if __APPLE__
|
||||
// ToUpper (invariant) here before going to the PAL since Mac OS 10.4 does this step
|
||||
// wrong (CFCompareString uses the current OS locale and does not let you specify a specific locale)
|
||||
return String.CompareOrdinal(strA.ToUpper(CultureInfo.InvariantCulture), indexA, strB.ToUpper(CultureInfo.InvariantCulture), indexB, Math.Max(lengthA, lengthB));
|
||||
#else
|
||||
return InternalCompareStringOrdinalIgnoreCase(strA, indexA, strB, indexB, lengthA, lengthB);
|
||||
#endif
|
||||
}
|
||||
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
@@ -291,16 +279,11 @@ namespace System.Globalization {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if __APPLE__
|
||||
string sourceUpper = source.ToUpper(CultureInfo.InvariantCulture);
|
||||
string valueUpper = value.ToUpper(CultureInfo.InvariantCulture);
|
||||
#else
|
||||
// fast path
|
||||
#if !MONO
|
||||
int ret = -1;
|
||||
if (TryFastFindStringOrdinalIgnoreCase(Microsoft.Win32.Win32Native.FIND_FROMSTART, source, startIndex, value, count, ref ret))
|
||||
return ret;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// the search space within [source] starts at offset [startIndex] inclusive and includes
|
||||
@@ -316,14 +299,10 @@ namespace System.Globalization {
|
||||
|
||||
for (; startIndex <= maxStartIndex; startIndex++)
|
||||
{
|
||||
#if __APPLE__
|
||||
if (String.CompareOrdinal(sourceUpper, startIndex, valueUpper, 0, value.Length)==0)
|
||||
#else
|
||||
// We should always have the same or more characters left to search than our actual pattern
|
||||
Contract.Assert(end - startIndex >= value.Length);
|
||||
// since this is an ordinal comparison, we can assume that the lengths must match
|
||||
if (CompareOrdinalIgnoreCaseEx(source, startIndex, value, 0, value.Length, value.Length) == 0)
|
||||
#endif
|
||||
{
|
||||
return startIndex;
|
||||
}
|
||||
@@ -333,16 +312,6 @@ namespace System.Globalization {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if FEATURE_CORECLR
|
||||
private static bool LegacyMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return CompatibilitySwitches.IsAppEarlierThanSilverlight4;
|
||||
}
|
||||
}
|
||||
#endif // FEATURE_CORECLR
|
||||
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
[ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
|
||||
internal static int LastIndexOfStringOrdinalIgnoreCase(String source, String value, int startIndex, int count)
|
||||
@@ -353,26 +322,16 @@ namespace System.Globalization {
|
||||
Contract.Assert(startIndex <= source.Length, "[TextInfo.LastIndexOfStringOrdinalIgnoreCase] Caller should've validated startIndex <= source.Length");
|
||||
|
||||
// If value is Empty, the return value is startIndex
|
||||
// <STRIP>we accidently shipped Silverlight 2 and 3 without this if-check</STRIP>
|
||||
if (value.Length == 0
|
||||
#if FEATURE_CORECLR
|
||||
&& !LegacyMode
|
||||
#endif // FEATURE_CORECLR
|
||||
)
|
||||
if (value.Length == 0)
|
||||
{
|
||||
return startIndex;
|
||||
}
|
||||
|
||||
#if __APPLE__
|
||||
string sourceUpper = source.ToUpper(CultureInfo.InvariantCulture);
|
||||
string valueUpper = value.ToUpper(CultureInfo.InvariantCulture);
|
||||
#else
|
||||
// fast path
|
||||
#if !MONO
|
||||
int ret = -1;
|
||||
if (TryFastFindStringOrdinalIgnoreCase(Microsoft.Win32.Win32Native.FIND_FROMEND, source, startIndex, value, count, ref ret))
|
||||
return ret;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// the search space within [source] ends at offset [startIndex] inclusive
|
||||
@@ -388,11 +347,7 @@ namespace System.Globalization {
|
||||
|
||||
for (; startIndex >= minIndex; startIndex--)
|
||||
{
|
||||
#if __APPLE__
|
||||
if (String.CompareOrdinal(sourceUpper, startIndex, valueUpper, 0, value.Length)==0)
|
||||
#else
|
||||
if (CompareOrdinalIgnoreCaseEx(source, startIndex, value, 0, value.Length, value.Length) == 0)
|
||||
#endif
|
||||
{
|
||||
return startIndex;
|
||||
}
|
||||
@@ -589,9 +544,6 @@ namespace System.Globalization {
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[System.Security.SecuritySafeCritical] // auto-generated
|
||||
#if !FEATURE_CORECLR
|
||||
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
||||
#endif
|
||||
public unsafe virtual char ToLower(char c)
|
||||
{
|
||||
if(IsAscii(c) && IsAsciiCasingSameAsInvariant)
|
||||
@@ -614,29 +566,7 @@ namespace System.Globalization {
|
||||
#if MONO
|
||||
return ToLowerInternal (str);
|
||||
#else
|
||||
String toLower = InternalChangeCaseString(this.m_dataHandle, this.m_handleOrigin, this.m_textInfoName, str, false);
|
||||
#if __APPLE__
|
||||
//
|
||||
// Mac OS X has a documented list of "illegal" (precomposed) characters
|
||||
// http://developer.apple.com/technotes/tn/tn1150table.html
|
||||
//
|
||||
// These characters are mostly in the EXTENDED_GREEK range. Apple decomposes
|
||||
// these characters into a sequence of two or more characters that is a
|
||||
// canonical or compatibility equivalent.
|
||||
//
|
||||
// In the extremely unlikely event that an illegal character is in the String,
|
||||
// fallback to using slower Char routines since they do not decompose
|
||||
// the illegal characters.
|
||||
//
|
||||
if (toLower.Length != str.Length) {
|
||||
char[] chars = new char[str.Length];
|
||||
for (int i = 0; i < str.Length; i++) {
|
||||
chars[i] = this.ToLower(str[i]);
|
||||
}
|
||||
toLower = new String(chars);
|
||||
}
|
||||
#endif
|
||||
return toLower;
|
||||
return InternalChangeCaseString(this.m_dataHandle, this.m_handleOrigin, this.m_textInfoName, str, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -659,9 +589,6 @@ namespace System.Globalization {
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[System.Security.SecuritySafeCritical] // auto-generated
|
||||
#if !FEATURE_CORECLR
|
||||
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
||||
#endif
|
||||
public unsafe virtual char ToUpper(char c)
|
||||
{
|
||||
if (IsAscii(c) && IsAsciiCasingSameAsInvariant)
|
||||
@@ -682,33 +609,10 @@ namespace System.Globalization {
|
||||
{
|
||||
if (str == null) { throw new ArgumentNullException("str"); }
|
||||
Contract.EndContractBlock();
|
||||
|
||||
#if MONO
|
||||
return ToUpperInternal (str);
|
||||
#else
|
||||
String toUpper = InternalChangeCaseString(this.m_dataHandle, this.m_handleOrigin, this.m_textInfoName, str, true);
|
||||
#if __APPLE__
|
||||
//
|
||||
// Mac OS X has a documented list of "illegal" (precomposed) characters
|
||||
// http://developer.apple.com/technotes/tn/tn1150table.html
|
||||
//
|
||||
// These characters are mostly in the EXTENDED_GREEK range. Apple decomposes
|
||||
// these characters into a sequence of two or more characters that is a
|
||||
// canonical or compatibility equivalent.
|
||||
//
|
||||
// In the extremely unlikely event that an illegal character is in the String,
|
||||
// fallback to using slower Char routines since they do not decompose
|
||||
// the illegal characters.
|
||||
//
|
||||
if (toUpper.Length != str.Length) {
|
||||
char[] chars = new char[str.Length];
|
||||
for (int i = 0; i < str.Length; i++) {
|
||||
chars[i] = this.ToUpper(str[i]);
|
||||
}
|
||||
toUpper = new String(chars);
|
||||
}
|
||||
#endif
|
||||
return toUpper;
|
||||
return InternalChangeCaseString(this.m_dataHandle, this.m_handleOrigin, this.m_textInfoName, str, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1024,7 +928,6 @@ namespace System.Globalization {
|
||||
#endif
|
||||
|
||||
|
||||
#if !FEATURE_CORECLR
|
||||
// IsRightToLeft
|
||||
//
|
||||
// Returns true if the dominant direction of text and UI such as the relative position of buttons and scroll bars
|
||||
@@ -1032,13 +935,11 @@ namespace System.Globalization {
|
||||
[System.Runtime.InteropServices.ComVisible(false)]
|
||||
public bool IsRightToLeft
|
||||
{
|
||||
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
|
||||
get
|
||||
{
|
||||
return this.m_cultureData.IsRightToLeft;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FEATURE_SERIALIZATION
|
||||
/// <internalonly/>
|
||||
@@ -1072,13 +973,30 @@ namespace System.Globalization {
|
||||
Contract.EndContractBlock();
|
||||
|
||||
#if MONO
|
||||
return StringComparer.CurrentCultureIgnoreCase.GetHashCode (str);
|
||||
return this == s_Invariant ? GetInvariantCaseInsensitiveHashCode (str) : StringComparer.CurrentCultureIgnoreCase.GetHashCode (str);
|
||||
#else
|
||||
// Return our result
|
||||
return (InternalGetCaseInsHash(this.m_dataHandle, this.m_handleOrigin, this.m_textInfoName, str, forceRandomizedHashing, additionalEntropy));
|
||||
#endif
|
||||
}
|
||||
#if !MONO
|
||||
#if MONO
|
||||
unsafe int GetInvariantCaseInsensitiveHashCode (string str)
|
||||
{
|
||||
fixed (char * c = str) {
|
||||
char * cc = c;
|
||||
char * end = cc + str.Length - 1;
|
||||
int h = 0;
|
||||
for (;cc < end; cc += 2) {
|
||||
h = (h << 5) - h + Char.ToUpperInvariant (*cc);
|
||||
h = (h << 5) - h + Char.ToUpperInvariant (cc [1]);
|
||||
}
|
||||
++end;
|
||||
if (cc < end)
|
||||
h = (h << 5) - h + Char.ToUpperInvariant (*cc);
|
||||
return h;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Change case (ToUpper/ToLower) -- COMNlsInfo::InternalChangeCaseChar
|
||||
[System.Security.SecurityCritical] // auto-generated
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
|
||||
@@ -280,7 +280,7 @@ namespace System.Globalization {
|
||||
return m_negLoc;
|
||||
}
|
||||
}
|
||||
//<STRIP>
|
||||
//<
|
||||
internal Boolean FullAppCompatMatch(TimeSpanFormat.FormatLiterals pattern) {
|
||||
return SepCount == 5
|
||||
&& NumCount == 4
|
||||
@@ -290,7 +290,7 @@ namespace System.Globalization {
|
||||
&& pattern.AppCompatLiteral == literals[3]
|
||||
&& pattern.End == literals[4];
|
||||
}
|
||||
//<STRIP>
|
||||
//<
|
||||
internal Boolean PartialAppCompatMatch(TimeSpanFormat.FormatLiterals pattern) {
|
||||
return SepCount == 4
|
||||
&& NumCount == 3
|
||||
|
||||
Reference in New Issue
Block a user