summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTarek Mahmoud Sayed <tarekms@microsoft.com>2018-04-19 13:14:12 -0700
committerGitHub <noreply@github.com>2018-04-19 13:14:12 -0700
commit3b3ef2add7b99d8acc3f0a156527d45a6f9e295b (patch)
tree934d5413fb8bf723e7d0b0790663415d2ecfe41b /src
parentfa89b5a850adcbb9dd7451ee883d35961a529919 (diff)
downloadcoreclr-3b3ef2add7b99d8acc3f0a156527d45a6f9e295b.tar.gz
coreclr-3b3ef2add7b99d8acc3f0a156527d45a6f9e295b.tar.bz2
coreclr-3b3ef2add7b99d8acc3f0a156527d45a6f9e295b.zip
Fix reading Time zone rules using Julian days (#17672)
Diffstat (limited to 'src')
-rw-r--r--src/mscorlib/Resources/Strings.resx61
-rw-r--r--src/mscorlib/shared/System/TimeZoneInfo.Unix.cs139
2 files changed, 138 insertions, 62 deletions
diff --git a/src/mscorlib/Resources/Strings.resx b/src/mscorlib/Resources/Strings.resx
index 5d37b50f3c..49c8e93249 100644
--- a/src/mscorlib/Resources/Strings.resx
+++ b/src/mscorlib/Resources/Strings.resx
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
- <!--
- Microsoft ResX Schema
-
+ <!--
+ Microsoft ResX Schema
+
Version 2.0
-
- The primary goals of this format is to allow a simple XML format
- that is mostly human readable. The generation and parsing of the
- various data types are done through the TypeConverter classes
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
associated with the data types.
-
+
Example:
-
+
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
@@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
-
- There are any number of "resheader" rows that contain simple
+
+ There are any number of "resheader" rows that contain simple
name/value pairs.
-
- Each data row contains a name, and value. The row also contains a
- type or mimetype. Type corresponds to a .NET class that support
- text/value conversion through the TypeConverter architecture.
- Classes that don't support this are serialized and stored with the
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
mimetype set.
-
- The mimetype is used for serialized objects, and tells the
- ResXResourceReader how to depersist the object. This is currently not
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
-
- Note - application/x-microsoft.net.object.binary.base64 is the format
- that the ResXResourceWriter will generate, however the reader can
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
-
+
mimetype: application/x-microsoft.net.object.binary.base64
- value : The object must be serialized with
+ value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
-
+
mimetype: application/x-microsoft.net.object.soap.base64
- value : The object must be serialized with
+ value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
- value : The object must be serialized into a byte array
+ value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
@@ -2734,8 +2734,11 @@
<data name="InvalidTimeZone_InvalidRegistryData" xml:space="preserve">
<value>The time zone ID '{0}' was found on the local computer, but the registry information was corrupt.</value>
</data>
- <data name="InvalidTimeZone_JulianDayNotSupported" xml:space="preserve">
- <value>Julian dates in POSIX strings are unsupported.</value>
+ <data name="InvalidTimeZone_InvalidJulianDay" xml:space="preserve">
+ <value>Invalid Julian day in POSIX strings.</value>
+ </data>
+ <data name="InvalidTimeZone_NJulianDayNotSupported" xml:space="preserve">
+ <value>Julian n day in POSIX strings is not supported.</value>
</data>
<data name="InvalidTimeZone_NoTTInfoStructures" xml:space="preserve">
<value>There are no ttinfo structures in the tzfile. At least one ttinfo structure is required in order to construct a TimeZoneInfo object.</value>
diff --git a/src/mscorlib/shared/System/TimeZoneInfo.Unix.cs b/src/mscorlib/shared/System/TimeZoneInfo.Unix.cs
index 2dcaf67bfd..cc386a111f 100644
--- a/src/mscorlib/shared/System/TimeZoneInfo.Unix.cs
+++ b/src/mscorlib/shared/System/TimeZoneInfo.Unix.cs
@@ -1117,6 +1117,37 @@ namespace System
return result;
}
+ private static DateTime ParseTimeOfDay(string 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(string date, string time)
{
if (string.IsNullOrEmpty(date))
@@ -1138,48 +1169,90 @@ namespace System
throw new InvalidTimeZoneException(SR.Format(SR.InvalidTimeZone_UnparseablePosixMDateString, date));
}
- 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(string 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[0] == 'J');
+ Debug.Assert(!String.IsNullOrEmpty(date));
+ month = day = 0;
+
+ int index = 1;
+
+ if (index >= date.Length || ((uint)(date[index] - '0') > '9'-'0'))
{
- // Jn
- // This specifies the Julian day, with n between 1 and 365.February 29 is never counted, even in leap years.
+ throw new InvalidTimeZoneException(SR.InvalidTimeZone_InvalidJulianDay);
+ }
+
+ int julianDay = 0;
- // n
- // This specifies the Julian day, with n between 0 and 365.February 29 is counted in leap years.
+ do
+ {
+ julianDay = julianDay * 10 + (int) (date[index] - '0');
+ index++;
+ } while (index < date.Length && ((uint)(date[index] - '0') <= '9'-'0'));
- // 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
+ int[] days = GregorianCalendarHelper.DaysToMonth365;
- throw new InvalidTimeZoneException(SR.InvalidTimeZone_JulianDayNotSupported);
+ if (julianDay == 0 || julianDay > days[days.Length - 1])
+ {
+ throw new InvalidTimeZoneException(SR.InvalidTimeZone_InvalidJulianDay);
}
+
+ 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>