using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
public static class PoorlyDesignedDateFormat {
private static readonly Dictionary<string, TimeZoneInfo> CodesToReferenceZones = new Dictionary<string, TimeZoneInfo>
{ "ET", TimeZoneInfo.FindSystemTimeZoneById("America/New_York") },
{ "CT", TimeZoneInfo.FindSystemTimeZoneById("America/Chicago") },
{ "MT", TimeZoneInfo.FindSystemTimeZoneById("America/Denver") },
{ "PT", TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles") },
private static readonly Regex PatternForWonkeyFormatUseDInOurTests = new Regex(
@"([0-1][0-9]):([0-5][0-9])([AaPp][Mm]) ([aA-zZ]{2}) ([A-Z][a-z]{2})-([0-3][0-9]) ([0-9]{4})");
private static readonly string IntermediaryFormat = "hh:mmtt 'TZC' MMM-dd yyyy";
public static (DateTimeOffset, TimeZoneInfo) Parse(string rawValue)
var match = PatternForWonkeyFormatUseDInOurTests.Match(rawValue);
throw new ArgumentException("String not in the poorly designed format");
var hours = Int32.Parse(match.Groups[1].Value);
var minutes = Int32.Parse(match.Groups[2].Value);
var amPM = match.Groups[3].Value.ToUpper();
var twoCharTz = match.Groups[4].Value.ToUpper();
var threeCharMonth = match.Groups[5].Value;
var dayOfMonth = Int32.Parse(match.Groups[6].Value);
var year = match.Groups[7].Value;
var referenceTimezone = CodesToReferenceZones[twoCharTz];
var intermediaryFormattedValue = string.Format(
"{0:D2}:{1:D2}{2} TZC {3}-{4:D2} {5}", hours, minutes,amPM,threeCharMonth, dayOfMonth, year);
var parsedDate = DateTime.ParseExact(
intermediaryFormattedValue,
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeLocal);
var unspecifiedDT = DateTime.SpecifyKind(parsedDate, DateTimeKind.Unspecified);
var dateTimeWithOffset = TimeZoneInfo.ConvertTime(
new DateTimeOffset(unspecifiedDT, referenceTimezone.GetUtcOffset(unspecifiedDT)), referenceTimezone);
return (dateTimeWithOffset, referenceTimezone);
public static string Format(DateTime dateValue, TimeZoneInfo tzInfo) => Format(TimeZoneInfo.ConvertTime(new DateTimeOffset(dateValue, TimeSpan.Zero), tzInfo));
public static string Format(DateTimeOffset dateValue) => Format(dateValue.DateTime, dateValue.Offset);
public static string Format(DateTime dateValue, TimeSpan utcOffset)
var ambigiousCodeToUse = CodesToReferenceZones
.First(kvPair => kvPair.Value.GetUtcOffset(dateValue) == utcOffset)
return dateValue.ToString(IntermediaryFormat)
.Replace("TZC", ambigiousCodeToUse)
public static void WriteOutParseInfo(string sourceDateTimeString)
var (dateTime, timeZone) = PoorlyDesignedDateFormat.Parse(sourceDateTimeString);
Console.WriteLine($"\n\tFormatted Date: {sourceDateTimeString}\t\n\tDate: {dateTime.ToString()}\n\tTimeZone: {timeZone.DisplayName}");
public static void WriteOutFormatInfo(DateTime utcDate, TimeZoneInfo targetTimeZone)
var formattedString = PoorlyDesignedDateFormat.Format(utcDate, targetTimeZone);
var dateInZone = TimeZoneInfo.ConvertTime(
new DateTimeOffset(utcDate, TimeSpan.Zero), targetTimeZone);
Console.WriteLine($"\n\tUtcDate: {utcDate.ToString()}\n\tZone:{targetTimeZone.DisplayName}\n\tDate In Targe TimeZone: {dateInZone.ToString()}\n\tFormattedDate: {formattedString}");
public static void WriteOutRoundTrip(string sourceDateTimeString)
var (dateTime, timeZone) = PoorlyDesignedDateFormat.Parse(sourceDateTimeString);
var reformattedDateTime = PoorlyDesignedDateFormat.Format(dateTime);
Console.WriteLine($"\n\tSourceDateTime: {sourceDateTimeString}\n\tParsedDateTime: {dateTime}\n\tFormattedDateTime: {reformattedDateTime}");
public static void Main()
Console.WriteLine("Going from the bad format to DateTimeOffset w/TimeZone looks like:\n");
WriteOutParseInfo("12:01am PT Jan-01 2001");
WriteOutParseInfo("12:01am PT Jul-01 2001");
WriteOutParseInfo("12:01am MT Jan-01 2001");
WriteOutParseInfo("12:01am MT Jul-01 2001");
Console.WriteLine("\n\nGoing the other way looks like\n");
var azTimezone = TimeZoneInfo.FindSystemTimeZoneById("America/Phoenix");
var janRefDateUTC = DateTime.SpecifyKind(DateTime.Parse("2021-01-01T07:00:00.0000000Z"), DateTimeKind.Unspecified);
var julRefDateUTC = DateTime.SpecifyKind(DateTime.Parse("2021-07-01T07:00:00.0000000Z"), DateTimeKind.Unspecified);
WriteOutFormatInfo(janRefDateUTC, azTimezone);
WriteOutFormatInfo(julRefDateUTC, azTimezone);
Console.WriteLine("\n\nThe full round trip looks like\n");
WriteOutRoundTrip("12:01am PT Jan-01 2001");
WriteOutRoundTrip("12:01am PT Jul-01 2001");