سؤال

I'm trying to write a XML parser for TV Schedule Pro (http://sourceforge.net/p/tvschedulerpro). One particular challenge is in Parsing the DateTime reported by the date elements.

According to the DTD file:

All dates and times in this DTD follow the same format, loosely based on ISO 8601. They can be 'YYYYMMDDhhmmss' or some initial substring, for example if you only know the year and month you can have 'YYYYMM'. You can also append a timezone to the end; if no explicit timezone is given, UTC is assumed. Examples: '200007281733 BST', '200209', '19880523083000 +0300'. (BST == +0100.)

This is challenging situation, where I initially thought about using DateTimeFormatInfo.GetAllDateTimePatterns and using DateTime.TryParseExact, the last line about the timezones and particular format with any delimiters make it impossible to use the above.

Is there a concise way to parse the above datetime specification or does one just need to keeping finding/adding various patterns to parse the strings as one finds them (looks like virtually endless combinations)

هل كانت مفيدة؟

المحلول

Well, you could probably do something like this, using the K format specifier (see Custom DateTime Format Strings for details):

public static DateTimeOffset parseIso8601CompactForm( string text )
{
  DateTimeStyles options = DateTimeStyles.AllowWhiteSpaces
                         | DateTimeStyles.AssumeLocal
                         ;
  DateTimeOffset value = DateTimeOffset.ParseExact( text , formats , CultureInfo.CurrentCulture , options ) ;
  return value ;
}
static readonly string[] formats =
{
  "yyyyMMddHHmmssK" , "yyyyMMddHHmmss" ,
  "yyyyMMddHHmmK"   , "yyyyMMddHHmm"   ,
  "yyyyMMddHHK"     , "yyyyMMddHH"     ,
  "yyyyMMddK"       , "yyyyMMdd"       ,
  "yyyyMMK"         , "yyyyMM"         ,
  "yyyyK"           , "yyyy"           ,
} ;

But you'll probably find something like this somewhat more performant:

public static DateTimeOffset parseIso8601CompactForm( string text )
{
  if ( string.IsNullOrEmpty(text) ) throw new ArgumentException("text") ;
  if ( string.Length < 4 ) throw new ArgumentException("text") ;

  int            YYYY  = text.Length >=  4 ? int.Parse(text.Substring(  0 , 4 ) ) : 1    ;
  int            MM    = text.Length >=  6 ? int.Parse(text.Substring(  4 , 2 ) ) : 1    ;
  int            DD    = text.Length >=  8 ? int.Parse(text.Substring(  6 , 2 ) ) : 1    ;
  int            hh    = text.Length >= 10 ? int.Parse(text.Substring(  8 , 2 ) ) : 0    ;
  int            mm    = text.Length >= 12 ? int.Parse(text.Substring( 10 , 2 ) ) : 0    ;
  int            ss    = text.Length >= 14 ? int.Parse(text.Substring( 12 , 2 ) ) : 0    ;
  string         tzid  = text.Length >  14 ? text.Substring(14).Trim()            : null ;
  TimeZoneInfo   tz    = TimeZoneInfo.FindSystemTimeZoneById( tzid ) ;
  DateTimeOffset value = new DateTimeOffset( YYYY , MM , DD , hh , mm , ss , tz.BaseUtcOffset ) ;
  return value ;
}

Though, I'm sure there's some oddities around dealing with the time zone/offset-from-UTC that I haven't properly considered and would have to be properly dealt with.

نصائح أخرى

Maybe try a variant of DateTime.TryParseExact(time, ["yyyyMMddHHmmss K", "yyyyMMddHHmmss zzz"] ...

Might not catch all of them, but search http://msdn.microsoft.com/en-us/library/8kb3ddd4%28v=vs.110%29.aspx#KSpecifier for more ideas.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top