FAQ
Hi Everybody,

I wonder how you handle user-specific timezones in Catalyst.

Our application is used by customers in various locations, and thus
timezones. I would now like to be able to specify the user's timezone in
his database entry and then show all times to her accordingly.
Most of the time data is stored in the database (also show some
filesystem dates at other places, and there are probably more sources,
but let's concentrate on the database first).
Is there a way to handle this transparently? If I use
inflation/deflation (as does DBIx::Class::DateTime for instance),
I could handle the conversion transparently, however, since the timezone
depends on the user, I cannot define it in the DBIx add_columns()
definition. And manually adjusting the timezone after the data leaves
the Model is probably no good idea either (to easy to forget something
or make a mistake).

Is there any magic switch I could set (for instance if the user is
authorized or the session restored) to automatically get the right time
for the user?

Christian

Search Discussions

  • Devin Austin at Jun 25, 2009 at 6:23 am
    I would store it in whatever user profile set up you have for each user.
    you could simply create a column and add the GMT offset.
    On Thu, Jun 25, 2009 at 12:19 AM, Christian Lackas wrote:

    Hi Everybody,

    I wonder how you handle user-specific timezones in Catalyst.

    Our application is used by customers in various locations, and thus
    timezones. I would now like to be able to specify the user's timezone in
    his database entry and then show all times to her accordingly.
    Most of the time data is stored in the database (also show some
    filesystem dates at other places, and there are probably more sources,
    but let's concentrate on the database first).
    Is there a way to handle this transparently? If I use
    inflation/deflation (as does DBIx::Class::DateTime for instance),
    I could handle the conversion transparently, however, since the timezone
    depends on the user, I cannot define it in the DBIx add_columns()
    definition. And manually adjusting the timezone after the data leaves
    the Model is probably no good idea either (to easy to forget something
    or make a mistake).

    Is there any magic switch I could set (for instance if the user is
    authorized or the session restored) to automatically get the right time
    for the user?

    Christian


    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive:
    http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/


    --
    Devin Austin
    http://www.codedright.net
    http://www.dreamhost.com/r.cgi?326568/hosting.html - Host with DreamHost!
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20090625/4a3419c1/attachment.htm
  • Christian Lackas at Jun 25, 2009 at 7:34 am
    * Devin Austin [090625 08:25]:

    Hi Devin,
    I wonder how you handle user-specific timezones in Catalyst.
    Is there any magic switch I could set (for instance if the user is
    authorized or the session restored) to automatically get the right time
    for the user?
    I would store it in whatever user profile set up you have for each user.
    you could simply create a column and add the GMT offset.
    thanks for your quick reply, and every user entry in the database
    already has a timezone field.
    The low level mechanics are not so much of a problem. However, I don't
    want to do this everywhere I access a date column from the database
    (basically every table has a creation timestamp, many also for deletion
    or last change).
    What I am looking for, is a transparent way to set a timezone for the
    rest of the request (for instance when the session is restored and thus
    Catalyst knows which user it is dealing with) and then inflate/deflate
    should automatically convert timezones from/to UTC automatically.
    My hope was that somebody has already solved this problem or has an idea
    on how to approach it efficiently.

    Christian
  • Devin Austin at Jun 25, 2009 at 7:40 am

    On Thu, Jun 25, 2009 at 1:34 AM, Christian Lackas wrote:

    * Devin Austin [090625 08:25]:

    Hi Devin,
    I wonder how you handle user-specific timezones in Catalyst.
    Is there any magic switch I could set (for instance if the user is
    authorized or the session restored) to automatically get the right time
    for the user?
    I would store it in whatever user profile set up you have for each user.
    you could simply create a column and add the GMT offset.
    thanks for your quick reply, and every user entry in the database
    already has a timezone field.
    The low level mechanics are not so much of a problem. However, I don't
    want to do this everywhere I access a date column from the database
    (basically every table has a creation timestamp, many also for deletion
    or last change).
    What I am looking for, is a transparent way to set a timezone for the
    rest of the request (for instance when the session is restored and thus
    Catalyst knows which user it is dealing with) and then inflate/deflate
    should automatically convert timezones from/to UTC automatically.
    My hope was that somebody has already solved this problem or has an idea
    on how to approach it efficiently.

    Christian

    --
    http://www.invicro.com/

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive:
    http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/
    I have to be honest, I'm not sure I understand. Perhaps I'm missing
    something.

    I would approach it so that when the user registers, they choose their time
    zone. When they login, this information is stored into their session, and
    retrieved whenever. I would store it in the session in the form you want it
    to be presented, which would save you whatever time it would take to be
    inflating it.

    If i'm still misunderstanding, please elaborate and maybe I can poke at it
    some more.

    hth,

    -devin

    --
    Devin Austin
    http://www.codedright.net
    http://www.dreamhost.com/r.cgi?326568/hosting.html - Host with DreamHost!
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20090625/52be2f19/attachment.htm
  • Christian Lackas at Jun 25, 2009 at 7:54 am
    * Devin Austin [090625 09:43]:

    Hi Devin,
    I would approach it so that when the user registers, they choose their time
    zone. When they login, this information is stored into their session, and
    retrieved whenever. agreed.
    I would store it in the session in the form you want it to be
    presented, which would save you whatever time it would take to be
    inflating it.
    Now the problem begins:
    I have tables for studies, series and images (and many more), each of
    them has multiple timestamps (e.g. when the study was created, the
    series acquired, the image processed, and when everything was created
    and deleted).
    So when I access all these times, I would have to convert all of them,
    e.g. in a template

    [% study.time.convertTZ(c.user) %]
    [% series.time.convertTZ(c.user) %]

    rather than just use (after Catalyst knows about the users timezone,
    somehow).

    [% study.time %]
    [% series.time %]

    and I must not miss a single value. And things get even more complicated
    when I filter for times (e.g. show images created in the last 3 hours),
    or if I want to show only datasets whose deletion date is in the past
    (could have be deleted in Europe and should also be gone in the US).

    I do know how to do all these things manually one by one, however, I
    already foresee that I will miss TZ conversions somewhere or
    accidentally do it twice in wrong direction, or ...

    I also know how to use inflation/deflation to a DateTime, which allows
    me to specify ONE timezone in the Model, however, how do I change the
    timezone on a per-user basis.

    Christian
  • Devin Austin at Jun 25, 2009 at 8:07 am

    On Thu, Jun 25, 2009 at 1:54 AM, Christian Lackas wrote:

    * Devin Austin [090625 09:43]:

    Hi Devin,
    I would approach it so that when the user registers, they choose their time
    zone. When they login, this information is stored into their session, and
    retrieved whenever. agreed.
    I would store it in the session in the form you want it to be
    presented, which would save you whatever time it would take to be
    inflating it.
    Now the problem begins:
    I have tables for studies, series and images (and many more), each of
    them has multiple timestamps (e.g. when the study was created, the
    series acquired, the image processed, and when everything was created
    and deleted).
    So when I access all these times, I would have to convert all of them,
    e.g. in a template

    [% study.time.convertTZ(c.user) %]
    [% series.time.convertTZ(c.user) %]

    rather than just use (after Catalyst knows about the users timezone,
    somehow).

    [% study.time %]
    [% series.time %]

    and I must not miss a single value. And things get even more complicated
    when I filter for times (e.g. show images created in the last 3 hours),
    or if I want to show only datasets whose deletion date is in the past
    (could have be deleted in Europe and should also be gone in the US).

    I do know how to do all these things manually one by one, however, I
    already foresee that I will miss TZ conversions somewhere or
    accidentally do it twice in wrong direction, or ...

    I also know how to use inflation/deflation to a DateTime, which allows
    me to specify ONE timezone in the Model, however, how do I change the
    timezone on a per-user basis.

    Christian

    --
    http://www.invicro.com/

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive:
    http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/
    Hi Christian,

    Now the problem begins:
    I have tables for studies, series and images (and many more), each of
    them has multiple timestamps (e.g. when the study was created, the
    series acquired, the image processed, and when everything was created
    and deleted).
    So when I access all these times, I would have to convert all of them,
    e.g. in a template

    There we go, that's better :-)

    Check this out:
    http://search.cpan.org/~dkamholz/Catalyst-Plugin-Session-PerUser-0.03/lib/Catalyst/Plugin/Session/PerUser.pm

    That should allow you to stuff things into your session *per user*. I know
    this doesn't exactly help with converting each timestamp, but it's a start.

    I mean, you're going to have to retrieve each record per user anyway, why
    not retrieve, convert, and stuff it into the per-user session?

    --
    Devin Austin
    http://www.codedright.net
    http://www.dreamhost.com/r.cgi?326568/hosting.html - Host with DreamHost!
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20090625/ae70d062/attachment.htm
  • Christian Lackas at Jun 25, 2009 at 10:32 am
    * Devin Austin [090625 10:12]:

    Hi Devin,
    unfortuantely, I don't have any issues with my session management, which
    this module could help me with.
    My issue is with the model. The models inflation/deflation to/from
    DateTime objects should depend on the current user (namely her timezone
    property).
    I mean, you're going to have to retrieve each record per user anyway,
    why not retrieve, convert, and stuff it into the per-user session?
    I cannot store all these times in the session, since I have a few
    million database entries that all have different timestamps, that should
    be converted transparently whenever I need them.

    Christian
  • Ian Wells at Jun 25, 2009 at 10:48 am

    2009/6/25 Christian Lackas <christian@lackas.net>:
    I mean, you're going to have to retrieve each record per user anyway,
    why not retrieve, convert, and stuff it into the per-user session?
    I cannot store all these times in the session, since I have a few
    million database entries that all have different timestamps, that should
    be converted transparently whenever I need them.
    I believe he's suggesting that you store the timezone that the user
    uses in the session.

    You seem to be confusing (a) the timezone to use in the DB and (b) the
    timezone that the user is using, and assuming that you should store
    the date in the DB in the timezone that the user is using. That's
    what it looks like to me, anyway.

    I would make use of user's timezone as part of the view/controller
    layers, and use a fixed timezone (say UTC) for the DB layers.

    Conversion is a function that your view layer's DateTime formatting
    function does - in the view, since it's a matter of what the user
    wants to see, rather than anything about the date data itself - and
    you similarly need a converter on input to attach a timezone to the
    DateTimes you create from user-supplied dates.

    Storing a DateTime with timezone to a UTC- (or otherwise) labelled
    DBIC DB column will convert the date to the correct timezone before
    saving it in the database. DateTime knows all about timezones; let it
    do all the work of converting.

    --
    Ian.
  • Christian Lackas at Jun 29, 2009 at 6:36 am
    * Ian Wells [090625 12:52]:

    Hi Everybody,

    first of all, thanks for all your input.
    I would make use of user's timezone as part of the view/controller
    layers, and use a fixed timezone (say UTC) for the DB layers.
    OK, as said before, I already had the feeling that it does not fit into
    the model, however, there it would have been the most convenient.
    That said, I will now bite the bullet and do it the hard way, but won't
    have the feeling to make it more complicated than necessary, anymore.

    Christian
  • Ian Wells at Jun 29, 2009 at 1:52 pm

    2009/6/29 Christian Lackas <christian@lackas.net>:
    OK, as said before, I already had the feeling that it does not fit into
    the model, however, there it would have been the most convenient.
    As I say, you'll need a formatting function or functions to turn
    dates-as-objects into dates in your page, regardless of timezones.
    You can set up your formatter that that it's initailised withh a
    timezone, and then your translation from DB-zone to view-zone comes
    for free as you would have to do the formatting call anyway.

    So:

    Once, somewhere once you've discovered the user and know their timezone:

    my $user=...
    DateFormatter->output_tz($user->timezone);

    In your view, and I assume TT here and that you've set up
    DateFormatter as a plugin or similar:

    [% DateFormatter.as_datetime(my_row.birthday) %]

    About as simple as it's ever likely to be, with the added advantage
    that you have a date formatter with a number of functions to output
    dates in one of a limited number of formats, so that your app has a
    consistent appearance.

    --
    Ian.
  • Moritz Onken at Jun 25, 2009 at 10:49 am

    Am 25.06.2009 um 09:54 schrieb Christian Lackas:

    * Devin Austin [090625 09:43]:

    Hi Devin,
    I would approach it so that when the user registers, they choose
    their time
    zone. When they login, this information is stored into their
    session, and
    retrieved whenever. agreed.
    I would store it in the session in the form you want it to be
    presented, which would save you whatever time it would take to be
    inflating it.
    Now the problem begins:
    I have tables for studies, series and images (and many more), each of
    them has multiple timestamps (e.g. when the study was created, the
    series acquired, the image processed, and when everything was created
    and deleted).
    So when I access all these times, I would have to convert all of them,
    e.g. in a template

    [% study.time.convertTZ(c.user) %]
    [% series.time.convertTZ(c.user) %]

    rather than just use (after Catalyst knows about the users timezone,
    somehow).

    [% study.time %]
    [% series.time %]

    and I must not miss a single value. And things get even more
    complicated
    when I filter for times (e.g. show images created in the last 3
    hours),
    or if I want to show only datasets whose deletion date is in the past
    (could have be deleted in Europe and should also be gone in the US).
    Hi Christian,

    I don't quite get the above paragraph. If you search for db entries
    which
    have been created in the last 3 hours and you have a column "created_on"
    which stores the time of creation incl. time zone (of your server) you
    won't face any problems because you can simply search for them.

    The problem occurs only if you store the current time of the user
    without
    time zone in the "created_on" column.

    To the original question:
    I'd say that the conversion between time zones belongs in the View. As
    you are
    doing it already with [% study.time.convertTZ(c.user) %]. I see that
    this
    means you have to type more but neither the controller nor the model
    should
    do this conversion.

    moritz
  • Ian Wells at Jun 25, 2009 at 11:34 am

    2009/6/25 Moritz Onken <onken@houseofdesign.de>:
    which stores the time of creation incl. time zone (of your server)
    A time column typically stores a time without the timezone. If you
    want to store the timezone you need a second column - otherwise you
    declare the timezone in the column definition and you can safely
    assume all times stored are in that timezone. (I think I'm saying
    what you *meant*, but it's not quite what you *wrote*.)
    To the original question:
    I'd say that the conversion between time zones belongs in the View. As you
    are
    doing it already with [% study.time.convertTZ(c.user) %]. I see that this
    means you have to type more
    ... but study.time stringifies the DateTime to a (by default) really
    ugly date, so you need a formatting call anyway. (Yes, you could
    specify the format when you define the column, too, but then your
    model is determining what format your view outputs - that's got issues
    with separation of responsibility.)

    --
    Ian.
  • Carl Johnstone at Jun 25, 2009 at 2:55 pm

    Devin Austin wrote:
    you could simply create a column and add the GMT offset.
    NO!

    If you only use GMT offsets you'll just annoy your users anywhere in the
    world that has DST. If that's the only solution don't bother - just use a
    relevant fixed timezone.

    Much better to use the Olsen DB timezone names (DateTime supports them).

    my $dt = DateTime->new( year => 2009,
    month => 6,
    day => 25,
    hour => 15,
    minute => 42,
    time_zone => 'Europe/London');
    print $dt->datetime, "\n";
    $dt->set_time_zone('America/New_York');
    print $dt->datetime, "\n";


    As far as the original question - you could pass the user's choice of
    timezone as a parameter when you call the model to request the time. So
    instead of:

    $object->creation_date->strftime(' ... ');
    $object->creation_date($user->prefs->tz)->strftime(' ... ');

    That still allows you to have a model that will work without being part of a
    web request and that is easily testable.

    Carl

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupcatalyst @
categoriescatalyst, perl
postedJun 25, '09 at 6:19a
activeJun 29, '09 at 1:52p
posts13
users5
websitecatalystframework.org
irc#catalyst

People

Translate

site design / logo © 2022 Grokbase