5

我正在尝试从以“jira time notation”输入的用户输入中提取分钟数。

例如,我想实现以下结果

  • 输入:“30m”/输出:30
  • 输入:“1h 20m”/输出:80
  • 输入:“3h”/输出 180

从研究中,我找到了 TimeSpan.ParseExact 但我不知道如何使用它来实现我所需要的。

所有帮助将不胜感激。

到目前为止我的代码:

public static int TextToMins(string TimeText)
    {
        CultureInfo culture = new CultureInfo("en-IE");
        string[] formats = { "What goes here?" };
        TimeSpan ts = TimeSpan.ParseExact(TimeText.Trim().ToLower(), formats, culture);
        return Convert.ToInt32(ts.TotalMinutes);
    }
4

5 回答 5

3

我可能会做这样的事情并避免使用 Timespan 的内置解析,因为每 [工作] 周的天数和每 [工作] 天的 [工作] 小时数是 Jira 中的可配置值(在我们的系统上,它们被配置为每周 5 天和每天 8 小时。)

class JiraTimeDurationParser
{

  /// <summary>
  /// Jira's configured value for [working] days per week ;
  /// </summary>
  public ushort DaysPerWeek     { get ; private set ; }

  /// <summary>
  /// Jira's configured value for [working] hours per day
  /// </summary>
  public ushort HoursPerDay     { get ; private set ; }

  public JiraTimeDurationParser( ushort daysPerWeek = 5 , ushort hoursPerDay = 8 )
  {
    if ( daysPerWeek < 1 || daysPerWeek >  7 ) throw new ArgumentOutOfRangeException( "daysPerWeek"  ) ;
    if ( hoursPerDay < 1 || hoursPerDay > 24 ) throw new ArgumentOutOfRangeException( "hoursPerDay"  ) ;

    this.DaysPerWeek = daysPerWeek ;
    this.HoursPerDay = hoursPerDay ;

    return ;
  }

  private static Regex rxDuration = new Regex( @"
    ^                                   # drop anchor at start-of-line
      [\x20\t]* ((?<weeks>   \d+ ) w )? # Optional whitespace, followed by an optional number of weeks
      [\x20\t]* ((?<days>    \d+ ) d )? # Optional whitesapce, followed by an optional number of days
      [\x20\t]* ((?<hours>   \d+ ) h )? # Optional whitespace, followed by an optional number of hours
      [\x20\t]* ((?<minutes> \d+ ) m )  # Optional whitespace, followed by a mandatory number of minutes
      [\x20\t]*                         # Optional trailing whitespace
    $                                   # followed by end-of-line
    " ,
    RegexOptions.IgnorePatternWhitespace
    ) ;

  public TimeSpan Parse( string jiraDuration )
  {
    if ( string.IsNullOrEmpty( jiraDuration ) ) throw new ArgumentOutOfRangeException("jiraDuration");

    Match m = rxDuration.Match( jiraDuration ) ;
    if ( !m.Success ) throw new ArgumentOutOfRangeException("jiraDuration") ;

    int weeks   ; bool hasWeeks   = int.TryParse( m.Groups[ "weeks"   ].Value , out weeks   ) ;
    int days    ; bool hasDays    = int.TryParse( m.Groups[ "days"    ].Value , out days    ) ;
    int hours   ; bool hasHours   = int.TryParse( m.Groups[ "hours"   ].Value , out hours   ) ;
    int minutes ; bool hasMinutes = int.TryParse( m.Groups[ "minutes" ].Value , out minutes ) ;

    bool isValid = hasWeeks|hasDays|hasHours|hasMinutes ;
    if ( !isValid ) throw new ArgumentOutOfRangeException("jiraDuration") ;

    TimeSpan duration = new TimeSpan( weeks*DaysPerWeek*HoursPerDay + days*HoursPerDay + hours , minutes , 0 );
    return duration ;

  }

  public bool TryParse( string jiraDuration , out TimeSpan timeSpan )
  {
    bool success ;
    try
    {
      timeSpan = Parse(jiraDuration) ;
      success = true ;
    }
    catch
    {
      timeSpan = default(TimeSpan) ;
      success  = false ;
    }
    return success ;
  }

}
于 2013-10-22T21:54:28.293 回答
2

“这里发生了什么”的答案是,由Custom Timespan Format Strings的选项构建的字符串。如果我正确阅读了文档,则不在该列表中的字符(包括空格)必须用\字符转义或用单引号括起来。

例如,尝试m\m解析“1m”,并h\h m\m解析“1h 10m”。所以你的代码是:

string[] formats = { "m\m", "h\h\ m\m" }; 

警告:我没有尝试解析TimeSpan对象。但是我已经完成了 DateTime 对象,并且非常相似。所以我认为这应该有效。

于 2013-10-22T21:27:08.053 回答
2

有点大锤的方法,但是怎么样:

public static int TextToMins(string timeText)
{
    var total = 0;
    foreach (var part in timeText.Split(' '))
    {
        if (part[part.Length - 1] == 'h')
        {
            total += 60 * int.Parse(part.Trim('h'));
        }
        else
        {
            total += int.Parse(part.Trim('m'));
        }
    }
    return total;
}
于 2013-10-22T21:15:16.940 回答
2

以下代码将解析字符串,如:“1h”、“1h30m”、“12h 45m”、“1 h 4 m”、“1d 12h 34m 20s”、“80h”、“3000ms”、“20mins”、“1min” .

在每种情况下“忽略空格”,它都支持“天、小时、分钟、秒和毫秒”,但您可以轻松添加月、周、年等……只需在条件列表中添加正确的表达式。

public static TimeSpan ParseHuman(string dateTime)
{
    TimeSpan ts = TimeSpan.Zero;
    string currentString = ""; string currentNumber = "";
    foreach (char ch in dateTime+' ')
        {
            currentString += ch;
            if (Regex.IsMatch(currentString, @"^(days(\d|\s)|day(\d|\s)|d(\d|\s))", RegexOptions.IgnoreCase)) { ts = ts.Add(TimeSpan.FromDays(int.Parse(currentNumber))); currentString = ""; currentNumber = ""; }
            if (Regex.IsMatch(currentString, @"^(hours(\d|\s)|hour(\d|\s)|h(\d|\s))", RegexOptions.IgnoreCase)) { ts = ts.Add(TimeSpan.FromHours(int.Parse(currentNumber))); currentString = ""; currentNumber = ""; }
            if (Regex.IsMatch(currentString, @"^(ms(\d|\s))", RegexOptions.IgnoreCase)) { ts = ts.Add(TimeSpan.FromMilliseconds(int.Parse(currentNumber))); currentString = ""; currentNumber = ""; }
            if (Regex.IsMatch(currentString, @"^(mins(\d|\s)|min(\d|\s)|m(\d|\s))", RegexOptions.IgnoreCase)) { ts = ts.Add(TimeSpan.FromMinutes(int.Parse(currentNumber))); currentString = ""; currentNumber = ""; }
            if (Regex.IsMatch(currentString, @"^(secs(\d|\s)|sec(\d|\s)|s(\d|\s))", RegexOptions.IgnoreCase)) { ts = ts.Add(TimeSpan.FromSeconds(int.Parse(currentNumber))); currentString = ""; currentNumber = ""; }
            if (Regex.IsMatch(ch.ToString(), @"\d")) { currentNumber += ch; currentString = ""; }
        }
    return ts;
}
于 2017-04-06T15:46:43.057 回答
1

刚遇到同样的问题。这是我的解决方案(单元测试),值得:

public static TimeSpan Parse(string s)
{
    long seconds = 0;
    long current = 0;

    int len = s.Length;
    for (int i=0; i<len; ++i)
    {
        char c = s[i];

        if (char.IsDigit(c))
        {
            current = current * 10 + (int)char.GetNumericValue(c);
        }
        else if (char.IsWhiteSpace(c))
        {
            continue;
        }
        else
        {
            long multiplier;

            switch (c)
            {
                case 's': multiplier = 1; break;      // seconds
                case 'm': multiplier = 60; break;     // minutes
                case 'h': multiplier = 3600; break;   // hours
                case 'd': multiplier = 86400; break;  // days
                case 'w': multiplier = 604800; break; // weeks
                default:
                    throw new FormatException(
                        String.Format(
                            "'{0}': Invalid duration character {1} at position {2}. Supported characters are s,m,h,d, and w", s, c, i));
            }

            seconds += current * multiplier;
            current = 0;
        }
    }

    if (current != 0)
    {
        throw new FormatException(
            String.Format("'{0}': missing duration specifier in the end of the string. Supported characters are s,m,h,d, and w", s));
    }

    return TimeSpan.FromSeconds(seconds);
}
于 2014-02-04T16:12:18.600 回答