Home | History | Annotate | Download | only in i18n
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/i18n/time_formatting.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/utf_string_conversions.h"
     10 #include "base/time.h"
     11 #include "unicode/datefmt.h"
     12 #include "unicode/dtptngen.h"
     13 #include "unicode/smpdtfmt.h"
     14 
     15 using base::Time;
     16 
     17 namespace {
     18 
     19 string16 TimeFormat(const icu::DateFormat* formatter,
     20                     const Time& time) {
     21   DCHECK(formatter);
     22   icu::UnicodeString date_string;
     23 
     24   formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string);
     25   return string16(date_string.getBuffer(),
     26                   static_cast<size_t>(date_string.length()));
     27 }
     28 
     29 }  // namespace
     30 
     31 namespace base {
     32 
     33 string16 TimeFormatTimeOfDay(const Time& time) {
     34   // We can omit the locale parameter because the default should match
     35   // Chrome's application locale.
     36   scoped_ptr<icu::DateFormat> formatter(
     37       icu::DateFormat::createTimeInstance(icu::DateFormat::kShort));
     38   return TimeFormat(formatter.get(), time);
     39 }
     40 
     41 string16 TimeFormatTimeOfDayWithHourClockType(const Time& time,
     42                                               HourClockType type) {
     43   // Just redirect to the normal function if the default type matches the
     44   // given type.
     45   HourClockType default_type = GetHourClockType();
     46   if (default_type == type) {
     47     return TimeFormatTimeOfDay(time);
     48   }
     49 
     50   // Generate a locale-dependent format pattern. The generator will take
     51   // care of locale-dependent formatting issues like which separator to
     52   // use (some locales use '.' instead of ':'), and where to put the am/pm
     53   // marker.
     54   UErrorCode status = U_ZERO_ERROR;
     55   icu::DateTimePatternGenerator *generator =
     56       icu::DateTimePatternGenerator::createInstance(status);
     57   CHECK(U_SUCCESS(status));
     58   const char* base_pattern = (type == k12HourClock ? "ahm" : "Hm");
     59   icu::UnicodeString generated_pattern =
     60       generator->getBestPattern(icu::UnicodeString(base_pattern), status);
     61   CHECK(U_SUCCESS(status));
     62 
     63   // Then, format the time using the generated pattern.
     64   icu::SimpleDateFormat formatter(generated_pattern, status);
     65   CHECK(U_SUCCESS(status));
     66   return TimeFormat(&formatter, time);
     67 }
     68 
     69 string16 TimeFormatShortDate(const Time& time) {
     70   scoped_ptr<icu::DateFormat> formatter(
     71       icu::DateFormat::createDateInstance(icu::DateFormat::kMedium));
     72   return TimeFormat(formatter.get(), time);
     73 }
     74 
     75 string16 TimeFormatShortDateNumeric(const Time& time) {
     76   scoped_ptr<icu::DateFormat> formatter(
     77       icu::DateFormat::createDateInstance(icu::DateFormat::kShort));
     78   return TimeFormat(formatter.get(), time);
     79 }
     80 
     81 string16 TimeFormatShortDateAndTime(const Time& time) {
     82   scoped_ptr<icu::DateFormat> formatter(
     83       icu::DateFormat::createDateTimeInstance(icu::DateFormat::kShort));
     84   return TimeFormat(formatter.get(), time);
     85 }
     86 
     87 string16 TimeFormatFriendlyDateAndTime(const Time& time) {
     88   scoped_ptr<icu::DateFormat> formatter(
     89       icu::DateFormat::createDateTimeInstance(icu::DateFormat::kFull));
     90   return TimeFormat(formatter.get(), time);
     91 }
     92 
     93 string16 TimeFormatFriendlyDate(const Time& time) {
     94   scoped_ptr<icu::DateFormat> formatter(icu::DateFormat::createDateInstance(
     95       icu::DateFormat::kFull));
     96   return TimeFormat(formatter.get(), time);
     97 }
     98 
     99 HourClockType GetHourClockType() {
    100   // TODO(satorux,jshin): Rework this with ures_getByKeyWithFallback()
    101   // once it becomes public. The short time format can be found at
    102   // "calendar/gregorian/DateTimePatterns/3" in the resources.
    103   scoped_ptr<icu::SimpleDateFormat> formatter(
    104       static_cast<icu::SimpleDateFormat*>(
    105           icu::DateFormat::createTimeInstance(icu::DateFormat::kShort)));
    106   // Retrieve the short time format.
    107   icu::UnicodeString pattern_unicode;
    108   formatter->toPattern(pattern_unicode);
    109 
    110   // Determine what hour clock type the current locale uses, by checking
    111   // "a" (am/pm marker) in the short time format. This is reliable as "a"
    112   // is used by all of 12-hour clock formats, but not any of 24-hour clock
    113   // formats, as shown below.
    114   //
    115   // % grep -A4 DateTimePatterns third_party/icu/source/data/locales/*.txt |
    116   //   grep -B1 -- -- |grep -v -- '--' |
    117   //   perl -nle 'print $1 if /^\S+\s+"(.*)"/' |sort -u
    118   //
    119   // H.mm
    120   // H:mm
    121   // HH.mm
    122   // HH:mm
    123   // a h:mm
    124   // ah:mm
    125   // ahh:mm
    126   // h-mm a
    127   // h:mm a
    128   // hh:mm a
    129   //
    130   // See http://userguide.icu-project.org/formatparse/datetime for details
    131   // about the date/time format syntax.
    132   if (pattern_unicode.indexOf('a') == -1) {
    133     return k24HourClock;
    134   } else {
    135     return k12HourClock;
    136   }
    137 }
    138 
    139 }  // namespace base
    140