77using Ical . Net . Utility ;
88using NodaTime ;
99using System ;
10+ using System . Diagnostics . CodeAnalysis ;
1011using System . Globalization ;
1112using System . IO ;
1213
@@ -55,6 +56,7 @@ public sealed class CalDateTime : IComparable<CalDateTime>, IFormattable
5556 /// <summary>
5657 /// This constructor is required for the SerializerFactory to work.
5758 /// </summary>
59+ [ ExcludeFromCodeCoverage ]
5860 private CalDateTime ( )
5961 {
6062 // required for the SerializerFactory to work
@@ -201,9 +203,15 @@ public CalDateTime(string value, string? tzId = null)
201203 {
202204 var serializer = new DateTimeSerializer ( ) ;
203205 CopyFrom ( serializer . Deserialize ( new StringReader ( value ) ) as CalDateTime
204- ?? throw new InvalidOperationException ( $ "$Failure for deserializing value '{ value } '") ) ;
206+ ?? throw new InvalidOperationException ( $ "$Failure when deserializing value '{ value } '") ) ;
207+
205208 // The string may contain a date only, meaning that the tzId should be ignored.
206- _tzId = HasTime ? tzId : null ;
209+ _tzId ??= HasTime ? tzId : null ;
210+
211+ if ( IsUtc && tzId != null && ! string . Equals ( tzId , UtcTzId , StringComparison . OrdinalIgnoreCase ) )
212+ {
213+ throw new ArgumentException ( $ "The value '{ value } ' is a UTC date/time, but the specified timezone '{ tzId } ' is not '{ UtcTzId } '.", nameof ( tzId ) ) ;
214+ }
207215 }
208216
209217 private void Initialize ( DateOnly dateOnly , TimeOnly ? timeOnly , string ? tzId )
@@ -218,7 +226,6 @@ private void Initialize(DateOnly dateOnly, TimeOnly? timeOnly, string? tzId)
218226 } ;
219227 }
220228
221- /// <inheritdoc/>
222229 private void CopyFrom ( CalDateTime calDt )
223230 {
224231 // Maintain the private date/time backing fields
@@ -436,12 +443,6 @@ public DateTime Value
436443 return new TimeOnly ( time . Value . Hour , time . Value . Minute , time . Value . Second ) ;
437444 }
438445
439- /// <summary>
440- /// Any <see cref="Time"/> values are truncated to seconds, because
441- /// RFC 5545, Section 3.3.5 does not allow for fractional seconds.
442- /// </summary>
443- private static TimeOnly ? TruncateTimeToSeconds ( DateTime dateTime ) => new TimeOnly ( dateTime . Hour , dateTime . Minute , dateTime . Second ) ;
444-
445446 /// <summary>
446447 /// Converts the <see cref="Value"/> to a date/time
447448 /// within the specified <see paramref="otherTzId"/> timezone.
0 commit comments