[Issue 1639] Date/Time deficiences
d-bugmail at puremagic.com
d-bugmail at puremagic.com
Thu Apr 30 08:42:33 PDT 2009
http://d.puremagic.com/issues/show_bug.cgi?id=1639
------- Comment #2 from ghaecker at 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");
>< }
>< }
><
><
><
--
More information about the Digitalmars-d-bugs
mailing list