Search code examples
c#dicom

C#: Custom time zone format strings


I need to read the timezone offset from UTC from a custom format. This is defined per standard as:

Encoded as an ASCII string in the format "&ZZXX". The components of this string, from left to right, are & = "+" or "-", and ZZ = Hours and XX = Minutes of offset. Leading space characters shall not be present.

The offset for UTC shall be +0000; -0000 shall not be used.

I fail to understand how I can use any of the modifiers in my case to read this format (and only this format):

So far I have:

bool isValidTimezoneOffsetFromUTC(string timezoneOffsetFromUTC)
{
    try
    {
        DateTimeOffset.ParseExact(timezoneOffsetFromUTC, "%K", CultureInfo.InvariantCulture);
        if (timezoneOffsetFromUTC.Length != 5 || timezoneOffsetFromUTC == "-0000") return false;
        return true;
    }
    catch (ArgumentNullException)
    {

    }
    catch (FormatException)
    {

    }
    return false;
}

Which seems overly complex...is there a way to simplify this code without external dependencies ?


Solution

  • +0000 is an offset, not full datetime and timezone offset. As the name explains, DateTimeOffset is used for a full datetime with offset. A valid value would be 2021-09-06T 15:36:49 +00:00 or 2021-09-06T15:36:49+00:00, not just +00:00

    The type used to specify offsets is TimeSpan. Parsing a custom timespan format is done using TimeSpan.ParseExact. The method TryParseExact is used to parse without throwing :

    var input="-0430";
    var formats=new[]{"\\+hhmm","\\-hhmm"};
    Console.WriteLine(TimeSpan.TryParseExact(input,
                                     formats, 
                                     CultureInfo.InvariantCulture, 
                                     out var result));
    -----
    True
    

    This method returns true if the value is valid. The parsed value is returned through the result output parameter.

    TimeSpan.ParseExact and TryParseExact don't parse negative timestamps, so two different formats are used, one for positive and one for negative offsets. In these formats the sign is used as a literal character that must appear in the input.

    The method can be rewritten as:

    const string[] formats=new[]{"\\+hhmm","\\-hhmm"};
    
    bool isValidTimezoneOffsetFromUTC(string timezoneOffsetFromUTC)
    {
    return TimeSpan.TryParseExact(timezoneOffsetFromUTC,
                  formats,
                  CultureInfo.InvariantCulture, 
                  out var result);
    }
    

    Update

    Discarding -0000 only needs a simple equality check :

    static readonly string[] formats=new[]{"\\+hhmm","\\-hhmm"};
    
    bool isValidTimezoneOffsetFromUTC(string offset)
    {
        if (offset=="-0000")
        {
            return false;
        }
        
        return TimeSpan.TryParseExact(s,
                  formats,
                  CultureInfo.InvariantCulture, 
                  out var result);
    }
    

    Using pattern matching this can become an expression-bodied method :

    static readonly string[] formats=new[]{"\\+hhmm","\\-hhmm"};
    
    bool isValidDicomOffset(string offset)=>
        offset switch 
        {
           "-0000"=>false,
           string s=> TimeSpan.TryParseExact(offset,
                          formats,
                          CultureInfo.InvariantCulture, 
                          out var result)
        };