Problem: I have strings of form "[d1, d2]" or sometimes just [d1] where d1 and d2 denote "times". I'm trying to convert these strings to their Mathematica Around equivalent. So for example

"[30min, 1hr]"

should be converted to

Around[Quantity[45, "Minutes"], Quantity[15, "Minutes"]]

Attempt: The following code snippet seems as a potential starting point for this conversion

StringCases["[30min, 1hr]", x : NumberString :> ToExpression[x]]
(* {30, 1} *)

however it only grabs raw numbers and not time quantities.

  • $\begingroup$ Are the designators for time, such as "m" and "hr" known? Are there any cases of "d" (for day) or "w" for week or similar? $\endgroup$
    – Mark R
    Jan 12 '20 at 21:13
  • $\begingroup$ Mark R: Can we say that the designators should be anything that Wolfram's SemanticInterpretation picks up when parsing time lengths? $\endgroup$
    – George
    Jan 12 '20 at 21:19
  • $\begingroup$ I think the problem is that "m" is ambiguous. Is it "meters" or "minutes". In your context, it is clear but I don't know that SemanticInterpretation has a context (such as time) as a qualifier. I have code that I think does what you want but was trying to clarify before posting. $\endgroup$
    – Mark R
    Jan 12 '20 at 21:24
  • $\begingroup$ Mark R: In that case, I'll adjust my example to have min instead of m (though "m" is more convenient in my case). $\endgroup$
    – George
    Jan 12 '20 at 21:27

This might work for you.

timeRules = {"m" -> "Minutes", "hr" -> "Hour", "min" -> "Minutes", 
   "h" -> "Hour"};
ParseTime[timeString_] := 
  With[{numberString = First@StringCases[timeString, NumberString]}, 
   Quantity @@ {ToExpression@numberString, 
     StringDelete[timeString, numberString] /. timeRules}];
ParseTimeString[bracketedTimeString_] := 
  ParseTime[#] & /@ 
   StringSplit[bracketedTimeString, {"[", ",", ", ", "]"}];
ApproximateTime[bracketedTimeString_] := 
 With[{parsedTime = ParseTimeString[bracketedTimeString]}, 
  If[Length[parsedTime] > 1, 
   Around[Median[parsedTime], Median[parsedTime] - Min[parsedTime]], 

Given an input of

aString = "[30m,1hr]"

It returns

Quantity[0.75, "Hours"], 
Quantity[15., "Minutes"]]

EDIT: Made a couple of minor changes so that I didn't assume the first element was the smallest and to handle the case where the string is something like this: "[20m]".

(* Quantity[20, "Minutes"] *)

EDIT 2: More minor changes in case there are spaces after the comma. And a new test case.

ApproximateTime[#] & /@ {"[20m,1h]", "[30m,45m]", "[45m, 2h]"}
(* {Around[
Quantity[0.6666666666666666, "Hours"], 
Quantity[20., "Minutes"]], 
 Quantity[Around[37.5, 7.5], "Minutes"], Around[
Quantity[1.375, "Hours"], 
Quantity[37.5, "Minutes"]]} *)


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.