@@ -1117,6 +1117,37 @@ private static AdjustmentRule TZif_CreateAdjustmentRuleForPosixFormat(string pos
1117
1117
return result ;
1118
1118
}
1119
1119
1120
+ private static DateTime ParseTimeOfDay ( string time )
1121
+ {
1122
+ DateTime timeOfDay ;
1123
+ TimeSpan ? timeOffset = TZif_ParseOffsetString ( time ) ;
1124
+ if ( timeOffset . HasValue )
1125
+ {
1126
+ // This logic isn't correct and can't be corrected until https://github.com/dotnet/corefx/issues/2618 is fixed.
1127
+ // Some time zones use time values like, "26", "144", or "-2".
1128
+ // This allows the week to sometimes be week 4 and sometimes week 5 in the month.
1129
+ // For now, strip off any 'days' in the offset, and just get the time of day correct
1130
+ timeOffset = new TimeSpan ( timeOffset . Value . Hours , timeOffset . Value . Minutes , timeOffset . Value . Seconds ) ;
1131
+ if ( timeOffset . Value < TimeSpan . Zero )
1132
+ {
1133
+ timeOfDay = new DateTime ( 1 , 1 , 2 , 0 , 0 , 0 ) ;
1134
+ }
1135
+ else
1136
+ {
1137
+ timeOfDay = new DateTime ( 1 , 1 , 1 , 0 , 0 , 0 ) ;
1138
+ }
1139
+
1140
+ timeOfDay += timeOffset . Value ;
1141
+ }
1142
+ else
1143
+ {
1144
+ // default to 2AM.
1145
+ timeOfDay = new DateTime ( 1 , 1 , 1 , 2 , 0 , 0 ) ;
1146
+ }
1147
+
1148
+ return timeOfDay ;
1149
+ }
1150
+
1120
1151
private static TransitionTime TZif_CreateTransitionTimeFromPosixRule ( string date , string time )
1121
1152
{
1122
1153
if ( string . IsNullOrEmpty ( date ) )
@@ -1138,48 +1169,90 @@ private static TransitionTime TZif_CreateTransitionTimeFromPosixRule(string date
1138
1169
throw new InvalidTimeZoneException ( SR . Format ( SR . InvalidTimeZone_UnparseablePosixMDateString , date ) ) ;
1139
1170
}
1140
1171
1141
- DateTime timeOfDay ;
1142
- TimeSpan ? timeOffset = TZif_ParseOffsetString ( time ) ;
1143
- if ( timeOffset . HasValue )
1144
- {
1145
- // This logic isn't correct and can't be corrected until https://github.com/dotnet/corefx/issues/2618 is fixed.
1146
- // Some time zones use time values like, "26", "144", or "-2".
1147
- // This allows the week to sometimes be week 4 and sometimes week 5 in the month.
1148
- // For now, strip off any 'days' in the offset, and just get the time of day correct
1149
- timeOffset = new TimeSpan ( timeOffset . Value . Hours , timeOffset . Value . Minutes , timeOffset . Value . Seconds ) ;
1150
- if ( timeOffset . Value < TimeSpan . Zero )
1151
- {
1152
- timeOfDay = new DateTime ( 1 , 1 , 2 , 0 , 0 , 0 ) ;
1153
- }
1154
- else
1155
- {
1156
- timeOfDay = new DateTime ( 1 , 1 , 1 , 0 , 0 , 0 ) ;
1157
- }
1158
-
1159
- timeOfDay += timeOffset . Value ;
1160
- }
1161
- else
1172
+ return TransitionTime . CreateFloatingDateRule ( ParseTimeOfDay ( time ) , month , week , day ) ;
1173
+ }
1174
+ else
1175
+ {
1176
+ if ( date [ 0 ] != 'J' )
1162
1177
{
1163
- // default to 2AM.
1164
- timeOfDay = new DateTime ( 1 , 1 , 1 , 2 , 0 , 0 ) ;
1178
+ // should be n Julian day format which we don't support.
1179
+ //
1180
+ // This specifies the Julian day, with n between 0 and 365. February 29 is counted in leap years.
1181
+ //
1182
+ // n would be a relative number from the begining of the year. which should handle if the
1183
+ // the year is a leap year or not.
1184
+ //
1185
+ // In leap year, n would be counted as:
1186
+ //
1187
+ // 0 30 31 59 60 90 335 365
1188
+ // |-------Jan--------|-------Feb--------|-------Mar--------|....|-------Dec--------|
1189
+ //
1190
+ // while in non leap year we'll have
1191
+ //
1192
+ // 0 30 31 58 59 89 334 364
1193
+ // |-------Jan--------|-------Feb--------|-------Mar--------|....|-------Dec--------|
1194
+ //
1195
+ //
1196
+ // For example if n is specified as 60, this means in leap year the rule will start at Mar 1,
1197
+ // while in non leap year the rule will start at Mar 2.
1198
+ //
1199
+ // If we need to support n format, we'll have to have a floating adjustment rule support this case.
1200
+
1201
+ throw new InvalidTimeZoneException ( SR . InvalidTimeZone_NJulianDayNotSupported ) ;
1165
1202
}
1166
1203
1167
- return TransitionTime . CreateFloatingDateRule ( timeOfDay , month , week , day ) ;
1204
+ // Julian day
1205
+ TZif_ParseJulianDay ( date , out int month , out int day ) ;
1206
+ return TransitionTime . CreateFixedDateRule ( ParseTimeOfDay ( time ) , month , day ) ;
1168
1207
}
1169
- else
1208
+ }
1209
+
1210
+ /// <summary>
1211
+ /// Parses a string like Jn or n into month and day values.
1212
+ /// </summary>
1213
+ /// <returns>
1214
+ /// true if the parsing succeeded; otherwise, false.
1215
+ /// </returns>
1216
+ private static void TZif_ParseJulianDay ( string date , out int month , out int day )
1217
+ {
1218
+ // Jn
1219
+ // This specifies the Julian day, with n between 1 and 365.February 29 is never counted, even in leap years.
1220
+ Debug . Assert ( date [ 0 ] == 'J' ) ;
1221
+ Debug . Assert ( ! String . IsNullOrEmpty ( date ) ) ;
1222
+ month = day = 0 ;
1223
+
1224
+ int index = 1 ;
1225
+
1226
+ if ( index >= date . Length || ( ( uint ) ( date [ index ] - '0' ) > '9' - '0' ) )
1170
1227
{
1171
- // Jn
1172
- // This specifies the Julian day, with n between 1 and 365.February 29 is never counted, even in leap years.
1228
+ throw new InvalidTimeZoneException ( SR . InvalidTimeZone_InvalidJulianDay ) ;
1229
+ }
1230
+
1231
+ int julianDay = 0 ;
1173
1232
1174
- // n
1175
- // This specifies the Julian day, with n between 0 and 365.February 29 is counted in leap years.
1233
+ do
1234
+ {
1235
+ julianDay = julianDay * 10 + ( int ) ( date [ index ] - '0' ) ;
1236
+ index ++ ;
1237
+ } while ( index < date . Length && ( ( uint ) ( date [ index ] - '0' ) <= '9' - '0' ) ) ;
1176
1238
1177
- // These two rules cannot be expressed with the current AdjustmentRules
1178
- // One of them *could* be supported if we relaxed the TransitionTime validation rules, and allowed
1179
- // "IsFixedDateRule = true, Month = 0, Day = n" to mean the nth day of the year, picking one of the rules above
1239
+ int [ ] days = GregorianCalendarHelper . DaysToMonth365 ;
1180
1240
1181
- throw new InvalidTimeZoneException ( SR . InvalidTimeZone_JulianDayNotSupported ) ;
1241
+ if ( julianDay == 0 || julianDay > days [ days . Length - 1 ] )
1242
+ {
1243
+ throw new InvalidTimeZoneException ( SR . InvalidTimeZone_InvalidJulianDay ) ;
1182
1244
}
1245
+
1246
+ int i = 1 ;
1247
+ while ( i < days . Length && julianDay > days [ i ] )
1248
+ {
1249
+ i ++ ;
1250
+ }
1251
+
1252
+ Debug . Assert ( i > 0 && i < days . Length ) ;
1253
+
1254
+ month = i ;
1255
+ day = julianDay - days [ i - 1 ] ;
1183
1256
}
1184
1257
1185
1258
/// <summary>
0 commit comments