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 import ae.utils.time.types : AbsTime;
19 
20 /// A variant of core.time.dur which accepts floating-point values.
21 /// Useful for parsing command-line arguments.
22 /// Beware of rounding / floating-point errors! Do not use where precision matters.
23 template dur(string units)
24 if (units == "weeks" ||
25 	units == "days" ||
26 	units == "hours" ||
27 	units == "minutes" ||
28 	units == "seconds" ||
29 	units == "msecs" ||
30 	units == "usecs" ||
31 	units == "hnsecs" ||
32 	units == "nsecs")
33 {
34 	Duration dur(T)(T length) @safe pure nothrow @nogc
35 	if (is(T : real) && !is(T : ulong))
36 	{
37 		auto hnsecs = length * convert!(units, "hnsecs")(1);
38 		// https://issues.dlang.org/show_bug.cgi?id=15900
39 		static import core.time;
40 		return core.time.hnsecs(cast(long)hnsecs);
41 	}
42 }
43 
44 alias weeks   = dur!"weeks";   /// Ditto
45 alias days    = dur!"days";    /// Ditto
46 alias hours   = dur!"hours";   /// Ditto
47 alias minutes = dur!"minutes"; /// Ditto
48 alias seconds = dur!"seconds"; /// Ditto
49 alias msecs   = dur!"msecs";   /// Ditto
50 alias usecs   = dur!"usecs";   /// Ditto
51 alias hnsecs  = dur!"hnsecs";  /// Ditto
52 alias nsecs   = dur!"nsecs";   /// Ditto
53 
54 ///
55 debug(ae_unittest) unittest
56 {
57 	import core.time : msecs;
58 	static assert(1.5.seconds == 1500.msecs);
59 }
60 
61 /// Multiply a duration by a floating-point number.
62 Duration durScale(F)(Duration d, F f)
63 if (is(F : real))
64 {
65 	return hnsecs(d.total!"hnsecs" * f);
66 }
67 
68 ///
69 debug(ae_unittest) unittest
70 {
71 	import core.time : seconds, msecs;
72 	assert(durScale(1.seconds, 1.5) == 1500.msecs);
73 }
74 
75 /// Like d.total!units, but returns fractional parts as well.
76 T fracTotal(string units, T = real)(Duration d)
77 {
78 	return T(d.total!"hnsecs") / convert!(units, "hnsecs")(1);
79 }
80 
81 ///
82 debug(ae_unittest) unittest
83 {
84 	import core.time : seconds, msecs;
85 	assert(1500.msecs.fracTotal!"seconds" == 1.5);
86 }
87 
88 AbsTime fromUnixTime(double unixTime)
89 {
90 	import std.datetime.systime : SysTime;
91 	import std.datetime.timezone : UTC;
92 
93 	auto durationSinceUnixEpoch = unixTime.seconds;
94 	enum stdTimeEpoch = SysTime.fromUnixTime(0, UTC()).stdTime;
95 	return AbsTime(stdTimeEpoch) + durationSinceUnixEpoch;
96 }