October 10, 2010
I haven't been paying enough attention to this thread, nor have I invested the time to review the code, but I'd like to give you guys something to chew on. Here's one of the interview questions I use from time to time:

Design a routine to return:
  -1 if less than one month apart
   0 if exactly one month apart
   1 if more than one month apart

The purpose of asking this is to get the candidate to realize that not all questions have technical answers or are as simple as they seem at first glance.

There's a class of functionality that seems like it make sense to include in low level libraries, at least at first, but in the end, is really the sort of thing where there isn't a clearly right answer.  Date math contains a lot of them.  I strongly urge caution when going beyond the simple, always right, primitives of dates and times.

Later,
Brad

October 11, 2010
On Sunday, October 10, 2010 08:16:52 Jonathan M Davis wrote:
> On Sunday 10 October 2010 07:45:14 Andrei Alexandrescu wrote:
> > Again, the action item is to find realistic use cases.
> 
> Really, the only major case that I can think of is that being able to generate arbitrary durations is useful when dealing with ranges. If you're simply trying to add a duration to a time point, it's not much worse to have to explicitly use addYears and/or addMonths in addition to adding a duration to the time point (a bit annoying perhaps, but not a big deal). Generic code also does better with durations (though we could always keep addTUnit() and that would solve the generic code issue just fine), but I question that that's all that big a deal.

It looks like dealing with some of the interval functions such as shift() and expand() is definitely more pleasant with durations which can hold months and years, but versions of them can be added which take years and months instead.

Looking at it, I think that having just a duration which holds hnsecs internally will simplify the library a fair bit and make learning it easier and less overwhelming but will be at least somewhat frustrating to anyone who's really trying to use some of its more advanced features. However, that bit of extra pain for those types of folks is likely heavily outweighed by the benefits to the more casual user.

Of course, if we drop intervals as Andrei suggested, then functions like shift() and expand() won't matter anymore (since they won't exist), but I'm not sure that we want to drop that functionality.

- Jonathan M Davis
October 11, 2010
On Sunday, October 10, 2010 09:20:31 Michel Fortin wrote:
> Le 2010-10-10 ? 11:16, Jonathan M Davis a ?crit :
> > Part of me would definitely like to keep MonthDuration, HNSecDuration, and JointDuration as is, but the more I think about it, the more it looks like it wouldn't be all that bad to have to work around their lack, and while using the durations as they are really isn't all that hard, it's going to confuse a fair number of people when they first encounter them. So, I'm beginning to lean towards just simplifying it to HNSecDuration (though I'd rename it as Duration in that case). It's annoying in some cases, but it'll definitely cut down on the learning curve for using the library.
> 
> Another option I might propose is to get rid of MonthDuration by using JointDuration instead and rename it to CalendarDuration.
> 
> But in my opinion, calendar things like this should simply belong to a separate module. This would simplify the API for those who don't need to deal with the complexities of the calendar.

That's not an entirely bad idea, but since any types which deal with durations would have to know about CalendarDuration, it wouldn't really help much. And while I completely agree that we want to make the more advanced features not get in the average users way, most of the calendar stuff is built into the types themselves, so you can't really create a calendar module to hold it. Fancier features like date recurrence patterns (which are heavily used by calendar applications) could be put in a separate module, but they can use the types in datetime rather than needing to be built into them (though they aren't implemented at present regardless). Durations a bit too integral for that.

- Jonathan M Davis
October 11, 2010
Le 2010-10-11 ? 13:19, Jonathan M Davis a ?crit :

> On Sunday, October 10, 2010 09:20:31 Michel Fortin wrote:
>> Another option I might propose is to get rid of MonthDuration by using JointDuration instead and rename it to CalendarDuration.
>> 
>> But in my opinion, calendar things like this should simply belong to a separate module. This would simplify the API for those who don't need to deal with the complexities of the calendar.
> 
> That's not an entirely bad idea, but since any types which deal with durations would have to know about CalendarDuration, it wouldn't really help much. And while I completely agree that we want to make the more advanced features not get in the average users way, most of the calendar stuff is built into the types themselves, so you can't really create a calendar module to hold it.

I'm aware that my suggestion doesn't fit very well the structure of your code. Personally, that the calendar stuff is built into the type themselves is what makes me a little uneasy with the current design; otherwise I like this API. But extracting calendar stuff would require rethinking a couple of things, I'm not too sure if it's worth it.

For instance, you say "any types which deal with durations would have to know about CalendarDuration", but you can generally fix that by making the duration responsible for the appropriate convertions. For instance, adding a duration to a timestamp could involve calling a function "duration.hnsecDurationFrom(timestamp)" to convert the duration in hnseconds. HNSecDuration would simply return itself while CalendarDuration would do the conversion based on the given timestamp. And the day someone wants to implement JapaneseCalendarDuration (or any other kind of duration), he'll just have to implement this function on his duration type.

I'm wondering if this can be implemented without too much code.

-- 
Michel Fortin
michel.fortin at michelf.com
http://michelf.com/



October 11, 2010
On Monday 11 October 2010 19:46:15 Michel Fortin wrote:
> Le 2010-10-11 ? 13:19, Jonathan M Davis a ?crit :
> > On Sunday, October 10, 2010 09:20:31 Michel Fortin wrote:
> >> Another option I might propose is to get rid of MonthDuration by using JointDuration instead and rename it to CalendarDuration.
> >> 
> >> But in my opinion, calendar things like this should simply belong to a separate module. This would simplify the API for those who don't need to deal with the complexities of the calendar.
> > 
> > That's not an entirely bad idea, but since any types which deal with durations would have to know about CalendarDuration, it wouldn't really help much. And while I completely agree that we want to make the more advanced features not get in the average users way, most of the calendar stuff is built into the types themselves, so you can't really create a calendar module to hold it.
> 
> I'm aware that my suggestion doesn't fit very well the structure of your code. Personally, that the calendar stuff is built into the type themselves is what makes me a little uneasy with the current design; otherwise I like this API. But extracting calendar stuff would require rethinking a couple of things, I'm not too sure if it's worth it.
> 
> For instance, you say "any types which deal with durations would have to know about CalendarDuration", but you can generally fix that by making the duration responsible for the appropriate convertions. For instance, adding a duration to a timestamp could involve calling a function "duration.hnsecDurationFrom(timestamp)" to convert the duration in hnseconds. HNSecDuration would simply return itself while CalendarDuration would do the conversion based on the given timestamp. And the day someone wants to implement JapaneseCalendarDuration (or any other kind of duration), he'll just have to implement this function on his duration type.
> 
> I'm wondering if this can be implemented without too much code.

Once you deal with any kind of date, you have to deal with a calendar, since all dates are specific to a calendar. Something as simple as having 12 months in a year is completely specific to a certain set of calendars. Sure, there's some leeway there since some calendars use very similar date types (like the Julian and Gregorian calendars), but once you deal with dates, you're pretty much committing yourself to a particular calendar. Code can obviously be written to convert between calendars, but I really don't think that it makes much sense to try and have a date type which is calendar agnostic. And since the vast majority of the planet uses the Gregorian Calendar, I really don't see much value in worrying about other calendars. I definitely think that trying to make a date type work with multiple calendars is going to needlessly complicate code for 99.99% of programmers out there for the .01% who might maybe care. Date, DateTime, and SysTime all provide enough information to convert them to be able to convert them to another calendar type if someone wrote it.

I know that there are date/time/calendar libraries which try and be calendar agnostic, but I've never even heard of a program that used anything other than the Gregorian Calendar (though there are bound to be at least a few out there somewhere). Java's API, for instance, theoretically supports multiple calendars, but they've only ever implemented the Gregorian Calendar. Boost tried to make their code calendar agnostic,but I think that it's a lot harder to understand and far more fragmented becausje of it. And I don't think that they even have a non-Gregorian implementation either.

So, I can understand wanting to make a date/time library calendar agnostic, but I really don't think that it's worth the cost.

- Jonathan M Davis
October 12, 2010
Le 2010-10-11 ? 23:12, Jonathan M Davis a ?crit :

> On Monday 11 October 2010 19:46:15 Michel Fortin wrote:
>> Le 2010-10-11 ? 13:19, Jonathan M Davis a ?crit :
>>> On Sunday, October 10, 2010 09:20:31 Michel Fortin wrote:
>>>> Another option I might propose is to get rid of MonthDuration by using JointDuration instead and rename it to CalendarDuration.
>>>> 
>>>> But in my opinion, calendar things like this should simply belong to a separate module. This would simplify the API for those who don't need to deal with the complexities of the calendar.
>>> 
>>> That's not an entirely bad idea, but since any types which deal with durations would have to know about CalendarDuration, it wouldn't really help much. And while I completely agree that we want to make the more advanced features not get in the average users way, most of the calendar stuff is built into the types themselves, so you can't really create a calendar module to hold it.
>> 
>> I'm aware that my suggestion doesn't fit very well the structure of your code. Personally, that the calendar stuff is built into the type themselves is what makes me a little uneasy with the current design; otherwise I like this API. But extracting calendar stuff would require rethinking a couple of things, I'm not too sure if it's worth it.
>> 
>> For instance, you say "any types which deal with durations would have to know about CalendarDuration", but you can generally fix that by making the duration responsible for the appropriate convertions. For instance, adding a duration to a timestamp could involve calling a function "duration.hnsecDurationFrom(timestamp)" to convert the duration in hnseconds. HNSecDuration would simply return itself while CalendarDuration would do the conversion based on the given timestamp. And the day someone wants to implement JapaneseCalendarDuration (or any other kind of duration), he'll just have to implement this function on his duration type.
>> 
>> I'm wondering if this can be implemented without too much code.
> 
> Once you deal with any kind of date, you have to deal with a calendar, since all dates are specific to a calendar.

I disagree.

A date can be expressed using different calendars, but can also be stored as an interval since a reference date (like the UNIX epoch). With your main storage format calendar-agnostic you can easily convert back and forth to different calendars-specific formats.

Also, if you're dealing only with time -- like calculating the time elapsed between two time points -- then you don't need any calendar unless you plan to display that elapsed time in months or years.

And of course I never meant that Phobos should provide more calendars than gregorian. That said, it'd be good if it its gregorian implementation could be used as a base to implement other calendars.

-- 
Michel Fortin
michel.fortin at michelf.com
http://michelf.com/



October 12, 2010
On 10/12/2010 08:26 AM, Michel Fortin wrote:
> A date can be expressed using different calendars, but can also be stored as an interval since a reference date (like the UNIX epoch). With your main storage format calendar-agnostic you can easily convert back and forth to different calendars-specific formats.

Interesting point. I wonder what Boost does.

> Also, if you're dealing only with time -- like calculating the time elapsed between two time points -- then you don't need any calendar unless you plan to display that elapsed time in months or years.
>
> And of course I never meant that Phobos should provide more calendars than gregorian. That said, it'd be good if it its gregorian implementation could be used as a base to implement other calendars.

Speaking of all this, Jonathan, what's your plan right now? There's been some points raised here and there by people, you replied "this is a good suggestion but there are cons as well", so I'm not sure whether you plan to keep the submission as is or operate changes to it. In the latter case, I'm unclear on what changes you have decided to make.

One other thing - it might be useful to take this entire review process to digitalmars.D. Is everyone comfortable with that?


Andrei
October 12, 2010
On 10/11/10 22:12 CDT, Jonathan M Davis wrote:
> So, I can understand wanting to make a date/time library calendar agnostic, but I really don't think that it's worth the cost.

FWIW that's also what the Jeff Garland (the author of Boost's date/time library) told me.

Andrei
October 12, 2010
On Tuesday, October 12, 2010 07:21:07 Andrei Alexandrescu wrote:
> Speaking of all this, Jonathan, what's your plan right now? There's been some points raised here and there by people, you replied "this is a good suggestion but there are cons as well", so I'm not sure whether you plan to keep the submission as is or operate changes to it. In the latter case, I'm unclear on what changes you have decided to make.
> 
> One other thing - it might be useful to take this entire review process to digitalmars.D. Is everyone comfortable with that?

I have been making various of the suggested changes, and I hope to have an updated version with most or all of them by this weekend at the latest, but I'm not at home at the moment with the updated code, so I can't say for sure what all the changes are that I've made or am making, though I'll give a list when I post the new code.

I did decide to make changes to reduce the durations to just Duration (which is basically HNSecDuration) and TickDuration and have removed most of the addXXX() functions. I'm not entirely happy with result since dealing with years and months is definitely more awkward in some cases, but I think that the places where it's a problem are relatively limited and that it's likely going to be easier for the average programmer.

I'm currently working on converting TUnit over to use strings as you suggested, and assuming that nothing particularly wrong with that pops up, I'll be going with that. Certainly, having to type stuff like TUnit.day seems pretty ugly, though I did manage to limite the number of places where TUnit needed to be used directly by the users of datetime.

I think that I'm applying most of your suggestions (and possibly some of the suggestions of others), but again, I'd have to look at what I've got at home to remember exactly what changes I've made thus far. I have no problem with taking the review process to digitalmars.D, particularly since there never seems to be many people beyond the Phobos devs themselves who post much on the Phobos list. So, I'll post it there as soon as it's ready.

- Jonathan M Davis
October 12, 2010
On Tuesday, October 12, 2010 06:26:16 Michel Fortin wrote:
> I disagree.
> 
> A date can be expressed using different calendars, but can also be stored as an interval since a reference date (like the UNIX epoch). With your main storage format calendar-agnostic you can easily convert back and forth to different calendars-specific formats.

Except that most of the logic is going to be calendar-specific such that you really don't gain much by trying to separate out the calendar-specific logic. Date, DateTime, and SysTime all have a property to give you the Xth day since the beginning of the Proleptic Gregorian Calendar (dayOfGregorianCal IIRC), and SysTime has the stdTime property which gives you its internal representation of hecto-nanoseconds (100 ns) since midnight January 1st, 1 AD UTC, so all of the information necessary to convert to other calendar systems is there. But since most of the operations on Date, DateTime, and SysTime are specific to the Gregorian Calendar, I don't see much - if any - gain in trying to refactor out the non-calendar-specific stuff.

If I do anything to make it easier to handle other calendars, it should be to make sure that the duration, interval, and range code is fairly calendar agnostic. And for the most part, I think that it is. Having removed MonthDuration and JointDuration, it's even more so.

> Also, if you're dealing only with time -- like calculating the time elapsed between two time points -- then you don't need any calendar unless you plan to display that elapsed time in months or years.
> 
> And of course I never meant that Phobos should provide more calendars than gregorian. That said, it'd be good if it its gregorian implementation could be used as a base to implement other calendars.

Well, if the duration, interval, and range stuff is reasonably calendar agnostic, then the portions that are really of much use to someone wanting to use datetime with their own, non-Gregorian Calendar code would be useable with that code. But I don't think that it makes much sense to try and make the time point types calendar agnostic. The only one that is is TimeOfDay, since it doesn't deal with dates at all, and that's quite re-usable in other calendar code.

- Jonathan M Davis