Unable to parse Oracle timestamp in C#

戏子无情 提交于 2019-12-01 21:00:23
TheQ

According to https://stackoverflow.com/a/23198962/328864, there is no way to skip parts of an exact pattern, so i guess you could do something like this:

CultureInfo provider = CultureInfo.InvariantCulture;
string timestamp = "10-DEC-07 10.32.47.797201123 AM";
String format = String.Format("yy-MMM-dd hh.mm.ss.fffffff{0} tt", timestamp.Substring(26,2));

DateTime date = DateTime.ParseExact(timestamp, format, provider);
Console.WriteLine(date);

Not very pretty though.

.NET DateTime structure has a precision of tick - 100 nanoseconds - 0.0000001 of second - 7 decimal positions after the point.

Oracle TimeStamp has a precision of up to nanosecond - 0.000000001 - 9 decimal positions after the point.


That is why standard DateTime cannot store all possible oracle TimeStamps. And its parsing function simply fail on more precise string representations of TimeStamp.


So, what could be tried:

Once we started to use ODP.NET, we had to implement an extension like below:

public static T ConvertOracleValue<T>(this object value)
{
     if (value != null)
     {
          Type typeOfValue = value.GetType();

          if (typeOfValue.Namespace.Contains("Oracle.DataAccess"))
          {
              if (typeOfValue.Name.Equals("OracleTimeStamp"))
              {
                   int tempInt = 0;
                   Oracle.DataAccess.Types.OracleTimeStamp ots = (Oracle.DataAccess.Types.OracleTimeStamp)value;
                   tempInt = Int32.TryParse(ots.Millisecond.ToString("000").Substring(0, 3), out tempInt) ? tempInt : 0;
                   DateTime ret = new DateTime(ots.Year, ots.Month, ots.Day, ots.Hour, ots.Minute, ots.Second, tempInt);
                    return ConvertHelper.ConvertValue<T>(ret);
              }
              if (typeOfValue.Name.Equals("OracleTimeStampLTZ"))
              {
                    int tempInt = 0;
                    Oracle.DataAccess.Types.OracleTimeStampLTZ ots = (Oracle.DataAccess.Types.OracleTimeStampLTZ)value;
                    tempInt = Int32.TryParse(ots.Millisecond.ToString("000").Substring(0, 3), out tempInt) ? tempInt : 0;
                    DateTime ret = new DateTime(ots.Year, ots.Month, ots.Day, ots.Hour, ots.Minute, ots.Second, tempInt);
                    return ConvertHelper.ConvertValue<T>(ret);
              }
              if (typeOfValue.Name.Equals("OracleTimeStampTZ"))
              {
                    int tempInt = 0;
                    Oracle.DataAccess.Types.OracleTimeStampTZ ots = (Oracle.DataAccess.Types.OracleTimeStampTZ)value;
                    tempInt = Int32.TryParse(ots.Millisecond.ToString("000").Substring(0, 3), out tempInt) ? tempInt : 0;
                    DateTime ret = new DateTime(ots.Year, ots.Month, ots.Day, ots.Hour, ots.Minute, ots.Second, tempInt);
                    return ConvertHelper.ConvertValue<T>(ret);
              }

              string temp = value.ToString();
              return ConvertHelper.ConvertValue<T>(temp);
          }
      }
      else
      {
           return default(T);
      }

      return ConvertHelper.ConvertValue<T>(value);
}

where ConvertHelper.ConvertValue is another extension:

public static class ConvertHelper
    {
        public static T ConvertValue<T>(object value)
        {
            Type typeOfT = typeof(T);
            if (typeOfT.BaseType != null && typeOfT.BaseType.ToString() == "System.Enum")
            {
                return (T)Enum.Parse(typeOfT, Convert.ToString(value));
            }
            if ((value == null || value == Convert.DBNull) && (typeOfT.IsValueType))
            {
                return default(T);
            }
            if (value is IConvertible)
            {
                return (T)Convert.ChangeType(value, typeOfT, new CultureInfo("en-GB"));
            }

            return (T)Convert.ChangeType(value, typeOfT);
        }
}

This worked like a charm in our test, integration and production environments.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!