C# Parse DateTime into specific Timezone If Offset isn't supplied - Stack Overflow

admin2025-05-01  2

I have a utility method that attempts to parse a datetime string into a datetime. A portion of it is below.

if (dateTime is { Kind: DateTimeKind.Unspecified, TimeOfDay.Ticks: > 0 })
{
    var cst = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
    dateTime = TimeZoneInfo.ConvertTimeToUtc(dateTime, cst);
}
return dateTime.ToUniversalTime();

sometimes the strings were trying to parse do not have a timezone offset specified. But they are implicitly Central Standard Times. For example this string value "20241010091157" should be 10/10/2024 09:11:57 CST. My utility method attempts to set the timezone for datetimes that don't have a kind specified but sill have time values.

The following unit test passes when I run locally on a machine in CST time zone but fails when I run on the build agent.

message.PV1.AdmitDateTime.Time.Value = "20241010091157";

var hl7DateTime = hl7Utils.GetHl7DateTimeUtc(message.PV1.AdmitDateTime);
Assert.IsNotNull(hl7DateTime);
Assert.AreEqual(2024, hl7DateTime.Value.Year);
Assert.AreEqual(10, hl7DateTime.Value.Month);
Assert.AreEqual(10, hl7DateTime.Value.Day);
Assert.AreEqual(14, hl7DateTime.Value.Hour);
Assert.AreEqual(11, hl7DateTime.Value.Minute);
Assert.AreEqual(57, hl7DateTime.Value.Second);
Assert.AreEqual(hl7DateTime.Value.Kind, DateTimeKind.Utc);

This assertion fails on the build agent: Assert.AreEqual(14, hl7DateTime.Value.Hour);

Assert.AreEqual failed. Expected:<14>. Actual:<4>

what is the right way to parse a string into a datetime and default the timezone if its not provided in the parsed string?

I have a utility method that attempts to parse a datetime string into a datetime. A portion of it is below.

if (dateTime is { Kind: DateTimeKind.Unspecified, TimeOfDay.Ticks: > 0 })
{
    var cst = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
    dateTime = TimeZoneInfo.ConvertTimeToUtc(dateTime, cst);
}
return dateTime.ToUniversalTime();

sometimes the strings were trying to parse do not have a timezone offset specified. But they are implicitly Central Standard Times. For example this string value "20241010091157" should be 10/10/2024 09:11:57 CST. My utility method attempts to set the timezone for datetimes that don't have a kind specified but sill have time values.

The following unit test passes when I run locally on a machine in CST time zone but fails when I run on the build agent.

message.PV1.AdmitDateTime.Time.Value = "20241010091157";

var hl7DateTime = hl7Utils.GetHl7DateTimeUtc(message.PV1.AdmitDateTime);
Assert.IsNotNull(hl7DateTime);
Assert.AreEqual(2024, hl7DateTime.Value.Year);
Assert.AreEqual(10, hl7DateTime.Value.Month);
Assert.AreEqual(10, hl7DateTime.Value.Day);
Assert.AreEqual(14, hl7DateTime.Value.Hour);
Assert.AreEqual(11, hl7DateTime.Value.Minute);
Assert.AreEqual(57, hl7DateTime.Value.Second);
Assert.AreEqual(hl7DateTime.Value.Kind, DateTimeKind.Utc);

This assertion fails on the build agent: Assert.AreEqual(14, hl7DateTime.Value.Hour);

Assert.AreEqual failed. Expected:<14>. Actual:<4>

what is the right way to parse a string into a datetime and default the timezone if its not provided in the parsed string?

Share Improve this question edited Jan 3 at 20:13 Soner Gönül 99k103 gold badges222 silver badges373 bronze badges asked Jan 2 at 22:07 cobolstinkscobolstinks 7,16118 gold badges73 silver badges105 bronze badges 5
  • The basic .NET time zone handling tools run out of capabilities pretty quickly. You may want to investigate Noda Time nodatime.org – Flydog57 Commented Jan 2 at 22:21
  • 1 Please share a minimal reproducible example. – mjwills Commented Jan 2 at 22:35
  • 2 If some string values include a timezone component while others do not, and you want to default those to CST, then you could just check the string for the timezone component and if not found, append the CST timezone to the string before parsing. – Steve Py Commented Jan 2 at 22:41
  • Please share the code that converts your input string to a DateTime. Are you sure the code returns the expected timestamp and DateTimeKind? – Michael Liu Commented Jan 2 at 23:00
  • where is your machine running this? Is it in UTC+5? Perhaps the if (...) {...}isn't correctly run, and .ToUniversalTime(); actually just tried to use local machine time instead. You can use debugger to find out. But the full parser as asked by Michael Liu is needed too. – Peko Miko Commented Jan 3 at 1:58
Add a comment  | 

1 Answer 1

Reset to default 0

So the issue turns out to be that we were using a library to parse the string into a date time. Its built into NHapi which is used for hl7 processing.

This is the libraries parse method.

 public virtual DateTime GetAsDate()
 {
     try
     {
         var dateFormats = new string[] { LongDateTimeFormat, ShortDateTimeFormat, LongDateTimeFormatWithSecond, LongDateTimeFormatWithOffset, LongDateTimeFormatWithFractionOfSecond };
         var val = DateTime.MinValue;
         var culture = Thread.CurrentThread.CurrentCulture;
         if (Value != null && Value.Length > 0)
         {
             val = DateTime.ParseExact(Value, dateFormats, culture, DateTimeStyles.NoCurrentDateDefault);
         }

         return val;
     }
     catch (Exception)
     {
         throw new HL7Exception("Could not get field as dateTime");
     }
 }

I left out my utility methods invocation of the method above, my util method looked like this:

public DateTime? GetHl7DateTimeUtc(TS? ts)
{
   if (ts is not { Time: not null } || ts.Time.GetAsDate() == DateTime.MinValue)
    {
       return null;
    }
 var dateTime = ts.Time.GetAsDate();
 if (dateTime is { Kind: DateTimeKind.Unspecified, TimeOfDay.Ticks: > 0 })
    {
        var cst = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
        dateTime = TimeZoneInfo.ConvertTimeToUtc(dateTime, cst);
    }
   return dateTime.ToUniversalTime();
}

So the library was using Thread.CurrentThread.CurrentCulture;

My solution was to avoid using the library method to parse the string into a dateTime and just roll that code myself. Here is my utility method that works:

public DateTime? GetHl7DateTimeUtc(TS? ts)
{
    if (ts is not { Time: not null } || ts.Time.GetAsDate() == DateTime.MinValue)
    {
        return null;
    }

    var dateFormats = new[]
    {
        "yyyyMMddHHmmss.FFFF", "yyyyMMddHHmmsszzz", "yyyyMMddHHmmss", "yyyyMMddHHmm", "yyyyMMdd",
        "yyyyMMddHHmmss-zzzz"
    };

    var dateTime = DateTime.ParseExact(ts.Time.Value, dateFormats, CultureInfo.InvariantCulture,
        DateTimeStyles.NoCurrentDateDefault);

    if (dateTime is { Kind: DateTimeKind.Unspecified, TimeOfDay.Ticks: > 0 })
    {
        var cst = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
        dateTime = TimeZoneInfo.ConvertTimeToUtc(dateTime, cst);
    }

    return dateTime.ToUniversalTime();
}

This method correctly parses string dateTimes both on my machine and on ADO agents. It also defaults the timezone to Central Standard Time if its not provided. Hamid was on the right track I'll accept his answer.

转载请注明原文地址:http://anycun.com/QandA/1746094813a91591.html