1 /** 2 Copyright: Copyright (c) 2020, Joakim Brännström. All rights reserved. 3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 */ 6 module my.parse; 7 8 import core.time : Duration, dur; 9 10 class TimeParseException : Exception { 11 this(string msg) @safe { 12 super(msg); 13 } 14 } 15 16 /** Parse a string as a duration. 17 * 18 * Example: 19 * --- 20 * auto d = parseDuration("1 hours 2 minutes"); 21 * --- 22 * 23 * Params: 24 * timeSpec = string to parse 25 * 26 * Returns: a `Duration` 27 * 28 * Throws: `TimeParseException` if unable to parse the string. 29 */ 30 Duration parseDuration(string timeSpec) @safe { 31 import std.conv : to; 32 import std.format : format; 33 import std.range : chunks; 34 import std.string : split; 35 36 Duration d; 37 const parts = timeSpec.split; 38 39 if (parts.length % 2 != 0) { 40 throw new TimeParseException("Invalid time specification. The format is: value unit"); 41 } 42 43 foreach (const p; parts.chunks(2)) { 44 const nr = p[0].to!long; 45 bool validUnit; 46 immutable Units = [ 47 "msecs", "seconds", "minutes", "hours", "days", "weeks" 48 ]; 49 static foreach (Unit; Units) { 50 if (p[1] == Unit) { 51 d += nr.dur!Unit; 52 validUnit = true; 53 } 54 } 55 if (!validUnit) { 56 throw new Exception(format!"Invalid unit '%s'. Valid are %-(%s, %)."(p[1], Units)); 57 } 58 } 59 60 return d; 61 } 62 63 @("shall parse a string to a duration") 64 unittest { 65 const expected = 1.dur!"weeks" + 1.dur!"days" + 3.dur!"hours" 66 + 2.dur!"minutes" + 5.dur!"seconds" + 9.dur!"msecs"; 67 const d = parseDuration("1 weeks 1 days 3 hours 2 minutes 5 seconds 9 msecs"); 68 assert(d == expected); 69 }