www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 1639] New: Date/Time deficiences

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1639

           Summary: Date/Time deficiences
           Product: D
           Version: unspecified
          Platform: PC
        OS/Version: Windows
            Status: NEW
          Severity: normal
          Priority: P2
         Component: Phobos
        AssignedTo: braddr puremagic.com
        ReportedBy: steve.teale britseyeview.com


The Date struct is lacking a day-of-year (Julian day) field.

Date instances can only be instantiated by parsing a string.  Should be
possible to instantiate from clock ticks and explicit date part values.

There needs to be a corresponding Time struct for example for use with ODBC.


-- 
Nov 04 2007
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1639





------- Comment #1 from steve.teale britseyeview.com  2007-11-04 03:04 -------
Created an attachment (id=200)
 --> (http://d.puremagic.com/issues/attachment.cgi?id=200&action=view)
Proposed modifications


-- 
Nov 04 2007
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1639


matti.niemenmaa+dbugzilla iki.fi changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Severity|normal                      |enhancement




-- 
Nov 04 2007
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1639





------- Comment #2 from ghaecker 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;

< * 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

< 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);

< 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));

< while (TimeFromYear(y + 1) <= t) < y++; ---
 	while (TimeFromYear(y + 1) <= t)
 	    y++;

< do < { < y--; < } while (TimeFromYear(y) > t); ---
 	do
 	{
 	    y--;
 	}
 	while (TimeFromYear(y) > t);

< 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"); < } < } < < <

--
Apr 30 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1639





------- Comment #3 from ghaecker idworld.net  2009-04-30 10:47 -------
In struct Time method fromTicks,

function calls
    HourFromTime
    MinFromTime
    SecFromTime

need to changed to
    hourFromTime
    minFromTime
    secFromTime

respectively.


-- 
Apr 30 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1639


smjg iname.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |smjg iname.com




------- Comment #4 from smjg iname.com  2009-04-30 19:06 -------
(In reply to comment #0)
 The Date struct is lacking a day-of-year (Julian day) field.
 
 Date instances can only be instantiated by parsing a string.  Should be
 possible to instantiate from clock ticks and explicit date part values.

The latter is possible. http://www.digitalmars.com/d/1.0/struct.html#StructLiteral Whether it checks the struct for validity or auto-fills weekday/yday is another matter....
 <        if (s < 0 || s > 59)
 <           throw new Exception("Second value out of range.");

This'll prevent storing a leap second time....
 There needs to be a corresponding Time struct for example for use with ODBC.

(In reply to comment #2)
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;

< * Time of day broken down into its components. < */ < struct Time < { < int hour; /// 0..23 < int minute; /// 0..59


What was the purpose of copying this long block of code here? But std.date could certainly do with improvements. BTW check out this alternative: http://pr.stewartsplace.org.uk/d/sutil/ --
Apr 30 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1639





------- Comment #5 from ghaecker idworld.net  2009-04-30 19:24 -------
(In reply to comment #4)
 What was the purpose of copying this long block of code here?

Sorry about that. I'm new to bugzilla. That long block of code resulted from my using the "Edit as Comment" feature on the proposed code attachment to this issue. If I had known that would be the result I would not have done it. That's why I added Comment #3 to clarify what I was attempting to point out. --
Apr 30 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1639


braddr puremagic.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
         AssignedTo|braddr puremagic.com        |bugzilla digitalmars.com




------- Comment #6 from braddr puremagic.com  2009-04-30 19:33 -------
Not sure why this is assigned to me.  Re-assigning it back to the default
owner.

One brief comment, unit tests shouldn't ever have that much output to them.  No
output other than assertion failures.


-- 
Apr 30 2009
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1639


Andrei Alexandrescu <andrei metalanguage.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |ASSIGNED
                 CC|                            |andrei metalanguage.com
         AssignedTo|nobody puremagic.com        |andrei metalanguage.com


-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 11 2009