@@ -28,32 +28,94 @@ namespace Org.XmlUnit.Placeholder
2828 /// <para>
2929 /// since 2.8.0
3030 /// </para>
31+ /// <para>
32+ /// The first optional argument is the date/time pattern, the second optional
33+ /// argument is the culture used to parse it, given as a culture name (for example
34+ /// <c>de</c> or <c>fr-FR</c>). When no culture is given <see cref="CultureInfo.InvariantCulture"/>
35+ /// is used.
36+ /// </para>
3137 /// </remarks>
3238 public class IsDateTimePlaceholderHandler : IPlaceholderHandler
3339 {
3440 private const string _keyword = "isDateTime" ;
3541
42+ private static readonly IEnumerable < string > _isoPatterns = new List < string >
43+ {
44+ "yyyy-MM-dd" ,
45+ "yyyy-MM-ddTHH:mm" ,
46+ "yyyy-MM-ddTHH:mm:ss" ,
47+ "yyyy-MM-ddTHH:mm:ss.fff" ,
48+ "yyyy-MM-ddTHH:mm:ssK" ,
49+ "yyyy-MM-ddTHH:mm:ss.fffK" ,
50+ "yyyy-MM-dd HH:mm" ,
51+ "yyyy-MM-dd HH:mm:ss" ,
52+ "yyyy-MM-dd HH:mm:ss.fff" ,
53+ "yyyy-MM-dd HH:mm:ssK" ,
54+ "yyyy-MM-dd HH:mm:ss.fffK"
55+ } ;
56+
3657 /// <inheritdoc/>
3758 public string Keyword { get { return _keyword ; } }
3859
3960 /// <inheritdoc/>
61+ /// <remarks>
62+ /// <para>
63+ /// When <paramref name="args"/> contains one element, it is used as the date/time pattern
64+ /// and <see cref="CultureInfo.InvariantCulture"/> is used for parsing.
65+ /// </para>
66+ /// <para>
67+ /// When <paramref name="args"/> contains two elements, the first is used as the date/time
68+ /// pattern and the second as the culture name for parsing.
69+ /// </para>
70+ /// <para>
71+ /// When no arguments are provided, the method tries to parse the text using ISO patterns
72+ /// with <see cref="CultureInfo.InvariantCulture"/>.
73+ /// </para>
74+ /// </remarks>
4075 public ComparisonResult Evaluate ( string testText , params string [ ] args )
4176 {
42- if ( args != null && args . Length == 1 ) {
43- return CanParse ( args [ 0 ] , testText )
77+ if ( args != null && args . Length >= 1 ) {
78+ var culture = args . Length >= 2 && ! string . IsNullOrEmpty ( args [ 1 ] )
79+ ? new CultureInfo ( args [ 1 ] )
80+ : CultureInfo . InvariantCulture ;
81+ return CanParse ( args [ 0 ] , testText , culture )
4482 ? ComparisonResult . EQUAL
4583 : ComparisonResult . DIFFERENT ;
4684 }
47- DateTime _ ;
48- var result = DateTime . TryParse ( testText , out _ ) ;
49- return result
85+ return CanParse ( testText )
5086 ? ComparisonResult . EQUAL
5187 : ComparisonResult . DIFFERENT ;
5288 }
5389
54- private bool CanParse ( string pattern , string testText ) {
90+ private bool CanParse ( string testText ) {
91+ if ( string . IsNullOrEmpty ( testText ) ) {
92+ return false ;
93+ }
94+ // Try locale-aware short date and datetime formats with current culture
95+ if ( CanParseWithCurrentCulture ( testText ) ) {
96+ return true ;
97+ }
98+ // Try all ISO patterns with InvariantCulture
99+ foreach ( var pattern in _isoPatterns ) {
100+ if ( CanParse ( pattern , testText , CultureInfo . InvariantCulture ) ) {
101+ return true ;
102+ }
103+ }
104+ return false ;
105+ }
106+
107+ private bool CanParseWithCurrentCulture ( string testText ) {
108+ DateTime result ;
109+ // Try short date format
110+ if ( DateTime . TryParse ( testText , out result ) ) {
111+ return true ;
112+ }
113+ return false ;
114+ }
115+
116+ private bool CanParse ( string pattern , string testText , CultureInfo culture ) {
55117 try {
56- var _ = DateTime . ParseExact ( testText , pattern , CultureInfo . InvariantCulture ) ;
118+ var _ = DateTime . ParseExact ( testText , pattern , culture ) ;
57119 return true ;
58120 } catch ( FormatException ) {
59121 return false ;
0 commit comments