Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

Changeset 483

Show
Ignore:
Timestamp:
01/08/11 06:09:01 (14 years ago)
Author:
sean
Message:

Added new core.time. Tested on OSX. Still need to test on Windows.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/core/sync/condition.d

    r445 r483  
    207207     * Returns: 
    208208     *  true if notified before the timeout and false if not. 
    209209     */ 
    210210    bool wait( long period ) 
    211211    in 
    212212    { 
    213213        assert( period >= 0 ); 
    214214    } 
    215215    body 
    216216    { 
    217         enum : uint 
    218         { 
    219             NANOS_PER_TICK = 100, 
    220         } 
    221  
    222         return wait( nanoseconds( period * NANOS_PER_TICK ) ); 
     217        return wait( dur!"hnsecs"( period ) ); 
    223218    } 
    224219 
    225220 
    226221    /** 
    227222     * Notifies one waiter. 
    228223     * 
    229224     * Throws: 
    230225     *  SyncException on error. 
    231226     */ 
    232227    void notify() 
  • trunk/src/core/sync/config.d

    r449 r483  
    4343 
    4444    void mktspec( ref timespec t, Duration delta ) 
    4545    { 
    4646        mktspec( t ); 
    4747        mvtspec( t, delta ); 
    4848    } 
    4949 
    5050 
    5151    void mvtspec( ref timespec t, Duration delta ) 
    5252    { 
    53         enum : uint 
    54         { 
    55             NANOS_PER_SECOND = 1000_000_000 
    56         } 
    57  
    5853        auto val  = delta; 
    59              val += seconds( cast(Duration.SecType) t.tv_sec ); 
    60              val += nanoseconds( cast(Duration.FracType) t.tv_nsec ); 
    61         //auto val = delta + seconds( cast(Duration.SecType) t.tv_sec ) + 
    62         //                 + nanoseconds( cast(Duration.FracType) t.tv_nsec ); 
     54             val += dur!("seconds")( t.tv_sec ); 
     55             val += dur!("nsecs")( t.tv_nsec ); 
    6356         
    64         if( val.totalSeconds > t.tv_sec.max ) 
     57        //auto val = delta + dur!("seconds")( t.tv_sec ) + 
     58        //                 + dur!("nsecs")( t.tv_nsec ); 
     59         
     60        if( val.total!("seconds")() > t.tv_sec.max ) 
    6561        { 
    6662            t.tv_sec  = t.tv_sec.max; 
    67             t.tv_nsec = cast(typeof(t.tv_nsec)) (val.totalNanoseconds % NANOS_PER_SECOND)
     63            t.tv_nsec = cast(typeof(t.tv_nsec)) val.fracSec.nsecs
    6864        } 
    6965        else 
    7066        { 
    71             t.tv_sec  = cast(typeof(t.tv_sec)) val.totalSeconds
    72             t.tv_nsec = cast(typeof(t.tv_nsec)) (val.totalNanoseconds % NANOS_PER_SECOND)
     67            t.tv_sec  = cast(typeof(t.tv_sec)) val.total!("seconds")()
     68            t.tv_nsec = cast(typeof(t.tv_nsec)) val.fracSec.nsecs
    7369        } 
    7470    } 
    7571} 
  • trunk/src/core/sync/semaphore.d

    r445 r483  
    178178     */ 
    179179    bool wait( Duration val ) 
    180180    in 
    181181    { 
    182182        assert( !val.isNegative ); 
    183183    } 
    184184    body 
    185185    { 
    186186        version( Win32 ) 
    187187        { 
    188             auto maxWaitMillis = milliseconds( uint.max - 1 ); 
     188            auto maxWaitMillis = dur!("msecs")( uint.max - 1 ); 
    189189 
    190190            while( val > maxWaitMillis ) 
    191191            { 
    192192                auto rc = WaitForSingleObject( m_hndl, cast(uint) 
    193                                                        maxWaitMillis.totalMilliseconds ); 
     193                                                       maxWaitMillis.total!("msecs")() ); 
    194194                switch( rc ) 
    195195                { 
    196196                case WAIT_OBJECT_0: 
    197197                    return true; 
    198198                case WAIT_TIMEOUT: 
    199199                    val -= maxWaitMillis; 
    200200                    continue; 
    201201                default: 
    202202                    throw new SyncException( "Unable to wait for semaphore" ); 
    203203                } 
    204204            } 
    205             switch( WaitForSingleObject( m_hndl, cast(uint) val.totalMilliseconds ) ) 
     205            switch( WaitForSingleObject( m_hndl, cast(uint) val.total!("msecs")() ) ) 
    206206            { 
    207207            case WAIT_OBJECT_0: 
    208208                return true; 
    209209            case WAIT_TIMEOUT: 
    210210                return false; 
    211211            default: 
    212212                throw new SyncException( "Unable to wait for semaphore" ); 
    213213            } 
    214214        } 
    215215        else version( OSX ) 
    216216        {             
    217217            mach_timespec_t t = void; 
    218218            (cast(byte*) &t)[0 .. t.sizeof] = 0; 
    219219 
    220             if( val.ticks != 0 ) 
    221             { 
    222                 enum : uint 
    223                 { 
    224                     NANOS_PER_SECOND = 1000_000_000 
    225                 } 
    226  
    227                 if( val.totalSeconds > t.tv_sec.max ) 
     220            if( dur!("nsecs")( 0 ) == val ) 
     221            { 
     222                if( val.total!("seconds")() > t.tv_sec.max ) 
    228223                { 
    229224                    t.tv_sec  = t.tv_sec.max; 
    230                     t.tv_nsec = cast(typeof(t.tv_nsec)) (val.totalNanoseconds % NANOS_PER_SECOND)
     225                    t.tv_nsec = cast(typeof(t.tv_nsec)) val.fracSec.nsecs
    231226                } 
    232227                else 
    233228                { 
    234                     t.tv_sec  = cast(typeof(t.tv_sec)) val.totalSeconds
    235                     t.tv_nsec = cast(typeof(t.tv_nsec)) (val.totalNanoseconds % NANOS_PER_SECOND)
     229                    t.tv_sec  = cast(typeof(t.tv_sec)) val.total!("seconds")()
     230                    t.tv_nsec = cast(typeof(t.tv_nsec)) val.fracSec.nsecs
    236231                } 
    237232            } 
    238233            while( true ) 
    239234            { 
    240235                auto rc = semaphore_timedwait( m_hndl, t ); 
    241236                if( !rc ) 
    242237                    return true; 
    243238                if( rc == KERN_OPERATION_TIMED_OUT ) 
    244239                    return false; 
    245240                if( rc != KERN_ABORTED || errno != EINTR ) 
     
    285280     * Returns: 
    286281     *  true if notified before the timeout and false if not. 
    287282     */ 
    288283    bool wait( long period ) 
    289284    in 
    290285    { 
    291286        assert( period >= 0 ); 
    292287    } 
    293288    body 
    294289    { 
    295         enum : uint 
    296         { 
    297             NANOS_PER_TICK = 100, 
    298         } 
    299  
    300         return wait( nanoseconds( period * NANOS_PER_TICK ) ); 
     290        return wait( dur!("hnsecs")( period ) ); 
    301291    } 
    302292 
    303293 
    304294    /** 
    305295     * Atomically increment the current count by one.  This will notify one 
    306296     * waiter, if there are any in the queue. 
    307297     * 
    308298     * Throws: 
    309299     *  SyncException on error. 
    310300     */ 
  • trunk/src/core/thread.d

    r423 r483  
    10951095                Sleep( cast(uint) 
    10961096                       maxSleepMillis.totalMilliseconds ); 
    10971097                val -= maxSleepMillis; 
    10981098            } 
    10991099            Sleep( cast(uint) val.totalMilliseconds ); 
    11001100        } 
    11011101        else version( Posix ) 
    11021102        { 
    11031103            timespec tin  = void; 
    11041104            timespec tout = void; 
    1105  
    1106             enum : uint 
    1107             { 
    1108                 NANOS_PER_SECOND = 1000_000_000 
    1109             } 
    11101105             
    1111             if( val.totalSeconds > tin.tv_sec.max ) 
     1106            if( val.total!("seconds")() > tin.tv_sec.max ) 
    11121107            { 
    11131108                tin.tv_sec  = tin.tv_sec.max; 
    1114                 tin.tv_nsec = cast(typeof(tin.tv_nsec)) (val.totalNanoseconds % NANOS_PER_SECOND)
     1109                tin.tv_nsec = cast(typeof(tin.tv_nsec)) val.fracSec.nsecs
    11151110            } 
    11161111            else 
    11171112            { 
    1118                 tin.tv_sec  = cast(typeof(tin.tv_sec)) val.totalSeconds
    1119                 tin.tv_nsec = cast(typeof(tin.tv_nsec)) (val.totalNanoseconds % NANOS_PER_SECOND)
     1113                tin.tv_sec  = cast(typeof(tin.tv_sec)) val.total!("seconds")()
     1114                tin.tv_nsec = cast(typeof(tin.tv_nsec)) val.fracSec.nsecs
    11201115            } 
    11211116            while( true ) 
    11221117            { 
    11231118                if( !nanosleep( &tin, &tout ) ) 
    11241119                    return; 
    11251120                if( getErrno() != EINTR ) 
    11261121                    throw new ThreadException( "Unable to sleep for the specified duration" ); 
    11271122                tin = tout; 
    11281123            } 
    11291124        } 
     
    11501145     * 
    11511146     * ------------------------------------------------------------------------ 
    11521147     */ 
    11531148    static void sleep( long period ) 
    11541149    in 
    11551150    { 
    11561151        assert( period >= 0 ); 
    11571152    } 
    11581153    body 
    11591154    { 
    1160         enum : uint 
    1161         { 
    1162             NANOS_PER_TICK = 100, 
    1163         } 
    1164  
    1165         sleep( nanoseconds( period * NANOS_PER_TICK ) ); 
     1155        sleep( dur!"hnsecs"( period ) ); 
    11661156    } 
    11671157 
    11681158 
    11691159    /** 
    11701160     * Forces a context switch to occur away from the calling thread. 
    11711161     */ 
    11721162    static void yield() 
    11731163    { 
    11741164        version( Windows ) 
    11751165        { 
     
    16801670    // 
    16811671    static void add( Thread t ) 
    16821672    in 
    16831673    { 
    16841674        assert( t ); 
    16851675        assert( !t.next && !t.prev ); 
    16861676        assert( t.isRunning ); 
    16871677    } 
    16881678    body 
    16891679    { 
    1690         synchronized( slock ) 
    1691         { 
    1692             if( sm_tbeg ) 
    1693             { 
    1694                 t.next = sm_tbeg; 
    1695                 sm_tbeg.prev = t; 
    1696             } 
    1697             sm_tbeg = t; 
    1698             ++sm_tlen; 
     1680        while( true ) 
     1681        { 
     1682            synchronized( slock ) 
     1683            { 
     1684                if( !suspendDepth ) 
     1685                { 
     1686                    if( sm_tbeg ) 
     1687                    { 
     1688                        t.next = sm_tbeg; 
     1689                        sm_tbeg.prev = t; 
     1690                    } 
     1691                    sm_tbeg = t; 
     1692                    ++sm_tlen; 
     1693                    return; 
     1694                } 
     1695            } 
     1696            yield(); 
    16991697        } 
    17001698    } 
    17011699 
    17021700 
    17031701    // 
    17041702    // Remove a thread from the global thread list. 
    17051703    // 
    17061704    static void remove( Thread t ) 
    17071705    in 
    17081706    { 
  • trunk/src/core/time.d

    r445 r483  
    1 /** 
    2  * The time module is intended to provide some basic support for time-based 
    3  * operations. 
    4  * 
    5  * Copyright: Copyright Sean Kelly 2010 - 2010. 
    6  * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>. 
    7  * Authors:   Sean Kelly 
    8  */ 
    9  
    10 /*          Copyright Sean Kelly 2010 - 2010. 
    11  * Distributed under the Boost Software License, Version 1.0. 
    12  *    (See accompanying file LICENSE_1_0.txt or copy at 
    13  *          http://www.boost.org/LICENSE_1_0.txt) 
    14  */ 
     1//Written in the D programming language 
     2 
     3/++ 
     4    Module containing core time functionality, such as Duration (which 
     5    represents a duration of time). 
     6 
     7    Various functions take a string (or strings) to represent a unit of time 
     8    (e.g. $(D convert!("days", "hours")(numDays))). The valid strings to use 
     9    with such functions are "years", "months", "weeks", "days", "hours", 
     10    "minutes", "seconds", "msecs" (milliseconds), "usecs" (microseconds), 
     11    "hnsecs" (hecto-nanoseconds - i.e. 100 ns) or some subset thereof. There 
     12    are a few functions that also allow "nsecs", but very little actually 
     13    has precision greater than hnsecs. 
     14 
     15    Copyright: Copyright Jonathan M Davis 2010 - 2010. 
     16    License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>. 
     17    Authors:   Jonathan M Davis and Kato Shoichi 
     18 +/ 
     19 
     20/+         Copyright Jonathan M Davis 2010 - 2010. 
     21   Distributed under the Boost Software License, Version 1.0. 
     22      (See accompanying file LICENSE_1_0.txt or copy at 
     23            http://www.boost.org/LICENSE_1_0.txt) 
     24 +/ 
    1525module core.time; 
    1626 
    17  
    18 private 
    19 
    20     auto _mkpos(T)( T val ) 
    21     { 
    22         return 0 > val ? -val : val; 
    23     } 
    24 
    25  
    26  
    27 ////////////////////////////////////////////////////////////////////////////// 
    28 // Duration 
    29 ////////////////////////////////////////////////////////////////////////////// 
    30  
    31  
    32 /** 
    33  * Represents a span of time. 
    34  * 
    35  * Authors: Based on the design of boost::time_duration by Jeff Garland and 
    36  *          Bart Garst of CrystalClear Software, Inc. 
    37  */ 
     27import core.exception; 
     28import core.stdc.time; 
     29import core.stdc.stdio; 
     30 
     31version(Windows) 
     32
     33import core.sys.windows.windows; 
     34import std.windows.syserror; 
     35
     36else version(Posix) 
     37
     38import core.sys.posix.time; 
     39import core.sys.posix.sys.time; 
     40
     41 
     42//This probably should be moved somewhere else in druntime which 
     43//is OSX-specific. 
     44//It's also totally untested, since I don't a have a Mac. 
     45version(OSX) 
     46
     47 
     48public import core.sys.osx.mach.kern_return; 
     49 
     50extern(C) 
     51
     52 
     53struct mach_timebase_info_data_t 
     54
     55    uint numer; 
     56    uint denom; 
     57
     58 
     59alias mach_timebase_info_data_t* mach_timebase_info_t; 
     60 
     61kern_return_t mach_timebase_info(mach_timebase_info_t); 
     62 
     63ulong mach_absolute_time(); 
     64 
     65
     66 
     67
     68 
     69 
     70/++ 
     71    Represents a duration of time of weeks or less (kept internally as hnsecs). 
     72    (e.g. 22 days or 700 seconds). 
     73 
     74    It is used when representing a duration of time - such as how long to 
     75    sleep with Thread.sleep(). 
     76 
     77    In std.datetime, it is also used as the result of various arithmetic 
     78    operations on time points. 
     79 
     80    Use the $(D dur!()) function to create Durations. 
     81 
     82    You cannot create a duration of months or years because the variable number 
     83    of days in a month or a year makes it so that you cannot convert between 
     84    months or years and smaller units without a specific date. Any type or 
     85    function which handles months or years has other functions for handling those 
     86    rather than using durations. For instance, $(D std.datetime.Date) has 
     87    $(D addYears()) and $(D addMonths()) for adding years and months, rather than 
     88    creating a duration of years or months and adding that to a 
     89    $(D std.datetime.Date). If you're dealing with weeks or smaller, however, 
     90    durations are what you use. 
     91 
     92    Examples: 
     93-------------------- 
     94assert(dur!"days"(12) == Duration(10_368_000_000_000L)); 
     95assert(dur!"hnsecs"(27) == Duration(27)); 
     96assert(std.datetime.Date(2010, 9, 7) + dur!"days"(5) == std.datetime.Date(2010, 9, 12)); 
     97-------------------- 
     98 +/ 
    3899struct Duration 
    39100{ 
    40     alias int   DayType; 
    41     alias int   HourType; 
    42     alias int   MinType; 
    43     alias int   SecType; 
    44     alias long  FracType; 
    45     alias long  TickType; 
    46      
    47      
    48     ////////////////////////////////////////////////////////////////////////// 
    49     // Constructors 
    50     ////////////////////////////////////////////////////////////////////////// 
    51      
    52  
    53     this( HourType h, MinType m, SecType s = 0, FracType f = 0 ) 
    54     { 
    55         m_ticks = toTicks( h, m, s, f ); 
    56     } 
    57      
    58      
    59     this( Duration other ) 
    60     { 
    61         m_ticks = other.m_ticks; 
    62     } 
    63      
    64      
    65     ////////////////////////////////////////////////////////////////////////// 
    66     // Time 
    67     ////////////////////////////////////////////////////////////////////////// 
    68  
    69  
    70     const @property HourType hours() nothrow 
    71     { 
    72         return cast(HourType)(ticks / (3600 * ticksPerSecond)); 
    73     } 
    74      
    75      
    76     const @property MinType minutes() nothrow 
    77     { 
    78         return cast(MinType)((ticks / (60 * ticksPerSecond)) % 60); 
    79     } 
    80      
    81      
    82     const @property SecType seconds() nothrow 
    83     { 
    84         return cast(SecType)((ticks / ticksPerSecond) % 60); 
    85     } 
    86      
    87      
    88     const @property SecType totalSeconds() nothrow 
    89     { 
    90         // TODO: Boost uses SecType here, but the result is really a tick count 
    91         //       and could be quite large, particularly if ticksPerSecond is 
    92         //       small.  Perhaps the return type should be changed to TickType? 
    93         return cast(SecType)(ticks / ticksPerSecond); 
    94     } 
    95      
    96      
    97     const @property TickType totalMilliseconds() nothrow 
    98     { 
    99         if( 1000 <= ticksPerSecond ) 
    100             return ticks / (ticksPerSecond / cast(TickType) 1000); 
    101         return ticks * (cast(TickType) 1000 / ticksPerSecond); 
    102     } 
    103      
    104      
    105     const @property TickType totalMicroseconds() nothrow 
    106     { 
    107         if( 1000_000 <= ticksPerSecond ) 
    108             return ticks / (ticksPerSecond / cast(TickType) 1000_000); 
    109         return ticks * (cast(TickType) 1000_000 / ticksPerSecond); 
    110     } 
    111      
    112      
    113     const @property TickType totalNanoseconds() nothrow 
    114     { 
    115         if( 1000_000_000 <= ticksPerSecond ) 
    116             return ticks / (ticksPerSecond / cast(TickType) 1000_000_000); 
    117         return ticks * (cast(TickType) 1000_000_000 / ticksPerSecond); 
    118     } 
    119      
    120      
    121     const @property FracType fractionalSeconds() nothrow 
    122     { 
    123         return ticks % ticksPerSecond; 
    124     } 
    125      
    126      
    127     const @property TickType ticks() nothrow 
    128     { 
    129         return m_ticks; 
    130     } 
    131      
    132      
    133     ////////////////////////////////////////////////////////////////////////// 
    134     // Properties 
    135     ////////////////////////////////////////////////////////////////////////// 
    136      
    137      
    138     const @property bool isNegative() nothrow 
    139     { 
    140         return 0 > ticks; 
    141     } 
    142      
    143      
    144     // TODO: Add support for specials and decide about the utility of NotDateTime. 
    145      
    146      
    147     const @property bool isNegInfinity() nothrow 
    148     { 
    149         return false; 
    150     } 
    151      
    152      
    153     const @property bool isPosInfinity() nothrow 
    154     { 
    155         return false; 
    156     } 
    157      
    158      
    159     const @property bool isNotDateTime() nothrow 
    160     { 
    161         return false; 
    162     } 
    163      
    164      
    165     const @property bool isSpecial() nothrow 
    166     { 
    167         return false; 
    168     } 
    169      
    170      
    171     ////////////////////////////////////////////////////////////////////////// 
    172     // Mutators 
    173     ////////////////////////////////////////////////////////////////////////// 
    174      
    175      
    176     const @property Duration invertSign() //nothrow 
    177     { 
    178         return Duration( -ticks ); 
    179     } 
    180      
    181      
    182     ////////////////////////////////////////////////////////////////////////// 
    183     // Operators 
    184     ////////////////////////////////////////////////////////////////////////// 
    185      
    186      
    187     Duration opUnary(string op)() 
    188         if( op == "-" || op == "+" ) 
    189     { 
    190         static if( op == "-" ) 
     101    unittest 
     102    { 
     103        //Verify Examples. 
     104        assert(dur!"days"(12) == Duration(10_368_000_000_000L)); 
     105        assert(dur!"hnsecs"(27) == Duration(27)); 
     106    } 
     107 
     108public: 
     109 
     110    /++ 
     111        Compares this Duration with the given Duration. 
     112 
     113        Returns: 
     114            $(TABLE 
     115            $(TR $(TD this &lt; rhs) $(TD &lt; 0)) 
     116            $(TR $(TD this == rhs) $(TD 0)) 
     117            $(TR $(TD this &gt; rhs) $(TD &gt; 0)) 
     118            ) 
     119     +/ 
     120    int opCmp(in Duration rhs) const pure nothrow 
     121    { 
     122        if(_hnsecs < rhs._hnsecs) 
     123            return -1; 
     124        if(_hnsecs > rhs._hnsecs) 
     125            return 1; 
     126 
     127        return 0; 
     128    } 
     129 
     130    unittest 
     131    { 
     132        assert(Duration(12).opCmp(Duration(12)) == 0); 
     133        assert(Duration(-12).opCmp(Duration(-12)) == 0); 
     134 
     135        assert(Duration(10).opCmp(Duration(12)) < 0); 
     136        assert(Duration(-12).opCmp(Duration(12)) < 0); 
     137 
     138        assert(Duration(12).opCmp(Duration(10)) > 0); 
     139        assert(Duration(12).opCmp(Duration(-12)) > 0); 
     140 
     141        auto dur = Duration(12); 
     142        const cdur = Duration(12); 
     143        immutable idur = Duration(12); 
     144        static assert(__traits(compiles, dur.opCmp(dur))); 
     145        static assert(__traits(compiles, cdur.opCmp(dur))); 
     146        static assert(__traits(compiles, idur.opCmp(dur))); 
     147        static assert(__traits(compiles, dur.opCmp(cdur))); 
     148        static assert(__traits(compiles, cdur.opCmp(cdur))); 
     149        static assert(__traits(compiles, idur.opCmp(cdur))); 
     150        static assert(__traits(compiles, dur.opCmp(idur))); 
     151        static assert(__traits(compiles, cdur.opCmp(idur))); 
     152        static assert(__traits(compiles, idur.opCmp(idur))); 
     153    } 
     154 
     155 
     156    /++ 
     157        Adds or subtracts two Durations. 
     158 
     159        The legal types of arithmetic for Duration using this operator are 
     160 
     161        $(TABLE 
     162        $(TR $(TD Duration) $(TD +) $(TD Duration) $(TD -->) $(TD Duration)) 
     163        $(TR $(TD Duration) $(TD -) $(TD Duration) $(TD -->) $(TD Duration)) 
     164        $(TR $(TD Duration) $(TD +) $(TD TickDuration) $(TD -->) $(TD Duration)) 
     165        $(TR $(TD Duration) $(TD -) $(TD TickDuration) $(TD -->) $(TD Duration)) 
     166        ) 
     167 
     168        Params: 
     169            duration = The duration to add to or subtract from this duration. 
     170 
     171        Note: 
     172            TUnqual is just a local copy of std.traits' Unqual, since core does 
     173            not have access to std.traits, and naming it Unqual as well would 
     174            result in a name clash, so it's TUnqual. 
     175      +/ 
     176    Duration opBinary(string op, D)(in D rhs) const pure nothrow 
     177        if((op == "+" || op == "-") && 
     178           (is(TUnqual!D == Duration) || 
     179           is(TUnqual!D == TickDuration))) 
     180    { 
     181        static if(is(TUnqual!D == Duration)) 
     182            return Duration(mixin("_hnsecs " ~ op ~ " rhs._hnsecs")); 
     183        else if(is(TUnqual!D == TickDuration)) 
     184            return Duration(mixin("_hnsecs " ~ op ~ " rhs.hnsecs")); 
     185    } 
     186 
     187    unittest 
     188    { 
     189        assert(Duration(5) + Duration(7) == Duration(12)); 
     190        assert(Duration(5) - Duration(7) == Duration(-2)); 
     191        assert(Duration(7) + Duration(5) == Duration(12)); 
     192        assert(Duration(7) - Duration(5) == Duration(2)); 
     193 
     194        assert(Duration(5) + Duration(-7) == Duration(-2)); 
     195        assert(Duration(5) - Duration(-7) == Duration(12)); 
     196        assert(Duration(7) + Duration(-5) == Duration(2)); 
     197        assert(Duration(7) - Duration(-5) == Duration(12)); 
     198 
     199        assert(Duration(-5) + Duration(7) == Duration(2)); 
     200        assert(Duration(-5) - Duration(7) == Duration(-12)); 
     201        assert(Duration(-7) + Duration(5) == Duration(-2)); 
     202        assert(Duration(-7) - Duration(5) == Duration(-12)); 
     203 
     204        assert(Duration(-5) + Duration(-7) == Duration(-12)); 
     205        assert(Duration(-5) - Duration(-7) == Duration(2)); 
     206        assert(Duration(-7) + Duration(-5) == Duration(-12)); 
     207        assert(Duration(-7) - Duration(-5) == Duration(-2)); 
     208 
     209        //This should run the test on Linux systems (I don't know about other Posix systems), 
     210        //but Windows doesn't seem to have a very round number for ticks per second 
     211        //(1_193_182 in wine on my Linux box), so testing on Windows is harder. 
     212        if(TickDuration.ticksPerSec == 1_000_000) 
    191213        { 
    192             return Duration( -m_ticks ); 
     214            assert(Duration(5) + TickDuration.from!"usecs"(7) == Duration(75)); 
     215            assert(Duration(5) - TickDuration.from!"usecs"(7) == Duration(-65)); 
     216            assert(Duration(7) + TickDuration.from!"usecs"(5) == Duration(57)); 
     217            assert(Duration(7) - TickDuration.from!"usecs"(5) == Duration(-43)); 
     218 
     219            assert(Duration(5) + TickDuration.from!"usecs"(-7) == Duration(-65)); 
     220            assert(Duration(5) - TickDuration.from!"usecs"(-7) == Duration(75)); 
     221            assert(Duration(7) + TickDuration.from!"usecs"(-5) == Duration(-43)); 
     222            assert(Duration(7) - TickDuration.from!"usecs"(-5) == Duration(57)); 
     223 
     224            assert(Duration(-5) + TickDuration.from!"usecs"(7) == Duration(65)); 
     225            assert(Duration(-5) - TickDuration.from!"usecs"(7) == Duration(-75)); 
     226            assert(Duration(-7) + TickDuration.from!"usecs"(5) == Duration(43)); 
     227            assert(Duration(-7) - TickDuration.from!"usecs"(5) == Duration(-57)); 
     228 
     229            assert(Duration(-5) + TickDuration.from!"usecs"(-7) == Duration(-75)); 
     230            assert(Duration(-5) - TickDuration.from!"usecs"(-7) == Duration(65)); 
     231            assert(Duration(-7) + TickDuration.from!"usecs"(-5) == Duration(-57)); 
     232            assert(Duration(-7) - TickDuration.from!"usecs"(-5) == Duration(43)); 
     233        } 
     234 
     235        auto hnsdur = Duration(12); 
     236        const chnsdur = Duration(12); 
     237        immutable ihnsdur = Duration(12); 
     238        auto tdur = TickDuration.from!"usecs"(12); 
     239        const ctdur = TickDuration.from!"usecs"(12); 
     240        immutable itdur = TickDuration.from!"usecs"(12); 
     241        static assert(__traits(compiles, hnsdur + hnsdur)); 
     242        static assert(__traits(compiles, chnsdur + hnsdur)); 
     243        static assert(__traits(compiles, ihnsdur + hnsdur)); 
     244        static assert(__traits(compiles, hnsdur + chnsdur)); 
     245        static assert(__traits(compiles, chnsdur + chnsdur)); 
     246        static assert(__traits(compiles, ihnsdur + chnsdur)); 
     247        static assert(__traits(compiles, hnsdur + ihnsdur)); 
     248        static assert(__traits(compiles, chnsdur + ihnsdur)); 
     249        static assert(__traits(compiles, ihnsdur + ihnsdur)); 
     250 
     251        static assert(__traits(compiles, hnsdur + tdur)); 
     252        static assert(__traits(compiles, chnsdur + tdur)); 
     253        static assert(__traits(compiles, ihnsdur + tdur)); 
     254        static assert(__traits(compiles, hnsdur + ctdur)); 
     255        static assert(__traits(compiles, chnsdur + ctdur)); 
     256        static assert(__traits(compiles, ihnsdur + ctdur)); 
     257        static assert(__traits(compiles, hnsdur + itdur)); 
     258        static assert(__traits(compiles, chnsdur + itdur)); 
     259        static assert(__traits(compiles, ihnsdur + itdur)); 
     260 
     261        static assert(__traits(compiles, hnsdur - hnsdur)); 
     262        static assert(__traits(compiles, chnsdur - hnsdur)); 
     263        static assert(__traits(compiles, ihnsdur - hnsdur)); 
     264        static assert(__traits(compiles, hnsdur - chnsdur)); 
     265        static assert(__traits(compiles, chnsdur - chnsdur)); 
     266        static assert(__traits(compiles, ihnsdur - chnsdur)); 
     267        static assert(__traits(compiles, hnsdur - ihnsdur)); 
     268        static assert(__traits(compiles, chnsdur - ihnsdur)); 
     269        static assert(__traits(compiles, ihnsdur - ihnsdur)); 
     270 
     271        static assert(__traits(compiles, hnsdur - tdur)); 
     272        static assert(__traits(compiles, chnsdur - tdur)); 
     273        static assert(__traits(compiles, ihnsdur - tdur)); 
     274        static assert(__traits(compiles, hnsdur - ctdur)); 
     275        static assert(__traits(compiles, chnsdur - ctdur)); 
     276        static assert(__traits(compiles, ihnsdur - ctdur)); 
     277        static assert(__traits(compiles, hnsdur - itdur)); 
     278        static assert(__traits(compiles, chnsdur - itdur)); 
     279        static assert(__traits(compiles, ihnsdur - itdur)); 
     280    } 
     281 
     282 
     283    /++ 
     284        Adds or subtracts two Durations as well as assigning the result 
     285        to this Duration. 
     286 
     287        The legal types of arithmetic for Duration using this operator are 
     288 
     289        $(TABLE 
     290        $(TR $(TD Duration) $(TD +) $(TD Duration) $(TD -->) $(TD Duration)) 
     291        $(TR $(TD Duration) $(TD -) $(TD Duration) $(TD -->) $(TD Duration)) 
     292        $(TR $(TD Duration) $(TD +) $(TD TickDuration) $(TD -->) $(TD Duration)) 
     293        $(TR $(TD Duration) $(TD -) $(TD TickDuration) $(TD -->) $(TD Duration)) 
     294        ) 
     295 
     296        Params: 
     297            rhs = The duration to add to or subtract from this DateTime. 
     298 
     299        Note: 
     300            TUnqual is just a local copy of std.traits' Unqual, since core does 
     301            not have access to std.traits, and naming it Unqual as well would 
     302            result in a name clash, so it's TUnqual. 
     303      +/ 
     304    /+ref+/ Duration opOpAssign(string op, D)(in D rhs) pure nothrow 
     305        if((op == "+" || op == "-") && 
     306           (is(TUnqual!D == Duration) || 
     307            is(TUnqual!D == TickDuration))) 
     308    { 
     309        static if(is(TUnqual!D == Duration)) 
     310            mixin("_hnsecs " ~ op ~ "= rhs._hnsecs;"); 
     311        else if(is(TUnqual!D == TickDuration)) 
     312            mixin("_hnsecs " ~ op ~ "= rhs.hnsecs;"); 
     313 
     314        return this; 
     315    } 
     316 
     317    unittest 
     318    { 
     319        static void testDur(string op, D)(Duration dur, in D rhs, in Duration expected, size_t line = __LINE__) 
     320        { 
     321            if(mixin("dur " ~ op ~ " rhs") != expected) 
     322                throw new AssertError("op failed", __FILE__, line); 
     323 
     324            if(dur != expected) 
     325                throw new AssertError("op assign failed", __FILE__, line); 
     326        } 
     327 
     328        testDur!"+="(Duration(5), Duration(7), Duration(12)); 
     329        testDur!"-="(Duration(5), Duration(7), Duration(-2)); 
     330        testDur!"+="(Duration(7), Duration(5), Duration(12)); 
     331        testDur!"-="(Duration(7), Duration(5), Duration(2)); 
     332 
     333        testDur!"+="(Duration(5), Duration(-7), Duration(-2)); 
     334        testDur!"-="(Duration(5), Duration(-7), Duration(12)); 
     335        testDur!"+="(Duration(7), Duration(-5), Duration(2)); 
     336        testDur!"-="(Duration(7), Duration(-5), Duration(12)); 
     337 
     338        testDur!"+="(Duration(-5), Duration(7), Duration(2)); 
     339        testDur!"-="(Duration(-5), Duration(7), Duration(-12)); 
     340        testDur!"+="(Duration(-7), Duration(5), Duration(-2)); 
     341        testDur!"-="(Duration(-7), Duration(5), Duration(-12)); 
     342 
     343        testDur!"+="(Duration(-5), Duration(-7), Duration(-12)); 
     344        testDur!"-="(Duration(-5), Duration(-7), Duration(2)); 
     345        testDur!"+="(Duration(-7), Duration(-5), Duration(-12)); 
     346        testDur!"-="(Duration(-7), Duration(-5), Duration(-2)); 
     347 
     348        //This should run the test on Linux systems (I don't know about other Posix systems), 
     349        //but Windows doesn't seem to have a very round number for ticks per second 
     350        //(1_193_182 in wine on my Linux box), so testing on Windows is harder. 
     351        if(TickDuration.ticksPerSec == 1_000_000) 
     352        { 
     353            testDur!"+="(Duration(5), TickDuration.from!"usecs"(7), Duration(75)); 
     354            testDur!"-="(Duration(5), TickDuration.from!"usecs"(7), Duration(-65)); 
     355            testDur!"+="(Duration(7), TickDuration.from!"usecs"(5), Duration(57)); 
     356            testDur!"-="(Duration(7), TickDuration.from!"usecs"(5), Duration(-43)); 
     357 
     358            testDur!"+="(Duration(5), TickDuration.from!"usecs"(-7), Duration(-65)); 
     359            testDur!"-="(Duration(5), TickDuration.from!"usecs"(-7), Duration(75)); 
     360            testDur!"+="(Duration(7), TickDuration.from!"usecs"(-5), Duration(-43)); 
     361            testDur!"-="(Duration(7), TickDuration.from!"usecs"(-5), Duration(57)); 
     362 
     363            testDur!"+="(Duration(-5), TickDuration.from!"usecs"(7), Duration(65)); 
     364            testDur!"-="(Duration(-5), TickDuration.from!"usecs"(7), Duration(-75)); 
     365            testDur!"+="(Duration(-7), TickDuration.from!"usecs"(5), Duration(43)); 
     366            testDur!"-="(Duration(-7), TickDuration.from!"usecs"(5), Duration(-57)); 
     367 
     368            testDur!"+="(Duration(-5), TickDuration.from!"usecs"(-7), Duration(-75)); 
     369            testDur!"-="(Duration(-5), TickDuration.from!"usecs"(-7), Duration(65)); 
     370            testDur!"+="(Duration(-7), TickDuration.from!"usecs"(-5), Duration(-57)); 
     371            testDur!"-="(Duration(-7), TickDuration.from!"usecs"(-5), Duration(43)); 
     372        } 
     373 
     374        auto hnsdur = Duration(12); 
     375        const chnsdur = Duration(12); 
     376        immutable ihnsdur = Duration(12); 
     377        auto tdur = TickDuration.from!"usecs"(12); 
     378        const ctdur = TickDuration.from!"usecs"(12); 
     379        immutable itdur = TickDuration.from!"usecs"(12); 
     380        static assert(__traits(compiles, hnsdur += hnsdur)); 
     381        static assert(!__traits(compiles, chnsdur += hnsdur)); 
     382        static assert(!__traits(compiles, ihnsdur += hnsdur)); 
     383        static assert(__traits(compiles, hnsdur += chnsdur)); 
     384        static assert(!__traits(compiles, chnsdur += chnsdur)); 
     385        static assert(!__traits(compiles, ihnsdur += chnsdur)); 
     386        static assert(__traits(compiles, hnsdur += ihnsdur)); 
     387        static assert(!__traits(compiles, chnsdur += ihnsdur)); 
     388        static assert(!__traits(compiles, ihnsdur += ihnsdur)); 
     389 
     390        static assert(__traits(compiles, hnsdur += tdur)); 
     391        static assert(!__traits(compiles, chnsdur += tdur)); 
     392        static assert(!__traits(compiles, ihnsdur += tdur)); 
     393        static assert(__traits(compiles, hnsdur += ctdur)); 
     394        static assert(!__traits(compiles, chnsdur += ctdur)); 
     395        static assert(!__traits(compiles, ihnsdur += ctdur)); 
     396        static assert(__traits(compiles, hnsdur += itdur)); 
     397        static assert(!__traits(compiles, chnsdur += itdur)); 
     398        static assert(!__traits(compiles, ihnsdur += itdur)); 
     399 
     400        static assert(__traits(compiles, hnsdur -= hnsdur)); 
     401        static assert(!__traits(compiles, chnsdur -= hnsdur)); 
     402        static assert(!__traits(compiles, ihnsdur -= hnsdur)); 
     403        static assert(__traits(compiles, hnsdur -= chnsdur)); 
     404        static assert(!__traits(compiles, chnsdur -= chnsdur)); 
     405        static assert(!__traits(compiles, ihnsdur -= chnsdur)); 
     406        static assert(__traits(compiles, hnsdur -= ihnsdur)); 
     407        static assert(!__traits(compiles, chnsdur -= ihnsdur)); 
     408        static assert(!__traits(compiles, ihnsdur -= ihnsdur)); 
     409 
     410        static assert(__traits(compiles, hnsdur -= tdur)); 
     411        static assert(!__traits(compiles, chnsdur -= tdur)); 
     412        static assert(!__traits(compiles, ihnsdur -= tdur)); 
     413        static assert(__traits(compiles, hnsdur -= ctdur)); 
     414        static assert(!__traits(compiles, chnsdur -= ctdur)); 
     415        static assert(!__traits(compiles, ihnsdur -= ctdur)); 
     416        static assert(__traits(compiles, hnsdur -= itdur)); 
     417        static assert(!__traits(compiles, chnsdur -= itdur)); 
     418        static assert(!__traits(compiles, ihnsdur -= itdur)); 
     419    } 
     420 
     421 
     422    /++ 
     423        The legal types of arithmetic for Duration using this operator overload are 
     424 
     425        $(TABLE 
     426        $(TR $(TD Duration) $(TD *) $(TD long) $(TD -->) $(TD Duration)) 
     427        ) 
     428 
     429        Params: 
     430            value = The value to multiply this duration by. 
     431      +/ 
     432    Duration opBinary(string op)(long value) const pure nothrow 
     433        if(op == "*") 
     434    { 
     435        return Duration(_hnsecs * value); 
     436    } 
     437 
     438    unittest 
     439    { 
     440        assert(Duration(5) * 7 == Duration(35)); 
     441        assert(Duration(7) * 5 == Duration(35)); 
     442 
     443        assert(Duration(5) * -7 == Duration(-35)); 
     444        assert(Duration(7) * -5 == Duration(-35)); 
     445 
     446        assert(Duration(-5) * 7 == Duration(-35)); 
     447        assert(Duration(-7) * 5 == Duration(-35)); 
     448 
     449        assert(Duration(-5) * -7 == Duration(35)); 
     450        assert(Duration(-7) * -5 == Duration(35)); 
     451 
     452        assert(Duration(5) * 0 == Duration(0)); 
     453        assert(Duration(-5) * 0 == Duration(0)); 
     454 
     455        auto dur = Duration(12); 
     456        const cdur = Duration(12); 
     457        immutable idur = Duration(12); 
     458        static assert(__traits(compiles, dur * 12)); 
     459        static assert(__traits(compiles, cdur * 12)); 
     460        static assert(__traits(compiles, idur * 12)); 
     461    } 
     462 
     463 
     464    /++ 
     465        The legal types of arithmetic for Duration using this operator overload are 
     466 
     467        $(TABLE 
     468        $(TR $(TD Duration) $(TD *) $(TD long) $(TD -->) $(TD Duration)) 
     469        ) 
     470 
     471        Params: 
     472            value = The value to multiply this duration by. 
     473      +/ 
     474    /+ref+/ Duration opOpAssign(string op)(long value) pure nothrow 
     475        if(op == "*") 
     476    { 
     477        _hnsecs *= value; 
     478 
     479       return this; 
     480    } 
     481 
     482    unittest 
     483    { 
     484        static void testDur(Duration dur, long value, in Duration expected, size_t line = __LINE__) 
     485        { 
     486            if((dur *= value) != expected) 
     487                throw new AssertError("op failed", __FILE__, line); 
     488 
     489            if(dur != expected) 
     490                throw new AssertError("op assign failed", __FILE__, line); 
     491        } 
     492 
     493        testDur(Duration(5), 7, Duration(35)); 
     494        testDur(Duration(7), 5, Duration(35)); 
     495 
     496        testDur(Duration(5), -7, Duration(-35)); 
     497        testDur(Duration(7), -5, Duration(-35)); 
     498 
     499        testDur(Duration(-5), 7, Duration(-35)); 
     500        testDur(Duration(-7), 5, Duration(-35)); 
     501 
     502        testDur(Duration(-5), -7, Duration(35)); 
     503        testDur(Duration(-7), -5, Duration(35)); 
     504 
     505        testDur(Duration(5), 0, Duration(0)); 
     506        testDur(Duration(-5), 0, Duration(0)); 
     507 
     508        auto dur = Duration(12); 
     509        const cdur = Duration(12); 
     510        immutable idur = Duration(12); 
     511        static assert(__traits(compiles, dur *= 12)); 
     512        static assert(!__traits(compiles, cdur *= 12)); 
     513        static assert(!__traits(compiles, idur *= 12)); 
     514    } 
     515 
     516 
     517    /++ 
     518        The legal types of arithmetic for Duration using this operator overload are 
     519 
     520        $(TABLE 
     521        $(TR $(TD Duration) $(TD /) $(TD long) $(TD -->) $(TD Duration)) 
     522        ) 
     523 
     524        Params: 
     525            value = The value to divide from this duration. 
     526 
     527        Throws: 
     528            TimeException if an attempt to divide by 0 is made. 
     529      +/ 
     530    Duration opBinary(string op)(long value) pure const 
     531        if(op == "/") 
     532    { 
     533        if(value == 0) 
     534            throw new TimeException("Attempted division by 0."); 
     535 
     536        return Duration(_hnsecs / value); 
     537    } 
     538 
     539    unittest 
     540    { 
     541        tAssertExThrown!TimeException((){Duration(5) / 0;}()); 
     542        tAssertExThrown!TimeException((){Duration(-5) / 0;}()); 
     543 
     544        assert(Duration(5) / 7 == Duration(0)); 
     545        assert(Duration(7) / 5 == Duration(1)); 
     546 
     547        assert(Duration(5) / -7 == Duration(0)); 
     548        assert(Duration(7) / -5 == Duration(-1)); 
     549 
     550        assert(Duration(-5) / 7 == Duration(0)); 
     551        assert(Duration(-7) / 5 == Duration(-1)); 
     552 
     553        assert(Duration(-5) / -7 == Duration(0)); 
     554        assert(Duration(-7) / -5 == Duration(1)); 
     555 
     556        auto dur = Duration(12); 
     557        const cdur = Duration(12); 
     558        immutable idur = Duration(12); 
     559        static assert(__traits(compiles, dur / 12)); 
     560        static assert(__traits(compiles, cdur / 12)); 
     561        static assert(__traits(compiles, idur / 12)); 
     562    } 
     563 
     564 
     565    /++ 
     566        The legal types of arithmetic for Duration using this operator overload are 
     567 
     568        $(TABLE 
     569        $(TR $(TD Duration) $(TD /) $(TD long) $(TD -->) $(TD Duration)) 
     570        ) 
     571 
     572        Params: 
     573            value = The value to divide from this duration. 
     574 
     575        Throws: 
     576            TimeException if an attempt to divide by 0 is made. 
     577      +/ 
     578    /+ref+/ Duration opOpAssign(string op)(long value) pure 
     579        if(op == "/") 
     580    { 
     581        if(value == 0) 
     582            throw new TimeException("Attempted division by 0."); 
     583 
     584        _hnsecs /= value; 
     585 
     586        return this; 
     587    } 
     588 
     589    unittest 
     590    { 
     591        tAssertExThrown!TimeException((){Duration(5) /= 0;}()); 
     592        tAssertExThrown!TimeException((){Duration(-5) /= 0;}()); 
     593 
     594        static void testDur(Duration dur, long value, in Duration expected, size_t line = __LINE__) 
     595        { 
     596            if((dur /= value) != expected) 
     597                throw new AssertError("op failed", __FILE__, line); 
     598 
     599            if(dur != expected) 
     600                throw new AssertError("op assign failed", __FILE__, line); 
     601        } 
     602 
     603        testDur(Duration(5), 7, Duration(0)); 
     604        testDur(Duration(7), 5, Duration(1)); 
     605 
     606        testDur(Duration(5), -7, Duration(0)); 
     607        testDur(Duration(7), -5, Duration(-1)); 
     608 
     609        testDur(Duration(-5), 7, Duration(0)); 
     610        testDur(Duration(-7), 5, Duration(-1)); 
     611 
     612        testDur(Duration(-5), -7, Duration(0)); 
     613        testDur(Duration(-7), -5, Duration(1)); 
     614 
     615        auto dur = Duration(12); 
     616        const cdur = Duration(12); 
     617        immutable idur = Duration(12); 
     618        static assert(__traits(compiles, dur /= 12)); 
     619        static assert(!__traits(compiles, cdur /= 12)); 
     620        static assert(!__traits(compiles, idur /= 12)); 
     621    } 
     622 
     623 
     624    /++ 
     625        Multiplies an integral value and a Duration. 
     626 
     627        The legal types of arithmetic for Duration using this operator overload are 
     628 
     629        $(TABLE 
     630        $(TR $(TD long) $(TD *) $(TD Duration) $(TD -->) $(TD Duration)) 
     631        ) 
     632 
     633        Params: 
     634            value = The number of units to multiply this duration by. 
     635      +/ 
     636    Duration opBinaryRight(string op)(long value) const pure nothrow 
     637        if(op == "*") 
     638    { 
     639        return opBinary!op(value); 
     640    } 
     641 
     642    unittest 
     643    { 
     644        assert(5 * Duration(7) == Duration(35)); 
     645        assert(7 * Duration(5) == Duration(35)); 
     646 
     647        assert(5 * Duration(-7) == Duration(-35)); 
     648        assert(7 * Duration(-5) == Duration(-35)); 
     649 
     650        assert(-5 * Duration(7) == Duration(-35)); 
     651        assert(-7 * Duration(5) == Duration(-35)); 
     652 
     653        assert(-5 * Duration(-7) == Duration(35)); 
     654        assert(-7 * Duration(-5) == Duration(35)); 
     655 
     656        assert(0 * Duration(5) == Duration(0)); 
     657        assert(0 * Duration(-5) == Duration(0)); 
     658 
     659        const cdur = Duration(12); 
     660        immutable idur = Duration(12); 
     661        static assert(__traits(compiles, 12 * cdur)); 
     662        static assert(__traits(compiles, 12 * idur)); 
     663    } 
     664 
     665 
     666    /++ 
     667        Returns the negation of this Duration. 
     668      +/ 
     669    Duration opUnary(string op)() const pure nothrow 
     670        if(op == "-") 
     671    { 
     672        return Duration(-_hnsecs); 
     673    } 
     674 
     675    unittest 
     676    { 
     677        assert(-Duration(7) == Duration(-7)); 
     678        assert(-Duration(5) == Duration(-5)); 
     679        assert(-Duration(-7) == Duration(7)); 
     680        assert(-Duration(-5) == Duration(5)); 
     681        assert(-Duration(0) == Duration(0)); 
     682 
     683        const cdur = Duration(12); 
     684        immutable idur = Duration(12); 
     685        static assert(__traits(compiles, -cdur)); 
     686        static assert(__traits(compiles, -idur)); 
     687    } 
     688 
     689 
     690    /++ 
     691        Returns the number of the given units in the duration 
     692        (minus the larger units). 
     693 
     694        Examples: 
     695-------------------- 
     696assert(dur!"weeks"(12).get!"weeks"() == 12); 
     697assert(dur!"weeks"(12).get!"days"() == 0); 
     698 
     699assert(dur!"days"(13).get!"weeks"() == 1); 
     700assert(dur!"days"(13).get!"days"() == 6); 
     701 
     702assert(dur!"hours"(49).get!"days"() == 2); 
     703assert(dur!"hours"(49).get!"hours"() == 1); 
     704-------------------- 
     705      +/ 
     706    long get(string units)() const pure nothrow 
     707        if(units == "weeks" || 
     708           units == "days" || 
     709           units == "hours" || 
     710           units == "minutes" || 
     711           units == "seconds") 
     712    { 
     713        static if(units == "weeks") 
     714            return getUnitsFromHNSecs!"weeks"(_hnsecs); 
     715        else 
     716        { 
     717            immutable hnsecs = removeUnitsFromHNSecs!(nextLargerTimeUnits!units)(_hnsecs); 
     718 
     719            return getUnitsFromHNSecs!units(hnsecs); 
     720        } 
     721    } 
     722 
     723    unittest 
     724    { 
     725        //Verify Examples. 
     726        assert(dur!"weeks"(12).get!"weeks"() == 12); 
     727        assert(dur!"weeks"(12).get!"days"() == 0); 
     728 
     729        assert(dur!"days"(13).get!"weeks"() == 1); 
     730        assert(dur!"days"(13).get!"days"() == 6); 
     731 
     732        assert(dur!"hours"(49).get!"days"() == 2); 
     733        assert(dur!"hours"(49).get!"hours"() == 1); 
     734 
     735        const dur = Duration(12); 
     736        const cdur = Duration(12); 
     737        immutable idur = Duration(12); 
     738        static assert(__traits(compiles, dur.get!"days"())); 
     739        static assert(__traits(compiles, cdur.get!"days"())); 
     740        static assert(__traits(compiles, idur.get!"days"())); 
     741    } 
     742 
     743 
     744    /++ 
     745        Returns the number of weeks in the duration. 
     746 
     747        Examples: 
     748-------------------- 
     749assert(dur!"weeks"(12).weeks == 12); 
     750assert(dur!"days"(13).weeks == 1); 
     751-------------------- 
     752      +/ 
     753    @property alias get!"weeks" weeks; 
     754 
     755    unittest 
     756    { 
     757        //Verify Examples. 
     758        assert(dur!"weeks"(12).weeks == 12); 
     759        assert(dur!"days"(13).weeks == 1); 
     760 
     761        const dur = Duration(12); 
     762        const cdur = Duration(12); 
     763        immutable idur = Duration(12); 
     764        static assert(__traits(compiles, dur.weeks)); 
     765        static assert(__traits(compiles, cdur.weeks)); 
     766        static assert(__traits(compiles, idur.weeks)); 
     767    } 
     768 
     769 
     770    /++ 
     771        Returns the number of days in the duration (minus the larger units). 
     772 
     773        Examples: 
     774-------------------- 
     775assert(dur!"weeks"(12).days == 0); 
     776assert(dur!"days"(13).days == 6); 
     777assert(dur!"hours"(49).days == 2); 
     778-------------------- 
     779      +/ 
     780    @property alias get!"days" days; 
     781 
     782    unittest 
     783    { 
     784        //Verify Examples. 
     785        assert(dur!"weeks"(12).days == 0); 
     786        assert(dur!"days"(13).days == 6); 
     787        assert(dur!"hours"(49).days == 2); 
     788 
     789        const dur = Duration(12); 
     790        const cdur = Duration(12); 
     791        immutable idur = Duration(12); 
     792        static assert(__traits(compiles, dur.days)); 
     793        static assert(__traits(compiles, cdur.days)); 
     794        static assert(__traits(compiles, idur.days)); 
     795    } 
     796 
     797 
     798    /++ 
     799        Returns the number of hours in the duration (minus the larger units). 
     800 
     801        Examples: 
     802-------------------- 
     803assert(dur!"days"(8).hours == 0); 
     804assert(dur!"hours"(49).hours == 1); 
     805assert(dur!"minutes"(121).hours == 2); 
     806-------------------- 
     807      +/ 
     808    @property alias get!"hours" hours; 
     809 
     810    unittest 
     811    { 
     812        //Verify Examples. 
     813        assert(dur!"days"(8).hours == 0); 
     814        assert(dur!"hours"(49).hours == 1); 
     815        assert(dur!"minutes"(121).hours == 2); 
     816 
     817        const dur = Duration(12); 
     818        const cdur = Duration(12); 
     819        immutable idur = Duration(12); 
     820        static assert(__traits(compiles, dur.hours)); 
     821        static assert(__traits(compiles, cdur.hours)); 
     822        static assert(__traits(compiles, idur.hours)); 
     823    } 
     824 
     825 
     826    /++ 
     827        Returns the number of minutes in the duration (minus the larger units). 
     828 
     829        Examples: 
     830-------------------- 
     831assert(dur!"hours"(47).minutes == 0); 
     832assert(dur!"minutes"(127).minutes == 7); 
     833assert(dur!"seconds"(121).minutes == 2); 
     834-------------------- 
     835      +/ 
     836    @property alias get!"minutes" minutes; 
     837 
     838    unittest 
     839    { 
     840        //Verify Examples. 
     841        assert(dur!"hours"(47).minutes == 0); 
     842        assert(dur!"minutes"(127).minutes == 7); 
     843        assert(dur!"seconds"(121).minutes == 2); 
     844 
     845        const dur = Duration(12); 
     846        const cdur = Duration(12); 
     847        immutable idur = Duration(12); 
     848        static assert(__traits(compiles, dur.minutes)); 
     849        static assert(__traits(compiles, cdur.minutes)); 
     850        static assert(__traits(compiles, idur.minutes)); 
     851    } 
     852 
     853 
     854    /++ 
     855        Returns the number of seconds in the duration (minus the larger units). 
     856 
     857        Examples: 
     858-------------------- 
     859assert(dur!"minutes"(47).seconds == 0); 
     860assert(dur!"seconds"(127).seconds == 7); 
     861assert(dur!"msecs"(1217).seconds == 1); 
     862-------------------- 
     863      +/ 
     864    @property alias get!"seconds" seconds; 
     865 
     866    unittest 
     867    { 
     868        //Verify Examples. 
     869        assert(dur!"minutes"(47).seconds == 0); 
     870        assert(dur!"seconds"(127).seconds == 7); 
     871        assert(dur!"msecs"(1217).seconds == 1); 
     872 
     873        const dur = Duration(12); 
     874        const cdur = Duration(12); 
     875        immutable idur = Duration(12); 
     876        static assert(__traits(compiles, dur.seconds)); 
     877        static assert(__traits(compiles, cdur.seconds)); 
     878        static assert(__traits(compiles, idur.seconds)); 
     879    } 
     880 
     881 
     882    /++ 
     883        Returns the fractional seconds passed the second. 
     884 
     885        Examples: 
     886-------------------- 
     887assert(dur!"msecs"(1000).fracSec == FracSec.from!"msecs"(0)); 
     888assert(dur!"msecs"(1217).fracSec == FracSec.from!"msecs"(217)); 
     889assert(dur!"usecs"(43).fracSec == FracSec.from!"usecs"(43)); 
     890assert(dur!"hnsecs"(50_007).fracSec == FracSec.from!"hnsecs"(50_007)); 
     891-------------------- 
     892     +/ 
     893    @property FracSec fracSec() const pure nothrow 
     894    { 
     895        try 
     896        { 
     897            long hnsecs = _hnsecs; 
     898            auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1; 
     899 
     900            if(hnsecs < 0) 
     901            { 
     902                hnsecs += convert!("hours", "hnsecs")(24); 
     903                --days; 
     904            } 
     905 
     906            hnsecs = removeUnitsFromHNSecs!"hours"(hnsecs); 
     907            hnsecs = removeUnitsFromHNSecs!"minutes"(hnsecs); 
     908            hnsecs = removeUnitsFromHNSecs!"seconds"(hnsecs); 
     909 
     910            return FracSec.from!"hnsecs"(cast(int)hnsecs); 
     911        } 
     912        catch(Exception e) 
     913            assert(0, "FracSec.from!\"hnsecs\"() threw."); 
     914    } 
     915 
     916    unittest 
     917    { 
     918        //Verify Examples. 
     919        assert(dur!"msecs"(1000).fracSec == FracSec.from!"msecs"(0)); 
     920        assert(dur!"msecs"(1217).fracSec == FracSec.from!"msecs"(217)); 
     921        assert(dur!"usecs"(43).fracSec == FracSec.from!"usecs"(43)); 
     922        assert(dur!"hnsecs"(50_007).fracSec == FracSec.from!"hnsecs"(50_007)); 
     923 
     924        const dur = Duration(12); 
     925        const cdur = Duration(12); 
     926        immutable idur = Duration(12); 
     927        static assert(__traits(compiles, dur.fracSec)); 
     928        static assert(__traits(compiles, cdur.fracSec)); 
     929        static assert(__traits(compiles, idur.fracSec)); 
     930    } 
     931 
     932 
     933    /++ 
     934        Returns the total number of the given units in the duration. 
     935        So, unlike $(D get()), it does not strip out the larger 
     936        units. 
     937 
     938        Examples: 
     939-------------------- 
     940assert(dur!"weeks"(12).total!"weeks"() == 12); 
     941assert(dur!"weeks"(12).total!"days"() == 84); 
     942 
     943assert(dur!"days"(13).total!"weeks"() == 1); 
     944assert(dur!"days"(13).total!"days"() == 13); 
     945 
     946assert(dur!"hours"(49).total!"days"() == 2); 
     947assert(dur!"hours"(49).total!"hours"() == 49); 
     948 
     949assert(dur!"nsecs"(2007).total!"hnsecs"() == 20); 
     950assert(dur!"nsecs"(2007).total!"nsecs"() == 2000); 
     951-------------------- 
     952      +/ 
     953    long total(string units)() const pure nothrow 
     954        if(units == "weeks" || 
     955           units == "days" || 
     956           units == "hours" || 
     957           units == "minutes" || 
     958           units == "seconds" || 
     959           units == "msecs" || 
     960           units == "usecs" || 
     961           units == "hnsecs" || 
     962           units == "nsecs") 
     963    { 
     964        static if(units == "nsecs") 
     965            return convert!("hnsecs", "nsecs")(_hnsecs); 
     966        else 
     967            return getUnitsFromHNSecs!units(_hnsecs); 
     968    } 
     969 
     970    unittest 
     971    { 
     972        //Verify Examples. 
     973        assert(dur!"weeks"(12).total!"weeks"() == 12); 
     974        assert(dur!"weeks"(12).total!"days"() == 84); 
     975 
     976        assert(dur!"days"(13).total!"weeks"() == 1); 
     977        assert(dur!"days"(13).total!"days"() == 13); 
     978 
     979        assert(dur!"hours"(49).total!"days"() == 2); 
     980        assert(dur!"hours"(49).total!"hours"() == 49); 
     981 
     982        assert(dur!"nsecs"(2007).total!"hnsecs"() == 20); 
     983        assert(dur!"nsecs"(2007).total!"nsecs"() == 2000); 
     984 
     985        const dur = Duration(12); 
     986        const cdur = Duration(12); 
     987        immutable idur = Duration(12); 
     988        static assert(__traits(compiles, dur.total!"days"())); 
     989        static assert(__traits(compiles, cdur.total!"days"())); 
     990        static assert(__traits(compiles, idur.total!"days"())); 
     991    } 
     992 
     993 
     994    /+ 
     995        Converts this duration to a string. 
     996      +/ 
     997    //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't 
     998    //have versions of toString() with extra modifiers, so we define one version 
     999    //with modifiers and one without. 
     1000    string toString() 
     1001    { 
     1002        return _toStringImpl(); 
     1003    } 
     1004 
     1005 
     1006    /++ 
     1007        Converts this duration to a string. 
     1008      +/ 
     1009    //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't 
     1010    //have versions of toString() with extra modifiers, so we define one version 
     1011    //with modifiers and one without. 
     1012    string toString() const pure nothrow 
     1013    { 
     1014        return _toStringImpl(); 
     1015    } 
     1016 
     1017    unittest 
     1018    { 
     1019        const dur = Duration(12); 
     1020        const cdur = Duration(12); 
     1021        immutable idur = Duration(12); 
     1022        static assert(__traits(compiles, dur.toString())); 
     1023        static assert(__traits(compiles, cdur.toString())); 
     1024        static assert(__traits(compiles, idur.toString())); 
     1025    } 
     1026 
     1027 
     1028    @property bool isNegative() const pure nothrow 
     1029    { 
     1030        return _hnsecs < 0; 
     1031    } 
     1032 
     1033    unittest 
     1034    { 
     1035        assert(!Duration(100).isNegative); 
     1036        assert(!Duration(1).isNegative); 
     1037        assert(!Duration(0).isNegative); 
     1038        assert(Duration(-1).isNegative); 
     1039        assert(Duration(-100).isNegative); 
     1040    } 
     1041 
     1042 
     1043private: 
     1044 
     1045    /++ 
     1046        Since we have two versions of toString(), we have _toStringImpl() 
     1047        so that they can share implementations. 
     1048      +/ 
     1049    string _toStringImpl() const pure nothrow 
     1050    { 
     1051        long hnsecs = _hnsecs; 
     1052 
     1053        immutable weeks = splitUnitsFromHNSecs!"weeks"(hnsecs); 
     1054        immutable days = splitUnitsFromHNSecs!"days"(hnsecs); 
     1055        immutable hours = splitUnitsFromHNSecs!"hours"(hnsecs); 
     1056        immutable minutes = splitUnitsFromHNSecs!"minutes"(hnsecs); 
     1057        immutable seconds = splitUnitsFromHNSecs!"seconds"(hnsecs); 
     1058        immutable milliseconds = splitUnitsFromHNSecs!"msecs"(hnsecs); 
     1059        immutable microseconds = splitUnitsFromHNSecs!"usecs"(hnsecs); 
     1060 
     1061        try 
     1062        { 
     1063            auto totalUnits = 0; 
     1064 
     1065            if(weeks != 0) 
     1066                ++totalUnits; 
     1067            if(days != 0) 
     1068                ++totalUnits; 
     1069            if(hours != 0) 
     1070                ++totalUnits; 
     1071            if(minutes != 0) 
     1072                ++totalUnits; 
     1073            if(seconds != 0) 
     1074                ++totalUnits; 
     1075            if(milliseconds != 0) 
     1076                ++totalUnits; 
     1077            if(microseconds != 0) 
     1078                ++totalUnits; 
     1079            if(hnsecs != 0) 
     1080                ++totalUnits; 
     1081 
     1082            string retval; 
     1083            auto unitsUsed = 0; 
     1084 
     1085            string unitsToPrint(string units, bool plural) 
     1086            { 
     1087                if(units == "seconds") 
     1088                    return plural ? "secs" : "sec"; 
     1089                else if(units == "msecs") 
     1090                    return "ms"; 
     1091                else if(units == "usecs") 
     1092                    return "ÃŽÅ’s"; 
     1093                else 
     1094                    return plural ? units : units[0 .. $-1]; 
     1095            } 
     1096 
     1097            void addUnitStr(string units, long value) 
     1098            { 
     1099                if(value != 0) 
     1100                { 
     1101                    auto utp = unitsToPrint(units, value != 1); 
     1102                    auto valueStr = numToString(value); 
     1103 
     1104                    if(unitsUsed == 0) 
     1105                        retval ~= valueStr ~ " " ~ utp; 
     1106                    else if(unitsUsed == totalUnits - 1) 
     1107                    { 
     1108                        if(totalUnits == 2) 
     1109                            retval ~= " and " ~ valueStr ~ " " ~ utp; 
     1110                        else 
     1111                            retval ~= ", and " ~ valueStr ~ " " ~ utp; 
     1112                    } 
     1113                    else 
     1114                        retval ~= ", " ~ valueStr ~ " " ~ utp; 
     1115 
     1116                    ++unitsUsed; 
     1117                } 
     1118            } 
     1119 
     1120            addUnitStr("weeks", weeks); 
     1121            addUnitStr("days", days); 
     1122            addUnitStr("hours", hours); 
     1123            addUnitStr("minutes", minutes); 
     1124            addUnitStr("seconds", seconds); 
     1125            addUnitStr("msecs", milliseconds); 
     1126            addUnitStr("usecs", microseconds); 
     1127            addUnitStr("hnsecs", hnsecs); 
     1128 
     1129            if(retval.length == 0) 
     1130                return "0 hnsecs"; 
     1131 
     1132            return retval; 
     1133        } 
     1134        catch(Exception e) 
     1135            assert(0, "Something threw when nothing can throw."); 
     1136    } 
     1137 
     1138    unittest 
     1139    { 
     1140        assert(Duration(0).toString() == "0 hnsecs"); 
     1141        assert(Duration(1).toString() == "1 hnsec"); 
     1142        assert(Duration(7).toString() == "7 hnsecs"); 
     1143        assert(Duration(10).toString() == "1 ÃŽÅ’s"); 
     1144        assert(Duration(20).toString() == "2 ÃŽÅ’s"); 
     1145        assert(Duration(10_000).toString() == "1 ms"); 
     1146        assert(Duration(20_000).toString() == "2 ms"); 
     1147        assert(Duration(10_000_000).toString() == "1 sec"); 
     1148        assert(Duration(20_000_000).toString() == "2 secs"); 
     1149        assert(Duration(600_000_000).toString() == "1 minute"); 
     1150        assert(Duration(1_200_000_000).toString() == "2 minutes"); 
     1151        assert(Duration(36_000_000_000).toString() == "1 hour"); 
     1152        assert(Duration(72_000_000_000).toString() == "2 hours"); 
     1153        assert(Duration(864_000_000_000).toString() == "1 day"); 
     1154        assert(Duration(1_728_000_000_000).toString() == "2 days"); 
     1155        assert(Duration(6_048_000_000_000).toString() == "1 week"); 
     1156        assert(Duration(12_096_000_000_000).toString() == "2 weeks"); 
     1157 
     1158        assert(Duration(12).toString() == "1 ÃŽÅ’s and 2 hnsecs"); 
     1159        assert(Duration(120_795).toString() == "12 ms, 79 ÃŽÅ’s, and 5 hnsecs"); 
     1160        assert(Duration(12_096_020_900_003).toString() == "2 weeks, 2 secs, 90 ms, and 3 hnsecs"); 
     1161 
     1162        assert(Duration(-1).toString() == "-1 hnsecs"); 
     1163        assert(Duration(-7).toString() == "-7 hnsecs"); 
     1164        assert(Duration(-10).toString() == "-1 ÃŽÅ’s"); 
     1165        assert(Duration(-20).toString() == "-2 ÃŽÅ’s"); 
     1166        assert(Duration(-10_000).toString() == "-1 ms"); 
     1167        assert(Duration(-20_000).toString() == "-2 ms"); 
     1168        assert(Duration(-10_000_000).toString() == "-1 secs"); 
     1169        assert(Duration(-20_000_000).toString() == "-2 secs"); 
     1170        assert(Duration(-600_000_000).toString() == "-1 minutes"); 
     1171        assert(Duration(-1_200_000_000).toString() == "-2 minutes"); 
     1172        assert(Duration(-36_000_000_000).toString() == "-1 hours"); 
     1173        assert(Duration(-72_000_000_000).toString() == "-2 hours"); 
     1174        assert(Duration(-864_000_000_000).toString() == "-1 days"); 
     1175        assert(Duration(-1_728_000_000_000).toString() == "-2 days"); 
     1176        assert(Duration(-6_048_000_000_000).toString() == "-1 weeks"); 
     1177        assert(Duration(-12_096_000_000_000).toString() == "-2 weeks"); 
     1178 
     1179        assert(Duration(-12).toString() == "-1 ÃŽÅ’s and -2 hnsecs"); 
     1180        assert(Duration(-120_795).toString() == "-12 ms, -79 ÃŽÅ’s, and -5 hnsecs"); 
     1181        assert(Duration(-12_096_020_900_003).toString() == "-2 weeks, -2 secs, -90 ms, and -3 hnsecs"); 
     1182    } 
     1183 
     1184 
     1185    /++ 
     1186        Params: 
     1187            hnsecs = The total number of hecto-nanoseconds in this duration. 
     1188      +/ 
     1189    @safe 
     1190    this(long hnsecs) pure nothrow 
     1191    { 
     1192        _hnsecs = hnsecs; 
     1193    } 
     1194 
     1195 
     1196    long _hnsecs; 
     1197
     1198 
     1199 
     1200/++ 
     1201    This allows you to construct a Duration from the given time units 
     1202    with the given length. 
     1203 
     1204    The possible values for units are "weeks", "days", "hours", "minutes", 
     1205    "seconds", "msecs" (milliseconds), "usecs", (microseconds), 
     1206    and "hnsecs" (hecto-nanoseconds, i.e. 100 ns). 
     1207 
     1208    Params: 
     1209        units  = The time units of the duration (e.g. "days"). 
     1210        length = The number of units in the duration. 
     1211  +/ 
     1212@safe 
     1213Duration dur(string units)(long length) pure nothrow 
     1214    if(units == "weeks" || 
     1215       units == "days" || 
     1216       units == "hours" || 
     1217       units == "minutes" || 
     1218       units == "seconds" || 
     1219       units == "msecs" || 
     1220       units == "usecs" || 
     1221       units == "hnsecs" || 
     1222       units == "nsecs") 
     1223
     1224    return Duration(convert!(units, "hnsecs")(length)); 
     1225
     1226 
     1227unittest 
     1228
     1229    assert(dur!"weeks"(7).total!"weeks"() == 7); 
     1230    assert(dur!"days"(7).total!"days"() == 7); 
     1231    assert(dur!"hours"(7).total!"hours"() == 7); 
     1232    assert(dur!"minutes"(7).total!"minutes"() == 7); 
     1233    assert(dur!"seconds"(7).total!"seconds"() == 7); 
     1234    assert(dur!"msecs"(7).total!"msecs"() == 7); 
     1235    assert(dur!"usecs"(7).total!"usecs"() == 7); 
     1236    assert(dur!"hnsecs"(7).total!"hnsecs"() == 7); 
     1237    assert(dur!"nsecs"(7).total!"nsecs"() == 0); 
     1238
     1239 
     1240 
     1241/++ 
     1242   Duration in system clock ticks. 
     1243 
     1244   This type maintains the most high precision ticks of system clock in each 
     1245   environment. 
     1246  +/ 
     1247struct TickDuration 
     1248
     1249@safe:// @@@BUG@@@ workaround for bug 4211 
     1250 
     1251 
     1252    /++ 
     1253       The number of ticks that the system clock has in one second. 
     1254 
     1255       Confirm that it is not 0, to examine whether you can use TickDuration. 
     1256      +/ 
     1257    static immutable long ticksPerSec; 
     1258 
     1259 
     1260    /++ 
     1261       TickDuration when application begins. 
     1262      +/ 
     1263    static immutable TickDuration appOrigin; 
     1264 
     1265 
     1266    @trusted 
     1267    shared static this() 
     1268    { 
     1269        version(Windows) 
     1270        { 
     1271            if(QueryPerformanceFrequency(cast(long*)&ticksPerSec) == 0) 
     1272                ticksPerSec = 0; 
     1273        } 
     1274        else version(OSX) 
     1275        { 
     1276            static if(is(typeof(mach_absolute_time))) 
     1277            { 
     1278                mach_timebase_info_data_t info; 
     1279 
     1280                if(mach_timebase_info(&info)) 
     1281                    ticksPerSec = 0; 
     1282                else 
     1283                    ticksPerSec = (1_000_000_000 * info.numer) / info.denom; 
     1284            } 
     1285            else 
     1286                ticksPerSec = 1_000_000; 
     1287        } 
     1288        else version(Posix) 
     1289        { 
     1290            static if(is(typeof(clock_gettime))) 
     1291            { 
     1292                timespec ts; 
     1293 
     1294                if(clock_getres(CLOCK_MONOTONIC, &ts) != 0) 
     1295                    ticksPerSec = 0; 
     1296                else 
     1297                    ticksPerSec = 1_000_000_000 / ts.tv_nsec; 
     1298            } 
     1299            else 
     1300                ticksPerSec = 1_000_000; 
     1301        } 
     1302 
     1303        if(ticksPerSec != 0) 
     1304            appOrigin = TickDuration.currSystemTick; 
     1305    } 
     1306 
     1307    unittest 
     1308    { 
     1309        assert(ticksPerSec); 
     1310    } 
     1311 
     1312 
     1313    /++ 
     1314       The number of ticks. 
     1315 
     1316       You can convert this length into number of seconds by dividing it 
     1317       by ticksPerSec. 
     1318      +/ 
     1319    long length; 
     1320 
     1321 
     1322    /++ 
     1323        Converts TickDuration to the given units as an integral value. 
     1324 
     1325        Params: 
     1326            units = The units to convert to. "seconds" and smaller only. 
     1327            T     = The integral type to convert to. 
     1328      +/ 
     1329    T to(string units, T)() const pure nothrow 
     1330        if((units == "seconds" || 
     1331            units == "msecs" || 
     1332            units == "usecs" || 
     1333            units == "hnsecs" || 
     1334            units == "nsecs") && 
     1335           (__traits(isIntegral, T) && T.sizeof >= 4)) 
     1336    { 
     1337        enum unitsPerSec = convert!("seconds", units)(1); 
     1338 
     1339        if(ticksPerSec >= unitsPerSec) 
     1340            return cast(T)(length / (ticksPerSec / unitsPerSec)); 
     1341        else 
     1342            return cast(T)(length * (unitsPerSec / ticksPerSec)); 
     1343    } 
     1344 
     1345 
     1346    /++ 
     1347        Converts TickDuration to the given units as a floating point value. 
     1348 
     1349        Params: 
     1350            units = The units to convert to. "seconds" and smaller only. 
     1351            T     = The floating point type to convert to. 
     1352      +/ 
     1353    T to(string units, T)() const pure nothrow 
     1354        if((units == "seconds" || 
     1355            units == "msecs" || 
     1356            units == "usecs" || 
     1357            units == "hnsecs" || 
     1358            units == "nsecs") && 
     1359           __traits(isFloating, T)) 
     1360    { 
     1361        static if(units == "seconds") 
     1362        { 
     1363            //@@@BUG@@@ workaround for bug 4689 
     1364            long t = ticksPerSec; 
     1365 
     1366            return length / cast(T)t; 
    1931367        } 
    1941368        else 
    195         static if( op == "+" ) 
    1961369        { 
    197             return Duration( +m_ticks ); 
     1370            enum unitsPerSec = convert!("seconds", units)(1); 
     1371 
     1372            return to!("seconds", T) * unitsPerSec; 
    1981373        } 
    199     } 
    200  
    201      
    202     Duration opBinary(string op)( Duration other ) 
    203     // TODO: It would be nice if ref const could be used here, but it doesn't 
    204     //       work for rvalues.  Give this another look once auto ref works. 
    205     //Duration opBinary(string op)( ref const(Duration) other ) 
    206         if( op == "+" || op == "-" || op == "*" || op == "/" ) 
    207     { 
    208         auto   x = this; 
    209         return x.opOpAssign!(op)( other ); 
    210     } 
    211      
    212      
    213     Duration opOpAssign(string op)( Duration other ) 
    214     // TODO: It would be nice if ref const could be used here, but it doesn't 
    215     //       work for rvalues.  Give this another look once auto ref works. 
    216     //Duration opOpAssign(string op)( ref const(Duration) other ) 
    217         if( op == "+" || op == "-" || op == "*" || op == "/" ) 
    218     { 
    219         static if( op == "+" ) 
     1374   } 
     1375 
     1376    /++ 
     1377        Alias for converting TickDuration to seconds. 
     1378      +/ 
     1379    @property alias to!("seconds", long) seconds; 
     1380 
     1381    unittest 
     1382    { 
     1383        auto t = TickDuration(ticksPerSec); 
     1384        assert(t.seconds == 1); 
     1385        t = TickDuration(ticksPerSec-1); 
     1386        assert(t.seconds == 0); 
     1387        t = TickDuration(ticksPerSec*2); 
     1388        assert(t.seconds == 2); 
     1389        t = TickDuration(ticksPerSec*2-1); 
     1390        assert(t.seconds == 1); 
     1391        t = TickDuration(-1); 
     1392        assert(t.seconds == 0); 
     1393        t = TickDuration(-ticksPerSec-1); 
     1394        assert(t.seconds == -1); 
     1395        t = TickDuration(-ticksPerSec); 
     1396        assert(t.seconds == -1); 
     1397    } 
     1398 
     1399    /++ 
     1400        Alias for converting TickDuration to milliseconds. 
     1401      +/ 
     1402    @property alias to!("msecs", long) msecs; 
     1403 
     1404 
     1405    /++ 
     1406        Alias for converting TickDuration to microseconds. 
     1407      +/ 
     1408 
     1409 
     1410    @property alias to!("usecs", long) usecs; 
     1411 
     1412 
     1413    /++ 
     1414        Alias for converting TickDuration to hecto-nanoseconds (100 ns). 
     1415      +/ 
     1416    @property alias to!("hnsecs", long) hnsecs; 
     1417 
     1418 
     1419    /++ 
     1420        Alias for converting TickDuration to nanoseconds. 
     1421      +/ 
     1422    @property alias to!("nsecs", long) nsecs; 
     1423 
     1424 
     1425    /++ 
     1426        Creates a TickDuration from the number of the given units. 
     1427 
     1428        Params: 
     1429            units = The units to convert from. "seconds" and smaller. 
     1430            value = The number of the units to convert from. 
     1431      +/ 
     1432    static TickDuration from(string units)(long value) pure nothrow 
     1433        if(units == "seconds" || 
     1434           units == "msecs" || 
     1435           units == "usecs" || 
     1436           units == "hnsecs" || 
     1437           units == "nsecs") 
     1438    { 
     1439        enum unitsPerSec = convert!("seconds", units)(1); 
     1440 
     1441        if(ticksPerSec >= unitsPerSec) 
     1442            return TickDuration(value * (ticksPerSec / unitsPerSec)); 
     1443        else 
     1444            return TickDuration(value / (unitsPerSec / ticksPerSec)); 
     1445    } 
     1446 
     1447    //test from!"seconds"(). 
     1448    unittest 
     1449    { 
     1450        auto t = TickDuration.from!"seconds"(1_000_000); 
     1451        assert(t.seconds == 1_000_000); 
     1452        t = TickDuration.from!"seconds"(2_000_000); 
     1453        assert(t.seconds == 2_000_000); 
     1454 
     1455        if(ticksPerSec >= 1) 
    2201456        { 
    221             m_ticks += other.m_ticks; 
     1457            t.length -= 1; 
     1458            assert(t.seconds == 1_999_999); 
    2221459        } 
     1460 
     1461        if(ticksPerSec >= 1) 
     1462            assert(TickDuration.from!"seconds"(7).seconds == 7); 
     1463    } 
     1464 
     1465    //test from!"msecs"(). 
     1466    unittest 
     1467    { 
     1468        auto t = TickDuration.from!"msecs"(1_000_000); 
     1469        assert(t.msecs == 1_000_000); 
     1470        t = TickDuration.from!"msecs"(2_000_000); 
     1471        assert(t.msecs == 2_000_000); 
     1472 
     1473        if(ticksPerSec >= 1000) 
     1474        { 
     1475            t.length -= 1; 
     1476            assert(t.msecs == 1_999_999); 
     1477        } 
     1478 
     1479        if(ticksPerSec >= 1_000) 
     1480            assert(TickDuration.from!"msecs"(7).msecs == 7); 
     1481    } 
     1482 
     1483    //test from!"usecs"(). 
     1484    unittest 
     1485    { 
     1486        auto t = TickDuration.from!"usecs"(1_000_000); 
     1487        assert(t.usecs == 1_000_000); 
     1488        t = TickDuration.from!"usecs"(2_000_000); 
     1489        assert(t.usecs == 2_000_000); 
     1490 
     1491        if(ticksPerSec >= 1_000_000) 
     1492        { 
     1493            t.length -= 1; 
     1494            assert(t.usecs == 1_999_999); 
     1495        } 
     1496 
     1497        if(ticksPerSec >= 1_000_000) 
     1498            assert(TickDuration.from!"usecs"(7).usecs == 7); 
     1499    } 
     1500 
     1501    //test from!"hnsecs"(). 
     1502    unittest 
     1503    { 
     1504        auto t = TickDuration.from!"hnsecs"(10_000_000); 
     1505        assert(t.hnsecs == 10_000_000); 
     1506        t = TickDuration.from!"hnsecs"(20_000_000); 
     1507        assert(t.hnsecs == 20_000_000); 
     1508 
     1509        if(ticksPerSec == 1_000_000) 
     1510        { 
     1511            t.length -= 1; 
     1512            assert(t.hnsecs == 19999990); 
     1513            assert(TickDuration.from!"hnsecs"(70).hnsecs == 70); 
     1514            assert(TickDuration.from!"hnsecs"(7).hnsecs == 0); 
     1515        } 
     1516 
     1517        if(ticksPerSec >= 10_000_000) 
     1518        { 
     1519            t.length -= 1; 
     1520            assert(t.hnsecs == 19999999); 
     1521            assert(TickDuration.from!"hnsecs"(70).hnsecs == 70); 
     1522            assert(TickDuration.from!"hnsecs"(7).hnsecs == 7); 
     1523        } 
     1524    } 
     1525 
     1526    //test from!"nsecs"(). 
     1527    unittest 
     1528    { 
     1529        auto t = TickDuration.from!"nsecs"(1_000_000_000); 
     1530        assert(t.nsecs == 1_000_000_000); 
     1531        t = TickDuration.from!"nsecs"(2_000_000_000); 
     1532        assert(t.nsecs == 2_000_000_000); 
     1533 
     1534        if(ticksPerSec == 1_000_000) 
     1535        { 
     1536            t.length -= 1; 
     1537            assert(t.nsecs == 1999999000); 
     1538        } 
     1539 
     1540        if(ticksPerSec >= 1_000_000_000) 
     1541        { 
     1542            t.length -= 1; 
     1543            assert(t.nsecs == 1999999999); 
     1544        } 
     1545    } 
     1546 
     1547 
     1548    /++ 
     1549        Returns a Duration with the same number of hnsecs as this TickDuration. 
     1550      +/ 
     1551    Duration opCast(T)() const pure nothrow 
     1552        if(is(T == Duration)) 
     1553    { 
     1554        return Duration(hnsecs); 
     1555    } 
     1556 
     1557    unittest 
     1558    { 
     1559        auto t = TickDuration.from!"hnsecs"(10000000); 
     1560        assert(cast(Duration)t == Duration(10000000)); 
     1561        t = TickDuration.from!"hnsecs"(20000000); 
     1562        assert(cast(Duration)t == Duration(20000000)); 
     1563 
     1564        if(ticksPerSec == 1_000_000) 
     1565        { 
     1566            t.length -= 1; 
     1567            assert(cast(Duration)t == Duration(19999990)); 
     1568            assert(cast(Duration)TickDuration.from!"hnsecs"(70) == Duration(70)); 
     1569            assert(cast(Duration)TickDuration.from!"hnsecs"(7) == Duration(0)); 
     1570        } 
     1571 
     1572        if(ticksPerSec >= 10_000_000) 
     1573        { 
     1574            t.length -= 1; 
     1575            assert(cast(Duration)t == Duration(19999999)); 
     1576            assert(cast(Duration)TickDuration.from!"hnsecs"(70) == Duration(70)); 
     1577            assert(cast(Duration)TickDuration.from!"hnsecs"(7) == Duration(7)); 
     1578        } 
     1579    } 
     1580 
     1581 
     1582    /++ 
     1583       operator overloading "-=, +=" 
     1584 
     1585       BUG: This should be return "ref TickDuration", but bug2460 prevents that. 
     1586      +/ 
     1587    /+ref TickDuration+/ void opOpAssign(string op)(in TickDuration rhs) pure nothrow 
     1588        if(op == "+" || op == "-") 
     1589    { 
     1590        mixin("length " ~ op ~ "= rhs.length;"); 
     1591        //return this; 
     1592    } 
     1593 
     1594    unittest 
     1595    { 
     1596        TickDuration a = TickDuration.currSystemTick, b = TickDuration.currSystemTick; 
     1597        a += TickDuration.currSystemTick; 
     1598        assert(a.to!("seconds", real)() >= 0); 
     1599        b -= TickDuration.currSystemTick; 
     1600        assert(b.to!("seconds", real)() <= 0); 
     1601    } 
     1602 
     1603 
     1604    /++ 
     1605       operator overloading "-, +" 
     1606      +/ 
     1607    TickDuration opBinary(string op)(in TickDuration rhs) const pure nothrow 
     1608        if(op == "-" || op == "+") 
     1609    { 
     1610        return TickDuration(mixin("length " ~ op ~ " rhs.length")); 
     1611    } 
     1612 
     1613    unittest 
     1614    { 
     1615        auto a = TickDuration.currSystemTick; 
     1616        auto b = TickDuration.currSystemTick; 
     1617        assert((a + b).to!("seconds", real) > 0); 
     1618        assert((a - b).to!("seconds", real) <= 0); 
     1619    } 
     1620 
     1621 
     1622    /++ 
     1623        Returns the negation of this TickDuration. 
     1624      +/ 
     1625    TickDuration opUnary(string op)() const pure nothrow 
     1626        if(op == "-") 
     1627    { 
     1628        return TickDuration(-length); 
     1629    } 
     1630 
     1631    unittest 
     1632    { 
     1633        assert(-TickDuration(7) == TickDuration(-7)); 
     1634        assert(-TickDuration(5) == TickDuration(-5)); 
     1635        assert(-TickDuration(-7) == TickDuration(7)); 
     1636        assert(-TickDuration(-5) == TickDuration(5)); 
     1637        assert(-TickDuration(0) == TickDuration(0)); 
     1638 
     1639        const cdur = TickDuration(12); 
     1640        immutable idur = TickDuration(12); 
     1641        static assert(__traits(compiles, -cdur)); 
     1642        static assert(__traits(compiles, -idur)); 
     1643    } 
     1644 
     1645 
     1646    /++ 
     1647       operator overloading "==" 
     1648      +/ 
     1649    bool opEquals(ref const TickDuration rhs) const pure nothrow 
     1650    { 
     1651        return length == rhs.length; 
     1652    } 
     1653 
     1654    unittest 
     1655    { 
     1656        auto t1 = TickDuration.currSystemTick; 
     1657        assert(t1 == t1); 
     1658    } 
     1659 
     1660 
     1661    /++ 
     1662       operator overloading "<, >, <=, >=" 
     1663      +/ 
     1664    int opCmp(ref const TickDuration rhs) const pure nothrow 
     1665    { 
     1666        return length < rhs.length ? -1 : (length == rhs.length ? 0 : 1); 
     1667    } 
     1668 
     1669    unittest 
     1670    { 
     1671        auto t1 = TickDuration.currSystemTick; 
     1672        auto t2 = TickDuration.currSystemTick; 
     1673        assert(t1 <= t2); 
     1674        assert(t2 >= t1); 
     1675    } 
     1676 
     1677 
     1678    /++ 
     1679        The legal types of arithmetic for TickDuration using this operator overload are 
     1680 
     1681        $(TABLE 
     1682        $(TR $(TD TickDuration) $(TD *) $(TD long) $(TD -->) $(TD TickDuration)) 
     1683        $(TR $(TD TickDuration) $(TD *) $(TD floating point) $(TD -->) $(TD TickDuration)) 
     1684        ) 
     1685 
     1686        Params: 
     1687            value = The value to divide from this duration. 
     1688      +/ 
     1689    void opOpAssign(string op, T)(T value) pure nothrow 
     1690        if(op == "*" && 
     1691           (__traits(isIntegral, T) || __traits(isFloating, T))) 
     1692    { 
     1693        length *= value; 
     1694    } 
     1695 
     1696    unittest 
     1697    { 
     1698        immutable t = TickDuration.currSystemTick; 
     1699        TickDuration t1 = t, t2 = t; 
     1700        t1 /= 2; 
     1701        assert(t1 < t); 
     1702        t2 /= 2.1L; 
     1703        assert(t2 < t1); 
     1704    } 
     1705 
     1706 
     1707    /++ 
     1708        The legal types of arithmetic for TickDuration using this operator overload are 
     1709 
     1710        $(TABLE 
     1711        $(TR $(TD TickDuration) $(TD /) $(TD long) $(TD -->) $(TD TickDuration)) 
     1712        $(TR $(TD TickDuration) $(TD /) $(TD floating point) $(TD -->) $(TD TickDuration)) 
     1713        ) 
     1714 
     1715        Params: 
     1716            value = The value to divide from this duration. 
     1717 
     1718        Throws: 
     1719            TimeException if an attempt to divide by 0 is made. 
     1720      +/ 
     1721    void opOpAssign(string op, T)(T value) pure 
     1722        if(op == "/" && 
     1723           (__traits(isIntegral, T) || __traits(isFloating, T))) 
     1724    { 
     1725        if(value == 0) 
     1726            throw new TimeException("Attempted division by 0."); 
     1727 
     1728        length /= value; 
     1729    } 
     1730 
     1731    unittest 
     1732    { 
     1733        immutable t = TickDuration.currSystemTick; 
     1734        TickDuration t1 = t, t2 = t; 
     1735        t1 /= 2; 
     1736        assert(t1 < t); 
     1737        t2 /= 2.1L; 
     1738        assert(t2 < t1); 
     1739    } 
     1740 
     1741 
     1742    /++ 
     1743        The legal types of arithmetic for TickDuration using this operator overload are 
     1744 
     1745        $(TABLE 
     1746        $(TR $(TD TickDuration) $(TD *) $(TD long) $(TD -->) $(TD TickDuration)) 
     1747        $(TR $(TD TickDuration) $(TD *) $(TD floating point) $(TD -->) $(TD TickDuration)) 
     1748        ) 
     1749 
     1750        Params: 
     1751            value = The value to divide from this duration. 
     1752      +/ 
     1753    TickDuration opBinary(string op, T)(T value) const pure nothrow 
     1754        if(op == "*" && 
     1755           (__traits(isIntegral, T) || __traits(isFloating, T))) 
     1756    { 
     1757        return TickDuration(cast(long)(length * value)); 
     1758    } 
     1759 
     1760    unittest 
     1761    { 
     1762        auto t = TickDuration.currSystemTick; 
     1763        auto t2 = t*2; 
     1764        assert(t < t2); 
     1765        assert(t*3.5 > t2); 
     1766    } 
     1767 
     1768 
     1769    /++ 
     1770        The legal types of arithmetic for TickDuration using this operator overload are 
     1771 
     1772        $(TABLE 
     1773        $(TR $(TD TickDuration) $(TD /) $(TD long) $(TD -->) $(TD TickDuration)) 
     1774        $(TR $(TD TickDuration) $(TD /) $(TD floating point) $(TD -->) $(TD TickDuration)) 
     1775        ) 
     1776 
     1777        Params: 
     1778            value = The value to divide from this duration. 
     1779 
     1780        Throws: 
     1781            TimeException if an attempt to divide by 0 is made. 
     1782      +/ 
     1783    TickDuration opBinary(string op, T)(T value) const pure 
     1784        if(op == "/" && 
     1785           (__traits(isIntegral, T) || __traits(isFloating, T))) 
     1786    { 
     1787        if(value == 0) 
     1788            throw new TimeException("Attempted division by 0."); 
     1789 
     1790        return TickDuration(cast(long)(length / value)); 
     1791    } 
     1792 
     1793 
     1794    /++ 
     1795        Params: 
     1796            ticks = The number of ticks in the TickDuration. 
     1797      +/ 
     1798    this(long ticks) pure nothrow 
     1799    { 
     1800        this.length = ticks; 
     1801    } 
     1802 
     1803 
     1804    /++ 
     1805        The current system tick. The number of ticks per second varies from 
     1806        system to system. This uses a monotonic clock, so it's intended for 
     1807        precision timing by comparing relative time values, not for getting 
     1808        the current system time. 
     1809 
     1810        On Windows, QueryPerformanceCounter() is used. On Mac OS X, 
     1811        mach_absolute_time() is used, while on other Posix systems, 
     1812        clock_gettime() is used. If mach_absolute_time() or clock_gettime() 
     1813        is unavailable, then Posix systems use gettimeofday(), which 
     1814        unfortunately, is not monotonic, but without 
     1815        mach_absolute_time()/clock_gettime() available, gettimeofday() is the 
     1816        the best that you can do. 
     1817 
     1818        Warning: 
     1819            On some systems, the monotonic clock may stop counting when 
     1820            the computer goes to sleep or hibernates. So, the monotonic 
     1821            clock could be off if that occurs. This is known to happen 
     1822            on Mac OS X. It has not been tested whether it occurs on 
     1823            either Windows or on Linux. 
     1824 
     1825        Throws: 
     1826            TimeException if it fails to get the time. 
     1827      +/ 
     1828    @trusted 
     1829    static @property TickDuration currSystemTick() 
     1830    { 
     1831        version(Windows) 
     1832        { 
     1833            ulong ticks; 
     1834 
     1835            if(QueryPerformanceCounter(cast(long*)&ticks) == 0) 
     1836                throw new TimeException(sysErrorString(GetLastError())); 
     1837 
     1838            return TickDuration(ticks); 
     1839        } 
     1840        else version(OSX) 
     1841        { 
     1842            static if(is(typeof(mach_absolute_time))) 
     1843                return TickDuration(cast(long)mach_absolute_time()); 
     1844            else 
     1845            { 
     1846                timeval tv; 
     1847                if(gettimeofday(&tv, null) != 0) 
     1848                    throw new TimeException("Failed in gettimeofday()."); 
     1849 
     1850                return TickDuration(tv.tv_sec * TickDuration.ticksPerSec + 
     1851                                    tv.tv_usec * TickDuration.ticksPerSec / 1000 / 1000); 
     1852            } 
     1853        } 
     1854        else version(Posix) 
     1855        { 
     1856            static if(is(typeof(clock_gettime))) 
     1857            { 
     1858                timespec ts; 
     1859 
     1860                if(clock_gettime(CLOCK_MONOTONIC, &ts) != 0) 
     1861                    throw new TimeException("Failed in clock_gettime()."); 
     1862 
     1863                return TickDuration(ts.tv_sec * TickDuration.ticksPerSec + 
     1864                                    ts.tv_nsec * TickDuration.ticksPerSec / 1000 / 1000 / 1000); 
     1865            } 
     1866            else 
     1867            { 
     1868                timeval tv; 
     1869                if(gettimeofday(&tv, null) != 0) 
     1870                    throw new TimeException("Failed in gettimeofday()."); 
     1871 
     1872                return TickDuration(tv.tv_sec * TickDuration.ticksPerSec + 
     1873                                    tv.tv_usec * TickDuration.ticksPerSec / 1000 / 1000); 
     1874            } 
     1875        } 
     1876    } 
     1877 
     1878    @trusted 
     1879    unittest 
     1880    { 
     1881        auto t = TickDuration.currSystemTick; 
     1882        assert(t.length > 0); 
     1883    } 
     1884} 
     1885 
     1886 
     1887/++ 
     1888    Generic way of converting between two time units. Conversions to smaller 
     1889    units use truncating division. 
     1890 
     1891    Params: 
     1892        tuFrom = The units of time to covert from. 
     1893        tuFrom = The units of time to covert type. 
     1894        value  = The value to convert. 
     1895 
     1896    Examples: 
     1897-------------------- 
     1898assert(convert!("years", "months")(1) == 12); 
     1899assert(convert!("months", "years")(12) == 1); 
     1900-------------------- 
     1901  +/ 
     1902@safe 
     1903long convert(string from, string to)(long value) pure nothrow 
     1904    if((from == "years" || from == "months") && 
     1905       (to == "years" || to == "months")) 
     1906{ 
     1907    static if(from == "years") 
     1908    { 
     1909        static if(to == "years") 
     1910            return value; 
     1911        else static if(to == "months") 
     1912            return value * 12; 
    2231913        else 
    224         static if( op == "-" ) 
     1914            static assert(0, "A generic month or year cannot be converted to or from smaller units."); 
     1915    } 
     1916    else static if(from == "months") 
     1917    { 
     1918        static if(to == "years") 
     1919            return value / 12; 
     1920        else static if(to == "months") 
     1921            return value; 
     1922        else 
     1923            static assert(0, "A generic month or year cannot be converted to or from smaller units."); 
     1924    } 
     1925    else 
     1926        static assert(0, "Template constraint broken. Invalid time unit string."); 
     1927
     1928 
     1929unittest 
     1930
     1931    static assert(!__traits(compiles, convert!("years", "weeks")(12))); 
     1932    static assert(!__traits(compiles, convert!("years", "days")(12))); 
     1933    static assert(!__traits(compiles, convert!("years", "hours")(12))); 
     1934    static assert(!__traits(compiles, convert!("years", "seconds")(12))); 
     1935    static assert(!__traits(compiles, convert!("years", "msecs")(12))); 
     1936    static assert(!__traits(compiles, convert!("years", "usecs")(12))); 
     1937    static assert(!__traits(compiles, convert!("years", "hnsecs")(12))); 
     1938 
     1939    static assert(!__traits(compiles, convert!("weeks", "years")(12))); 
     1940    static assert(!__traits(compiles, convert!("days", "years")(12))); 
     1941    static assert(!__traits(compiles, convert!("hours", "years")(12))); 
     1942    static assert(!__traits(compiles, convert!("seconds", "years")(12))); 
     1943    static assert(!__traits(compiles, convert!("msecs", "years")(12))); 
     1944    static assert(!__traits(compiles, convert!("usecs", "years")(12))); 
     1945    static assert(!__traits(compiles, convert!("hnsecs", "years")(12))); 
     1946 
     1947    assert(convert!("years", "years")(12) == 12); 
     1948    assert(convert!("months", "months")(12) == 12); 
     1949 
     1950    //Verify Examples. 
     1951    assert(convert!("years", "months")(1) == 12); 
     1952    assert(convert!("months", "years")(12) == 1); 
     1953
     1954 
     1955 
     1956/++ 
     1957    Generic way of converting between two time units. Conversions to smaller 
     1958    units use truncating division. 
     1959 
     1960    Params: 
     1961        tuFrom = The units of time to covert from. 
     1962        tuFrom = The units of time to covert type. 
     1963        value  = The value to convert. 
     1964 
     1965    Examples: 
     1966-------------------- 
     1967assert(convert!("weeks", "days")(1) == 7); 
     1968assert(convert!("hours", "seconds")(1) == 3600); 
     1969assert(convert!("seconds", "days")(1) == 0); 
     1970assert(convert!("seconds", "days")(86_400) == 1); 
     1971-------------------- 
     1972  +/ 
     1973@safe 
     1974static long convert(string from, string to)(long value) pure nothrow 
     1975    if((from == "weeks" || 
     1976        from == "days" || 
     1977        from == "hours" || 
     1978        from == "minutes" || 
     1979        from == "seconds" || 
     1980        from == "msecs" || 
     1981        from == "usecs" || 
     1982        from == "hnsecs") && 
     1983       (to == "weeks" || 
     1984        to == "days" || 
     1985        to == "hours" || 
     1986        to == "minutes" || 
     1987        to == "seconds" || 
     1988        to == "msecs" || 
     1989        to == "usecs" || 
     1990        to == "hnsecs")) 
     1991
     1992    return (hnsecsPer!from * value) / hnsecsPer!to; 
     1993
     1994 
     1995unittest 
     1996
     1997    assert(convert!("weeks", "hnsecs")(1) == 6_048_000_000_000L); 
     1998    assert(convert!("days", "hnsecs")(1) == 864_000_000_000L); 
     1999    assert(convert!("hours", "hnsecs")(1) == 36_000_000_000L); 
     2000    assert(convert!("minutes", "hnsecs")(1) == 600_000_000L); 
     2001    assert(convert!("seconds", "hnsecs")(1) == 10_000_000L); 
     2002    assert(convert!("msecs", "hnsecs")(1) == 10_000); 
     2003    assert(convert!("usecs", "hnsecs")(1) == 10); 
     2004 
     2005    assert(convert!("hnsecs", "weeks")(6_048_000_000_000L) == 1); 
     2006    assert(convert!("hnsecs", "days")(864_000_000_000L) == 1); 
     2007    assert(convert!("hnsecs", "hours")(36_000_000_000L) == 1); 
     2008    assert(convert!("hnsecs", "minutes")(600_000_000L) == 1); 
     2009    assert(convert!("hnsecs", "seconds")(10_000_000L) == 1); 
     2010    assert(convert!("hnsecs", "msecs")(10_000) == 1); 
     2011    assert(convert!("hnsecs", "usecs")(10) == 1); 
     2012 
     2013    assert(convert!("weeks", "weeks")(12) == 12); 
     2014    assert(convert!("days", "days")(12) == 12); 
     2015    assert(convert!("hours", "hours")(12) == 12); 
     2016    assert(convert!("minutes", "minutes")(12) == 12); 
     2017    assert(convert!("seconds", "seconds")(12) == 12); 
     2018    assert(convert!("msecs", "msecs")(12) == 12); 
     2019    assert(convert!("usecs", "usecs")(12) == 12); 
     2020    assert(convert!("hnsecs", "hnsecs")(12) == 12); 
     2021 
     2022    assert(convert!("weeks", "days")(1) == 7); 
     2023    assert(convert!("days", "weeks")(7) == 1); 
     2024 
     2025    assert(convert!("days", "hours")(1) == 24); 
     2026    assert(convert!("hours", "days")(24) == 1); 
     2027 
     2028    assert(convert!("hours", "minutes")(1) == 60); 
     2029    assert(convert!("minutes", "hours")(60) == 1); 
     2030 
     2031    assert(convert!("minutes", "seconds")(1) == 60); 
     2032    assert(convert!("seconds", "minutes")(60) == 1); 
     2033 
     2034    assert(convert!("seconds", "msecs")(1) == 1000); 
     2035    assert(convert!("msecs", "seconds")(1000) == 1); 
     2036 
     2037    assert(convert!("msecs", "usecs")(1) == 1000); 
     2038    assert(convert!("usecs", "msecs")(1000) == 1); 
     2039 
     2040    assert(convert!("usecs", "hnsecs")(1) == 10); 
     2041    assert(convert!("hnsecs", "usecs")(10) == 1); 
     2042 
     2043    assert(convert!("hnsecs", "hnsecs")(10) == 10); 
     2044    assert(convert!("hnsecs", "hnsecs")(10) == 10); 
     2045 
     2046    //Verify Examples. 
     2047    assert(convert!("weeks", "days")(1) == 7); 
     2048    assert(convert!("hours", "seconds")(1) == 3600); 
     2049    assert(convert!("seconds", "days")(1) == 0); 
     2050    assert(convert!("seconds", "days")(86_400) == 1); 
     2051
     2052 
     2053 
     2054/++ 
     2055    Generic way of converting between two time units. Conversions to smaller 
     2056    units use truncating division. 
     2057 
     2058    Params: 
     2059        tuFrom = The units of time to covert from. 
     2060        tuFrom = The units of time to covert type. 
     2061        value  = The value to convert. 
     2062 
     2063    Examples: 
     2064-------------------- 
     2065assert(convert!("nsecs", "nsecs")(1) == 1); 
     2066assert(convert!("nsecs", "hnsecs")(1) == 0); 
     2067assert(convert!("hnsecs", "nsecs")(1) == 100); 
     2068assert(convert!("nsecs", "seconds")(1) == 0); 
     2069assert(convert!("seconds", "nsecs")(1) == 1_000_000_000); 
     2070-------------------- 
     2071  +/ 
     2072@safe 
     2073static long convert(string from, string to)(long value) pure nothrow 
     2074    if((from == "nsecs" && 
     2075        (to == "weeks" || 
     2076         to == "days" || 
     2077         to == "hours" || 
     2078         to == "minutes" || 
     2079         to == "seconds" || 
     2080         to == "msecs" || 
     2081         to == "usecs" || 
     2082         to == "hnsecs" || 
     2083         to == "nsecs")) || 
     2084       (to == "nsecs" && 
     2085        (from == "weeks" || 
     2086         from == "days" || 
     2087         from == "hours" || 
     2088         from == "minutes" || 
     2089         from == "seconds" || 
     2090         from == "msecs" || 
     2091         from == "usecs" || 
     2092         from == "hnsecs" || 
     2093         from == "nsecs"))) 
     2094
     2095    static if(from == "nsecs" && to == "nsecs") 
     2096        return value; 
     2097    else static if(from == "nsecs") 
     2098        return convert!("hnsecs", to)(value / 100); 
     2099    else static if(to == "nsecs") 
     2100        return convert!(from, "hnsecs")(value) * 100; 
     2101    else 
     2102        static assert(0); 
     2103
     2104 
     2105unittest 
     2106
     2107    assert(convert!("weeks", "nsecs")(1) == 604_800_000_000_000L); 
     2108    assert(convert!("days", "nsecs")(1) == 86_400_000_000_000L); 
     2109    assert(convert!("hours", "nsecs")(1) == 3_600_000_000_000L); 
     2110    assert(convert!("minutes", "nsecs")(1) == 60_000_000_000L); 
     2111    assert(convert!("seconds", "nsecs")(1) == 1_000_000_000L); 
     2112    assert(convert!("msecs", "nsecs")(1) == 1_000_000); 
     2113    assert(convert!("usecs", "nsecs")(1) == 1000); 
     2114    assert(convert!("hnsecs", "nsecs")(1) == 100); 
     2115 
     2116    assert(convert!("nsecs", "weeks")(604_800_000_000_000L) == 1); 
     2117    assert(convert!("nsecs", "days")(86_400_000_000_000L) == 1); 
     2118    assert(convert!("nsecs", "hours")(3_600_000_000_000L) == 1); 
     2119    assert(convert!("nsecs", "minutes")(60_000_000_000L) == 1); 
     2120    assert(convert!("nsecs", "seconds")(1_000_000_000L) == 1); 
     2121    assert(convert!("nsecs", "msecs")(1_000_000) == 1); 
     2122    assert(convert!("nsecs", "usecs")(1000) == 1); 
     2123    assert(convert!("nsecs", "hnsecs")(100) == 1); 
     2124 
     2125    assert(convert!("nsecs", "nsecs")(1) == 1); 
     2126 
     2127    //Verify Examples. 
     2128    assert(convert!("nsecs", "nsecs")(1) == 1); 
     2129    assert(convert!("nsecs", "hnsecs")(1) == 0); 
     2130    assert(convert!("hnsecs", "nsecs")(1) == 100); 
     2131    assert(convert!("nsecs", "seconds")(1) == 0); 
     2132    assert(convert!("seconds", "nsecs")(1) == 1_000_000_000); 
     2133
     2134 
     2135 
     2136/++ 
     2137    Represents fractional seconds. 
     2138 
     2139    This is the portion of the time which is smaller than a second and cannot 
     2140    hold values which would equal or exceed a second. 
     2141 
     2142    It holds hnsecs internally, but you can create it using either milliseconds, 
     2143    microseconds, or hnsecs. What it does is allow for a simple way to set or adjust 
     2144    the fractional seconds portion of a Duration or a std.datetime.SysTime without 
     2145    having to worry about whether you're dealing with milliseconds, microseconds, 
     2146    or hnsecs. 
     2147 
     2148    FracSec's functions which take time unit strings do accept "nsecs", but the 
     2149    because the resolution for Duration and std.datetime.SysTime is hnsecs, you 
     2150    don't actually get precision higher than hnsecs. "nsecs" is accepted merely 
     2151    for convenience. Any values given as nsecs will be converted to hnsecs using 
     2152    convert!() (which uses truncation when converting to smaller units). 
     2153  +/ 
     2154struct FracSec 
     2155
     2156public: 
     2157 
     2158    /++ 
     2159        Create a FracSec from the given units ("msecs", "usecs", or "hnsecs"). 
     2160 
     2161        Params: 
     2162            units = The units to create a FracSec from. 
     2163            value = The number of the given units passed the second. 
     2164 
     2165        Throws: 
     2166            TimeException if the given value is less than 0 or would result in a 
     2167            FracSec greater than or equal to 1 second. 
     2168      +/ 
     2169    static FracSec from(string units)(int value) pure 
     2170        if(units == "msecs" || 
     2171           units == "usecs" || 
     2172           units == "hnsecs" || 
     2173           units == "nsecs") 
     2174    { 
     2175        return FracSec(cast(int)convert!(units, "hnsecs")(value)); 
     2176    } 
     2177 
     2178    unittest 
     2179    { 
     2180        tAssertExThrown!TimeException(from!"msecs"(-1)); 
     2181        tAssertExThrown!TimeException(from!"msecs"(1000)); 
     2182 
     2183        assert(FracSec.from!"msecs"(0) == FracSec(0)); 
     2184        assert(FracSec.from!"msecs"(1) == FracSec(10_000)); 
     2185        assert(FracSec.from!"msecs"(999) == FracSec(9_990_000)); 
     2186 
     2187        tAssertExThrown!TimeException(from!"usecs"(-1)); 
     2188        tAssertExThrown!TimeException(from!"usecs"(1_000_000)); 
     2189 
     2190        assert(FracSec.from!"usecs"(0) == FracSec(0)); 
     2191        assert(FracSec.from!"usecs"(1) == FracSec(10)); 
     2192        assert(FracSec.from!"usecs"(999) == FracSec(9990)); 
     2193        assert(FracSec.from!"usecs"(999_999) == FracSec(9999_990)); 
     2194 
     2195        tAssertExThrown!TimeException(from!"hnsecs"(-1)); 
     2196        tAssertExThrown!TimeException(from!"hnsecs"(10_000_000)); 
     2197 
     2198        assert(FracSec.from!"hnsecs"(0) == FracSec(0)); 
     2199        assert(FracSec.from!"hnsecs"(1) == FracSec(1)); 
     2200        assert(FracSec.from!"hnsecs"(999) == FracSec(999)); 
     2201        assert(FracSec.from!"hnsecs"(999_999) == FracSec(999_999)); 
     2202        assert(FracSec.from!"hnsecs"(9_999_999) == FracSec(9_999_999)); 
     2203 
     2204        assert(FracSec.from!"nsecs"(0) == FracSec(0)); 
     2205        assert(FracSec.from!"nsecs"(1) == FracSec(0)); 
     2206        assert(FracSec.from!"nsecs"(10) == FracSec(0)); 
     2207        assert(FracSec.from!"nsecs"(99) == FracSec(0)); 
     2208        assert(FracSec.from!"nsecs"(100) == FracSec(1)); 
     2209        assert(FracSec.from!"nsecs"(99_999) == FracSec(999)); 
     2210        assert(FracSec.from!"nsecs"(99_999_999) == FracSec(999_999)); 
     2211        assert(FracSec.from!"nsecs"(999_999_999) == FracSec(9_999_999)); 
     2212    } 
     2213 
     2214 
     2215    /++ 
     2216        The value of this FracSec as milliseconds. 
     2217      +/ 
     2218    @property int msecs() const pure nothrow 
     2219    { 
     2220        return cast(int)convert!("hnsecs", "msecs")(_hnsecs); 
     2221    } 
     2222 
     2223    unittest 
     2224    { 
     2225        assert(FracSec(0).msecs == 0); 
     2226        assert(FracSec(1).msecs == 0); 
     2227        assert(FracSec(999).msecs == 0); 
     2228        assert(FracSec(999_999).msecs == 99); 
     2229        assert(FracSec(9_999_999).msecs == 999); 
     2230 
     2231        auto fs = FracSec(12); 
     2232        const cfs = FracSec(12); 
     2233        immutable ifs = FracSec(12); 
     2234        static assert(__traits(compiles, fs.msecs)); 
     2235        static assert(__traits(compiles, cfs.msecs)); 
     2236        static assert(__traits(compiles, ifs.msecs)); 
     2237    } 
     2238 
     2239 
     2240    /++ 
     2241        The value of this FracSec as milliseconds. 
     2242 
     2243        Params: 
     2244            milliseconds = The number of milliseconds passed the second. 
     2245 
     2246        Throws: 
     2247            TimeException if the given value is not less than one second. 
     2248      +/ 
     2249    @property void msecs(int milliseconds) pure 
     2250    { 
     2251        immutable hnsecs = cast(int)convert!("msecs", "hnsecs")(milliseconds); 
     2252 
     2253        _enforceValid(hnsecs); 
     2254        _hnsecs = hnsecs; 
     2255    } 
     2256 
     2257    unittest 
     2258    { 
     2259        static void testFS(int ms, in FracSec expected = FracSec.init, size_t line = __LINE__) 
    2252260        { 
    226             m_ticks -= other.m_ticks; 
     2261            FracSec fs; 
     2262 
     2263            fs.msecs = ms; 
     2264 
     2265            if(fs != expected) 
     2266                throw new AssertError("", __FILE__, line); 
    2272267        } 
     2268 
     2269        tAssertExThrown!TimeException(testFS(-1)); 
     2270        tAssertExThrown!TimeException(testFS(1000)); 
     2271 
     2272        testFS(0, FracSec(0)); 
     2273        testFS(1, FracSec(10_000)); 
     2274        testFS(999, FracSec(9_990_000)); 
     2275 
     2276        auto fs = FracSec(12); 
     2277        const cfs = FracSec(12); 
     2278        immutable ifs = FracSec(12); 
     2279        static assert(__traits(compiles, fs.msecs = 54)); 
     2280        static assert(!__traits(compiles, cfs.msecs = 54)); 
     2281        static assert(!__traits(compiles, ifs.msecs = 54)); 
     2282    } 
     2283 
     2284 
     2285    /++ 
     2286        The value of this FracSec as microseconds. 
     2287      +/ 
     2288    @property int usecs() const pure nothrow 
     2289    { 
     2290        return cast(int)convert!("hnsecs", "usecs")(_hnsecs); 
     2291    } 
     2292 
     2293    unittest 
     2294    { 
     2295        assert(FracSec(0).usecs == 0); 
     2296        assert(FracSec(1).usecs == 0); 
     2297        assert(FracSec(999).usecs == 99); 
     2298        assert(FracSec(999_999).usecs == 99_999); 
     2299        assert(FracSec(9_999_999).usecs == 999_999); 
     2300 
     2301        auto fs = FracSec(12); 
     2302        const cfs = FracSec(12); 
     2303        immutable ifs = FracSec(12); 
     2304        static assert(__traits(compiles, fs.usecs)); 
     2305        static assert(__traits(compiles, cfs.usecs)); 
     2306        static assert(__traits(compiles, ifs.usecs)); 
     2307    } 
     2308 
     2309 
     2310    /++ 
     2311        The value of this FracSec as microseconds. 
     2312 
     2313        Params: 
     2314            microseconds = The number of microseconds passed the second. 
     2315 
     2316        Throws: 
     2317            TimeException if the given value is not less than one second. 
     2318      +/ 
     2319    @property void usecs(int microseconds) pure 
     2320    { 
     2321        immutable hnsecs = cast(int)convert!("usecs", "hnsecs")(microseconds); 
     2322 
     2323        _enforceValid(hnsecs); 
     2324        _hnsecs = hnsecs; 
     2325    } 
     2326 
     2327    unittest 
     2328    { 
     2329        static void testFS(int ms, in FracSec expected = FracSec.init, size_t line = __LINE__) 
     2330        { 
     2331            FracSec fs; 
     2332 
     2333            fs.usecs = ms; 
     2334 
     2335            if(fs != expected) 
     2336                throw new AssertError("", __FILE__, line); 
     2337        } 
     2338 
     2339        tAssertExThrown!TimeException(testFS(-1)); 
     2340        tAssertExThrown!TimeException(testFS(1_000_000)); 
     2341 
     2342        testFS(0, FracSec(0)); 
     2343        testFS(1, FracSec(10)); 
     2344        testFS(999, FracSec(9990)); 
     2345        testFS(999_999, FracSec(9_999_990)); 
     2346 
     2347        auto fs = FracSec(12); 
     2348        const cfs = FracSec(12); 
     2349        immutable ifs = FracSec(12); 
     2350        static assert(__traits(compiles, fs.usecs = 54)); 
     2351        static assert(!__traits(compiles, cfs.usecs = 54)); 
     2352        static assert(!__traits(compiles, ifs.usecs = 54)); 
     2353    } 
     2354 
     2355 
     2356    /++ 
     2357        The value of this FracSec as hnsecs. 
     2358      +/ 
     2359    @property int hnsecs() const pure nothrow 
     2360    { 
     2361        return _hnsecs; 
     2362    } 
     2363 
     2364    unittest 
     2365    { 
     2366        assert(FracSec(0).hnsecs == 0); 
     2367        assert(FracSec(1).hnsecs == 1); 
     2368        assert(FracSec(999).hnsecs == 999); 
     2369        assert(FracSec(999_999).hnsecs == 999_999); 
     2370        assert(FracSec(9_999_999).hnsecs == 9_999_999); 
     2371 
     2372        auto fs = FracSec(12); 
     2373        const cfs = FracSec(12); 
     2374        immutable ifs = FracSec(12); 
     2375        static assert(__traits(compiles, fs.hnsecs)); 
     2376        static assert(__traits(compiles, cfs.hnsecs)); 
     2377        static assert(__traits(compiles, ifs.hnsecs)); 
     2378    } 
     2379 
     2380 
     2381    /++ 
     2382        The value of this FracSec as hnsecs. 
     2383 
     2384        Params: 
     2385            hnsecs = The number of hnsecs passed the second. 
     2386 
     2387        Throws: 
     2388            TimeException if the given value is not less than one second. 
     2389      +/ 
     2390    @property void hnsecs(int hnsecs) pure 
     2391    { 
     2392        _enforceValid(hnsecs); 
     2393        _hnsecs = hnsecs; 
     2394    } 
     2395 
     2396    unittest 
     2397    { 
     2398        static void testFS(int hnsecs, in FracSec expected = FracSec.init, size_t line = __LINE__) 
     2399        { 
     2400            FracSec fs; 
     2401 
     2402            fs.hnsecs = hnsecs; 
     2403 
     2404            if(fs != expected) 
     2405                throw new AssertError("", __FILE__, line); 
     2406        } 
     2407 
     2408        tAssertExThrown!TimeException(testFS(-1)); 
     2409        tAssertExThrown!TimeException(testFS(10_000_000)); 
     2410 
     2411        testFS(0, FracSec(0)); 
     2412        testFS(1, FracSec(1)); 
     2413        testFS(999, FracSec(999)); 
     2414        testFS(999_999, FracSec(999_999)); 
     2415        testFS(9_999_999, FracSec(9_999_999)); 
     2416 
     2417        auto fs = FracSec(12); 
     2418        const cfs = FracSec(12); 
     2419        immutable ifs = FracSec(12); 
     2420        static assert(__traits(compiles, fs.hnsecs = 54)); 
     2421        static assert(!__traits(compiles, cfs.hnsecs = 54)); 
     2422        static assert(!__traits(compiles, ifs.hnsecs = 54)); 
     2423    } 
     2424 
     2425 
     2426    /++ 
     2427        The value of this FracSec as nsecs. 
     2428 
     2429        Note that this does not give you any greater precision 
     2430        than getting the value of this FracSec as hnsecs. 
     2431      +/ 
     2432    @property int nsecs() const pure nothrow 
     2433    { 
     2434        return cast(int)convert!("hnsecs", "nsecs")(_hnsecs); 
     2435    } 
     2436 
     2437    unittest 
     2438    { 
     2439        assert(FracSec(0).nsecs == 0); 
     2440        assert(FracSec(1).nsecs == 100); 
     2441        assert(FracSec(999).nsecs == 99_900); 
     2442        assert(FracSec(999_999).nsecs == 99_999_900); 
     2443        assert(FracSec(9_999_999).nsecs == 999_999_900); 
     2444 
     2445        auto fs = FracSec(12); 
     2446        const cfs = FracSec(12); 
     2447        immutable ifs = FracSec(12); 
     2448        static assert(__traits(compiles, fs.nsecs)); 
     2449        static assert(__traits(compiles, cfs.nsecs)); 
     2450        static assert(__traits(compiles, ifs.nsecs)); 
     2451    } 
     2452 
     2453 
     2454    /++ 
     2455        The value of this FracSec as nsecs. 
     2456 
     2457        Note that this does not give you any greater precision 
     2458        than setting the value of this FracSec as hnsecs. 
     2459 
     2460        Params: 
     2461            nsecs = The number of nsecs passed the second. 
     2462 
     2463        Throws: 
     2464            TimeException if the given value is not less than one second. 
     2465      +/ 
     2466    @property void nsecs(int nsecs) pure 
     2467    { 
     2468        //So that -99 through -1 throw instead of result in FracSec(0). 
     2469        if(nsecs < 0) 
     2470            _enforceValid(-1); 
     2471 
     2472        immutable hnsecs = cast(int)convert!("nsecs", "hnsecs")(nsecs); 
     2473 
     2474        _enforceValid(hnsecs); 
     2475        _hnsecs = hnsecs; 
     2476    } 
     2477 
     2478    unittest 
     2479    { 
     2480        static void testFS(int nsecs, in FracSec expected = FracSec.init, size_t line = __LINE__) 
     2481        { 
     2482            FracSec fs; 
     2483 
     2484            fs.nsecs = nsecs; 
     2485 
     2486            if(fs != expected) 
     2487                throw new AssertError("", __FILE__, line); 
     2488        } 
     2489 
     2490        tAssertExThrown!TimeException(testFS(-1)); 
     2491        tAssertExThrown!TimeException(testFS(1_000_000_000)); 
     2492 
     2493        testFS(0, FracSec(0)); 
     2494        testFS(1, FracSec(0)); 
     2495        testFS(10, FracSec(0)); 
     2496        testFS(100, FracSec(1)); 
     2497        testFS(999, FracSec(9)); 
     2498        testFS(999_999, FracSec(9999)); 
     2499        testFS(9_999_999, FracSec(99_999)); 
     2500 
     2501        auto fs = FracSec(12); 
     2502        const cfs = FracSec(12); 
     2503        immutable ifs = FracSec(12); 
     2504        static assert(__traits(compiles, fs.nsecs = 54)); 
     2505        static assert(!__traits(compiles, cfs.nsecs = 54)); 
     2506        static assert(!__traits(compiles, ifs.nsecs = 54)); 
     2507    } 
     2508 
     2509 
     2510    /+ 
     2511        Converts this duration to a string. 
     2512      +/ 
     2513    //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't 
     2514    //have versions of toString() with extra modifiers, so we define one version 
     2515    //with modifiers and one without. 
     2516    string toString() 
     2517    { 
     2518        return _toStringImpl(); 
     2519    } 
     2520 
     2521 
     2522    /++ 
     2523        Converts this duration to a string. 
     2524      +/ 
     2525    //Due to bug http://d.puremagic.com/issues/show_bug.cgi?id=3715 , we can't 
     2526    //have versions of toString() with extra modifiers, so we define one version 
     2527    //with modifiers and one without. 
     2528    string toString() const pure nothrow 
     2529    { 
     2530        return _toStringImpl(); 
     2531    } 
     2532 
     2533    unittest 
     2534    { 
     2535        auto fs = FracSec(12); 
     2536        const cfs = FracSec(12); 
     2537        immutable ifs = FracSec(12); 
     2538        static assert(__traits(compiles, fs.toString())); 
     2539        static assert(__traits(compiles, cfs.toString())); 
     2540        static assert(__traits(compiles, ifs.toString())); 
     2541    } 
     2542 
     2543 
     2544private: 
     2545 
     2546    /++ 
     2547        Since we have two versions of toString(), we have _toStringImpl() 
     2548        so that they can share implementations. 
     2549      +/ 
     2550    string _toStringImpl() const pure nothrow 
     2551    { 
     2552        try 
     2553        { 
     2554            long hnsecs = _hnsecs; 
     2555 
     2556            immutable milliseconds = splitUnitsFromHNSecs!"msecs"(hnsecs); 
     2557            immutable microseconds = splitUnitsFromHNSecs!"usecs"(hnsecs); 
     2558 
     2559            if(hnsecs == 0) 
     2560            { 
     2561                if(microseconds == 0) 
     2562                { 
     2563                    if(milliseconds == 0) 
     2564                        return "0 hnsecs"; 
     2565                    else 
     2566                    { 
     2567                        if(milliseconds == 1) 
     2568                            return "1 ms"; 
     2569                        else 
     2570                            return numToString(milliseconds) ~ " ms"; 
     2571                    } 
     2572                } 
     2573                else 
     2574                { 
     2575                    immutable fullMicroseconds = getUnitsFromHNSecs!"usecs"(_hnsecs); 
     2576 
     2577                    if(fullMicroseconds == 1) 
     2578                        return "1 ÃŽÅ’s"; 
     2579                    else 
     2580                        return numToString(fullMicroseconds) ~ " ÃŽÅ’s"; 
     2581                } 
     2582            } 
     2583            else 
     2584            { 
     2585                if(_hnsecs == 1) 
     2586                    return "1 hnsec"; 
     2587                else 
     2588                    return numToString(_hnsecs) ~ " hnsecs"; 
     2589            } 
     2590        } 
     2591        catch(Exception e) 
     2592            assert(0, "Something threw when nothing can throw."); 
     2593    } 
     2594 
     2595    unittest 
     2596    { 
     2597        assert(FracSec.from!"msecs"(0).toString() == "0 hnsecs"); 
     2598        assert(FracSec.from!"msecs"(1).toString() == "1 ms"); 
     2599        assert(FracSec.from!"msecs"(2).toString() == "2 ms"); 
     2600        assert(FracSec.from!"msecs"(100).toString() == "100 ms"); 
     2601        assert(FracSec.from!"msecs"(999).toString() == "999 ms"); 
     2602 
     2603        assert(FracSec.from!"usecs"(0).toString() == "0 hnsecs"); 
     2604        assert(FracSec.from!"usecs"(1).toString() == "1 ÃŽÅ’s"); 
     2605        assert(FracSec.from!"usecs"(2).toString() == "2 ÃŽÅ’s"); 
     2606        assert(FracSec.from!"usecs"(100).toString() == "100 ÃŽÅ’s"); 
     2607        assert(FracSec.from!"usecs"(999).toString() == "999 ÃŽÅ’s"); 
     2608        assert(FracSec.from!"usecs"(1000).toString() == "1 ms"); 
     2609        assert(FracSec.from!"usecs"(2000).toString() == "2 ms"); 
     2610        assert(FracSec.from!"usecs"(9999).toString() == "9999 ÃŽÅ’s"); 
     2611        assert(FracSec.from!"usecs"(10_000).toString() == "10 ms"); 
     2612        assert(FracSec.from!"usecs"(20_000).toString() == "20 ms"); 
     2613        assert(FracSec.from!"usecs"(100_000).toString() == "100 ms"); 
     2614        assert(FracSec.from!"usecs"(100_001).toString() == "100001 ÃŽÅ’s"); 
     2615        assert(FracSec.from!"usecs"(999_999).toString() == "999999 ÃŽÅ’s"); 
     2616 
     2617        assert(FracSec.from!"hnsecs"(0).toString() == "0 hnsecs"); 
     2618        assert(FracSec.from!"hnsecs"(1).toString() == "1 hnsec"); 
     2619        assert(FracSec.from!"hnsecs"(2).toString() == "2 hnsecs"); 
     2620        assert(FracSec.from!"hnsecs"(100).toString() == "10 ÃŽÅ’s"); 
     2621        assert(FracSec.from!"hnsecs"(999).toString() == "999 hnsecs"); 
     2622        assert(FracSec.from!"hnsecs"(1000).toString() == "100 ÃŽÅ’s"); 
     2623        assert(FracSec.from!"hnsecs"(2000).toString() == "200 ÃŽÅ’s"); 
     2624        assert(FracSec.from!"hnsecs"(9999).toString() == "9999 hnsecs"); 
     2625        assert(FracSec.from!"hnsecs"(10_000).toString() == "1 ms"); 
     2626        assert(FracSec.from!"hnsecs"(20_000).toString() == "2 ms"); 
     2627        assert(FracSec.from!"hnsecs"(100_000).toString() == "10 ms"); 
     2628        assert(FracSec.from!"hnsecs"(100_001).toString() == "100001 hnsecs"); 
     2629        assert(FracSec.from!"hnsecs"(200_000).toString() == "20 ms"); 
     2630        assert(FracSec.from!"hnsecs"(999_999).toString() == "999999 hnsecs"); 
     2631        assert(FracSec.from!"hnsecs"(1_000_001).toString() == "1000001 hnsecs"); 
     2632        assert(FracSec.from!"hnsecs"(9_999_999).toString() == "9999999 hnsecs"); 
     2633    } 
     2634 
     2635 
     2636    /++ 
     2637        Returns whether the given number of hnsecs fits within the range of FracSec. 
     2638 
     2639        Params: 
     2640            hnsecs = The number of hnsecs. 
     2641      +/ 
     2642    static bool _valid(int hnsecs) pure 
     2643    { 
     2644        return hnsecs >= 0 && hnsecs < convert!("seconds", "hnsecs")(1); 
     2645    } 
     2646 
     2647 
     2648    /++ 
     2649        Throws: 
     2650            TimeException if valid(hnsecs) is false. 
     2651      +/ 
     2652    static void _enforceValid(int hnsecs) pure 
     2653    { 
     2654        if(!_valid(hnsecs)) 
     2655            throw new TimeException("FracSec must be greater than equal to 0 and less than 1 second."); 
     2656    } 
     2657 
     2658 
     2659    /++ 
     2660        Params: 
     2661            hnsecs = The number of hnsecs passed the second. 
     2662 
     2663        Throws: 
     2664            TimeException if the given hnsecs less than 0 or would result in a 
     2665            FracSec greater than or equal to 1 second. 
     2666      +/ 
     2667    this(int hnsecs) pure 
     2668    { 
     2669        _enforceValid(hnsecs); 
     2670        _hnsecs = hnsecs; 
     2671    } 
     2672 
     2673 
     2674    pure invariant() 
     2675    { 
     2676        if(!_valid(_hnsecs)) 
     2677            throw new AssertError("Invaliant Failure: hnsecs [" ~ numToString(_hnsecs) ~ "]", __FILE__, __LINE__); 
     2678    } 
     2679 
     2680 
     2681    int _hnsecs; 
     2682} 
     2683 
     2684 
     2685/++ 
     2686    Exception type used by core.time. 
     2687  +/ 
     2688class TimeException : Exception 
     2689{ 
     2690    /++ 
     2691        Params: 
     2692            msg  = The message for the exception. 
     2693            file = The file where the exception occurred. 
     2694            line = The line number where the exception occurred. 
     2695            next = The previous exception in the chain of exceptions, if any. 
     2696      +/ 
     2697    this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) nothrow 
     2698    { 
     2699        super(msg, file, line, next); 
     2700    } 
     2701} 
     2702 
     2703 
     2704//============================================================================== 
     2705// Private Section. 
     2706// 
     2707// Much of this is a copy or simplified copy of what's in std.datetime. 
     2708//============================================================================== 
     2709private: 
     2710 
     2711 
     2712/+ 
     2713    Template to help with converting between time units. 
     2714 +/ 
     2715template hnsecsPer(string units) 
     2716    if(units == "weeks" || 
     2717       units == "days" || 
     2718       units == "hours" || 
     2719       units == "minutes" || 
     2720       units == "seconds" || 
     2721       units == "msecs" || 
     2722       units == "usecs" || 
     2723       units == "hnsecs") 
     2724{ 
     2725    static if(units == "hnsecs") 
     2726        enum hnsecsPer = 1L; 
     2727    else static if(units == "usecs") 
     2728        enum hnsecsPer = 10L; 
     2729    else static if(units == "msecs") 
     2730        enum hnsecsPer = 1000 * hnsecsPer!"usecs"; 
     2731    else static if(units == "seconds") 
     2732        enum hnsecsPer = 1000 * hnsecsPer!"msecs"; 
     2733    else static if(units == "minutes") 
     2734        enum hnsecsPer = 60 * hnsecsPer!"seconds"; 
     2735    else static if(units == "hours") 
     2736        enum hnsecsPer = 60 * hnsecsPer!"minutes"; 
     2737    else static if(units == "days") 
     2738        enum hnsecsPer = 24 * hnsecsPer!"hours"; 
     2739    else static if(units == "weeks") 
     2740        enum hnsecsPer = 7 * hnsecsPer!"days"; 
     2741} 
     2742 
     2743/+ 
     2744    Splits out a particular unit from hnsecs and gives you the value for that 
     2745    unit and the remaining hnsecs. It really shouldn't be used unless unless 
     2746    all units larger than the given units have already been split out. 
     2747 
     2748    Params: 
     2749        units  = The units to split out. 
     2750        hnsecs = The current total hnsecs. Upon returning, it is the hnsecs left 
     2751                 after splitting out the given units. 
     2752 
     2753    Returns: 
     2754        The number of the given units from converting hnsecs to those units. 
     2755 
     2756    Examples: 
     2757-------------------- 
     2758auto hnsecs = 2595000000007L; 
     2759immutable days = splitUnitsFromHNSecs!"days"(hnsecs); 
     2760assert(days == 3); 
     2761assert(hnsecs == 3000000007); 
     2762 
     2763immutable minutes = splitUnitsFromHNSecs!"minutes"(hnsecs); 
     2764assert(minutes == 5); 
     2765assert(hnsecs == 7); 
     2766-------------------- 
     2767  +/ 
     2768long splitUnitsFromHNSecs(string units)(ref long hnsecs) pure nothrow 
     2769    if(units == "weeks" || 
     2770       units == "days" || 
     2771       units == "hours" || 
     2772       units == "minutes" || 
     2773       units == "seconds" || 
     2774       units == "msecs" || 
     2775       units == "usecs" || 
     2776       units == "hnsecs") 
     2777{ 
     2778    immutable value = convert!("hnsecs", units)(hnsecs); 
     2779    hnsecs -= convert!(units, "hnsecs")(value); 
     2780 
     2781    return value; 
     2782} 
     2783 
     2784unittest 
     2785{ 
     2786    //Verify Example. 
     2787    auto hnsecs = 2595000000007L; 
     2788    immutable days = splitUnitsFromHNSecs!"days"(hnsecs); 
     2789    assert(days == 3); 
     2790    assert(hnsecs == 3000000007); 
     2791 
     2792    immutable minutes = splitUnitsFromHNSecs!"minutes"(hnsecs); 
     2793    assert(minutes == 5); 
     2794    assert(hnsecs == 7); 
     2795} 
     2796 
     2797 
     2798/+ 
     2799    This function is used to split out the units without getting the remaining 
     2800    hnsecs. 
     2801 
     2802    See_Also: 
     2803        splitUnitsFromHNSecs() 
     2804 
     2805    Params: 
     2806        units  = The units to split out. 
     2807        hnsecs = The current total hnsecs. 
     2808 
     2809    Returns: 
     2810        The split out value. 
     2811 
     2812    Examples: 
     2813-------------------- 
     2814auto hnsecs = 2595000000007L; 
     2815immutable days = getUnitsFromHNSecs!"days"(hnsecs); 
     2816assert(days == 3); 
     2817assert(hnsecs == 2595000000007L); 
     2818-------------------- 
     2819  +/ 
     2820long getUnitsFromHNSecs(string units)(long hnsecs) pure nothrow 
     2821    if(units == "weeks" || 
     2822       units == "days" || 
     2823       units == "hours" || 
     2824       units == "minutes" || 
     2825       units == "seconds" || 
     2826       units == "msecs" || 
     2827       units == "usecs" || 
     2828       units == "hnsecs") 
     2829{ 
     2830    return convert!("hnsecs", units)(hnsecs); 
     2831} 
     2832 
     2833unittest 
     2834{ 
     2835    //Verify Example. 
     2836    auto hnsecs = 2595000000007L; 
     2837    immutable days = getUnitsFromHNSecs!"days"(hnsecs); 
     2838    assert(days == 3); 
     2839    assert(hnsecs == 2595000000007L); 
     2840} 
     2841 
     2842 
     2843/+ 
     2844    This function is used to split out the units without getting the units but 
     2845    just the remaining hnsecs. 
     2846 
     2847    See_Also: 
     2848        splitUnitsFromHNSecs() 
     2849 
     2850    Params: 
     2851        units  = The units to split out. 
     2852        hnsecs = The current total hnsecs. 
     2853 
     2854    Returns: 
     2855        The remaining hnsecs. 
     2856 
     2857    Examples: 
     2858-------------------- 
     2859auto hnsecs = 2595000000007L; 
     2860auto returned = removeUnitsFromHNSecs!"days"(hnsecs); 
     2861assert(returned == 3000000007); 
     2862assert(hnsecs == 2595000000007L); 
     2863-------------------- 
     2864  +/ 
     2865long removeUnitsFromHNSecs(string units)(long hnsecs) pure nothrow 
     2866    if(units == "weeks" || 
     2867       units == "days" || 
     2868       units == "hours" || 
     2869       units == "minutes" || 
     2870       units == "seconds" || 
     2871       units == "msecs" || 
     2872       units == "usecs" || 
     2873       units == "hnsecs") 
     2874{ 
     2875    immutable value = convert!("hnsecs", units)(hnsecs); 
     2876 
     2877    return hnsecs - convert!(units, "hnsecs")(value); 
     2878} 
     2879 
     2880unittest 
     2881{ 
     2882    //Verify Example. 
     2883    auto hnsecs = 2595000000007L; 
     2884    auto returned = removeUnitsFromHNSecs!"days"(hnsecs); 
     2885    assert(returned == 3000000007); 
     2886    assert(hnsecs == 2595000000007L); 
     2887} 
     2888 
     2889 
     2890/++ 
     2891    Whether all of the given strings are valid units of time. 
     2892  +/ 
     2893bool validTimeUnits(string[] units...) 
     2894{ 
     2895    foreach(str; units) 
     2896    { 
     2897        switch(str) 
     2898        { 
     2899            case "years": 
     2900            case "months": 
     2901            case "weeks": 
     2902            case "days": 
     2903            case "hours": 
     2904            case "minutes": 
     2905            case "seconds": 
     2906            case "msecs": 
     2907            case "usecs": 
     2908            case "hnsecs": 
     2909                return true; 
     2910            default: 
     2911                return false; 
     2912        } 
     2913    } 
     2914 
     2915    return false; 
     2916} 
     2917 
     2918 
     2919/+ 
     2920    The time units which are one step larger than the given units. 
     2921 
     2922    Examples: 
     2923-------------------- 
     2924assert(nextLargerTimeUnits!"minutes" == "hours"); 
     2925assert(nextLargerTimeUnits!"hnsecs" == "usecs"); 
     2926-------------------- 
     2927  +/ 
     2928template nextLargerTimeUnits(string units) 
     2929    if(units == "days" || 
     2930       units == "hours" || 
     2931       units == "minutes" || 
     2932       units == "seconds" || 
     2933       units == "msecs" || 
     2934       units == "usecs" || 
     2935       units == "hnsecs" || 
     2936       units == "nsecs") 
     2937{ 
     2938    static if(units == "days") 
     2939        enum nextLargerTimeUnits = "weeks"; 
     2940    else static if(units == "hours") 
     2941        enum nextLargerTimeUnits = "days"; 
     2942    else static if(units == "minutes") 
     2943        enum nextLargerTimeUnits = "hours"; 
     2944    else static if(units == "seconds") 
     2945        enum nextLargerTimeUnits = "minutes"; 
     2946    else static if(units == "msecs") 
     2947        enum nextLargerTimeUnits = "seconds"; 
     2948    else static if(units == "usecs") 
     2949        enum nextLargerTimeUnits = "msecs"; 
     2950    else static if(units == "hnsecs") 
     2951        enum nextLargerTimeUnits = "usecs"; 
     2952    else static if(units == "nsecs") 
     2953        enum nextLargerTimeUnits = "hnsecs"; 
     2954    else 
     2955        static assert(0, "Broken template constraint"); 
     2956} 
     2957 
     2958unittest 
     2959{ 
     2960    assert(nextLargerTimeUnits!"nsecs" == "hnsecs"); 
     2961    assert(nextLargerTimeUnits!"hnsecs" == "usecs"); 
     2962    assert(nextLargerTimeUnits!"usecs" == "msecs"); 
     2963    assert(nextLargerTimeUnits!"msecs" == "seconds"); 
     2964    assert(nextLargerTimeUnits!"seconds" == "minutes"); 
     2965    assert(nextLargerTimeUnits!"minutes" == "hours"); 
     2966    assert(nextLargerTimeUnits!"hours" == "days"); 
     2967    assert(nextLargerTimeUnits!"days" == "weeks"); 
     2968 
     2969    static assert(!__traits(compiles, nextLargerTimeUnits!"weeks")); 
     2970    static assert(!__traits(compiles, nextLargerTimeUnits!"months")); 
     2971    static assert(!__traits(compiles, nextLargerTimeUnits!"years")); 
     2972 
     2973    //Verify Examples 
     2974    assert(nextLargerTimeUnits!"minutes" == "hours"); 
     2975    assert(nextLargerTimeUnits!"hnsecs" == "usecs"); 
     2976} 
     2977 
     2978 
     2979/++ 
     2980    Unfortunately, snprintf is not pure, so here's a way to convert 
     2981    a number to a string which is. 
     2982  +/ 
     2983string numToString(long value) pure nothrow 
     2984{ 
     2985    try 
     2986    { 
     2987        immutable negative = value < 0; 
     2988        char[25] str; 
     2989        size_t i = str.length; 
     2990 
     2991        if(negative) 
     2992            value = -value; 
     2993 
     2994        while(1) 
     2995        { 
     2996            char digit = cast(char)('0' + value % 10); 
     2997            value /= 10; 
     2998 
     2999            str[--i] = digit; 
     3000            assert(i > 0); 
     3001 
     3002            if(value == 0) 
     3003                break; 
     3004        } 
     3005 
     3006        if(negative) 
     3007            return "-" ~ str[i .. $].idup; 
    2283008        else 
    229         static if( op == "*" ) 
    230         { 
    231             m_ticks *= other.m_ticks; 
    232         } 
     3009            return str[i .. $].idup; 
     3010    } 
     3011    catch(Exception e) 
     3012        assert(0, "Something threw when nothing can throw."); 
     3013
     3014 
     3015 
     3016/+ 
     3017  Copied from std.traits for Duration's template constraints. Because of 
     3018  bug #2775 makes it impossible to make templates actually private, it 
     3019  was renamed to TUnqual to avoid name clashes. version(D_Ddoc) sections 
     3020  are used on any functions which use it in their template constraints, 
     3021  so TUnqual is at least hidden name-wise. 
     3022 +/ 
     3023template TUnqual(T) 
     3024
     3025    version (none) // Error: recursive alias declaration @@@BUG1308@@@ 
     3026    { 
     3027             static if (is(T U ==     const U)) alias TUnqual!U TUnqual; 
     3028        else static if (is(T U == immutable U)) alias TUnqual!U TUnqual; 
     3029        else static if (is(T U ==    shared U)) alias TUnqual!U TUnqual; 
     3030        else                                    alias        T TUnqual; 
     3031    } 
     3032    else // workaround 
     3033    { 
     3034             static if (is(T U == shared(const U))) alias U TUnqual; 
     3035        else static if (is(T U ==        const U )) alias U TUnqual; 
     3036        else static if (is(T U ==    immutable U )) alias U TUnqual; 
     3037        else static if (is(T U ==       shared U )) alias U TUnqual; 
     3038        else                                        alias T TUnqual; 
     3039    } 
     3040
     3041 
     3042unittest 
     3043
     3044    static assert(is(TUnqual!(int) == int)); 
     3045    static assert(is(TUnqual!(const int) == int)); 
     3046    static assert(is(TUnqual!(immutable int) == int)); 
     3047    static assert(is(TUnqual!(shared int) == int)); 
     3048    static assert(is(TUnqual!(shared(const int)) == int)); 
     3049    alias immutable(int[]) ImmIntArr; 
     3050    static assert(is(TUnqual!(ImmIntArr) == immutable(int)[])); 
     3051
     3052 
     3053 
     3054//assertExThrown have a t tacked onto the front so that it 
     3055//don't conflict with the one that std.datetime uses. You'd think that 
     3056//it being private would be enough, but apparently not. 
     3057version(unittest) 
     3058
     3059 
     3060 
     3061/+ 
     3062    Asserts that the given function and arguments throws the given exception 
     3063    type. That exception is caught and does not escape assertExThrown!(). 
     3064    However, any other exceptions will escape. assertExThrown!() also works 
     3065    with Errors - including AssertError. 
     3066 
     3067    Params: 
     3068        E        = The exception to test for. 
     3069        funcCall = The function call to make. 
     3070 
     3071    Examples: 
     3072-------------------- 
     3073tAssertExThrown!Exception(myfunc(param1, param2)); 
     3074-------------------- 
     3075  +/ 
     3076void tAssertExThrown(E : Throwable = Exception, T) 
     3077                    (lazy T funcToCall, string msg = null, string file = __FILE__, size_t line = __LINE__) 
     3078
     3079    bool thrown = false; 
     3080 
     3081    try 
     3082        funcToCall(); 
     3083    catch(E e) 
     3084        thrown = true; 
     3085 
     3086    if(!thrown) 
     3087    { 
     3088        if(msg.length == 0) 
     3089            throw new AssertError("assertExThrown() failed: No " ~ E.stringof ~ " was thrown.", file, line); 
    2333090        else 
    234         static if( op == "/" ) 
    235         { 
    236             m_ticks /= other.m_ticks; 
    237         } 
    238         return this; 
    239     } 
    240      
    241      
    242     const equals_t opEquals( ref const(Duration) other ) nothrow 
    243     { 
    244         return m_ticks == other.m_ticks; 
    245     } 
    246      
    247      
    248     const int opCmp( ref const(Duration) other ) nothrow 
    249     { 
    250         return m_ticks < other.m_ticks ? 
    251                  -1 : m_ticks > other.m_ticks ? 
    252                         1 : 0; 
    253     } 
    254      
    255      
    256     ////////////////////////////////////////////////////////////////////////// 
    257     // Statics 
    258     ////////////////////////////////////////////////////////////////////////// 
    259   
    260 /+ 
    261     pure @property TimeResolution resolution() nothrow 
    262     { 
    263         return TimeResolution.nano; 
    264     } 
    265 +/ 
    266      
    267     static @property ushort numFractionalDigits() nothrow 
    268     { 
    269         return 9; 
    270     } 
    271      
    272      
    273     static @property TickType ticksPerSecond() nothrow 
    274     { 
    275         return 1000_000_000; // nanosecond 
    276     } 
    277      
    278      
    279     static @property Duration unit() //nothrow 
    280     { 
    281         return Duration( 0, 0, 0, 1 ); 
    282     } 
    283      
    284      
    285 private: 
    286     TickType toTicks( HourType h, MinType m, SecType s, FracType f ) 
    287     { 
    288         if( 0 <= h && 0 <= m && 0 <= s && 0 <= f ) 
    289         { 
    290             return (((cast(FracType) h * 3600) + 
    291                      (cast(FracType) m * 60) + 
    292                      (cast(FracType) s)) * 
    293                      ticksPerSecond) + 
    294                      f; 
    295         } 
    296         h = _mkpos( h ); m = _mkpos( m ); 
    297         s = _mkpos( s ); f = _mkpos( f ); 
    298         return ((((cast(FracType) h * 3600) + 
    299                   (cast(FracType) m * 60) + 
    300                   (cast(FracType) s)) * 
    301                   ticksPerSecond) + 
    302                   f) * -1; 
    303     } 
    304      
    305      
    306     this( TickType t ) 
    307     { 
    308         m_ticks = t; 
    309     } 
    310      
    311      
    312 private: 
    313     TickType    m_ticks; 
    314 
    315  
    316  
    317 ////////////////////////////////////////////////////////////////////////////// 
    318 // Utility Functions 
    319 ////////////////////////////////////////////////////////////////////////////// 
    320  
    321  
    322 Duration hours( Duration.HourType n ) 
    323 
    324     return Duration( n, 0, 0, 0 ); 
    325 
    326  
    327  
    328 Duration minutes( Duration.MinType n ) 
    329 
    330     return Duration( 0, n, 0, 0 ); 
    331 
    332  
    333  
    334 Duration seconds( Duration.SecType n ) 
    335 
    336     return Duration( 0, 0, n, 0 ); 
    337 
    338  
    339  
    340 Duration milliseconds( Duration.FracType n ) 
    341 
    342     if( 1000 <= Duration.ticksPerSecond ) 
    343     { 
    344         n *= (Duration.ticksPerSecond / 1000); 
    345         return Duration( 0, 0, 0, n );  
    346     } 
    347     n /= (1000 / Duration.ticksPerSecond); 
    348     return Duration( 0, 0, 0, n ); 
    349 
    350  
    351  
    352 Duration microseconds( Duration.FracType n ) 
    353 
    354     if( 1000_000 <= Duration.ticksPerSecond ) 
    355     { 
    356         n *= (Duration.ticksPerSecond / 1000_000); 
    357         return Duration( 0, 0, 0, n );  
    358     } 
    359     n /= (1000_000 / Duration.ticksPerSecond); 
    360     return Duration( 0, 0, 0, n );    
    361 
    362  
    363  
    364 Duration nanoseconds( Duration.FracType n ) 
    365 
    366     if( 1000_000_000 <= Duration.ticksPerSecond ) 
    367     { 
    368         n *= (Duration.ticksPerSecond / 1000_000_000); 
    369         return Duration( 0, 0, 0, n );  
    370     } 
    371     n /= (1000_000_000 / Duration.ticksPerSecond); 
    372     return Duration( 0, 0, 0, n ); 
    373 
     3091            throw new AssertError("assertExThrown() failed: No " ~ E.stringof ~ " was thrown: " ~ msg, file, line); 
     3092    } 
     3093
     3094 
     3095unittest 
     3096
     3097    void throwEx(Throwable t) 
     3098    { 
     3099        throw t; 
     3100    } 
     3101 
     3102    void nothrowEx() 
     3103    { 
     3104    } 
     3105 
     3106    try 
     3107        tAssertExThrown!Exception(throwEx(new Exception("It's an Exception"))); 
     3108    catch(AssertError) 
     3109        assert(0); 
     3110 
     3111    try 
     3112        tAssertExThrown!Exception(throwEx(new Exception("It's an Exception")), "It's a message"); 
     3113    catch(AssertError) 
     3114        assert(0); 
     3115 
     3116    try 
     3117        tAssertExThrown!AssertError(throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__))); 
     3118    catch(AssertError) 
     3119        assert(0); 
     3120 
     3121    try 
     3122        tAssertExThrown!AssertError(throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__)), "It's a message"); 
     3123    catch(AssertError) 
     3124        assert(0); 
     3125 
     3126 
     3127    { 
     3128        bool thrown = false; 
     3129        try 
     3130            tAssertExThrown!Exception(nothrowEx()); 
     3131        catch(AssertError) 
     3132            thrown = true; 
     3133 
     3134        assert(thrown); 
     3135    } 
     3136 
     3137    { 
     3138        bool thrown = false; 
     3139        try 
     3140            tAssertExThrown!Exception(nothrowEx(), "It's a message"); 
     3141        catch(AssertError) 
     3142            thrown = true; 
     3143 
     3144        assert(thrown); 
     3145    } 
     3146 
     3147    { 
     3148        bool thrown = false; 
     3149        try 
     3150            tAssertExThrown!AssertError(nothrowEx()); 
     3151        catch(AssertError) 
     3152            thrown = true; 
     3153 
     3154        assert(thrown); 
     3155    } 
     3156 
     3157    { 
     3158        bool thrown = false; 
     3159        try 
     3160            tAssertExThrown!AssertError(nothrowEx(), "It's a message"); 
     3161        catch(AssertError) 
     3162            thrown = true; 
     3163 
     3164        assert(thrown); 
     3165    } 
     3166
     3167
     3168