How Do I use the formats in DateTime::Locale with a DateTime object?
Asked Answered
K

2

5

DateTime::Locale has a very comprehensive list of date and time formats for various locales and countries. I would like to use it in emails to customers, depending on which country the customer is from.

Unfortunately, it is a little hard to understand from the documentation how to actually use the functions for a medium or a long date. For example, DateTime::Locale::de_DE lists these date formats (excerpt) in the doc:

Long
 2008-02-05T18:30:30 = 5. Februar 2008
 1995-12-22T09:05:02 = 22. Dezember 1995
-0010-09-15T04:44:23 = 15. September -10

Medium
 2008-02-05T18:30:30 = 05.02.2008
 1995-12-22T09:05:02 = 22.12.1995
 -0010-09-15T04:44:23 = 15.09.-010

This is great. According to DateTime::Locale::Base there are methods in the locale object to get these formats: $locale->date_format_long() and $locale->date_format_medium().

After some googling I came up with Sinan Ünür's blog, where he shows this code (excerpt):

for my $locale ( qw(ar da de en_GB es fr ru tr) ) {
    $dt->set_locale( $locale );
    print_date( $dt );
}

sub print_date {
    my ($dt) = @_;
    my $locale = $dt->locale;

    printf(
        "In %s: %s\n", $locale->name,
        $dt->format_cldr($locale->date_format_full)
    );
}

So the format that comes out of these methods is a cldr format. Cool. But what Sinan shows looks tedius. In short, it would be:

for (qw( ar da de en_GB es fr ru tr )) {
  my $dt2 = DateTime->now( locale => $_ );
  printf "%s: %s\n", $_, $dt2->format_cldr($dt2->locale->date_format_long);
}

In order to make that shorter, I could of course do something like this:

package DateTime;

sub stringify_long {
  return $_[0]->format_cldr($_[0]->locale->date_format_long);
}

package Main;
use strict; use warnings;    
use DateTime;

my $dt = DateTime->now( locale => 'de_DE' );
print $dt->stringify_long;

But I don't want to do that. So my question: Is there a way to stringify a DateTime object according to one of these formats from its locale with a build-in method that I am missing?

Kyungkyushu answered 4/11, 2013 at 11:15 Comment(0)
G
5

I'm not sure what your opposition is to Sinan Ünür's method, so I don't know if this will appeal to you or not, but you can specify a formatter object to control stringification of DateTime objects:

use DateTime;
use DateTime::Format::CLDR;
use DateTime::Locale;

my $locale = DateTime::Locale->load('de_DE');
my $formatter = DateTime::Format::CLDR->new(
    pattern => $locale->date_format_long,
    locale => $locale
);
my $dt = DateTime->now( locale => $locale, formatter => $formatter );
print $dt;

or

use DateTime;
use DateTime::Format::CLDR;
use DateTime::Locale;

my $locale = DateTime::Locale->load('de_DE');
my $dt = DateTime->now( locale => $locale );
my $formatter = DateTime::Format::CLDR->new(
    pattern => $locale->date_format_long,
    locale => $locale
);
$dt->set_formatter($formatter);
print $dt;

The nice thing about this approach is that once you've set a formatter, printing the date is easy-peasy.

Goethe answered 4/11, 2013 at 23:24 Comment(1)
A formatter seems to be a good option. Thanks for demonstrating it. I am primarily looking for an option that is less repetition if I do that kind of thing a lot.Kyungkyushu
B
3

It's been 11 years since the OP, but I have worked very hard and released a very elaborate module DateTime::Format::Intl, which addresses the need expressed by the OP, i.e. localising datetime, such as:

use DateTime;
use DateTime::Format::Intl;
my $dt = DateTime->now;
my $fmt = DateTime::Format::Intl->new(
    # You can use ja-JP (Unicode / web-style) or ja_JP (system-style), it does not matter.
    'ja_JP', {
        localeMatcher => 'best fit',
        # The only one supported. You can use 'gregory' or 'gregorian' indifferently
        calendar => 'gregorian',
        # see getNumberingSystems() in Locale::Intl for the supported number systems
        numberingSystem => 'latn',
        formatMatcher => 'best fit',
        dateStyle => 'long',
        timeStyle => 'long',
    },
) || die( DateTime::Format::Intl->error );
say $fmt->format( $dt );

This modules mirrors the API of its JavaScript equivalent of Intl.DateTimeFormat.

And, this Perl module uses another: DateTime::Locale::FromCLDR I also created, which relies on a very comprehensive SQLite database of Unicode CLDR data (Common Locale Data Repository), and provides the same methods as DateTime::Locale (actually it is DateTime::Locale::FromData), and more. You can see the other module I created to rely on those CLDR data with Locale::Unicode::Data

So, this helps localise datetime in your project, by providing a more powerful and simpler layer above DateTime::Locale::FromCLDR, although you still can access all those methods if you want or need direct access to them.

Barnaba answered 1/11 at 7:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.