OdraEncoded

String to TimeSpan parsing

Sep 11th, 2012
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 5.22 KB | None | 0 0
  1. public static bool TryParseTime(string input, out TimeSpan result)
  2. {
  3.     const int maxUnitCount = 4;
  4.    
  5.     input = input.Trim( );
  6.  
  7.     result = new TimeSpan();
  8.  
  9.     if( string.IsNullOrEmpty( input ) ) // This makes easier to undo
  10.         return false;
  11.    
  12.     bool hasLeftSymbol; // This is a "+" or '-" symbol
  13.     bool isNegative; // ...or is it?
  14.     bool hasHours, hasMinutes, hasSeconds, hasMilli;
  15.     hasLeftSymbol = isNegative =
  16.         hasHours = hasMinutes = hasSeconds = hasMilli = false;
  17.  
  18.     int hoursIndex, minutesIndex, secondsIndex, milliIndex;
  19.     hoursIndex = minutesIndex = secondsIndex = milliIndex = -1;
  20.  
  21.     int hoursVal, minutesVal, secondsVal, milliVal;
  22.     hoursVal = minutesVal = secondsVal = milliVal = 0;
  23.  
  24.     bool knowSeparatorType, usesAbbreviations;
  25.     knowSeparatorType = usesAbbreviations = false;
  26.  
  27.     int unitCount = 0;
  28.     string[] manyUnitStrings = new string[maxUnitCount];
  29.    
  30.     for(int i = 0; i < input.Length;)
  31.     {
  32.         if(char.IsDigit(input[i]))
  33.         {
  34.             if(unitCount == maxUnitCount)
  35.                 return false;
  36.            
  37.             string timeUnit = "";
  38.  
  39.             do // Bet ya haven't seen one of these in a _while_
  40.             {
  41.                 timeUnit += input[i];
  42.                 i++;
  43.             } while(i < input.Length && char.IsDigit(input[i]));
  44.  
  45.             manyUnitStrings[unitCount] = timeUnit;
  46.             unitCount++;
  47.         }
  48.         else
  49.         {
  50.             string nonDigitPart = "";
  51.            
  52.             do
  53.             {
  54.                 nonDigitPart += input[i];
  55.                 i++;
  56.             } while(i < input.Length && !char.IsDigit(input[i]));
  57.            
  58.             nonDigitPart = nonDigitPart.Trim().ToLowerInvariant();
  59.  
  60.             if(unitCount == 0)
  61.             {
  62.                 if(!hasLeftSymbol)
  63.                 {
  64.                     isNegative = nonDigitPart == "-";
  65.  
  66.                     if(isNegative) hasLeftSymbol = true;
  67.                     else if(nonDigitPart == "+") hasLeftSymbol = true;
  68.                     else return false;
  69.                 }
  70.                 else return false;
  71.  
  72.                 continue;
  73.             }
  74.  
  75.             if(!knowSeparatorType)
  76.             {
  77.                 // Clearly, this will fail to check non valid separators.
  78.                 // Those are handled next.
  79.                 usesAbbreviations = !(nonDigitPart == ":" || nonDigitPart == ".");
  80.                 knowSeparatorType = true;
  81.             }
  82.            
  83.             if(usesAbbreviations)
  84.             {
  85.                 // While using abbreviations, order doesn't matter
  86.                 if(!hasHours && nonDigitPart == "h")
  87.                 {
  88.                     hasHours = true;
  89.                     hoursIndex = unitCount - 1;
  90.                 }
  91.                 else if(!hasMinutes && nonDigitPart == "m")
  92.                 {
  93.                     hasMinutes = true;
  94.                     minutesIndex = unitCount - 1;
  95.                 }
  96.                 else if(!hasSeconds && nonDigitPart == "s")
  97.                 {
  98.                     hasSeconds = true;
  99.                     secondsIndex = unitCount - 1;
  100.                 }
  101.                 else if(!hasMilli && nonDigitPart == "ms")
  102.                 {
  103.                     hasMilli = true;
  104.                     milliIndex = unitCount - 1;
  105.                 }
  106.                 else return false;
  107.             }
  108.             else
  109.             {
  110.                 // There are no separators at the end of the string.
  111.                 // What would they separate if there were?
  112.                 if(i == input.Length)
  113.                     return false;
  114.  
  115.                 if(nonDigitPart == ":" && !(hasHours && hasMinutes))
  116.                 {
  117.                     // The format is invalid if the "." separators comes
  118.                     // before the ":" separator.
  119.                     if(hasMilli)
  120.                         return false;
  121.  
  122.                     if(!hasMinutes) hasMinutes = true;
  123.                     else hasHours = true;
  124.                 }
  125.                 else if(nonDigitPart == "." && !hasMilli)
  126.                 {
  127.                     hasMilli = true;
  128.                 }
  129.                 else return false;
  130.             }
  131.         }
  132.     }
  133.  
  134.     if(unitCount == 0)
  135.         return false;
  136.  
  137.     // If there are neither separators or abbreviations
  138.     // The program implies they are all seconds.
  139.     if(!knowSeparatorType) // Implicit unitCount == 1
  140.     {
  141.         hasSeconds = true;
  142.         usesAbbreviations = false;
  143.     }
  144.  
  145.     if(!usesAbbreviations)
  146.     {
  147.         hasSeconds = true; // This is always true in this case.
  148.  
  149.         // Infer unit positioning from separator order here.
  150.         if(hasHours) hoursIndex = 0;
  151.         if(hasMinutes) minutesIndex = hasHours ? hoursIndex + 1 : 0;
  152.         if(hasSeconds) secondsIndex = hasMinutes ? minutesIndex + 1 : 0;
  153.         if(hasMilli) milliIndex = secondsIndex + 1;
  154.     }
  155.  
  156.     for(int i = 0; i < unitCount; i++)
  157.     {
  158.         int unitVal;
  159.         string unitString = manyUnitStrings[i];
  160.  
  161.         if(!usesAbbreviations)
  162.         {
  163.             if(i == milliIndex)
  164.             {
  165.                 if(unitString.Length > 3)
  166.                     return false;
  167.                
  168.                 unitString = unitString.PadRight(3, '0');
  169.             }
  170.  
  171.             if(i != 0 && (i == secondsIndex || i == minutesIndex))
  172.             {
  173.                 if(unitString.Length != 2)
  174.                     return false;
  175.             }
  176.         }
  177.  
  178.         // Even though the string is all digits, that won't prevent overflow errors
  179.         if(!int.TryParse(unitString, out unitVal))
  180.             return false;
  181.  
  182.         int maxUnitValue;
  183.         if(i == milliIndex)
  184.         {
  185.             milliVal = unitVal;
  186.  
  187.             if(hasSeconds || hasMinutes || hasHours)
  188.                 maxUnitValue = 999;
  189.             // One week worth of milliseconds
  190.             else maxUnitValue = 7 * 24 * 60 * 60 * 1000;
  191.         }
  192.         else if (i == secondsIndex)
  193.         {
  194.             secondsVal = unitVal;
  195.  
  196.             if(hasMinutes || hasHours)
  197.                 maxUnitValue = 59;
  198.             else maxUnitValue = 7 * 24 * 60 * 60;
  199.         }
  200.         else if(i == minutesIndex)
  201.         {
  202.             minutesVal = unitVal;
  203.  
  204.             if(hasHours)
  205.                 maxUnitValue = 59;
  206.             else maxUnitValue = 7 * 24 * 60;
  207.         }
  208.         else if(i == hoursIndex)
  209.         {
  210.             hoursVal = unitVal;
  211.  
  212.             maxUnitValue = 7 * 24; // Hours are only capped to a week
  213.         }
  214.         else return false; // This supposedly never happens though.
  215.  
  216.         if(unitVal > maxUnitValue)
  217.             return false;
  218.     }
  219.  
  220.     result = new TimeSpan(0, hoursVal, minutesVal, secondsVal, milliVal);
  221.  
  222.     if(result > new TimeSpan(7, 0, 0, 0, 0))
  223.         return false;
  224.  
  225.     if(isNegative) result = result.Negate();
  226.  
  227.     return true;
  228. }
Advertisement
Add Comment
Please, Sign In to add comment