Thread overview
SysTime in a Struct
Mar 01, 2012
albatroz
Mar 01, 2012
Ali Çehreli
Mar 01, 2012
albatroz
Mar 01, 2012
Ali Çehreli
Mar 01, 2012
albatroz
Mar 02, 2012
Ali Çehreli
Mar 02, 2012
Jonathan M Davis
Mar 06, 2012
albatroz
Mar 01, 2012
Jonathan M Davis
March 01, 2012
Hi,

I have defined this struct
struct preEv {
    string edate; //010112
    string etime; //00:00:00
    string etext; //
    SysTime esystime;
    this (this) {
      SysTime esystime = SysTime(DateTime(
          Clock.currTime.year,
          to!int(this.edate[2..4]),
          to!int(this.edate[0..2]),
          to!int(etime[0..2]),
          to!int(etime[3..5]),
          to!int(etime[6..8])));
    }
}

If I write to the sctruct and then print it I'm able to see the
SysTime variable with a value.
writeln(preEv) //previousEvents("140212", "05:13:26", "9 140212
05:13:26 d", "2012-Feb-14 05:13:26")

but if trying to get the value from the SysTime variable I get a
Segmentation fault. Trying to read any other variable inside this
struct will not be a problem.

writeln (preEv.esystime.day) // will compile but segfaults

On DMD32 D Compiler v2.058

Any correct way to do this?

Thank you.
March 01, 2012
On 03/01/2012 06:15 AM, albatroz wrote:
> Hi,
>
> I have defined this struct
> struct preEv {
> string edate; //010112
> string etime; //00:00:00
> string etext; //
> SysTime esystime;

That is a member of this type.

> this (this) {
> SysTime esystime = SysTime(DateTime(

That is a separate local variable within this(this). Also, this(this) is the postblit (similar to a copy constructor). Is that what you want to define?

I think you want to simply do this anyway:

   esystime =

or this:

   this.esystime =

> Clock.currTime.year,
> to!int(this.edate[2..4]),
> to!int(this.edate[0..2]),
> to!int(etime[0..2]),
> to!int(etime[3..5]),
> to!int(etime[6..8])));
> }
> }
>
> If I write to the sctruct and then print it I'm able to see the
> SysTime variable with a value.
> writeln(preEv) //previousEvents("140212", "05:13:26", "9 140212
> 05:13:26 d", "2012-Feb-14 05:13:26")
>
> but if trying to get the value from the SysTime variable I get a
> Segmentation fault.

Probably because esystime member is no initialized.

> Trying to read any other variable inside this
> struct will not be a problem.
>
> writeln (preEv.esystime.day) // will compile but segfaults
>
> On DMD32 D Compiler v2.058
>
> Any correct way to do this?
>
> Thank you.

Ali

March 01, 2012
Have fixed the segfault by using DateTime instead of SysTime.
>
> That is a separate local variable within this(this). Also, this(this) is the postblit (similar to a copy constructor). Is that what you want to define?

No, but not using this(this) will fail to build with:
static variable _initialized cannot be read at compile time

Making the struct similar to what you suggest will work.
struct prevEv {
  string edate;
  string etime;
  string etext;
  DateTime edatetime;
  this (this)
  {
    edatetime = DateTime(
      Clock.currTime.year,
      to!int(this.edate[2..4]),
      to!int(this.edate[0..2]),
      to!int(etime[0..2]),
      to!int(etime[3..5]),
      to!int(etime[6..8]));
    }
}

Just not has expected, do you have any suggestion how to do it properly?

writeln ( prevEv.edatetime ); //0001-Jan-01 00:00:00
writeln ( prevEv ); // preEv("140212", "05:13:26", "9 140212 05:13:26 d", 2012-Feb-14 05:13:26)

>
>
> Ali
Thanks

March 01, 2012
On 03/01/2012 09:14 AM, albatroz wrote:
> Have fixed the segfault by using DateTime instead of SysTime.
>>
>> That is a separate local variable within this(this). Also, this(this)
>> is the postblit (similar to a copy constructor). Is that what you want
>> to define?
>
> No, but not using this(this) will fail to build with:
> static variable _initialized cannot be read at compile time

So you are trying to initialize the member with a default initializer, like this:

struct prevEv {
// ...
  DateTime edatetime = DateTime(/* ... */);
}

For that to work, the initial value must be a compile-time value. I am not sure that you want that.

Also, this(this) is needed in very rare cases. Are you trying to create objects of prevEv? Then you should use this(). Unfortunately, structs cannot have default constructors.

A solution might be to use a function that makes and returns a prevEv:

prevEv make_prevEv()
{
    return prevEv(/* ... */, DateTime(/* ... */));
}

> Making the struct similar to what you suggest will work.
> struct prevEv {
> string edate;
> string etime;
> string etext;
> DateTime edatetime;
> this (this)
> {
> edatetime = DateTime(
> Clock.currTime.year,
> to!int(this.edate[2..4]),
> to!int(this.edate[0..2]),
> to!int(etime[0..2]),
> to!int(etime[3..5]),
> to!int(etime[6..8]));
> }
> }
>
> Just not has expected, do you have any suggestion how to do it properly?

Are you trying to record the time when a prevEv is copied from another one? If not, I suggest not defining this(this). It is the postblit, to make things right for rare structs and only when the compiler generated copying is wrong for a that type.

Or, are you just trying to define a type that contains time information?

>
> writeln ( prevEv.edatetime ); //0001-Jan-01 00:00:00
> writeln ( prevEv ); // preEv("140212", "05:13:26", "9 140212 05:13:26
> d", 2012-Feb-14 05:13:26)
>
>>
>>
>> Ali
> Thanks
>

Ali

March 01, 2012
On Thursday, March 01, 2012 15:15:00 albatroz wrote:
> Hi,
> 
> I have defined this struct
> struct preEv {
> string edate; //010112
> string etime; //00:00:00
> string etext; //
> SysTime esystime;
> this (this) {
> SysTime esystime = SysTime(DateTime(
> Clock.currTime.year,
> to!int(this.edate[2..4]),
> to!int(this.edate[0..2]),
> to!int(etime[0..2]),
> to!int(etime[3..5]),
> to!int(etime[6..8])));
> }
> }
> 
> If I write to the sctruct and then print it I'm able to see the
> SysTime variable with a value.
> writeln(preEv) //previousEvents("140212", "05:13:26", "9 140212
> 05:13:26 d", "2012-Feb-14 05:13:26")
> 
> but if trying to get the value from the SysTime variable I get a Segmentation fault. Trying to read any other variable inside this struct will not be a problem.
> 
> writeln (preEv.esystime.day) // will compile but segfaults
> 
> On DMD32 D Compiler v2.058
> 
> Any correct way to do this?

A default-initialized SysTime is useless. It hasn't been properly initialized. SysTime contains a time zone object, which is a class and must be initialized at runtime (so directly initializing it won't work), and that object is null in SysTime.init (and it can't be anything else, because you can't construct a class at compile and have it persist to runtime). You need to actually initialize a SysTime before using it. So, using the init value of struct which has a SysTime as a member probably isn't a great idea.

- Jonathan M Davis
March 01, 2012
> Are you trying to record the time when a prevEv is copied from another one? If not, I suggest not defining this(this). It is the postblit, to make things right for rare structs and only when the compiler generated copying is wrong for a that type.
>
> Or, are you just trying to define a type that contains time information?

Hi Ali, just tring to define a type that holds this information. It was just an attempt to create a type DateTime with the values from the known strings, I thought it was possible to create the definition directly in the Struct, with no need for an external function.
edate and etime are strings that I will read in to the struct, but for operations with time and dates I need to create/define a DateTime type.

Thanks


March 02, 2012
On 03/01/2012 03:46 PM, albatroz wrote:

> Hi Ali, just tring to define a type that holds this information. It was
> just an attempt to create a type DateTime with the values from the known
> strings, I thought it was possible to create the definition directly in
> the Struct, with no need for an external function.
> edate and etime are strings that I will read in to the struct, but for
> operations with time and dates I need to create/define a DateTime type.

From that description, it looks like you can hold edate etc. as members and produce SysTime as needed. The following demonstrates how to convert preEv to SysTime by opCast implicitly and by sys_time explicitly:

import std.stdio;
import std.conv;
import std.datetime;

struct preEv
{
    string edate; //010112
    string etime; //00:00:00
    string etext; //

    SysTime opCast(T : SysTime)() const
    {
        return SysTime(DateTime(
                           Clock.currTime.year,
                           to!int(this.edate[2..4]),
                           to!int(this.edate[0..2]),
                           to!int(etime[0..2]),
                           to!int(etime[3..5]),
                           to!int(etime[6..8])));
    }

    SysTime sys_time() const @property
    {
        return to!SysTime(this);
    }
}

void main()
{
    auto pe = preEv("010312", "15:53:00", "The event");

    // Explicit conversion
    auto st0 = to!SysTime(pe);
    writeln(st0);

    // Casting
    auto st1 = cast(SysTime)(pe);
    writeln(st1);

    // As a property
    auto st2 = pe.sys_time;
    writeln(st2);
}

If you think that you need to cache SysTime in the object itself, you can do that for example in opCast.

On the other hand, if all you need to store is SysTime and etext, then you need to create SysTime in the constructor:

import std.stdio;
import std.conv;
import std.datetime;

struct preEv
{
    SysTime time;
    string etext;

    this (string edate, string etime, string etext)
    {
        this.time = SysTime(DateTime(
                                Clock.currTime.year,
                                to!int(edate[2..4]),
                                to!int(edate[0..2]),
                                to!int(etime[0..2]),
                                to!int(etime[3..5]),
                                to!int(etime[6..8])));
        this.etext = etext;
    }
}

void main()
{
    auto pe = preEv("010312", "15:53:00", "The event");

    writeln(pe.time);
}

Ali

March 02, 2012
On Thursday, March 01, 2012 16:00:09 Ali Çehreli wrote:
> On 03/01/2012 03:46 PM, albatroz wrote:
> > Hi Ali, just tring to define a type that holds this information. It was
> > just an attempt to create a type DateTime with the values from the known
> > strings, I thought it was possible to create the definition directly in
> > the Struct, with no need for an external function.
> > edate and etime are strings that I will read in to the struct, but for
> > operations with time and dates I need to create/define a DateTime type.
> 
> From that description, it looks like you can hold edate etc. as members and produce SysTime as needed. The following demonstrates how to convert preEv to SysTime by opCast implicitly and by sys_time explicitly:
> 
> import std.stdio;
> import std.conv;
> import std.datetime;
> 
> struct preEv
> {
> string edate; //010112
> string etime; //00:00:00
> string etext; //
> 
> SysTime opCast(T : SysTime)() const
> {
> return SysTime(DateTime(
> Clock.currTime.year,
> to!int(this.edate[2..4]),
> to!int(this.edate[0..2]),
> to!int(etime[0..2]),
> to!int(etime[3..5]),
> to!int(etime[6..8])));
> }
> 
> SysTime sys_time() const @property
> {
> return to!SysTime(this);
> }
> }
> 
> void main()
> {
> auto pe = preEv("010312", "15:53:00", "The event");
> 
> // Explicit conversion
> auto st0 = to!SysTime(pe);
> writeln(st0);
> 
> // Casting
> auto st1 = cast(SysTime)(pe);
> writeln(st1);
> 
> // As a property
> auto st2 = pe.sys_time;
> writeln(st2);
> }
> 
> If you think that you need to cache SysTime in the object itself, you can do that for example in opCast.
> 
> On the other hand, if all you need to store is SysTime and etext, then you need to create SysTime in the constructor:
> 
> import std.stdio;
> import std.conv;
> import std.datetime;
> 
> struct preEv
> {
> SysTime time;
> string etext;
> 
> this (string edate, string etime, string etext)
> {
> this.time = SysTime(DateTime(
> Clock.currTime.year,
> to!int(edate[2..4]),
> to!int(edate[0..2]),
> to!int(etime[0..2]),
> to!int(etime[3..5]),
> to!int(etime[6..8])));
> this.etext = etext;
> }
> }
> 
> void main()
> {
> auto pe = preEv("010312", "15:53:00", "The event");
> 
> writeln(pe.time);
> }


You know, you can create a TimeOfDay from "15:53:00" with TimeOfDay.fromISOExtString. That won't work with the date, since it's not in either the ISO or ISO Extended format, but it would work for the time.

I'd also point out that currTime isn't a property (since it takes an optional TimeZone argument), so you really should be using parens when you call it. Otherwise, once property enforcement is enabled, your code won't compile.

Also, you should use std.conv.to, not a cast, when converting, since std.conv.to now supports calling user-defined opCasts, and there's less risk of screwing up the cast if you use std.conv.to. So, defining an opCast is fine, but it should probably be used with std.conv.to rather than directly.

- Jonathan M Davis
March 06, 2012
Hi Ali,

only today I had the time to implement your suggestion it's working now has expected.

Thank you for your patience, also thank you for the work translating such a good D book to English.


On Friday, 2 March 2012 at 00:00:10 UTC, Ali Çehreli wrote:
> On 03/01/2012 03:46 PM, albatroz wrote:
>
> > Hi Ali, just tring to define a type that holds this
> information. It was
> > just an attempt to create a type DateTime with the values
> from the known
> > strings, I thought it was possible to create the definition
> directly in
> > the Struct, with no need for an external function.
> > edate and etime are strings that I will read in to the
> struct, but for
> > operations with time and dates I need to create/define a
> DateTime type.
>
> From that description, it looks like you can hold edate etc. as members and produce SysTime as needed. The following demonstrates how to convert preEv to SysTime by opCast implicitly and by sys_time explicitly:
>
> import std.stdio;
> import std.conv;
> import std.datetime;
>
> struct preEv
> {
>     string edate; //010112
>     string etime; //00:00:00
>     string etext; //
>
>     SysTime opCast(T : SysTime)() const
>     {
>         return SysTime(DateTime(
>                            Clock.currTime.year,
>                            to!int(this.edate[2..4]),
>                            to!int(this.edate[0..2]),
>                            to!int(etime[0..2]),
>                            to!int(etime[3..5]),
>                            to!int(etime[6..8])));
>     }
>
>     SysTime sys_time() const @property
>     {
>         return to!SysTime(this);
>     }
> }
>
> void main()
> {
>     auto pe = preEv("010312", "15:53:00", "The event");
>
>     // Explicit conversion
>     auto st0 = to!SysTime(pe);
>     writeln(st0);
>
>     // Casting
>     auto st1 = cast(SysTime)(pe);
>     writeln(st1);
>
>     // As a property
>     auto st2 = pe.sys_time;
>     writeln(st2);
> }
>
> If you think that you need to cache SysTime in the object itself, you can do that for example in opCast.
>
> On the other hand, if all you need to store is SysTime and etext, then you need to create SysTime in the constructor:
>
> import std.stdio;
> import std.conv;
> import std.datetime;
>
> struct preEv
> {
>     SysTime time;
>     string etext;
>
>     this (string edate, string etime, string etext)
>     {
>         this.time = SysTime(DateTime(
>                                 Clock.currTime.year,
>                                 to!int(edate[2..4]),
>                                 to!int(edate[0..2]),
>                                 to!int(etime[0..2]),
>                                 to!int(etime[3..5]),
>                                 to!int(etime[6..8])));
>         this.etext = etext;
>     }
> }
>
> void main()
> {
>     auto pe = preEv("010312", "15:53:00", "The event");
>
>     writeln(pe.time);
> }
>
> Ali