Setting system date fields

From ClassDBI

Using SYSDATE

Problem: You want to update a date field with SYSDATE.

Solution: Write some custom SQL.

Details:

You can't currently use SYSDATE directly through CDBI, but it is easy enough to write some custom SQL. Here is an example for an update:

In your CDBI class, add a method like the following:

 __PACKAGE__->set_sql(set_sysdate => qq{
   UPDATE __TABLE__
      SET date_column_name = SYSDATE
    WHERE __IDENTIFIER__
 });

You can then call this method like this:

 $object->sql_set_sysdate()->execute($object->id);
 $object->dbi_commit;

If you need to do something akin to this in many different classes, you could move this up into your main Class::DBI-derived base class, and allow subclasses to specify the column name to be used. Here you would set up the SQL slightly differently:

 __PACKAGE__->set_sql(set_sysdate => qq{
   UPDATE __TABLE__
      SET %s = SYSDATE
    WHERE __IDENTIFIER__
 });

Then, in subclasses, you would need to pass the column name in question to the sql_set_sysdate column:

 $object->sql_set_sysdate("date_column_name")->execute($object->id);

Here is an example that handles a similar situation, but on a create. In this case, you want to override the MakeNewObj SQL statement.

__PACKAGE__->set_sql(MakeNewObj => <<'');
   INSERT INTO __TABLE__ (my_date_column, %s)
   VALUES (SYSDATE, %s)

Now you can call 'create' on a table and leave out 'my_date_column'. It will automatically be populated with SYSDATE on the insert.

my $object = My::Class->create
 ({
   column1 => 'value1'
   column2 => 'value2',
  });

On this create, 'my_date_column' will also be populated.

Note: This doesn't appear to work if my_date_column is part of the primary key in your CDBI class.

Note: in MySQL, you would use the 'CURDATE()' function, of course.

Note: In PostgreSQL, you would use either the NOW() function, or the CURRENT_TIMESTAMP placeholder.

Auto-updating dates in Sybase

Problem: You want to update a date field on every update

Solution: Write a custom update method with some extra sql in it

Details:

For a pseudo-TIMESTAMP column in sybase (ie one that is updated on every write), you can override the update method:

__PACKAGE__->set_sql(update =>
  'UPDATE __TABLE__
  SET    last_updated_dt = getdate(), %s
  WHERE  __IDENTIFIER__'
);

Precision dates in Sybase

Problem: Accessing a DATETIME field is only accurate to minutes

Solution: Define a custom column to access the data using convert()

Details:

To access a datetime to any precision higher than minutes, you need to either set the precision globally, or use the convert() function to give you the desired format. We define a custom Class::DBI::Column to do this for us.

my $precise_updated_dt = Class::DBI::Column->new(
  'convert (char(26), topic_updated_dt, 109)' => {  # the column name is used in the SELECT
    accessor => 'precise',                          # this is what we use to access it
  }
);

Ensure your custom column is in one of the column groups:

__PACKAGE__->columns(
  Others => (
    $topic_precise_updated_dt,
    ...
   )
);

and then you can access it something like this:

$precise_date = $obj->precise;

NOTE: If you are using a custom accessor_name_for() method, you need to manipulate $column->accessor rather than just $column, as $column is a Class::DBI::Column, which stringifies to $column->name rather than $column->accessor.