Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs')
-rw-r--r--src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs262
1 files changed, 179 insertions, 83 deletions
diff --git a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs
index 410eaf3ff..5645c2a38 100644
--- a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs
+++ b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs
@@ -384,8 +384,8 @@ namespace System
string symlinkPath = Interop.Sys.ReadLink(tzFilePath);
if (symlinkPath != null)
{
- // Use Path.Combine to resolve links that contain a relative path (e.g. /etc/localtime).
- symlinkPath = Path.Combine(tzFilePath, symlinkPath);
+ // symlinkPath can be relative path, use Path to get the full absolute path.
+ symlinkPath = Path.GetFullPath(symlinkPath, Path.GetDirectoryName(tzFilePath));
string timeZoneDirectory = GetTimeZoneDirectory();
if (symlinkPath.StartsWith(timeZoneDirectory, StringComparison.Ordinal))
@@ -398,7 +398,7 @@ namespace System
}
/// <summary>
- /// Enumerate files
+ /// Enumerate files
/// </summary>
private static IEnumerable<string> EnumerateFilesRecursively(string path)
{
@@ -595,6 +595,7 @@ namespace System
}
catch (ArgumentException) { }
catch (InvalidTimeZoneException) { }
+
try
{
return new TimeZoneInfo(rawData, id, dstDisabled: true); // create a TimeZoneInfo instance from the TZif data w/o DST support
@@ -602,7 +603,6 @@ namespace System
catch (ArgumentException) { }
catch (InvalidTimeZoneException) { }
}
-
return null;
}
@@ -866,7 +866,7 @@ namespace System
index++;
}
- if (index == 0)
+ if (rulesList.Count == 0 && index < dts.Length)
{
TZifType transitionType = TZif_GetEarlyDateTransitionType(transitionTypes);
DateTime endTransitionDate = dts[index];
@@ -883,6 +883,12 @@ namespace System
default(TransitionTime),
baseUtcDelta,
noDaylightTransitions: true);
+
+ if (!IsValidAdjustmentRuleOffest(timeZoneBaseUtcOffset, r))
+ {
+ NormalizeAdjustmentRuleOffset(timeZoneBaseUtcOffset, ref r);
+ }
+
rulesList.Add(r);
}
else if (index < dts.Length)
@@ -920,6 +926,12 @@ namespace System
default(TransitionTime),
baseUtcDelta,
noDaylightTransitions: true);
+
+ if (!IsValidAdjustmentRuleOffest(timeZoneBaseUtcOffset, r))
+ {
+ NormalizeAdjustmentRuleOffset(timeZoneBaseUtcOffset, ref r);
+ }
+
rulesList.Add(r);
}
else
@@ -932,8 +944,14 @@ namespace System
if (!string.IsNullOrEmpty(futureTransitionsPosixFormat))
{
AdjustmentRule r = TZif_CreateAdjustmentRuleForPosixFormat(futureTransitionsPosixFormat, startTransitionDate, timeZoneBaseUtcOffset);
+
if (r != null)
{
+ if (!IsValidAdjustmentRuleOffest(timeZoneBaseUtcOffset, r))
+ {
+ NormalizeAdjustmentRuleOffset(timeZoneBaseUtcOffset, ref r);
+ }
+
rulesList.Add(r);
}
}
@@ -954,6 +972,12 @@ namespace System
default(TransitionTime),
baseUtcDelta,
noDaylightTransitions: true);
+
+ if (!IsValidAdjustmentRuleOffest(timeZoneBaseUtcOffset, r))
+ {
+ NormalizeAdjustmentRuleOffset(timeZoneBaseUtcOffset, ref r);
+ }
+
rulesList.Add(r);
}
}
@@ -1012,17 +1036,15 @@ namespace System
/// </remarks>
private static AdjustmentRule TZif_CreateAdjustmentRuleForPosixFormat(string posixFormat, DateTime startTransitionDate, TimeSpan timeZoneBaseUtcOffset)
{
- string standardName;
- string standardOffset;
- string daylightSavingsName;
- string daylightSavingsOffset;
- string start;
- string startTime;
- string end;
- string endTime;
-
- if (TZif_ParsePosixFormat(posixFormat, out standardName, out standardOffset, out daylightSavingsName,
- out daylightSavingsOffset, out start, out startTime, out end, out endTime))
+ if (TZif_ParsePosixFormat(posixFormat,
+ out ReadOnlySpan<char> standardName,
+ out ReadOnlySpan<char> standardOffset,
+ out ReadOnlySpan<char> daylightSavingsName,
+ out ReadOnlySpan<char> daylightSavingsOffset,
+ out ReadOnlySpan<char> start,
+ out ReadOnlySpan<char> startTime,
+ out ReadOnlySpan<char> end,
+ out ReadOnlySpan<char> endTime))
{
// a valid posixFormat has at least standardName and standardOffset
@@ -1033,7 +1055,7 @@ namespace System
baseOffset = TZif_CalculateTransitionOffsetFromBase(baseOffset, timeZoneBaseUtcOffset);
// having a daylightSavingsName means there is a DST rule
- if (!string.IsNullOrEmpty(daylightSavingsName))
+ if (!daylightSavingsName.IsEmpty)
{
TimeSpan? parsedDaylightSavings = TZif_ParseOffsetString(daylightSavingsOffset);
TimeSpan daylightSavingsTimeSpan;
@@ -1079,16 +1101,16 @@ namespace System
return null;
}
- private static TimeSpan? TZif_ParseOffsetString(string offset)
+ private static TimeSpan? TZif_ParseOffsetString(ReadOnlySpan<char> offset)
{
TimeSpan? result = null;
- if (!string.IsNullOrEmpty(offset))
+ if (offset.Length > 0)
{
bool negative = offset[0] == '-';
if (negative || offset[0] == '+')
{
- offset = offset.Substring(1);
+ offset = offset.Slice(1);
}
// Try parsing just hours first.
@@ -1117,9 +1139,40 @@ namespace System
return result;
}
- private static TransitionTime TZif_CreateTransitionTimeFromPosixRule(string date, string time)
+ private static DateTime ParseTimeOfDay(ReadOnlySpan<char> time)
+ {
+ DateTime timeOfDay;
+ TimeSpan? timeOffset = TZif_ParseOffsetString(time);
+ if (timeOffset.HasValue)
+ {
+ // This logic isn't correct and can't be corrected until https://github.com/dotnet/corefx/issues/2618 is fixed.
+ // Some time zones use time values like, "26", "144", or "-2".
+ // This allows the week to sometimes be week 4 and sometimes week 5 in the month.
+ // For now, strip off any 'days' in the offset, and just get the time of day correct
+ timeOffset = new TimeSpan(timeOffset.Value.Hours, timeOffset.Value.Minutes, timeOffset.Value.Seconds);
+ if (timeOffset.Value < TimeSpan.Zero)
+ {
+ timeOfDay = new DateTime(1, 1, 2, 0, 0, 0);
+ }
+ else
+ {
+ timeOfDay = new DateTime(1, 1, 1, 0, 0, 0);
+ }
+
+ timeOfDay += timeOffset.Value;
+ }
+ else
+ {
+ // default to 2AM.
+ timeOfDay = new DateTime(1, 1, 1, 2, 0, 0);
+ }
+
+ return timeOfDay;
+ }
+
+ private static TransitionTime TZif_CreateTransitionTimeFromPosixRule(ReadOnlySpan<char> date, ReadOnlySpan<char> time)
{
- if (string.IsNullOrEmpty(date))
+ if (date.IsEmpty)
{
return default(TransitionTime);
}
@@ -1135,51 +1188,93 @@ namespace System
DayOfWeek day;
if (!TZif_ParseMDateRule(date, out month, out week, out day))
{
- throw new InvalidTimeZoneException(SR.Format(SR.InvalidTimeZone_UnparseablePosixMDateString, date));
+ throw new InvalidTimeZoneException(SR.Format(SR.InvalidTimeZone_UnparseablePosixMDateString, date.ToString()));
}
- DateTime timeOfDay;
- TimeSpan? timeOffset = TZif_ParseOffsetString(time);
- if (timeOffset.HasValue)
- {
- // This logic isn't correct and can't be corrected until https://github.com/dotnet/corefx/issues/2618 is fixed.
- // Some time zones use time values like, "26", "144", or "-2".
- // This allows the week to sometimes be week 4 and sometimes week 5 in the month.
- // For now, strip off any 'days' in the offset, and just get the time of day correct
- timeOffset = new TimeSpan(timeOffset.Value.Hours, timeOffset.Value.Minutes, timeOffset.Value.Seconds);
- if (timeOffset.Value < TimeSpan.Zero)
- {
- timeOfDay = new DateTime(1, 1, 2, 0, 0, 0);
- }
- else
- {
- timeOfDay = new DateTime(1, 1, 1, 0, 0, 0);
- }
-
- timeOfDay += timeOffset.Value;
- }
- else
+ return TransitionTime.CreateFloatingDateRule(ParseTimeOfDay(time), month, week, day);
+ }
+ else
+ {
+ if (date[0] != 'J')
{
- // default to 2AM.
- timeOfDay = new DateTime(1, 1, 1, 2, 0, 0);
+ // should be n Julian day format which we don't support.
+ //
+ // This specifies the Julian day, with n between 0 and 365. February 29 is counted in leap years.
+ //
+ // n would be a relative number from the begining of the year. which should handle if the
+ // the year is a leap year or not.
+ //
+ // In leap year, n would be counted as:
+ //
+ // 0 30 31 59 60 90 335 365
+ // |-------Jan--------|-------Feb--------|-------Mar--------|....|-------Dec--------|
+ //
+ // while in non leap year we'll have
+ //
+ // 0 30 31 58 59 89 334 364
+ // |-------Jan--------|-------Feb--------|-------Mar--------|....|-------Dec--------|
+ //
+ //
+ // For example if n is specified as 60, this means in leap year the rule will start at Mar 1,
+ // while in non leap year the rule will start at Mar 2.
+ //
+ // If we need to support n format, we'll have to have a floating adjustment rule support this case.
+
+ throw new InvalidTimeZoneException(SR.InvalidTimeZone_NJulianDayNotSupported);
}
- return TransitionTime.CreateFloatingDateRule(timeOfDay, month, week, day);
+ // Julian day
+ TZif_ParseJulianDay(date, out int month, out int day);
+ return TransitionTime.CreateFixedDateRule(ParseTimeOfDay(time), month, day);
}
- else
+ }
+
+ /// <summary>
+ /// Parses a string like Jn or n into month and day values.
+ /// </summary>
+ /// <returns>
+ /// true if the parsing succeeded; otherwise, false.
+ /// </returns>
+ private static void TZif_ParseJulianDay(ReadOnlySpan<char> date, out int month, out int day)
+ {
+ // Jn
+ // This specifies the Julian day, with n between 1 and 365.February 29 is never counted, even in leap years.
+ Debug.Assert(!date.IsEmpty);
+ Debug.Assert(date[0] == 'J');
+ month = day = 0;
+
+ int index = 1;
+
+ if (index >= date.Length || ((uint)(date[index] - '0') > '9'-'0'))
+ {
+ throw new InvalidTimeZoneException(SR.InvalidTimeZone_InvalidJulianDay);
+ }
+
+ int julianDay = 0;
+
+ do
{
- // Jn
- // This specifies the Julian day, with n between 1 and 365.February 29 is never counted, even in leap years.
+ julianDay = julianDay * 10 + (int) (date[index] - '0');
+ index++;
+ } while (index < date.Length && ((uint)(date[index] - '0') <= '9'-'0'));
- // n
- // This specifies the Julian day, with n between 0 and 365.February 29 is counted in leap years.
+ int[] days = GregorianCalendarHelper.DaysToMonth365;
- // These two rules cannot be expressed with the current AdjustmentRules
- // One of them *could* be supported if we relaxed the TransitionTime validation rules, and allowed
- // "IsFixedDateRule = true, Month = 0, Day = n" to mean the nth day of the year, picking one of the rules above
+ if (julianDay == 0 || julianDay > days[days.Length - 1])
+ {
+ throw new InvalidTimeZoneException(SR.InvalidTimeZone_InvalidJulianDay);
+ }
- throw new InvalidTimeZoneException(SR.InvalidTimeZone_JulianDayNotSupported);
+ int i = 1;
+ while (i < days.Length && julianDay > days[i])
+ {
+ i++;
}
+
+ Debug.Assert(i > 0 && i < days.Length);
+
+ month = i;
+ day = julianDay - days[i - 1];
}
/// <summary>
@@ -1188,19 +1283,20 @@ namespace System
/// <returns>
/// true if the parsing succeeded; otherwise, false.
/// </returns>
- private static bool TZif_ParseMDateRule(string dateRule, out int month, out int week, out DayOfWeek dayOfWeek)
+ private static bool TZif_ParseMDateRule(ReadOnlySpan<char> dateRule, out int month, out int week, out DayOfWeek dayOfWeek)
{
if (dateRule[0] == 'M')
{
- int firstDotIndex = dateRule.IndexOf('.');
- if (firstDotIndex > 0)
+ int monthWeekDotIndex = dateRule.IndexOf('.');
+ if (monthWeekDotIndex > 0)
{
- int secondDotIndex = dateRule.IndexOf('.', firstDotIndex + 1);
- if (secondDotIndex > 0)
+ ReadOnlySpan<char> weekDaySpan = dateRule.Slice(monthWeekDotIndex + 1);
+ int weekDayDotIndex = weekDaySpan.IndexOf('.');
+ if (weekDayDotIndex > 0)
{
- if (int.TryParse(dateRule.AsSpan().Slice(1, firstDotIndex - 1), out month) &&
- int.TryParse(dateRule.AsSpan().Slice(firstDotIndex + 1, secondDotIndex - firstDotIndex - 1), out week) &&
- int.TryParse(dateRule.AsSpan().Slice(secondDotIndex + 1), out int day))
+ if (int.TryParse(dateRule.Slice(1, monthWeekDotIndex - 1), out month) &&
+ int.TryParse(weekDaySpan.Slice(0, weekDayDotIndex), out week) &&
+ int.TryParse(weekDaySpan.Slice(weekDayDotIndex + 1), out int day))
{
dayOfWeek = (DayOfWeek)day;
return true;
@@ -1216,15 +1312,15 @@ namespace System
}
private static bool TZif_ParsePosixFormat(
- string posixFormat,
- out string standardName,
- out string standardOffset,
- out string daylightSavingsName,
- out string daylightSavingsOffset,
- out string start,
- out string startTime,
- out string end,
- out string endTime)
+ ReadOnlySpan<char> posixFormat,
+ out ReadOnlySpan<char> standardName,
+ out ReadOnlySpan<char> standardOffset,
+ out ReadOnlySpan<char> daylightSavingsName,
+ out ReadOnlySpan<char> daylightSavingsOffset,
+ out ReadOnlySpan<char> start,
+ out ReadOnlySpan<char> startTime,
+ out ReadOnlySpan<char> end,
+ out ReadOnlySpan<char> endTime)
{
standardName = null;
standardOffset = null;
@@ -1240,7 +1336,7 @@ namespace System
standardOffset = TZif_ParsePosixOffset(posixFormat, ref index);
daylightSavingsName = TZif_ParsePosixName(posixFormat, ref index);
- if (!string.IsNullOrEmpty(daylightSavingsName))
+ if (!daylightSavingsName.IsEmpty)
{
daylightSavingsOffset = TZif_ParsePosixOffset(posixFormat, ref index);
@@ -1257,10 +1353,10 @@ namespace System
}
}
- return !string.IsNullOrEmpty(standardName) && !string.IsNullOrEmpty(standardOffset);
+ return !standardName.IsEmpty && !standardOffset.IsEmpty;
}
- private static string TZif_ParsePosixName(string posixFormat, ref int index)
+ private static ReadOnlySpan<char> TZif_ParsePosixName(ReadOnlySpan<char> posixFormat, ref int index)
{
bool isBracketEnclosed = index < posixFormat.Length && posixFormat[index] == '<';
if (isBracketEnclosed)
@@ -1268,7 +1364,7 @@ namespace System
// move past the opening bracket
index++;
- string result = TZif_ParsePosixString(posixFormat, ref index, c => c == '>');
+ ReadOnlySpan<char> result = TZif_ParsePosixString(posixFormat, ref index, c => c == '>');
// move past the closing bracket
if (index < posixFormat.Length && posixFormat[index] == '>')
@@ -1287,10 +1383,10 @@ namespace System
}
}
- private static string TZif_ParsePosixOffset(string posixFormat, ref int index) =>
+ private static ReadOnlySpan<char> TZif_ParsePosixOffset(ReadOnlySpan<char> posixFormat, ref int index) =>
TZif_ParsePosixString(posixFormat, ref index, c => !char.IsDigit(c) && c != '+' && c != '-' && c != ':');
- private static void TZif_ParsePosixDateTime(string posixFormat, ref int index, out string date, out string time)
+ private static void TZif_ParsePosixDateTime(ReadOnlySpan<char> posixFormat, ref int index, out ReadOnlySpan<char> date, out ReadOnlySpan<char> time)
{
time = null;
@@ -1302,13 +1398,13 @@ namespace System
}
}
- private static string TZif_ParsePosixDate(string posixFormat, ref int index) =>
+ private static ReadOnlySpan<char> TZif_ParsePosixDate(ReadOnlySpan<char> posixFormat, ref int index) =>
TZif_ParsePosixString(posixFormat, ref index, c => c == '/' || c == ',');
- private static string TZif_ParsePosixTime(string posixFormat, ref int index) =>
+ private static ReadOnlySpan<char> TZif_ParsePosixTime(ReadOnlySpan<char> posixFormat, ref int index) =>
TZif_ParsePosixString(posixFormat, ref index, c => c == ',');
- private static string TZif_ParsePosixString(string posixFormat, ref int index, Func<char, bool> breakCondition)
+ private static ReadOnlySpan<char> TZif_ParsePosixString(ReadOnlySpan<char> posixFormat, ref int index, Func<char, bool> breakCondition)
{
int startIndex = index;
for (; index < posixFormat.Length; index++)
@@ -1320,7 +1416,7 @@ namespace System
}
}
- return posixFormat.Substring(startIndex, index - startIndex);
+ return posixFormat.Slice(startIndex, index - startIndex);
}
// Returns the Substring from zoneAbbreviations starting at index and ending at '\0'