Search code examples
c#csvdelimiterfilehelpers

hot to parse csv time in this format 06:00:00;00?


I have csv and reading it per line so I can save it in the DB. I am using filehelper to separate each by comma delimiter but ignore those that are inside "". It is throwing exception coz of the data 06:00:00;00. I am not sure what is that. How do I parse that? Is that timespan but why does it have extra 00 after the ;? Sorry the data was just given to me and nothing was explained about what it is for.

Here is the actual data from a text file.

01/10/2013,06:00:00;00,06:09:40;08,00:09:40:09,01/10/2013,06:00:00;00,06:09:40;08,00:09:40:09,"January 9, 2013 - Dreams_01.mp4",Aired,7CFB84BD-A5B6-43E8-82EC-E78E7219B1C7

Is there a converter for filhelper for that? I have used [FieldConverter(ConverterKind.Date, "dd/MM/yyyy")] for the date but I am not sure about the time.


Solution

  • You can provide your own FieldConverter which gives you the ability to add whatever logic you decide is necessary. It looks like your data is not very strictly structured, so you might have to play around quite a bit, but here's a working program which handles the first few fields:

    [DelimitedRecord(",")]
    public partial class MyClass
    {
        [FieldConverter(ConverterKind.Date, "dd/MM/yyyy")]
        public DateTime Date;
        [FieldConverter(typeof(MyTimeConverter))]
        public DateTime Time1;
        [FieldConverter(typeof(MyTimeConverter))]
        public DateTime Time2;
        [FieldConverter(typeof(MyTimeConverter))]
        public DateTime Time3;
        [FieldConverter(ConverterKind.Date, "dd/MM/yyyy")]
        public DateTime Time4;
        [FieldDelimiter("|")] // ignore the rest of the fields for this example
        public string Optional3;
    }      
    
    class Program
    {
        private static void Main(string[] args)
        {
            var engine = new FileHelperEngine<MyClass>();
            var records = engine.ReadString(@"01/10/2013,06:00:00;00,06:09:40;08,00:09:40:09,01/10/2013,06:00:00;00,06:09:40;08,00:09:40:09,""January 9, 2013 - Dreams_01.mp4"",Aired,7CFB84BD-A5B6-43E8-82EC-E78E7219B1C7");
            Assert.AreEqual(records[0].Date, new DateTime(2013, 10, 1));
            Assert.AreEqual(records[0].Time1, DateTime.MinValue.Date.Add(new TimeSpan(0, 6, 0, 0)));
            Assert.AreEqual(records[0].Time2, DateTime.MinValue.Date.Add(new TimeSpan(0, 6, 9, 40, 08)));
            Assert.AreEqual(records[0].Time3, DateTime.MinValue.Date.Add(new TimeSpan(0, 0, 9, 40, 09)));
        }
    }
    
    public class MyTimeConverter : ConverterBase
    {
        public override string FieldToString(object from)
        {
            return base.FieldToString(from);
        }
    
        public override object StringToField(string from)
        {
            /// apply any logic to clear up the input here
            /// for instance, split the string at any ';' or ':'
            var parts = from
                .Split(';', ':')
                .Select(x => Convert.ToInt32(x))
                .ToList();
    
            // if it has three parts assume there are no milliseconds
            if (parts.Count == 3)
                return DateTime.MinValue.Date.Add(new TimeSpan(0, parts[0], parts[1], parts[3]));
            else if (parts.Count == 4) // if it has four parts include milliseconds
                return DateTime.MinValue.Date.Add(new TimeSpan(0, parts[0], parts[1], parts[2], parts[3]));
            throw new Exception("Unexpected format");
        }
    }
    

    You can see I've implemented a MyTimeConverter. (The DateTime.MinValue.Date.Add(new TimeSpan()) is the best way I know of to create a DateTime with an empty Date part.)