1 /**
2  * Duration functions.
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <ae@cy.md>
12  */
13 
14 module ae.utils.time.fpdur;
15 
16 import core.time;
17 
18 /// A variant of core.time.dur which accepts floating-point values.
19 /// Useful for parsing command-line arguments.
20 /// Beware of rounding / floating-point errors! Do not use where precision matters.
21 template dur(string units)
22 if (units == "weeks" ||
23 	units == "days" ||
24 	units == "hours" ||
25 	units == "minutes" ||
26 	units == "seconds" ||
27 	units == "msecs" ||
28 	units == "usecs" ||
29 	units == "hnsecs" ||
30 	units == "nsecs")
31 {
32 	Duration dur(T)(T length) @safe pure nothrow @nogc
33 	if (is(T : real) && !is(T : ulong))
34 	{
35 		auto hnsecs = length * convert!(units, "hnsecs")(1);
36 		// https://issues.dlang.org/show_bug.cgi?id=15900
37 		static import core.time;
38 		return core.time.hnsecs(cast(long)hnsecs);
39 	}
40 }
41 
42 alias weeks   = dur!"weeks";   /// Ditto
43 alias days    = dur!"days";    /// Ditto
44 alias hours   = dur!"hours";   /// Ditto
45 alias minutes = dur!"minutes"; /// Ditto
46 alias seconds = dur!"seconds"; /// Ditto
47 alias msecs   = dur!"msecs";   /// Ditto
48 alias usecs   = dur!"usecs";   /// Ditto
49 alias hnsecs  = dur!"hnsecs";  /// Ditto
50 alias nsecs   = dur!"nsecs";   /// Ditto
51 
52 ///
53 unittest
54 {
55 	import core.time : msecs;
56 	static assert(1.5.seconds == 1500.msecs);
57 }
58 
59 /// Multiply a duration by a floating-point number.
60 Duration durScale(F)(Duration d, F f)
61 if (is(F : real))
62 {
63 	return hnsecs(d.total!"hnsecs" * f);
64 }
65 
66 ///
67 unittest
68 {
69 	import core.time : seconds, msecs;
70 	assert(durScale(1.seconds, 1.5) == 1500.msecs);
71 }
72 
73 /// Like d.total!units, but returns fractional parts as well.
74 T fracTotal(string units, T = real)(Duration d)
75 {
76 	return T(d.total!"hnsecs") / convert!(units, "hnsecs")(1);
77 }
78 
79 ///
80 unittest
81 {
82 	import core.time : seconds, msecs;
83 	assert(1500.msecs.fracTotal!"seconds" == 1.5);
84 }