1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Use of this source code is governed by a BSD-style license that can be
306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// found in the LICENSE file.
406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "chrome/common/time_format.h"
606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include <vector>
806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/lazy_instance.h"
1006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/logging.h"
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h"
1206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/stl_util-inl.h"
133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string16.h"
1406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/time.h"
1506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/utf_string_conversions.h"
1606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "grit/generated_resources.h"
1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h"
1806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "unicode/datefmt.h"
1906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "unicode/locid.h"
2006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "unicode/plurfmt.h"
2106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "unicode/plurrule.h"
2206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "unicode/smpdtfmt.h"
2306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
2406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochusing base::Time;
2506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochusing base::TimeDelta;
2606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
2706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochnamespace {
2806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
2906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstatic const char kFallbackFormatSuffixShort[] = "}";
3006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstatic const char kFallbackFormatSuffixLeft[] = " left}";
3106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstatic const char kFallbackFormatSuffixAgo[] = " ago}";
3206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
3306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Contains message IDs for various time units and pluralities.
3406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstruct MessageIDs {
3506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // There are 4 different time units and 6 different pluralities.
3606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  int ids[4][6];
3706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch};
3806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
3906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Message IDs for different time formats.
4006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstatic const MessageIDs kTimeShortMessageIDs = { {
4106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  {
4206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_SECS_DEFAULT, IDS_TIME_SEC_SINGULAR, IDS_TIME_SECS_ZERO,
4306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_SECS_TWO, IDS_TIME_SECS_FEW, IDS_TIME_SECS_MANY
4406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  },
4506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  {
4606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_MINS_DEFAULT, IDS_TIME_MIN_SINGULAR, IDS_TIME_MINS_ZERO,
4706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_MINS_TWO, IDS_TIME_MINS_FEW, IDS_TIME_MINS_MANY
4806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  },
4906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  {
5006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_HOURS_DEFAULT, IDS_TIME_HOUR_SINGULAR, IDS_TIME_HOURS_ZERO,
5106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_HOURS_TWO, IDS_TIME_HOURS_FEW, IDS_TIME_HOURS_MANY
5206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  },
5306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  {
5406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_DAYS_DEFAULT, IDS_TIME_DAY_SINGULAR, IDS_TIME_DAYS_ZERO,
5506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_DAYS_TWO, IDS_TIME_DAYS_FEW, IDS_TIME_DAYS_MANY
5606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
5706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch} };
5806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
5906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstatic const MessageIDs kTimeRemainingMessageIDs = { {
6006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  {
6106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_REMAINING_SECS_DEFAULT, IDS_TIME_REMAINING_SEC_SINGULAR,
6206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_REMAINING_SECS_ZERO, IDS_TIME_REMAINING_SECS_TWO,
6306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_REMAINING_SECS_FEW, IDS_TIME_REMAINING_SECS_MANY
6406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  },
6506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  {
6606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_REMAINING_MINS_DEFAULT, IDS_TIME_REMAINING_MIN_SINGULAR,
6706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_REMAINING_MINS_ZERO, IDS_TIME_REMAINING_MINS_TWO,
6806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_REMAINING_MINS_FEW, IDS_TIME_REMAINING_MINS_MANY
6906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  },
7006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  {
7106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_REMAINING_HOURS_DEFAULT, IDS_TIME_REMAINING_HOUR_SINGULAR,
7206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_REMAINING_HOURS_ZERO, IDS_TIME_REMAINING_HOURS_TWO,
7306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_REMAINING_HOURS_FEW, IDS_TIME_REMAINING_HOURS_MANY
7406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  },
7506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  {
7606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_REMAINING_DAYS_DEFAULT, IDS_TIME_REMAINING_DAY_SINGULAR,
7706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_REMAINING_DAYS_ZERO, IDS_TIME_REMAINING_DAYS_TWO,
7806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_REMAINING_DAYS_FEW, IDS_TIME_REMAINING_DAYS_MANY
7906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
8006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch} };
8106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
8206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstatic const MessageIDs kTimeElapsedMessageIDs = { {
8306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  {
8406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_ELAPSED_SECS_DEFAULT, IDS_TIME_ELAPSED_SEC_SINGULAR,
8506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_ELAPSED_SECS_ZERO, IDS_TIME_ELAPSED_SECS_TWO,
8606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_ELAPSED_SECS_FEW, IDS_TIME_ELAPSED_SECS_MANY
8706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  },
8806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  {
8906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_ELAPSED_MINS_DEFAULT, IDS_TIME_ELAPSED_MIN_SINGULAR,
9006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_ELAPSED_MINS_ZERO, IDS_TIME_ELAPSED_MINS_TWO,
9106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_ELAPSED_MINS_FEW, IDS_TIME_ELAPSED_MINS_MANY
9206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  },
9306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  {
9406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_ELAPSED_HOURS_DEFAULT, IDS_TIME_ELAPSED_HOUR_SINGULAR,
9506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_ELAPSED_HOURS_ZERO, IDS_TIME_ELAPSED_HOURS_TWO,
9606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_ELAPSED_HOURS_FEW, IDS_TIME_ELAPSED_HOURS_MANY
9706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  },
9806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  {
9906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_ELAPSED_DAYS_DEFAULT, IDS_TIME_ELAPSED_DAY_SINGULAR,
10006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_ELAPSED_DAYS_ZERO, IDS_TIME_ELAPSED_DAYS_TWO,
10106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    IDS_TIME_ELAPSED_DAYS_FEW, IDS_TIME_ELAPSED_DAYS_MANY
10206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
10306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch} };
10406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
10506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Different format types.
10606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochenum FormatType {
10706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  FORMAT_SHORT,
10806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  FORMAT_REMAINING,
10906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  FORMAT_ELAPSED,
11006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch};
11106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
11206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}  // namespace
11306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
11406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochclass TimeFormatter {
11506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  public:
11606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    const std::vector<icu::PluralFormat*>& formatter(FormatType format_type) {
11706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      switch (format_type) {
11806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        case FORMAT_SHORT:
11906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          return short_formatter_;
12006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        case FORMAT_REMAINING:
12106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          return time_left_formatter_;
12206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        case FORMAT_ELAPSED:
12306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          return time_elapsed_formatter_;
12406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        default:
12506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          NOTREACHED();
12606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          return short_formatter_;
12706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      }
12806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
12906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  private:
13006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    static const MessageIDs& GetMessageIDs(FormatType format_type) {
13106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      switch (format_type) {
13206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        case FORMAT_SHORT:
13306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          return kTimeShortMessageIDs;
13406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        case FORMAT_REMAINING:
13506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          return kTimeRemainingMessageIDs;
13606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        case FORMAT_ELAPSED:
13706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          return kTimeElapsedMessageIDs;
13806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        default:
13906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          NOTREACHED();
14006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          return kTimeShortMessageIDs;
14106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      }
14206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
14306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
14406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    static const char* GetFallbackFormatSuffix(FormatType format_type) {
14506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      switch (format_type) {
14606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        case FORMAT_SHORT:
14706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          return kFallbackFormatSuffixShort;
14806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        case FORMAT_REMAINING:
14906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          return kFallbackFormatSuffixLeft;
15006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        case FORMAT_ELAPSED:
15106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          return kFallbackFormatSuffixAgo;
15206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        default:
15306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          NOTREACHED();
15406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          return kFallbackFormatSuffixShort;
15506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      }
15606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
15706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
15806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    TimeFormatter() {
15906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      BuildFormats(FORMAT_SHORT, &short_formatter_);
16006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      BuildFormats(FORMAT_REMAINING, &time_left_formatter_);
16106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      BuildFormats(FORMAT_ELAPSED, &time_elapsed_formatter_);
16206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
16306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    ~TimeFormatter() {
16406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      STLDeleteContainerPointers(short_formatter_.begin(),
16506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                 short_formatter_.end());
16606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      STLDeleteContainerPointers(time_left_formatter_.begin(),
16706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                 time_left_formatter_.end());
16806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      STLDeleteContainerPointers(time_elapsed_formatter_.begin(),
16906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                 time_elapsed_formatter_.end());
17006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
17121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    friend struct base::DefaultLazyInstanceTraits<TimeFormatter>;
17206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
17306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    std::vector<icu::PluralFormat*> short_formatter_;
17406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    std::vector<icu::PluralFormat*> time_left_formatter_;
17506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    std::vector<icu::PluralFormat*> time_elapsed_formatter_;
17606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    static void BuildFormats(FormatType format_type,
17706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                             std::vector<icu::PluralFormat*>* time_formats);
17806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    static icu::PluralFormat* createFallbackFormat(
17906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        const icu::PluralRules& rules, int index, FormatType format_type);
18006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
18106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    DISALLOW_COPY_AND_ASSIGN(TimeFormatter);
18206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch};
18306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
18421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenstatic base::LazyInstance<TimeFormatter> g_time_formatter(
18521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    base::LINKER_INITIALIZED);
18621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
18706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochvoid TimeFormatter::BuildFormats(
18806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    FormatType format_type, std::vector<icu::PluralFormat*>* time_formats) {
18906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  static const icu::UnicodeString kKeywords[] = {
19006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    UNICODE_STRING_SIMPLE("other"), UNICODE_STRING_SIMPLE("one"),
19106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    UNICODE_STRING_SIMPLE("zero"), UNICODE_STRING_SIMPLE("two"),
19206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    UNICODE_STRING_SIMPLE("few"), UNICODE_STRING_SIMPLE("many")
19306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  };
19406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  UErrorCode err = U_ZERO_ERROR;
19506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  scoped_ptr<icu::PluralRules> rules(
19606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      icu::PluralRules::forLocale(icu::Locale::getDefault(), err));
19706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (U_FAILURE(err)) {
19806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    err = U_ZERO_ERROR;
19906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    icu::UnicodeString fallback_rules("one: n is 1", -1, US_INV);
20006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    rules.reset(icu::PluralRules::createRules(fallback_rules, err));
20106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    DCHECK(U_SUCCESS(err));
20206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
20306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
20406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  const MessageIDs& message_ids = GetMessageIDs(format_type);
20506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
20606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  for (int i = 0; i < 4; ++i) {
20706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    icu::UnicodeString pattern;
20806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    for (size_t j = 0; j < arraysize(kKeywords); ++j) {
20906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      int msg_id = message_ids.ids[i][j];
2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      std::string sub_pattern = l10n_util::GetStringUTF8(msg_id);
21106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      // NA means this keyword is not used in the current locale.
21206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      // Even if a translator translated for this keyword, we do not
21306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      // use it unless it's 'other' (j=0) or it's defined in the rules
21406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      // for the current locale. Special-casing of 'other' will be removed
21506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      // once ICU's isKeyword is fixed to return true for isKeyword('other').
21606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      if (sub_pattern.compare("NA") != 0 &&
21706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          (j == 0 || rules->isKeyword(kKeywords[j]))) {
21806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          pattern += kKeywords[j];
21906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          pattern += UNICODE_STRING_SIMPLE("{");
22006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          pattern += icu::UnicodeString(sub_pattern.c_str(), "UTF-8");
22106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch          pattern += UNICODE_STRING_SIMPLE("}");
22206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      }
22306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
22406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    icu::PluralFormat* format = new icu::PluralFormat(*rules, pattern, err);
22506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    if (U_SUCCESS(err)) {
22606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      time_formats->push_back(format);
22706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    } else {
22806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      delete format;
22906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      time_formats->push_back(createFallbackFormat(*rules, i, format_type));
23006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      // Reset it so that next ICU call can proceed.
23106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      err = U_ZERO_ERROR;
23206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
23306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
23406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
23506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
23606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Create a hard-coded fallback plural format. This will never be called
23706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// unless translators make a mistake.
23806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochicu::PluralFormat* TimeFormatter::createFallbackFormat(
23906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    const icu::PluralRules& rules, int index, FormatType format_type) {
24006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  static const icu::UnicodeString kUnits[4][2] = {
24106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    { UNICODE_STRING_SIMPLE("sec"), UNICODE_STRING_SIMPLE("secs") },
24206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    { UNICODE_STRING_SIMPLE("min"), UNICODE_STRING_SIMPLE("mins") },
24306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    { UNICODE_STRING_SIMPLE("hour"), UNICODE_STRING_SIMPLE("hours") },
24406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    { UNICODE_STRING_SIMPLE("day"), UNICODE_STRING_SIMPLE("days") }
24506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  };
24606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  icu::UnicodeString suffix(GetFallbackFormatSuffix(format_type), -1, US_INV);
24706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  icu::UnicodeString pattern;
24806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (rules.isKeyword(UNICODE_STRING_SIMPLE("one"))) {
24906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    pattern += UNICODE_STRING_SIMPLE("one{# ") + kUnits[index][0] + suffix;
25006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
25106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  pattern += UNICODE_STRING_SIMPLE(" other{# ") + kUnits[index][1] + suffix;
25206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  UErrorCode err = U_ZERO_ERROR;
25306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  icu::PluralFormat* format = new icu::PluralFormat(rules, pattern, err);
25406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK(U_SUCCESS(err));
25506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return format;
25606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
25706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
2583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic string16 FormatTimeImpl(const TimeDelta& delta, FormatType format_type) {
25906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (delta.ToInternalValue() < 0) {
26006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    NOTREACHED() << "Negative duration";
2613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return string16();
26206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
26306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
26406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  int number;
26506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
26606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  const std::vector<icu::PluralFormat*>& formatters =
26721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    g_time_formatter.Get().formatter(format_type);
26806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
26906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  UErrorCode error = U_ZERO_ERROR;
27006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  icu::UnicodeString time_string;
27106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Less than a minute gets "X seconds left"
27206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (delta.ToInternalValue() < Time::kMicrosecondsPerMinute) {
27306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    number = static_cast<int>(delta.ToInternalValue() /
27406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                              Time::kMicrosecondsPerSecond);
27506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    time_string = formatters[0]->format(number, error);
27606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
27706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Less than 1 hour gets "X minutes left".
27806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  } else if (delta.ToInternalValue() < Time::kMicrosecondsPerHour) {
27906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    number = static_cast<int>(delta.ToInternalValue() /
28006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                              Time::kMicrosecondsPerMinute);
28106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    time_string = formatters[1]->format(number, error);
28206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
28306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Less than 1 day remaining gets "X hours left"
28406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  } else if (delta.ToInternalValue() < Time::kMicrosecondsPerDay) {
28506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    number = static_cast<int>(delta.ToInternalValue() /
28606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                              Time::kMicrosecondsPerHour);
28706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    time_string = formatters[2]->format(number, error);
28806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
28906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Anything bigger gets "X days left"
29006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  } else {
29106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    number = static_cast<int>(delta.ToInternalValue() /
29206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                              Time::kMicrosecondsPerDay);
29306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    time_string = formatters[3]->format(number, error);
29406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
29506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
29606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // With the fallback added, this should never fail.
29706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK(U_SUCCESS(error));
29806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  int capacity = time_string.length() + 1;
2993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  string16 result;
30006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  time_string.extract(static_cast<UChar*>(
3013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                      WriteInto(&result, capacity)),
30206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                      capacity, error);
30306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK(U_SUCCESS(error));
3043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return result;
30506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
30606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
30706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// static
3083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstring16 TimeFormat::TimeElapsed(const TimeDelta& delta) {
30906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return FormatTimeImpl(delta, FORMAT_ELAPSED);
31006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
31106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
31206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// static
3133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstring16 TimeFormat::TimeRemaining(const TimeDelta& delta) {
31406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return FormatTimeImpl(delta, FORMAT_REMAINING);
31506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
31606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
31706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// static
3183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstring16 TimeFormat::TimeRemainingShort(const TimeDelta& delta) {
31906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return FormatTimeImpl(delta, FORMAT_SHORT);
32006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
32106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
32206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// static
3233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstring16 TimeFormat::RelativeDate(
32406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    const Time& time,
32506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    const Time* optional_midnight_today) {
32606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  Time midnight_today = optional_midnight_today ? *optional_midnight_today :
32706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      Time::Now().LocalMidnight();
32806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
32906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Filter out "today" and "yesterday"
33006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (time >= midnight_today)
3313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return l10n_util::GetStringUTF16(IDS_PAST_TIME_TODAY);
33206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  else if (time >= midnight_today -
33306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                   TimeDelta::FromMicroseconds(Time::kMicrosecondsPerDay))
3343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return l10n_util::GetStringUTF16(IDS_PAST_TIME_YESTERDAY);
33506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
3363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return string16();
33706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
338