http://d.puremagic.com/issues/show_bug.cgi?id=1639
------- Comment #2 from ghaec...@idworld.net 2009-04-30 10:42 ------- (From update of attachment 200) >22,25c22,23 >< private import std.conv; >< private import std.stdio; >< private import std.dateparse; >< private import std.string; >--- >> private import std.stdio; >> private import std.dateparse; >46,277d43 >< * Time of day broken down into its components. >< */ >< struct Time >< { >< int hour; /// 0..23 >< int minute; /// 0..59 >< int second; /// 0..59 >< int ms; /// 0..999 >< >< void fromTimeParts(int h, int m, int s, int msec = 0) >< { >< if (h < 0 || h > 23) >< throw new Exception("Hour value out of range."); >< if (m < 0 || m > 59) >< throw new Exception("Minute value out of range."); >< if (s < 0 || s > 59) >< throw new Exception("Second value out of range."); >< if (ms < 0 || ms > 999) >< throw new Exception("Millisecond value out of range."); >< hour = h; >< minute = m; >< second = s; >< ms = msec; >< } >< >< void fromTicks(d_time t) >< { >< hour = hourFromTime(t); >< minute = minFromTime(t); >< second = secFromTime(t); >< ms = msFromTime(t); >< } >< void parse(string s) >< { >< // Will parse time strings in the following forms: >< // 22:02 >< // 22:02:02 >< // 22:02:02:000 >< // 22:02:02.000 >< // 10:02pm >< // 10:02:02pm >< // 10:02:02:000pm >< // 10:02:02.000pm >< // 09:02 >< // 09:02am >< // 09:02:02 >< // 9:02:02 >< // 09:02:02am >< // 9:12 >< // 9:12am >< // 9:12:12am >< // ... >< >< int sp; >< int lms; >< >< void adjusthour(bool pm) >< { >< if (pm) >< { >< if (hour < 12) >< hour += 12; >< else if (hour > 12) >< throw new Exception("Inconsistent hour with pm."); >< } >< else >< { >< if (hour > 12) >< throw new Exception("Inconsistent hour with am."); >< if (hour == 12) >< hour = 0; >< } >< } >< >< int splitmsp(string msp, out int msv) >< { >< if (msp.length == 0) >< return 0; >< msv = std.conv.parse!(int)(msp); >< if (msp.length == 0) >< return 0; >< if (msp == "am") >< return 1; >< else if (msp == "pm") >< return 2; >< else >< throw new Exception("Expected am, pm or nothing."); >< } >< >< bool splithop(string hop, out int hv) >< { >< hv = std.conv.parse!(int)(hop); >< if (hop == "am") >< return false; >< else if (hop == "pm") >< return true; >< else >< throw new Exception("Expected am or pm."); >< } >< >< bool splitmsop(string sop, out int sv) >< { >< sv = std.conv.parse!(int)(sop); >< if (sop == "am") >< return false; >< else if (sop == "pm") >< return true; >< else >< throw new Exception("Expected am or pm."); >< } >< >< void splitsp(string last, out int sv, out int msv) >< { >< int dot = find(last, '.'); >< if (dot == -1) >< { >< msv = 0; >< if (last.length == 4) >< { >< bool pm = splitmsop(last, sv); >< adjusthour(pm); >< } >< else >< throw new Exception("Expected NNam or NNpm."); >< } >< else >< { >< if (dot != 2) >< throw new Exception("Seconds not 2 digits in time string."); >< sv = std.conv.parse!(int)(last); >< munch(last, "."); >< if (last.length > 5) >< throw new Exception("Malformed miliseconds-am/pm string."); >< if (last.length == 0) >< msv = 0; >< else >< { >< int dp = splitmsp(last, msv); >< if (dp == 1) >< adjusthour(false); >< else if (dp == 2) >< adjusthour(true); >< } >< } >< } >< >< bool tmc = false; >< s = tolower(cast(string) s); >< s = replace(cast(string) s, " ", ""); >< string[] parts = split(cast(string) s, ":"); >< if (parts.length == 1) >< { >< if (parts[0].length > 2) >< { >< bool pm = splithop(parts[0], hour); >< adjusthour(pm); >< } >< else >< hour = to!(int)(parts[0]); >< minute = 0; >< second = 0; >< ms = 0; >< } >< else if (parts.length == 2) >< { >< // Hour and minute >< hour = to!(int)(parts[0]); >< if (parts[1].length > 2) >< { >< bool pm = splitmsop(parts[1], minute); >< adjusthour(pm); >< } >< else >< minute = to!(int)(parts[1]); >< second = 0; >< ms = 0; >< } >< else if (parts.length == 3) >< { >< hour = to!(int)(parts[0]); >< minute = to!(int)(parts[1]); >< if (parts[2].length > 2) >< { >< splitsp(parts[2], second, ms); >< } >< else >< { >< second = to!(int)(parts[2]); >< ms = 0; >< } >< } >< else if (parts.length == 4) >< { >< hour = to!(int)(parts[0]); >< minute = to!(int)(parts[1]); >< second = to!(int)(parts[2]); >< if (parts[3].length > 3) >< { >< int dp = splitmsp(parts[3], ms); >< if (dp == 1) >< adjusthour(false); >< else if (dp == 2) >< adjusthour(true); >< } >< else >< ms = (parts[3].length > 0)? to!(int)(parts[3]): 0; >< } >< else >< tmc = true; >< if (tmc) >< throw new Exception("Too many colons in time string."); >< if (hour < 0 || hour > 23) >< throw new Exception("Hour value out of range."); >< if (minute < 0 || minute > 59) >< throw new Exception("Minute value out of range."); >< if (second < 0 || second > 59) >< throw new Exception("Second value out of range."); >< if (ms < 0 || ms > 999) >< throw new Exception("Millisecond value out of range."); >< } >< >< string T24String(bool secs = false, bool msecs = false) >< { >< if (msecs) >< return format("%02d:%02d:%02d.%03d", hour, minute, second, ms); >< else if (secs) >< return format("%02d:%02d:%02d", hour, minute, second); >< else >< return format("%02d:%02d", hour, minute); >< } >< } >< /** >283,406c49,56 >< int month; /// 1..12 >< int day; /// 1..31 >< int hour; /// 0..23 >< int minute; /// 0..59 >< int second; /// 0..59 >< int ms; /// 0..999 >< int weekday; /// 0: not specified, 1..7: Sunday..Saturday >< int yday; /// 1..365(366) >< int tzcorrection = int.min; /// -1200..1200 correction in hours >< >< void fromDateParts(int y, int m, int d, int h, int mn, int s, int msi = >0) >< { >< year = y; >< month = m; >< day = d; >< hour = h; >< minute = mn; >< second = s; >< ms = msi; >< weekday = DOWFromDate(year, month, day); >< yday = YDayFromDate(year, month, day); >< } >< >< >< void fromTicks(d_time t) >< { >< int y; >< int d; >< int m; >< >< if (t == d_time_nan) >< throw new Exception("Bad d_time value"); >< >< // Hazard a guess >< y = 1970 + cast(int) (t / (3652425 * (msPerDay / 10000))); >< >< if (TimeFromYear(y) <= t) >< { >< while (TimeFromYear(y + 1) <= t) >< y++; >< } >< else >< { >< do >< { >< y--; >< } while (TimeFromYear(y) > t); >< } >< year = y; >< >< int leap = LeapYear(y); >< d = Day(t) - DayFromYear(year); >< >< if (d < 59) >< { >< if (d < 31) >< { >< assert(d >= 0); >< m = 0; >< } >< else >< { >< m = 1; >< } >< } >< else >< { >< d -= leap; >< if (d < 212) >< { >< if (d < 59) >< m = 1; >< else if (d < 90) >< m = 2; >< else if (d < 120) >< m = 3; >< else if (d < 151) >< m = 4; >< else if (d < 181) >< m = 5; >< else >< m = 6; >< } >< else >< { >< if (d < 243) >< m = 7; >< else if (d < 273) >< m = 8; >< else if (d < 304) >< m = 9; >< else if (d < 334) >< m = 10; >< else if (d < 365) >< m = 11; >< else >< assert(0); >< } >< } >< month = m+1; >< switch (m) >< { >< case 0: day = d + 1; break; >< case 1: day = d - 30; break; >< case 2: day = d - 58 - leap; break; >< case 3: day = d - 89 - leap; break; >< case 4: day = d - 119 - leap; break; >< case 5: day = d - 150 - leap; break; >< case 6: day = d - 180 - leap; break; >< case 7: day = d - 211 - leap; break; >< case 8: day = d - 242 - leap; break; >< case 9: day = d - 272 - leap; break; >< case 10: day = d - 303 - leap; break; >< case 11: day = d - 333 - leap; break; >< default: >< assert(0); >< } >< hour = HourFromTime(t); >< minute = MinFromTime(t); >< second = SecFromTime(t); >< ms = msFromTime(t); >< weekday = WeekDay(t)+1; >< yday = YDayFromDate(year, month, day); >< } >--- >> int month; /// 1..12 >> int day; /// 1..31 >> int hour; /// 0..23 >> int minute; /// 0..59 >> int second; /// 0..59 >> int ms; /// 0..999 >> int weekday; /// 0: not specified, 1..7: Sunday..Saturday >> int tzcorrection = int.min; /// -1200..1200 correction in hours >411,419c61,63 >< DateParse dp; >< dp.parse(s, *this); >< } >< >< string toISODateString() >< { >< return (ms == 0)? >< std.string.format("%d-%02d-%02d %02d:%02d:%02d", year, month, day, >hour, minute, second): >< std.string.format("%d-%02d-%02d %02d:%02d:%02d.%03d", year, month, >day, hour, minute, second, ms); >--- >> DateParse dp; >> >> dp.parse(s, *this); >552,577d195 >< int DOWFromDate(int year, int month, int day) >< { >< static int[13] mdd = [ -1, 3, 28, 0, 4, 9, 6, 11, 8, 5, 10, 7, 12 ]; >< >< int century = year/100+1; >< int a = century*5; >< int b = (century-1)/4; >< int anchor = (a+b+4)%7; >< >< int e = (year%100)/12; >< int f = (year%100)%12; >< int g = f/4; >< int dday = (e+f+g+anchor)%7; >< >< int mday = (month <= 2 && LeapYear(year))? mdd[month]+1: mdd[month]; >< int delta = (day - mday); >< return 1+(dday+delta)%7; >< } >< >< int YDayFromDate(int year, int month, int day) >< { >< static int[13] mcum = [ -1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, >304, 334 ]; >< int n = (month > 2 && LeapYear(year))? mcum[month]+1: mcum[month]; >< return n + day; >< } >< >617,624c235,241 >< { >< int y; >< >< if (t == d_time_nan) >< return 0; >< >< // Hazard a guess >< // y = 1970 + cast(int) (t / (365.2425 * msPerDay)); >--- >> { int y; >> >> if (t == d_time_nan) >> return 0; >> >> // Hazard a guess >> //y = 1970 + cast(int) (t / (365.2425 * msPerDay)); >630,631c247,248 >< while (TimeFromYear(y + 1) <= t) >< y++; >--- >> while (TimeFromYear(y + 1) <= t) >> y++; >635,638c252,256 >< do >< { >< y--; >< } while (TimeFromYear(y) > t); >--- >> do >> { >> y--; >> } >> while (TimeFromYear(y) > t); >908d525 >< >1373,1599d989 >< >< unittest >< { >< LocalTZA = getLocalTZA(); >< Date date; >< >< SYSTEMTIME st; >< GetLocalTime(&st); >< >< d_time t = getUTCtime(); >< d_time loc = UTCtoLocalTime(t); >< writefln("%d %d", t, loc); >< date.fromTicks(loc); >< >< writefln(date.year); >< writefln(date.month); >< writefln(date.day); >< writefln(date.hour); >< writefln(date.minute); >< writefln(date.second); >< writefln(date.ms); >< writefln(date.weekday); >< writefln(date.yday); >< writefln(""); >< >< writefln(st.wYear); >< assert(st.wYear == date.year); >< writefln(st.wMonth); >< assert(st.wMonth == date.month); >< writefln(st.wDay); >< assert(st.wDay == date.day); >< writefln(st.wHour); >< assert(st.wHour == date.hour); >< writefln(st.wMinute); >< assert(st.wMinute == date.minute); >< writefln(st.wSecond); >< assert(st.wSecond == date.second); >< writefln(st.wMilliseconds); >< writefln(st.wDayOfWeek); >< assert(st.wDayOfWeek+1 == date.weekday); >< writefln(""); >< >< date.fromDateParts(2007,10,31,12,12,12,123); >< >< writefln(date.year); >< assert(date.year == 2007); >< writefln(date.month); >< assert(date.month == 10); >< writefln(date.day); >< assert(date.day == 31); >< writefln(date.hour); >< assert(date.hour == 12); >< writefln(date.minute); >< assert(date.minute == 12); >< writefln(date.second); >< assert(date.second == 12); >< writefln(date.ms); >< assert(date.ms == 123); >< writefln(date.weekday); >< assert(date.weekday == 4); >< writefln(date.yday); >< assert(date.yday == 304); >< >< writefln(""); date.fromDateParts(2004,10,31,12,12,12,123); // leap >year >< writefln(date.weekday); >< assert(date.weekday == 1); >< writefln(date.yday); >< assert(date.yday == 305); >< >< >< // Time stuff >< >< // 22:02 >< // 22:02:02 >< // 22:02:02:000 >< // 22:02:02.000 >< // 10:02pm >< // 10:02:02pm >< // 10:02:02:000pm >< // 10:02:02.000pm >< // 09:02 >< // 09:02am >< // 09:02:02 >< // 9:02:02 >< // 09:02:02am >< // 9:12 >< // 9:12am >< // 9:12:12am >< >< Time ts; >< ts.parse("22:02"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 2 && ts.second == 0 && ts.ms == 0); >< ts.parse("22:02:02"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 2 && ts.second == 2 && ts.ms == 0); >< ts.parse("22:02:02:123"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 2 && ts.second == 2 && ts.ms == >123); >< ts.parse("22:02:02:1"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 2 && ts.second == 2 && ts.ms == 1); >< ts.parse("22:02:02:12"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 2 && ts.second == 2 && ts.ms == 12); >< ts.parse("22:02:02:"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 2 && ts.second == 2 && ts.ms == 0); >< ts.parse("22:02:02.123"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 2 && ts.second == 2 && ts.ms == >123); >< ts.parse("22:02:02.1"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 2 && ts.second == 2 && ts.ms == 1); >< ts.parse("22:02:02.12"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 2 && ts.second == 2 && ts.ms == 12); >< ts.parse("22:02:02."); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 2 && ts.second == 2 && ts.ms == 0); >< >< Time ts2; >< ts2.fromTimeParts(ts.hour, ts.minute, ts.second, ts.ms); >< writefln(ts2.T24String(true, true)); >< assert(ts.hour == ts2.hour && ts.minute == ts2.minute && ts.second == >ts2.second && ts.ms == ts2.ms); >< >< ts.parse("10:02pm"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 2 && ts.second == 0 && ts.ms == 0); >< ts.parse("10:02:02pm"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 2 && ts.second == 2 && ts.ms == 0); >< ts.parse("10:02:02:123pm"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 2 && ts.second == 2 && ts.ms == >123); >< ts.parse("10:02:02.123pm"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 2 && ts.second == 2 && ts.ms == >123); >< ts.parse("10:02:02.12pm"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 2 && ts.second == 2 && ts.ms == 12); >< ts.parse("10:02:02.1pm"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 2 && ts.second == 2 && ts.ms == 1); >< >< ts.parse("9:02am"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 9 && ts.minute == 2 && ts.second == 0 && ts.ms == 0); >< ts.parse("9:02:02am"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 9 && ts.minute == 2 && ts.second == 2 && ts.ms == 0); >< ts.parse("9:02:02:123am"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 9 && ts.minute == 2 && ts.second == 2 && ts.ms == 123); >< ts.parse("9:02:02.123am"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 9 && ts.minute == 2 && ts.second == 2 && ts.ms == 123); >< >< ts.parse("9:02pm"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 21 && ts.minute == 2 && ts.second == 0 && ts.ms == 0); >< ts.parse("9:02:02pm"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 21 && ts.minute == 2 && ts.second == 2 && ts.ms == 0); >< ts.parse("9:02:02:123pm"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 21 && ts.minute == 2 && ts.second == 2 && ts.ms == >123); >< ts.parse("9:02:02.123pm"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 21 && ts.minute == 2 && ts.second == 2 && ts.ms == >123); >< >< ts.parse("9am"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 9 && ts.minute == 0 && ts.second == 0 && ts.ms == 0); >< ts.parse("9pm"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 21 && ts.minute == 0 && ts.second == 0 && ts.ms == 0); >< ts.parse("10am"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 10 && ts.minute == 0 && ts.second == 0 && ts.ms == 0); >< ts.parse("10pm"); >< writefln(ts.T24String(true, true)); >< assert(ts.hour == 22 && ts.minute == 0 && ts.second == 0 && ts.ms == 0); >< >< try >< { >< ts.parse("123:12:12"); >< } >< catch (Exception ex) >< { >< writefln(ex.toString()); >< assert(ex.toString() == "Hour value out of range."); >< } >< >< try >< { >< ts.parse("22:12:12.12am"); >< } >< catch (Exception ex) >< { >< writefln(ex.toString()); >< assert(ex.toString() == "Inconsistent hour with am."); >< } >< >< try >< { >< ts.parse("12:12:12:12:12"); >< } >< catch (Exception ex) >< { >< writefln(ex.toString()); >< assert(ex.toString() == "Too many colons in time string."); >< } >< >< try >< { >< ts.parse("12:12:12.pm"); >< } >< catch (Exception ex) >< { >< writefln(ex.toString()); >< assert(ex.toString() == "conversion pm"); >< } >< } >< >< >< --