September 16, 2010
On Sep 16, 2010, at 4:27 PM, Jonathan M Davis wrote:

> On Thursday, September 16, 2010 15:39:19 Sean Kelly wrote:
>> On Sep 9, 2010, at 5:25 PM, Jonathan M Davis wrote:
>>> Just so you know, I fully expect that the datetime code that I've been working on will be done in less than a month. It'll be at least a week (probably closer to two), but it certainly won't be in the range of a month. Now, how many changes will be required after it's reviewed, or whether it will be accepted at all, is another matter. But it shouldn't be all that much longer before I'm done.
>> 
>> There are a bunch of routines in druntime that could really use a
>> structured timespan representation (Boost actually even uses a full
>> SystemTime class for most of these) and I'm trying to work out the best
>> way to do this.  In Tango, the decision was to have the routines all
>> accept a long value that is the same resolution as the tick count from
>> TimeSpan, which is why everything currently works as it does.  I've always
>> hated this and would love to do something more structured, but
>> complications arise from possible redundancy or incompatibility with
>> std.time.  What I've done for now is duplicate Boost's time_duration
>> struct (as TimeDuration) into core.time, and I'm looking at using this for
>> Thread.sleep(), etc.  Thoughts?
>> _______________________________________________
>> phobos mailing list
>> phobos at puremagic.com
>> http://lists.puremagic.com/mailman/listinfo/phobos
> 
> For what I've done, I have an enum of possible time units : year, month, week, day, hour, second, minute, second, millisecond, microsecond,  and tick (where a tick is 100 nanoseconds). I then have a Duration struct which is templatized on the time unit enum and takes a value. So, you end up with a Duration which which has a value (which is a long) and a type of time unit (e.g. 10 seconds or 1000 days). All of the functions that take a Duration are templatized so they will take any Duration with units that they're compatible with (the main problem with making them compatible with _all_ time units being that you cannot convert between years or months and any other units without a specific date because the number of days in a month is not consistent).
> 
> How all that would be applied to core.time, I don't know. I'd have to look at what it's doing.

It's pretty much a straight port of time_duration, described here:

http://www.boost.org/doc/libs/1_44_0/doc/html/date_time/posix_time.html#date_time.posix_time.time_duration

I haven't bothered with the operator overloading yet though.
September 16, 2010
On Thu, 16 Sep 2010 17:39:19 -0500, Sean Kelly <sean at invisibleduck.org> wrote:

> There are a bunch of routines in druntime that could really use a structured timespan representation (Boost actually even uses a full SystemTime class for most of these) and I'm trying to work out the best way to do this.  In Tango, the decision was to have the routines all accept a long value that is the same resolution as the tick count from TimeSpan, which is why everything currently works as it does.  I've always hated this and would love to do something more structured, but complications arise from possible redundancy or incompatibility with std.time.  What I've done for now is duplicate Boost's time_duration struct (as TimeDuration) into core.time, and I'm looking at using this for Thread.sleep(), etc.  Thoughts?

Sean.

I've been porting the Boost date_time library to D. But I have been busy these last weeks and it's on hold. In essence, is finished, but I need to add unit test and more documentation, specially to the time module.  The library is huge: I had to use three modules (core.d, date.d and time.d). In the time.d module is the TimeDuration struct. But right now, as I did an almost straight port, is somewhat inefficient (at least to use it as a measure element for the runtime), for two reasons:

1. The resolution is in nanoseconds, meaning that the operations to
calculate the times uses big numbers
2. Internally, it uses a special struct to emulate (+/-) infinity and NAD
(not a date) so most of the time operations are delegated to this struct.

Maybe you can take something from these modules, instead of reimplement it, and just adapt it or refactor it to make it more efficient. Here's the code:
> http://bitbucket.org/gomez/yao-library/src/tip/src/yao/datetime/core.d http://bitbucket.org/gomez/yao-library/src/tip/src/yao/datetime/date.d http://bitbucket.org/gomez/yao-library/src/tip/src/yao/datetime/time.d

And some (incomplete) documentation in pretty looking html:
> http://d.yao.com.mx/datetime/core.html http://d.yao.com.mx/datetime/date.html http://d.yao.com.mx/datetime/time.html

The documentation of TimeDuration:
> http://d.yao.com.mx/datetime/time.html#TimeDuration

-- 
Yao G.
September 16, 2010

Sean Kelly wrote:
>
> There are a bunch of routines in druntime that could really use a structured timespan representation (Boost actually even uses a full SystemTime class for most of these) and I'm trying to work out the best way to do this.  In Tango, the decision was to have the routines all accept a long value that is the same resolution as the tick count from TimeSpan, which is why everything currently works as it does.  I've always hated this and would love to do something more structured, but complications arise from possible redundancy or incompatibility with std.time.  What I've done for now is duplicate Boost's time_duration struct (as TimeDuration) into core.time, and I'm looking at using this for Thread.sleep(), etc.  Thoughts?
>
> 

I thought Tango used a floating point representation of time? (BTW, I think such a representation is a mistake for various reasons.)
September 17, 2010
On Sep 16, 2010, at 7:38 PM, Walter Bright wrote:
> 
> Sean Kelly wrote:
>> 
>> There are a bunch of routines in druntime that could really use a structured timespan representation (Boost actually even uses a full SystemTime class for most of these) and I'm trying to work out the best way to do this.  In Tango, the decision was to have the routines all accept a long value that is the same resolution as the tick count from TimeSpan, which is why everything currently works as it does.  I've always hated this and would love to do something more structured, but complications arise from possible redundancy or incompatibility with std.time.  What I've done for now is duplicate Boost's time_duration struct (as TimeDuration) into core.time, and I'm looking at using this for Thread.sleep(), etc.  Thoughts?
>> 
>> 
> 
> I thought Tango used a floating point representation of time? (BTW, I think such a representation is a mistake for various reasons.)

First let me qualify this by saying that my knowledge of Tango is a few years out of date.  Tango used a double to represent timespans for a while, but once the time modules were created it switched to using a long representing tick count (100ns resolution).  I lobbied for using the TimeSpan struct directly and the idea was vetoed.  So you'd do something like:

Thread.sleep(TimeSpan.fromSeconds(1).toTicks());

I can't remember the exact syntax, but it was along those lines.
September 17, 2010



----- Original Message ----
> From: Walter Bright <walter at digitalmars.com>
> To: Discuss the phobos library for D <phobos at puremagic.com>
> Sent: Thu, September 16, 2010 10:38:56 PM
> Subject: Re: [phobos] next release
> 
> 
> 
> Sean Kelly wrote:
> >
> > There are a bunch of routines in  druntime that could really use a structured
>timespan representation (Boost  actually even uses a full SystemTime class for most of these) and I'm trying to  work out the best way to do this.  In Tango, the decision was to have the  routines all accept a long value that is the same resolution as the tick count  from TimeSpan, which is why everything currently works as it does.  I've  always hated this and would love to do something more structured, but  complications arise from possible redundancy or incompatibility with  std.time.  What I've done for now is duplicate Boost's time_duration struct  (as TimeDuration) into core.time, and I'm looking at using this for Thread.sleep(), etc.  Thoughts?
> >
> > 
> 
> I thought  Tango used a floating point representation of time? (BTW, I think such a  representation is a mistake for various  reasons.)

This was my main problem with Tango's time functions when I first proposed the changes I eventually made for Tango.  So yes, it did use this at one point, but no longer does (since about 3 years ago?).   See this thread (no Tango code involved, just samples): http://www.dsource.org/projects/tango/forums/topic/205

Using floating point is actually not that bad, you just need to add a proper epsilon when converting.  But since most core functions use an integral time representation, converting from one integer into another is faster.

In response to Sean, I think the time span type can live in core, even if it's used in std.time.  std.datetime can easily just public include core.time.  In fact, I think I at one point had Tango set up this way (with all the time-related core functions taking a TimeSpan), but Kris rejected it.

-Steve




September 17, 2010



----- Original Message ----
> From: Jonathan M Davis <jmdavisProg at gmx.com>
> To: phobos at puremagic.com
> Sent: Thu, September 16, 2010 7:27:21 PM
> Subject: Re: [phobos] next release
> 
> On Thursday, September 16, 2010 15:39:19 Sean Kelly wrote:
> > On Sep 9,  2010, at 5:25 PM, Jonathan M Davis wrote:
> > > Just so you know, I fully  expect that the datetime code that I've been
> > > working on will be  done in less than a month. It'll be at least a week
> > > (probably  closer to two), but it certainly won't be in the range of a
> > > month.  Now, how many changes will be required after it's reviewed, or
> > >  whether it will be accepted at all, is another matter. But it shouldn't
> >  > be all that much longer before I'm done.
> > 
> > There are a bunch  of routines in druntime that could really use a
> > structured timespan  representation (Boost actually even uses a full
> > SystemTime class for  most of these) and I'm trying to work out the best
> > way to do this.   In Tango, the decision was to have the routines all
> > accept a long value  that is the same resolution as the tick count from
> > TimeSpan, which is  why everything currently works as it does.  I've always
> > hated this  and would love to do something more structured, but
> > complications arise  from possible redundancy or incompatibility with
> > std.time.  What  I've done for now is duplicate Boost's time_duration
> > struct (as  TimeDuration) into core.time, and I'm looking at using this for
> >  Thread.sleep(), etc.  Thoughts?
> >  _______________________________________________
> > phobos mailing  list
> > phobos at puremagic.com
> >  http://lists.puremagic.com/mailman/listinfo/phobos
> 
> For what I've done, I  have an enum of possible time units : year, month, week,
>
> day, hour, second,  minute, second, millisecond, microsecond,  and tick (where
>a
>
> tick is  100 nanoseconds). I then have a Duration struct which is templatized
>on
>
> the  time unit enum and takes a value. So, you end up with a Duration which
>which
>
> has a value (which is a long) and a type of time unit (e.g. 10 seconds or  1000
>
> days). All of the functions that take a Duration are templatized so  they will

> take any Duration with units that they're compatible with (the  main problem
>with
>
> making them compatible with _all_ time units being that  you cannot convert between years or months and any other units without a  specific date because
>the
>
> number of days in a month is not  consistent).

I don't see the point of doing this.  If you just say the Duration is not templated, and defines a number of ticks, you get a 20,000 year span.  Is that not enough span?  It just seems like its unnecessarily complicated.  Now if I want to add two Durations together and one is in seconds and the other is in milliseconds, I have to generate a new function because it's templated.  It's trivial to get the number of seconds from a number of ticks, if that's what you are interested in.

-Steve




September 17, 2010
On Sep 17, 2010, at 10:50 AM, Steve Schveighoffer wrote:
> 
> In response to Sean, I think the time span type can live in core, even if it's used in std.time.  std.datetime can easily just public include core.time.  In fact, I think I at one point had Tango set up this way (with all the time-related core functions taking a TimeSpan), but Kris rejected it.

Yeah.  The bid to make the runtime as small as possible got a bit extreme at times.  I think I'll go ahead and define a TimeDuration (maybe renamed to Duration) and see how it goes.  Worst case I use a name that doesn't collide with what std.datetime uses and we just have two.  All I really need is a formalized way to specify timespans anyway.
September 17, 2010
On Friday, September 17, 2010 11:08:54 Steve Schveighoffer wrote:
> I don't see the point of doing this.  If you just say the Duration is not templated, and defines a number of ticks, you get a 20,000 year span.  Is that not enough span?  It just seems like its unnecessarily complicated. Now if I want to add two Durations together and one is in seconds and the other is in milliseconds, I have to generate a new function because it's templated.  It's trivial to get the number of seconds from a number of ticks, if that's what you are interested in.

Well, if nothing else, I did it that way because it's nice and generic. The same Duration type works with multiple types of time points, unlike how Boost has duration types which are specific to each of its time point types.

The problem with using ticks for a Duration is that it doesn't work for any units greater than weeks. Because the number of days in a month is variable, you can't convert between months and anything smaller without a specific date. So, if you want to be able to have durations of months or years, you have to have at least 2 duration types - one which covers months and years and one which covers the smaller units (presumably by being in ticks as you suggest). I just simplified it by having a Duration have both units and length rather than burdening the programmer with figuring out whether they're dealing with a duration which deals with years and months or one which deals with smaller units. They just use the duration with whatever units that they want (or whatever they get from a function) and as long as an operation works with that type of time unit, it will compile (if it doesn't work, it's because of the lack of conversion between months and smaller units and the operation in question lacking the context to allow such a conversion to work).

I could probably find a way to make the API work essentially as it does now and restrict the number of actual Duration types which are generated to two (by having one specialized template for years and months and one for the smaller units), but I haven't spent the time to look at doing that sort of optimization.

- Jonathan M Davis
September 17, 2010



----- Original Message ----
> From: Jonathan M Davis <jmdavisProg at gmx.com>
> To: phobos at puremagic.com
> Sent: Fri, September 17, 2010 2:43:16 PM
> Subject: Re: [phobos] next release
> 
> On Friday, September 17, 2010 11:08:54 Steve Schveighoffer wrote:
> > I  don't see the point of doing this.  If you just say the Duration is  not templated, and defines a number of ticks, you get a 20,000 year  span.  Is that not enough span?  It just seems like its  unnecessarily complicated. Now if I want to add two Durations together  and one is in seconds and the other is in milliseconds, I have to  generate a new function because it's templated.  It's trivial to  get the number of seconds from a number of ticks, if that's what you are  interested in.
> 
> Well, if nothing else, I did it that way because it's nice  and generic. The
>same
>
> Duration type works with multiple types of time  points, unlike how Boost has duration types which are specific to each of  its time point types.
> 
> The problem with using ticks for a Duration is that  it doesn't work for any units greater than weeks. Because the number of days  in a month is variable,
>you
>
> can't convert between months and anything  smaller without a specific date.

Ah, I see.

Yes, in my implementation (on Tango), TimeSpan only dealt with up to days.  It did not deal with years or months because those were calendar functions.

Months are very tricky to deal with.  For instance, if a date is 1/30, and one wants to add a month, what happens?  You run into weird situations, and I left that awkwardness in another module.  The Span type (Duration, whatever) I think should be calendar-free.  This allows a very very simple implementation, and can be used in areas where you don't need the complexity of calendars (for instance, in thread.sleep).

In the calendar class, I had addMonths and addYears (which essentially was addMonths(x * 12)) to deal with dates/times.

> So, if you want to be able to have  durations of months or years, you have to have at

> least 2 duration types -  one which covers months and years and one which
>covers
>
> the smaller units  (presumably by being in ticks as you suggest).

No matter what solution you use, there will be some awkwardness.  For example, if you wanted to determine how many months were between two dates, d1 and d2, how does that work?  Intuitively, you'd do:

d2 - d1

But the type may not have enough information to convert to months.  If you want to have a separate months/years type, then you need to have functions like monthsBetween(d1, d2) which returns a months type.

I guess I will wait and see what the final API looks like and then see how I like it.

-Steve




September 17, 2010
datetime.time documentation is almost complete:

> http://d.yao.com.mx/datetime/time.html

and I'm halfway through the TimeZone and LocalDate implementation (coming
soon).

--
Yao G.