Jump to page: 1 24  
Page
Thread overview
I made std.time for Phobos, please review my code.
Apr 27, 2010
SHOO
Apr 27, 2010
Bernard Helyer
Apr 27, 2010
SHOO
Apr 27, 2010
Michel Fortin
Apr 27, 2010
Bernard Helyer
Apr 27, 2010
Michel Fortin
Apr 27, 2010
SHOO
Apr 28, 2010
Sean Kelly
Apr 27, 2010
bearophile
Apr 27, 2010
Adam D. Ruppe
Apr 27, 2010
Michel Fortin
Apr 27, 2010
bearophile
Apr 27, 2010
Adam D. Ruppe
Apr 27, 2010
bearophile
Apr 27, 2010
SHOO
Apr 27, 2010
SHOO
Apr 28, 2010
Bernard Helyer
Apr 27, 2010
SHOO
Apr 28, 2010
SHOO
Apr 30, 2010
Nick Sabalausky
I rewrite std.time for Phobos
May 13, 2010
SHOO
May 13, 2010
Bill Baxter
May 14, 2010
SHOO
May 13, 2010
Walter Bright
May 14, 2010
SHOO
May 15, 2010
retard
May 14, 2010
SHOO
April 27, 2010
I make std.time module for Phobos. This module provides Time, Span,
Clock, StopWatch and some utility functions for time operation.
I hope combine this module to Phobos instead of std.date.

download is here:
	http://j.mp/95aS1K (== http://dusers.dip.jp/ ... /time.d)
	http://j.mp/9p5DDu (patch for Phobos's trunk r1481)
	http://ideone.com/eiQ19 (for code view)

Besides, is there the necessary function? (This module lacks the daylight saving time handling, because of a lack of my understanding.)


I talk about the process that reached making...

Tango is great library for D1. I am Tango user and I am indebted to Tango well. But Tango has some probrems.

- Tango's license is BSD lisence or AFL. This license is incompatible to
Phobos's Boost license.
- The specification is disregarded, for example Object.dispose and string.
- Tango supports only D1
- In particular, deep regret is to have split resources of D into two
halves.

If possible, I want to migrate to D2. And I want to be separated from
Tango. However, some functions are insufficient for Phobos compared with
Tango.
The std.date module is one of the list of dissatisfaction to Phobos.
I summarize my (and some of Japanese users's) opinion following:

- I want to handle it as another thing for the time and the time span.
- I want a more structural class for time operating.
- std.date is a bit buggy...

By these reasons, I made std.time module as the first step of the contribution for Phobos.
April 27, 2010
On 27/04/10 20:55, SHOO wrote:
> std.date is a bit buggy...

Yeah, like a loaded gun is a bit dangerous.  :D

I will download and try, after all the issues I had with std.date. Although, I think that handling DST is pretty vital (but very confusing).
April 27, 2010
Bernard Helyer さんは書きました:
> On 27/04/10 20:55, SHOO wrote:
>> std.date is a bit buggy...
> 
> Yeah, like a loaded gun is a bit dangerous.  :D
> 
> I will download and try, after all the issues I had with std.date. Although, I think that handling DST is pretty vital (but very confusing).

Thanks to your response.

I think that handling DST is necessary too.
But I am unfamiliar about DST so that people of the Ascii character
string zone are unfamiliar about multi-byte character string.
(I live in Japan which does not use DST.)
I may not exactly recognize bugs even if I implemented it.
I want to leave the implementation to other people who knows DST well.
April 27, 2010
module test;

import std.stdio;
static import std.date;

import time;


void main()
{
    auto ttime = localtime();
    auto dtime = std.date.getUTCtime();
    dtime = std.date.UTCtoLocalTime(dtime);

    writeln(ttime);
    writeln(std.date.toString(dtime));
}

[tmp]$ ./test
2010-04-28 00:14:15,016  # CORRECT  n_n
Tue Apr 27 12:14:15 GMT+0000 2010   # BZZZT, Thanks for playing.




Looking good so far.   :]




April 27, 2010
On 2010-04-27 04:55:28 -0400, SHOO <zan77137@nifty.com> said:

> By these reasons, I made std.time module as the first step of the
> contribution for Phobos.

Looks nice. I think defining structs as you did to handle date and time is the way to go.

I've done something similar in the past to store dates and times which I like a lot. What I did was just a storage format, but templates allowed me to store dates and time spans with any precision while exposing always the same public API.

I'm pasting my code below in case it can inspire you (note that this code predates the new operator overloading syntax), and feel free to use any of this under the Boost license if applicable.


import std.date : d_time, ticksPerMs;


template isDateTime(T) {
	enum bool isDateTime = __traits(compiles, T.tick);
}

template isTimeSpan(T) {
	enum bool isTimeSpan = __traits(compiles, T.ticks);
}

enum Unit {
	// Need to be from higher precision to lower precision
	tick = 1,
	millisecond = ticksPerMs,
	second = 1000 * millisecond,
	minute = 60 * second,
	hour = 60 * minute,
	day = 24 * hour,
}

private Unit smaller(Unit a, Unit b) {
	return a < b ? a : b;
}

struct TimeSpan(T = d_time, Unit _unit = Unit.ticks) {
	// Milliseconds since 1970-01-01 00:00:00.0 UTC
	private T units = 0;
	enum Unit unit = _unit;
	
	void opAssign(T)(const T other) if (is(typeof(other.unit) == Unit) && smaller(unit, other.unit) == unit) {
		units = other.units * (other.unit / unit);
	}
	
	bool opEquals(ref const TimeSpan value) const {
		return units == value.units;
	}
//	bool opEquals(const TimeSpan value) const {
//		return units == value.units;
//	}
	
	TimeSpan opNeg() const {
		TimeSpan t;
		t.units = -units;
		return t;
	}
	
	void opAddAssign(T)(const T other) if (is(typeof(other.unit) == Unit) && smaller(unit, other.unit) == unit) {
		units += other.units * (other.unit / unit);
	}
	auto opAdd(T)(const T other) const {
		TimeSpan!(typeof(units + other.units), smaller(unit, other.unit)) t;
		t = this;
		t += other;
		return t;
	}
	
	void opSubAssign(T)(const T other) if (is(typeof(other.unit) == Unit) && smaller(unit, other.unit) == unit) {
		units -= other.units * (other.unit / unit);
	}
	auto opSub(T)(const T other) const {
		TimeSpan!(typeof(units - other.units), smaller(unit, other.unit)) t;
		t = this;
		t -= other;
		return t;
	}
	
	void opMulAssign(const T value) {
		units *= value;
	}
	TimeSpan opMul(const T value) const {
		TimeSpan t = this;
		t *= value;
		return t;
	}
	
	void opDivAssign(const T value) {
		units /= value;
	}
	TimeSpan opDiv(const T value) const {
		TimeSpan t = this;
		t /= value;
		return t;
	}
	
	@property:
	T ticks() {
		static if (unit == Unit.tick)
			return units;
		else static if (unit < Unit.tick)
			static assert(0);
		else static if (unit > Unit.tick)
			return cast(T)(milliseconds * ticksPerMs);
	}
	static if (unit == Unit.tick) {
		void ticks(T value) {
			static if (unit == Unit.tick)
				units = value;
			else static if (unit < Unit.tick)
				static assert(0);
			else static if (unit > Unit.tick)
				milliseconds = value / ticksPerMs;
		}
	}
	
	T milliseconds() {
		static if (unit == Unit.millisecond)
			return units;
		else static if (unit < Unit.millisecond)
			return cast(T)(ticks / ticksPerMs);
		else static if (unit > Unit.millisecond)
			return cast(T)(seconds * 1000);
	}
	static if (unit <= Unit.millisecond) {
		void milliseconds(T value) {
			static if (unit == Unit.millisecond)
				units = value;
			else static if (unit < Unit.millisecond)
				ticks = value * ticksPerMs;
			else static if (unit > Unit.millisecond)
				seconds = value / 1000;
		}
	}
	
	T seconds() {
		static if (unit == Unit.second)
			return units;
		else static if (unit < Unit.second)
			return cast(T)(milliseconds / 1000);
		else static if (unit > Unit.second)
			return cast(T)(minutes * 60);
	}
	static if (unit <= Unit.second) {
		void seconds(T value) {
			static if (unit == Unit.second)
				units = value;
			else static if (unit < Unit.second)
				milliseconds = value * 1000;
			else static if (unit > Unit.second)
				minutes = value / 60;
		}
	}
	
	T minutes() {
		static if (unit == Unit.minute)
			return units;
		else static if (unit < Unit.minute)
			return cast(T)(seconds / 60);
		else static if (unit > Unit.minute)
			return cast(T)(hours * 60);
	}
	static if (unit <= Unit.minute) {
		void minutes(T value) {
			static if (unit == Unit.minute)
				units = value;
			else static if (unit < Unit.minute)
				seconds = value * 60;
			else static if (unit > Unit.minute)
				hours = value / 60;
		}
	}
	
	T hours() {
		static if (unit == Unit.hour)
			return units;
		else static if (unit < Unit.hour)
			return cast(T)(minutes / 60);
		else static if (unit > Unit.hour)
			return cast(T)(days * 24);
	}
	static if (unit <= Unit.hour) {
		void hours(T value) {
			static if (unit == Unit.hour)
				units = value;
			else static if (unit < Unit.hour)
				minutes = cast(T)(value * 60);
			else static if (unit > Unit.hour)
				days = cast(T)(value / 24);
		}
	}
	
	T days() {
		static if (unit == Unit.day)
			return units;
		else static if (unit < Unit.day)
			return cast(T)(hours / 24);
		else static if (unit > Unit.day)
			static assert(0);
	}
	static if (unit <= Unit.day) {
		void days(T value) {
			static if (unit == Unit.day)
				units = value;
			else static if (unit < Unit.day)
				hours = cast(T)(value * 24);
			else static if (unit > Unit.day)
				static assert(0);
		}
	}
}


TimeSpan!(T, Unit.millisecond) milliseconds(T)(T count) {
	TimeSpan!(T, Unit.millisecond) t;
	t.milliseconds = count;
	return t;
}
TimeSpan!(T, Unit.second) seconds(T)(T count) {
	TimeSpan!(T, Unit.second) t;
	t.seconds = count;
	return t;
}
TimeSpan!(T, Unit.minute) minutes(T)(T count) {
	TimeSpan!(T, Unit.minute) t;
	t.minutes = count;
	return t;
}
TimeSpan!(T, Unit.hour) hours(T)(T count) {
	TimeSpan!(T, Unit.hour) t;
	t.hours = count;
	return t;
}
TimeSpan!(T, Unit.day) days(T)(T count) {
	TimeSpan!(T, Unit.day) t;
	t.days = count;
	return t;
}

unittest {
//	assert(seconds(10) + minutes(1) == seconds(70));
	
	auto t = seconds(70);
	assert(seconds(10) + minutes(1) == t);
	assert(minutes(1) + seconds(10) == t);
	
	auto t2 = seconds(50);
	assert(minutes(1) - seconds(10) == t2);
}


struct UtcDateTime(T = d_time, Unit unit = Unit.tick) {
	// Time span since epoch
	TimeSpan!(T, unit) span;
	
	// The length in each unit since epoch.
	alias span.ticks ticks;
	alias span.milliseconds milliseconds;
	alias span.seconds seconds;
	alias span.minutes minutes;
	alias span.hours hours;
	alias span.days days;
	
	// The truncated value for each unit (seconds can never exceed 60)
	T millisecond() { return span.milliseconds % 1000; }
	T second() { return span.seconds % 60; }
	T minute() { return span.minutes % 60; }
	T hour() { return span.hours % 24; }
	T day() { return span.days; }
	
	// UTC Offset, always zero.
	enum offset = TimeSpan!(short, Unit.minute)();
}

struct DateTime(T = d_time, Unit unit = Unit.tick) {
	// Time span since epoch
	TimeSpan!(T, unit) span;
	
	// The length in each unit since epoch.
	alias span.ticks ticks;
	alias span.milliseconds milliseconds;
	alias span.seconds seconds;
	alias span.minutes minutes;
	alias span.hours hours;
	alias span.days days;
	
	// The truncated value for each unit (seconds can never exceed 60)
	T millisecond() { return span.milliseconds % 1000; }
	T second() { return span.seconds % 60; }
	T minute() { return span.minutes % 60; }
	T hour() { return span.hours % 24; }
	T day() { return span.days; }
	
	// UTC Offset
	TimeSpan!(short, Unit.minute) offset;
}

alias UtcDateTime!(int, Unit.tick) UtcTime;
alias DateTime!(int, Unit.tick) Time;

alias UtcDateTime!(int, Unit.day) UtcDate;
alias DateTime!(int, Unit.day) Date;

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

April 27, 2010
On 2010-04-27 07:22:12 -0400, SHOO <zan77137@nifty.com> said:

> Thanks to your response.
> 
> I think that handling DST is necessary too.
> But I am unfamiliar about DST so that people of the Ascii character
> string zone are unfamiliar about multi-byte character string.
> (I live in Japan which does not use DST.)
> I may not exactly recognize bugs even if I implemented it.
> I want to leave the implementation to other people who knows DST well.

The problem with DST (and time zones in general) is that it's subject to change. DST dates were changed a couple of years ago here in Canada and in the United States; operating system vendors made a patch for this and things went smoothy (for the most part) for applications using the OS to know about DST. This can get more complicated though: for Israel (post 2005) you'll need to follow the hebrew calendar[1], and before 2005 it's mostly arbitrary.

I think timezones and DST management are better left to the OS. What is most important to have is a way to convert local dates and times to UTC and the reverse, and to determine the local UTC offset for a given time. I'd leave the rest to other libraries, or OS-specific APIs.

[1]: http://en.wikipedia.org/wiki/Israel_Summer_Time

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

April 27, 2010
On Tue, 27 Apr 2010 04:55:28 -0400, SHOO <zan77137@nifty.com> wrote:

> Tango is great library for D1. I am Tango user and I am indebted to
> Tango well. But Tango has some probrems.
>
> - Tango's license is BSD lisence or AFL. This license is incompatible to
> Phobos's Boost license.
> - The specification is disregarded, for example Object.dispose and string.
> - Tango supports only D1
> - In particular, deep regret is to have split resources of D into two
> halves.
>
> If possible, I want to migrate to D2. And I want to be separated from
> Tango. However, some functions are insufficient for Phobos compared with
> Tango.
> The std.date module is one of the list of dissatisfaction to Phobos.
> I summarize my (and some of Japanese users's) opinion following:
>
> - I want to handle it as another thing for the time and the time span.
> - I want a more structural class for time operating.
> - std.date is a bit buggy...
>
> By these reasons, I made std.time module as the first step of the
> contribution for Phobos.

I like what you've done.  It's very similar to what was done in Tango.  I hate to ask this, but I just want to verify that you did not base your code on Tango, especially since you have used Tango.  I was planning to implement a Time system for Tango that mimics Tango's design, if that is what you have done, I think that's perfectly legit.  Basically, I want to verify that you rewrote all your implementation from scratch.

More comments:

I'd like accessors for seconds/milliseconds/etc from Span.

I'm not sure I like the Clocks structure.  Why have a separate Span that is in terms of some arbitrary OS resolution?  Can you give an example of why I'd want to use Clocks instead of Span?

-Steve
April 27, 2010
On Tue, 27 Apr 2010 10:50:34 -0400, Steven Schveighoffer <schveiguy@yahoo.com> wrote:

> I was planning to implement a Time system for Tango that mimics Tango's design

I meant implement a Time system for *Phobos* that mimics Tango's design.

Duh, me need more brain.

-Steve
April 27, 2010
Steven Schveighoffer:
> I like what you've done.  It's very similar to what was done in Tango.  I hate to ask this, but I just want to verify that you did not base your code on Tango, especially since you have used Tango.

In D2 the runtime of Phobos and Tango have being merged, so all D programmers can install both libs. So the two libs must have distinct contents.
So I'm for removing the time module from Phobos, and keep only the Tango one. So this module is waste of time, and efforts have to be redirected in improving or rewriting the time module of Tango.
Othrwise in D2 it will happen the same mess it's happend in D1, where you have two partially duplicated libs. All D2 programmers will want to install both libs, and they will not desire to choose what time lib to use. One time lit is enough.

Bye,
bearophile
April 27, 2010
On Tue, Apr 27, 2010 at 10:58:33AM -0400, bearophile wrote:
> So I'm for removing the time module from Phobos, and keep only the Tango one. So this module is waste of time, and efforts have to be redirected in improving or rewriting the time module of Tango.

Tango is unacceptable for use for a lot of us, due to the license. The more in Phobos, licensed that way, the better. That's the stuff everybody can use.

-- 
Adam D. Ruppe
http://arsdnet.net
« First   ‹ Prev
1 2 3 4