Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Changeset 3033

Show
Ignore:
Timestamp:
12/16/07 20:46:10 (1 year ago)
Author:
kris
Message:

* added simple DateTime? struct
* Date module usage replaced with Date and DateTime? structs
* Date module removed
* Clocks now use DateTime?
* Calendar.Date replaced with generic Date

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/example/system/localtime.d

    r2978 r3033  
    1919{ 
    2020        // retreive local time 
    21         auto date = WallClock.toDate; 
     21        auto dt = WallClock.toDate; 
    2222 
    2323        // get GMT difference in minutes 
     
    2929        // format date 
    3030        Stdout.formatln ("{}, {} {:d2} {:d2}:{:d2}:{:d2} GMT{}{:d2}:{:d2} {}", 
    31                           date.asDay, 
    32                           date.asMonth, 
    33                           date.day, 
    34                           date.hour,  
    35                           date.min
    36                           date.sec
     31                          dt.date.asDay, 
     32                          dt.date.asMonth, 
     33                          dt.date.day, 
     34                          dt.time.hours,  
     35                          dt.time.minutes
     36                          dt.time.seconds
    3737                          sign, 
    3838                          tz / 60, 
    3939                          tz % 60, 
    40                           date.year 
     40                          dt.date.year 
    4141                         ); 
    4242} 
  • trunk/install/snapshot/srcsnapshot.d

    r2979 r3033  
    9696 
    9797    Stdout("!! Exporting from working copy for packaging").newline; 
    98     auto date = WallClock.toDate; 
     98    auto dt = WallClock.toDate; 
    9999    char[] datestr;  
    100     datestr = Stdout.layout.sprint(new char[10], "{}{:2}{:2}", date.year, date.month, date.day); 
     100    datestr = Stdout.layout.sprint(new char[10], "{}{:2}{:2}", dt.date.year, dt.date.month, dt.date.day); 
    101101    char[] packdirdate = projname ~ "-src-SNAPSHOT-" ~ datestr; 
    102102    char[] packdircurrent = projname ~ "-src-SNAPSHOT-CURRENT";  
  • trunk/tango/text/convert/TimeStamp.d

    r3025 r3033  
    4242/****************************************************************************** 
    4343 
    44         We use a Gregorian calendar for all date calculations 
    45  
    46 ******************************************************************************/ 
    47  
    48 private alias GregorianCalendar Cal; 
    49  
    50 /****************************************************************************** 
    51  
    5244        Parse provided input and return a UTC epoch time. An exception 
    5345        is raised where the provided string is not fully parsed. 
     
    151143        // convert time to field values 
    152144        auto time = t.time; 
    153         auto date = Cal.generic.toDate (t); 
     145        auto date = GregorianCalendar.generic.toDate (t); 
    154146 
    155147        // use the featherweight formatter ... 
    156148        T[14] tmp = void; 
    157149        return Util.layout (output, "%0, %1 %2 %3 %4:%5:%6 GMT",  
    158                             Days[date.dayOfWeek], 
     150                            Days[date.dow], 
    159151                            convert (tmp[0..2], date.day), 
    160152                            Months[date.month-1], 
     
    207199{ 
    208200        TimeOfDay       tod; 
    209         Cal.Date        date; 
     201        Date            date; 
    210202        T*              p = src.ptr; 
    211203 
     
    228220            p[0..3] == "GMT") 
    229221            { 
    230             value = Cal.generic.toTime (date, tod); 
     222            value = GregorianCalendar.generic.toTime (date, tod); 
    231223            return (p+3) - src.ptr; 
    232224            } 
     
    248240{ 
    249241        TimeOfDay       tod; 
    250         Cal.Date        date; 
     242        Date            date; 
    251243        T*              p = src.ptr; 
    252244 
     
    275267                   date.year += 1900; 
    276268 
    277             value = Cal.generic.toTime (date, tod); 
     269            value = GregorianCalendar.generic.toTime (date, tod); 
    278270            return (p+3) - src.ptr; 
    279271            } 
     
    295287{ 
    296288        TimeOfDay       tod; 
    297         Cal.Date        date; 
     289        Date            date; 
    298290        T*              p = src.ptr; 
    299291 
     
    315307            (date.year = parseInt (p)) > 0) 
    316308            { 
    317             value = Cal.generic.toTime (date, tod); 
     309            value = GregorianCalendar.generic.toTime (date, tod); 
    318310            return p - src.ptr; 
    319311            } 
     
    334326{ 
    335327        TimeOfDay       tod; 
    336         Cal.Date        date; 
     328        Date            date; 
    337329        T*              p = src.ptr; 
    338330 
     
    362354                   date.year += 1900; 
    363355             
    364             value = Cal.generic.toTime (date, tod); 
     356            value = GregorianCalendar.generic.toTime (date, tod); 
    365357            return (p+2) - src.ptr; 
    366358            } 
     
    381373{ 
    382374        TimeOfDay       tod; 
    383         Cal.Date        date; 
     375        Date            date; 
    384376        T*              p = src.ptr; 
    385377 
     
    399391            { 
    400392            date.ms = parseInt (p); 
    401             value = Cal.generic.toTime (date, tod); 
     393            value = GregorianCalendar.generic.toTime (date, tod); 
    402394            return p - src.ptr; 
    403395            } 
  • trunk/tango/time/Clock.d

    r2986 r3033  
    1313module tango.time.Clock; 
    1414 
     15public  import  tango.time.Time; 
     16 
    1517private import  tango.sys.Common; 
    1618 
    17 private import  tango.time.Date; 
    18  
    1919private import  tango.core.Exception; 
    20  
    21 public  import  tango.time.Time; 
    2220 
    2321/****************************************************************************** 
     
    5856                ***************************************************************/ 
    5957 
    60                 static Date toDate () 
     58                static DateTime toDate () 
    6159                { 
    6260                        return toDate (now); 
     
    7573                ***************************************************************/ 
    7674 
    77                 static Date toDate (Time time) 
    78                 { 
    79                         Date date = void; 
     75                static DateTime toDate (Time time) 
     76                { 
     77                        DateTime dt = void; 
    8078                        SYSTEMTIME sTime = void; 
    8179 
     
    8381                        FileTimeToSystemTime (&fTime, &sTime); 
    8482 
    85                         date.year  = sTime.wYear; 
    86                         date.month = sTime.wMonth; 
    87                         date.day   = sTime.wDay; 
    88                         date.hour  = sTime.wHour; 
    89                         date.min   = sTime.wMinute; 
    90                         date.sec   = sTime.wSecond; 
    91                         date.ms    = sTime.wMilliseconds; 
    92                         date.dow   = sTime.wDayOfWeek; 
    93                         return date; 
     83                        dt.date.year    = sTime.wYear; 
     84                        dt.date.month   = sTime.wMonth; 
     85                        dt.date.day     = sTime.wDay; 
     86                        dt.date.dow     = sTime.wDayOfWeek; 
     87                        dt.date.doy     = 0; 
     88                        dt.date.era     = 0; 
     89                        dt.time.hours   = sTime.wHour; 
     90                        dt.time.minutes = sTime.wMinute; 
     91                        dt.time.seconds = sTime.wSecond; 
     92                        dt.time.millis  = sTime.wMilliseconds; 
     93                        return dt; 
    9494                } 
    9595 
     
    107107                ***************************************************************/ 
    108108 
    109                 static Time fromDate (inout Date date
     109                static Time fromDate (inout DateTime dt
    110110                { 
    111111                        SYSTEMTIME sTime = void; 
    112112                        FILETIME   fTime = void; 
    113113 
    114                         sTime.wYear         = cast(ushort) date.year; 
    115                         sTime.wMonth        = cast(ushort) date.month; 
     114                        sTime.wYear         = cast(ushort) dt.date.year; 
     115                        sTime.wMonth        = cast(ushort) dt.date.month; 
    116116                        sTime.wDayOfWeek    = 0; 
    117                         sTime.wDay          = cast(ushort) date.day; 
    118                         sTime.wHour         = cast(ushort) date.hour
    119                         sTime.wMinute       = cast(ushort) date.min
    120                         sTime.wSecond       = cast(ushort) date.sec
    121                         sTime.wMilliseconds = cast(ushort) date.ms; 
     117                        sTime.wDay          = cast(ushort) dt.date.day; 
     118                        sTime.wHour         = cast(ushort) dt.time.hours
     119                        sTime.wMinute       = cast(ushort) dt.time.minutes
     120                        sTime.wSecond       = cast(ushort) dt.time.seconds
     121                        sTime.wMilliseconds = cast(ushort) dt.time.millis; 
    122122 
    123123                        SystemTimeToFileTime (&sTime, &fTime); 
     
    178178                ***************************************************************/ 
    179179 
    180                 static Date toDate () 
     180                static DateTime toDate () 
    181181                { 
    182182                        return toDate (now); 
     
    195195                **************************************************************/ 
    196196 
    197                 static Date toDate (Time time) 
    198                 { 
    199                         Date date = void; 
     197                static DateTime toDate (Time time) 
     198                { 
     199                        DateTime dt = void; 
    200200                        auto timeval = convert (time); 
    201                         date.ms = timeval.tv_usec / 1000; 
     201                        dt.time.millis = timeval.tv_usec / 1000; 
    202202 
    203203                        tm t = void; 
    204204                        gmtime_r (&timeval.tv_sec, &t); 
    205205         
    206                         date.year  = t.tm_year + 1900; 
    207                         date.month = t.tm_mon + 1; 
    208                         date.day   = t.tm_mday; 
    209                         date.hour  = t.tm_hour; 
    210                         date.min   = t.tm_min; 
    211                         date.sec   = t.tm_sec; 
    212                         date.dow   = t.tm_wday; 
    213                         return date; 
     206                        dt.date.year    = t.tm_year + 1900; 
     207                        dt.date.month   = t.tm_mon + 1; 
     208                        dt.date.day     = t.tm_mday; 
     209                        dt.date.dow     = t.tm_wday; 
     210                        dt.date.doy     = 0; 
     211                        dt.date.era     = 0; 
     212                        dt.time.hours   = t.tm_hour; 
     213                        dt.time.minutes = t.tm_min; 
     214                        dt.time.seconds = t.tm_sec; 
     215                        return dt; 
    214216                } 
    215217 
     
    227229                ***************************************************************/ 
    228230 
    229                 static Time fromDate (inout Date date
     231                static Time fromDate (inout DateTime dt
    230232                { 
    231233                        tm t = void; 
    232234 
    233                         t.tm_year = date.year - 1900; 
    234                         t.tm_mon  = date.month - 1; 
    235                         t.tm_mday = date.day; 
    236                         t.tm_hour = date.hour
    237                         t.tm_min  = date.min
    238                         t.tm_sec  = date.sec
     235                        t.tm_year = dt.date.year - 1900; 
     236                        t.tm_mon  = dt.date.month - 1; 
     237                        t.tm_mday = dt.date.day; 
     238                        t.tm_hour = dt.time.hours
     239                        t.tm_min  = dt.time.minutes
     240                        t.tm_sec  = dt.time.seconds
    239241 
    240242                        auto seconds = timegm (&t); 
    241243                        return Time.epoch1970 +  
    242244                               TimeSpan.seconds(seconds) +  
    243                                TimeSpan.millis(date.ms); 
     245                               TimeSpan.millis(dt.time.millis); 
    244246                } 
    245247 
     
    294296debug (Clock) 
    295297{ 
    296         void main() {} 
     298        void main()  
     299        { 
     300                auto time = Clock.now; 
     301        } 
    297302} 
  • trunk/tango/time/ISO8601.d

    r3024 r3033  
    4848/// Fields in date will either be correct (e.g. months will be >= 1 and <= 12) or zero. 
    4949 
    50 size_t iso8601Date(T)(T[] src, ref Calendar.Date date, size_t expanded = 0) { 
    51    ubyte dummy = void; 
    52    T* p = src.ptr; 
    53    return doIso8601Date(p, src, date, expanded, dummy); 
    54 } 
    55  
    56 private size_t doIso8601Date(T)(ref T* p, T[] src, ref Calendar.Date date, size_t expanded, out ubyte separators) 
     50size_t iso8601Date(T)(T[] src, ref Date date, size_t expanded = 0) { 
     51    ubyte dummy = void; 
     52    T* p = src.ptr; 
     53    return doIso8601Date(p, src, date, expanded, dummy); 
     54} 
     55 
     56private size_t doIso8601Date(T)(ref T* p, T[] src, ref Date date, size_t expanded, out ubyte separators) 
    5757out { 
    58    assert (!date.month || (              date.month >= 1 && date.month <= 12)); 
    59    assert (!date.day   || (date.month && date.day   >= 1 && date.day   <= daysPerMonth(date.month, date.year))); 
     58    assert (!date.month || (date.month >= 1 && date.month <= 12)); 
     59    assert (!date.day   || (date.month && date.day   >= 1 && date.day   <= daysPerMonth(date.month, date.year))); 
    6060} body { 
    6161 
     
    6363        date.era = GregorianCalendar.AD_ERA; 
    6464 
    65    size_t eaten() { return p - src.ptr; } 
    66    bool done(T[] s) { return .done(eaten(), src.length, *p, s); } 
    67  
    68    if (!parseYear(p, expanded, date.year)) 
    69        return (date.year = 0); 
    70  
    71    auto onlyYear = eaten(); 
    72  
    73    // /([+-]Y{expanded})?(YYYY|YY)/ 
    74    if (done("-0123W")) 
    75        return onlyYear; 
    76  
    77    if (accept(p, '-')) 
    78        separators = true; 
    79  
    80    if (accept(p, 'W')) { 
    81        // (year)-Www-D 
    82  
    83        T* p2 = p; 
    84  
    85        int i = parseIntMax(p, 3u); 
    86  
    87        if (i) if (p - p2 == 2) { 
    88  
    89            // (year)-Www 
    90            if (done("-")) { 
    91                if (getMonthAndDayFromWeek(date, i)) 
    92                    return eaten(); 
    93  
    94            // (year)-Www-D 
    95            } else if (demand(p, '-')) 
    96                if (getMonthAndDayFromWeek(date, i, *p++ - '0')) 
    97                    return eaten(); 
    98  
    99        } else if (p - p2 == 3) 
    100            // (year)WwwD 
    101            if (getMonthAndDayFromWeek(date, i / 10, i % 10)) 
    102                return eaten(); 
    103  
    104        return onlyYear; 
    105    
    106  
    107    // next up, MM or MM[-]DD or DDD 
    108  
    109    T* p2 = p; 
    110  
    111    int i = parseIntMax(p); 
    112    if (!i) 
    113        return onlyYear; 
    114  
    115    switch (p - p2) { 
    116        case 2: 
    117            date.month = i; 
    118  
    119            if (!(date.month >= 1 && date.month <= 12)) { 
    120                date.month = 0; 
    121                return onlyYear; 
    122            
    123  
    124            auto onlyMonth = eaten(); 
    125  
    126            // (year)-MM 
    127            if (done("-")) 
    128                return onlyMonth; 
    129  
    130            // (year)-MM-DD 
    131            if (!( 
    132                demand(p, '-') && 
    133                (date.day = parseIntMax(p, 2u)) != 0 && date.day <= daysPerMonth(date.month, date.year) 
    134            )) { 
    135                date.day = 0; 
    136                return onlyMonth; 
    137            
    138  
    139            break; 
    140  
    141        case 4: 
    142            // e.g. 20010203, i = 203 now 
    143  
    144            date.month = i / 100; 
    145            date.day   = i % 100; 
    146  
    147            // (year)MMDD 
    148            if (!( 
    149                date.month >= 1 && date.month <= 12 && 
    150                date.day   >= 0 && date.day   <= daysPerMonth(date.month, date.year) 
    151            )) { 
    152                date.month = date.day = 0; 
    153                return onlyYear; 
    154            
    155  
    156            break; 
    157  
    158        case 3: 
    159            // (year)-DDD 
    160            // i is the ordinal of the day within the year 
    161  
    162            bool leap = isLeapYear(date.year); 
    163  
    164            if (i > 365 + leap) 
    165                return onlyYear; 
    166  
    167            if (i <= 31) { 
    168                date.month = 1; 
    169                date.day   = i; 
    170  
    171            } else if (i <= 59 + leap) { 
    172                date.month = 2; 
    173                date.day   = i - 31 - leap; 
    174  
    175            } else if (i <= 90 + leap) { 
    176                date.month = 3; 
    177                date.day   = i - 59 - leap; 
    178  
    179            } else if (i <= 120 + leap) { 
    180                date.month = 4; 
    181                date.day   = i - 90 - leap; 
    182  
    183            } else if (i <= 151 + leap) { 
    184                date.month = 5; 
    185                date.day   = i - 120 - leap; 
    186  
    187            } else if (i <= 181 + leap) { 
    188                date.month = 6; 
    189                date.day   = i - 151 - leap; 
    190  
    191            } else if (i <= 212 + leap) { 
    192                date.month = 7; 
    193                date.day   = i - 181 - leap; 
    194  
    195            } else if (i <= 243 + leap) { 
    196                date.month = 8; 
    197                date.day   = i - 212 - leap; 
    198  
    199            } else if (i <= 273 + leap) { 
    200                date.month = 9; 
    201                date.day   = i - 243 - leap; 
    202  
    203            } else if (i <= 304 + leap) { 
    204                date.month = 10; 
    205                date.day   = i - 273 - leap; 
    206  
    207            } else if (i <= 334 + leap) { 
    208                date.month = 11; 
    209                date.day   = i - 304 - leap; 
    210  
    211            } else { 
    212                if (i > 365 + leap) 
    213                    assert (false); 
    214  
    215                date.month = 12; 
    216                date.day   = i - 334 - leap; 
    217            
    218  
    219        default: break; 
    220    
    221  
    222    return eaten(); 
     65    size_t eaten() { return p - src.ptr; } 
     66    bool done(T[] s) { return .done(eaten(), src.length, *p, s); } 
     67 
     68    if (!parseYear(p, expanded, date.year)) 
     69        return (date.year = 0); 
     70 
     71    auto onlyYear = eaten(); 
     72 
     73    // /([+-]Y{expanded})?(YYYY|YY)/ 
     74    if (done("-0123W")) 
     75        return onlyYear; 
     76 
     77    if (accept(p, '-')) 
     78        separators = true; 
     79 
     80    if (accept(p, 'W')) { 
     81        // (year)-Www-D 
     82 
     83        T* p2 = p; 
     84 
     85        int i = parseIntMax(p, 3u); 
     86 
     87        if (i) if (p - p2 == 2) { 
     88 
     89            // (year)-Www 
     90            if (done("-")) { 
     91                if (getMonthAndDayFromWeek(date, i)) 
     92                    return eaten(); 
     93 
     94            // (year)-Www-D 
     95            } else if (demand(p, '-')) 
     96                if (getMonthAndDayFromWeek(date, i, *p++ - '0')) 
     97                    return eaten(); 
     98 
     99        } else if (p - p2 == 3) 
     100            // (year)WwwD 
     101            if (getMonthAndDayFromWeek(date, i / 10, i % 10)) 
     102                return eaten(); 
     103 
     104        return onlyYear; 
     105   
     106 
     107    // next up, MM or MM[-]DD or DDD 
     108 
     109    T* p2 = p; 
     110 
     111    int i = parseIntMax(p); 
     112    if (!i) 
     113        return onlyYear; 
     114 
     115    switch (p - p2) { 
     116        case 2: 
     117            date.month = i; 
     118 
     119            if (!(date.month >= 1 && date.month <= 12)) { 
     120                date.month = 0; 
     121                return onlyYear; 
     122           
     123 
     124            auto onlyMonth = eaten(); 
     125 
     126            // (year)-MM 
     127            if (done("-")) 
     128                return onlyMonth; 
     129 
     130            // (year)-MM-DD 
     131            if (!( 
     132                demand(p, '-') && 
     133                (date.day = parseIntMax(p, 2u)) != 0 && date.day <= daysPerMonth(date.month, date.year) 
     134            )) { 
     135                date.day = 0; 
     136                return onlyMonth; 
     137           
     138 
     139            break; 
     140 
     141        case 4: 
     142            // e.g. 20010203, i = 203 now 
     143 
     144            date.month = i / 100; 
     145            date.day   = i % 100; 
     146 
     147            // (year)MMDD 
     148            if (!( 
     149                date.month >= 1 && date.month <= 12 && 
     150                date.day   >= 0 && date.day   <= daysPerMonth(date.month, date.year) 
     151            )) { 
     152                date.month = date.day = 0; 
     153                return onlyYear; 
     154           
     155 
     156            break; 
     157 
     158        case 3: 
     159            // (year)-DDD 
     160            // i is the ordinal of the day within the year 
     161 
     162            bool leap = isLeapYear(date.year); 
     163 
     164            if (i > 365 + leap) 
     165                return onlyYear; 
     166 
     167            if (i <= 31) { 
     168                date.month = 1; 
     169                date.day   = i; 
     170 
     171            } else if (i <= 59 + leap) { 
     172                date.month = 2; 
     173                date.day   = i - 31 - leap; 
     174 
     175            } else if (i <= 90 + leap) { 
     176                date.month = 3; 
     177                date.day   = i - 59 - leap; 
     178 
     179            } else if (i <= 120 + leap) { 
     180                date.month = 4; 
     181                date.day   = i - 90 - leap; 
     182 
     183            } else if (i <= 151 + leap) { 
     184                date.month = 5; 
     185                date.day   = i - 120 - leap; 
     186 
     187            } else if (i <= 181 + leap) { 
     188                date.month = 6; 
     189                date.day   = i - 151 - leap; 
     190 
     191            } else if (i <= 212 + leap) { 
     192                date.month = 7; 
     193                date.day   = i - 181 - leap; 
     194 
     195            } else if (i <= 243 + leap) { 
     196                date.month = 8; 
     197                date.day   = i - 212 - leap; 
     198 
     199            } else if (i <= 273 + leap) { 
     200                date.month = 9; 
     201                date.day   = i - 243 - leap; 
     202 
     203            } else if (i <= 304 + leap) { 
     204                date.month = 10; 
     205                date.day   = i - 273 - leap; 
     206 
     207            } else if (i <= 334 + leap) { 
     208                date.month = 11; 
     209                date.day   = i - 304 - leap; 
     210 
     211            } else { 
     212                if (i > 365 + leap) 
     213                    assert (false); 
     214 
     215                date.month = 12; 
     216                date.day   = i - 334 - leap; 
     217           
     218 
     219        default: break; 
     220   
     221 
     222    return eaten(); 
    223223} 
    224224 
     
    228228/// time.hours may be 0 or 24: the latter marks the end of a day, the former the beginning. 
    229229 
    230 size_t iso8601Time(T)(T[] src, ref Calendar.Date date, ref TimeOfDay time) { 
    231    bool dummy = void; 
    232    T* p = src.ptr; 
    233    return doIso8601Time(p, src, date, time, WHATEVER, dummy); 
     230size_t iso8601Time(T)(T[] src, ref Date date, ref TimeOfDay time) { 
     231    bool dummy = void; 
     232    T* p = src.ptr; 
     233    return doIso8601Time(p, src, date, time, WHATEVER, dummy); 
    234234} 
    235235 
     
    237237 
    238238// bothValid is used only to get iso8601() to catch errors correctly 
    239 private size_t doIso8601Time(T)(ref T* p, T[] src, ref Calendar.Date date, ref TimeOfDay time, ubyte separators, out bool bothValid) 
     239private size_t doIso8601Time(T)(ref T* p, T[] src, ref Date date, ref TimeOfDay time, ubyte separators, out bool bothValid) 
    240240out { 
    241    // yes, I could just write >= 0, but this emphasizes the difference between == 0 and != 0 
    242    assert (!time.hours   || (time.hours   > 0 && time.hours   <=  24)); 
    243    assert (!time.minutes || (time.minutes > 0 && time.minutes <=  59)); 
    244    assert (!time.seconds || (time.seconds > 0 && time.seconds <=  60)); 
    245    assert (!time.millis  || (time.millis  > 0 && time.millis  <= 999)); 
     241    // yes, I could just write >= 0, but this emphasizes the difference between == 0 and != 0 
     242    assert (!time.hours   || (time.hours   > 0 && time.hours   <=  24)); 
     243    assert (!time.minutes || (time.minutes > 0 && time.minutes <=  59)); 
     244    assert (!time.seconds || (time.seconds > 0 && time.seconds <=  60)); 
     245    assert (!time.millis  || (time.millis  > 0 && time.millis  <= 999)); 
    246246} body { 
    247     size_t eaten() { return p - src.ptr; } 
    248     bool done(T[] s) { return .done(eaten(), src.length, *p, s); } 
    249  
    250     bool checkColon() { 
    251         if (separators == WHATEVER) 
    252             accept(p, ':'); 
    253  
    254         else if (accept(p, ':') != separators) 
    255             return false; 
    256  
    257         return true; 
    258     } 
    259  
    260     byte getTimeZone() { return .getTimeZone(p, date, time, separators, &done); } 
    261  
    262     // TODO/BUG: need to convert from local time if got T 
    263     // however, Tango provides nothing like Phobos's std.date.getLocalTZA 
    264     // (which doesn't look like it should work on Windows, it should use tzi.bias only, and GetTimeZoneInformationForYear) 
    265     // (and which uses too complicated code for Posix, tzset should be enough) 
    266     // and I'm not interested in delving into system-specific code right now 
    267     // remember also that -1 BC is the year zero in ISO 8601... -2 BC is -1, etc 
    268     if (separators == WHATEVER) 
    269         accept(p, 'T'); 
    270  
    271     if (parseInt(p, 2u, time.hours) != 2 || time.hours > 24) 
    272         return (time.hours = 0); 
    273  
    274     auto onlyHour = eaten(); 
    275  
    276     // hh 
    277     if (done("+,-.012345:")) 
    278         return onlyHour; 
    279  
    280     switch (getDecimal(p, time, HOUR)) { 
    281         case NOTFOUND: break; 
    282         case    FOUND: 
    283             auto onlyDecimal = eaten(); 
    284             if (getTimeZone() == BAD) 
    285                 return onlyDecimal; 
    286  
    287             // /hh,h+/ 
    288             return eaten(); 
    289  
    290         case BAD: return onlyHour; 
    291         default: assert (false); 
    292     } 
    293  
    294     switch (getTimeZone()) { 
    295         case NOTFOUND: break; 
    296         case    FOUND: return eaten(); 
    297         case BAD:      return onlyHour; 
    298         default: assert (false); 
    299     } 
    300  
    301     if ( 
    302         !checkColon() || 
    303  
    304         parseInt(p, 2u, time.minutes) != 2 || time.minutes > 59 || 
    305  
    306         // hour 24 is only for 24:00:00 
    307         (time.hours == 24 && time.minutes != 0) 
    308     ) { 
    309         time.minutes = 0; 
    310         return onlyHour; 
    311     } 
    312  
    313     auto onlyMinute = eaten(); 
    314  
    315     // hh:mm 
    316     if (done("+,-.0123456:")) { 
    317         bothValid = true; 
    318         return onlyMinute; 
    319     } 
    320  
    321     switch (getDecimal(p, time, MINUTE)) { 
    322         case NOTFOUND: break; 
    323         case    FOUND: 
    324             auto onlyDecimal = eaten(); 
    325             if (getTimeZone() == BAD) 
    326                 return onlyDecimal; 
    327  
    328             // /hh:mm,m+/ 
    329             bothValid = true; 
    330             return eaten(); 
    331  
    332         case BAD: return onlyMinute; 
    333         default: assert (false); 
    334     } 
    335  
    336     switch (getTimeZone()) { 
    337         case NOTFOUND: break; 
    338         case    FOUND: bothValid = true; return eaten(); 
    339         case BAD:      return onlyMinute; 
    340         default: assert (false); 
    341     } 
    342  
    343     if ( 
    344         !checkColon() || 
    345  
    346         parseInt(p, 2u, time.seconds) != 2 || time.seconds > 60 || 
    347  
    348         (time.hours == 24 && time.seconds  != 0) || 
    349         (time.seconds  == 60 && time.hours != 23 && time.minutes != 59) 
    350     ) { 
    351         time.seconds = 0; 
    352         return onlyMinute; 
    353     } 
    354  
    355     auto onlySecond = eaten(); 
    356  
    357     // hh:mm:ss 
    358     if (done("+,-.Z")) { 
    359         bothValid = true; 
    360         return onlySecond; 
    361     } 
    362  
    363     switch (getDecimal(p, time, SECOND)) { 
    364         case NOTFOUND: break; 
    365         case    FOUND: 
    366             auto onlyDecimal = eaten(); 
    367             if (getTimeZone() == BAD) 
    368                 return onlyDecimal; 
    369  
    370             // /hh:mm:ss,s+/ 
    371             bothValid = true; 
    372             return eaten(); 
    373  
    374         case BAD: return onlySecond; 
    375         default: assert (false); 
    376     } 
    377  
    378     if (getTimeZone() == BAD) 
    379         return onlySecond; 
    380     else { 
    381         bothValid = true; 
    382         return eaten(); // hh:mm:ss with timezone 
    383     } 
     247    size_t eaten() { return p - src.ptr; } 
     248    bool done(T[] s) { return .done(eaten(), src.length, *p, s); } 
     249 
     250    bool checkColon() { 
     251        if (separators == WHATEVER) 
     252            accept(p, ':'); 
     253 
     254        else if (accept(p, ':') != separators) 
     255            return false; 
     256 
     257        return true; 
     258    } 
     259 
     260    byte getTimeZone() { return .getTimeZone(p, date, time, separators, &done); } 
     261 
     262    // TODO/BUG: need to convert from local time if got T 
     263    // however, Tango provides nothing like Phobos's std.date.getLocalTZA 
     264    // (which doesn't look like it should work on Windows, it should use tzi.bias only, and GetTimeZoneInformationForYear) 
     265    // (and which uses too complicated code for Posix, tzset should be enough) 
     266    // and I'm not interested in delving into system-specific code right now 
     267    // remember also that -1 BC is the year zero in ISO 8601... -2 BC is -1, etc 
     268    if (separators == WHATEVER) 
     269        accept(p, 'T'); 
     270 
     271    if (parseInt(p, 2u, time.hours) != 2 || time.hours > 24) 
     272        return (time.hours = 0); 
     273 
     274    auto onlyHour = eaten(); 
     275 
     276    // hh 
     277    if (done("+,-.012345:")) 
     278        return onlyHour; 
     279 
     280    switch (getDecimal(p, time, HOUR)) { 
     281        case NOTFOUND: break; 
     282        case    FOUND: 
     283            auto onlyDecimal = eaten(); 
     284            if (getTimeZone() == BAD) 
     285                return onlyDecimal; 
     286 
     287            // /hh,h+/ 
     288            return eaten(); 
     289 
     290        case BAD: return onlyHour; 
     291        default: assert (false); 
     292    } 
     293 
     294    switch (getTimeZone()) { 
     295        case NOTFOUND: break; 
     296        case    FOUND: return eaten(); 
     297        case BAD:      return onlyHour; 
     298        default: assert (false); 
     299    } 
     300 
     301    if ( 
     302        !checkColon() || 
     303 
     304        parseInt(p, 2u, time.minutes) != 2 || time.minutes > 59 || 
     305 
     306        // hour 24 is only for 24:00:00 
     307        (time.hours == 24 && time.minutes != 0) 
     308    ) { 
     309        time.minutes = 0; 
     310        return onlyHour; 
     311    } 
     312 
     313    auto onlyMinute = eaten(); 
     314 
     315    // hh:mm 
     316    if (done("+,-.0123456:")) { 
     317        bothValid = true; 
     318        return onlyMinute; 
     319    } 
     320 
     321    switch (getDecimal(p, time, MINUTE)) { 
     322        case NOTFOUND: break; 
     323        case    FOUND: 
     324            auto onlyDecimal = eaten(); 
     325            if (getTimeZone() == BAD) 
     326                return onlyDecimal; 
     327 
     328            // /hh:mm,m+/ 
     329            bothValid = true; 
     330            return eaten(); 
     331 
     332        case BAD: return onlyMinute; 
     333        default: assert (false); 
     334    } 
     335 
     336    switch (getTimeZone()) { 
     337        case NOTFOUND: break; 
     338        case    FOUND: bothValid = true; return eaten(); 
     339        case BAD:      return onlyMinute; 
     340        default: assert (false); 
     341    } 
     342 
     343    if ( 
     344        !checkColon() || 
     345         parseInt(p, 2u, time.seconds) != 2 || time.seconds > 60 || 
     346        (time.hours == 24 && time.seconds  != 0) || 
     347        (time.seconds  == 60 && time.hours != 23 && time.minutes != 59) 
     348    ) { 
     349        time.seconds = 0; 
     350        return onlyMinute; 
     351    } 
     352 
     353    auto onlySecond = eaten(); 
     354 
     355    // hh:mm:ss 
     356    if (done("+,-.Z")) { 
     357        bothValid = true; 
     358        return onlySecond; 
     359    } 
     360 
     <