| OLD | NEW |
| (Empty) |
| 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 "ui/base/l10n/time_format.h" | |
| 6 | |
| 7 #include <limits> | |
| 8 | |
| 9 #include "base/lazy_instance.h" | |
| 10 #include "base/logging.h" | |
| 11 #include "base/strings/string_util.h" | |
| 12 #include "base/time/time.h" | |
| 13 #include "third_party/icu/source/common/unicode/unistr.h" | |
| 14 #include "ui/base/l10n/formatter.h" | |
| 15 #include "ui/base/l10n/l10n_util.h" | |
| 16 #include "ui/base/ui_base_export.h" | |
| 17 #include "ui/strings/grit/ui_strings.h" | |
| 18 | |
| 19 using base::Time; | |
| 20 using base::TimeDelta; | |
| 21 using ui::TimeFormat; | |
| 22 | |
| 23 namespace ui { | |
| 24 | |
| 25 UI_BASE_EXPORT base::LazyInstance<FormatterContainer> g_container = | |
| 26 LAZY_INSTANCE_INITIALIZER; | |
| 27 | |
| 28 // static | |
| 29 base::string16 TimeFormat::Simple(TimeFormat::Format format, | |
| 30 TimeFormat::Length length, | |
| 31 const base::TimeDelta& delta) { | |
| 32 return Detailed(format, length, 0, delta); | |
| 33 } | |
| 34 | |
| 35 // static | |
| 36 base::string16 TimeFormat::Detailed(TimeFormat::Format format, | |
| 37 TimeFormat::Length length, | |
| 38 int cutoff, | |
| 39 const base::TimeDelta& delta) { | |
| 40 if (delta < TimeDelta::FromSeconds(0)) { | |
| 41 NOTREACHED() << "Negative duration"; | |
| 42 return base::string16(); | |
| 43 } | |
| 44 | |
| 45 // Negative cutoff: always use two-value format. | |
| 46 if (cutoff < 0) | |
| 47 cutoff = std::numeric_limits<int>::max(); | |
| 48 | |
| 49 const TimeDelta one_minute(TimeDelta::FromMinutes(1)); | |
| 50 const TimeDelta one_hour(TimeDelta::FromHours(1)); | |
| 51 const TimeDelta one_day(TimeDelta::FromDays(1)); | |
| 52 const TimeDelta half_second(TimeDelta::FromMilliseconds(500)); | |
| 53 const TimeDelta half_minute(TimeDelta::FromSeconds(30)); | |
| 54 const TimeDelta half_hour(TimeDelta::FromMinutes(30)); | |
| 55 const TimeDelta half_day(TimeDelta::FromHours(12)); | |
| 56 | |
| 57 // Rationale: Start by determining major (first) unit, then add minor (second) | |
| 58 // unit if mandated by |cutoff|. | |
| 59 icu::UnicodeString time_string; | |
| 60 const Formatter* formatter = g_container.Get().Get(format, length); | |
| 61 if (delta < one_minute - half_second) { | |
| 62 // Anything up to 59.500 seconds is formatted as seconds. | |
| 63 const int seconds = static_cast<int>((delta + half_second).InSeconds()); | |
| 64 formatter->Format(Formatter::UNIT_SEC, seconds, time_string); | |
| 65 | |
| 66 } else if (delta < one_hour - (cutoff < 60 ? half_minute : half_second)) { | |
| 67 // Anything up to 59.5 minutes (respectively 59:59.500 when |cutoff| permits | |
| 68 // two-value output) is formatted as minutes (respectively minutes and | |
| 69 // seconds). | |
| 70 if (delta >= cutoff * one_minute - half_second) { | |
| 71 const int minutes = (delta + half_minute).InMinutes(); | |
| 72 formatter->Format(Formatter::UNIT_MIN, minutes, time_string); | |
| 73 } else { | |
| 74 const int minutes = (delta + half_second).InMinutes(); | |
| 75 const int seconds = static_cast<int>( | |
| 76 (delta + half_second).InSeconds() % 60); | |
| 77 formatter->Format(Formatter::TWO_UNITS_MIN_SEC, | |
| 78 minutes, seconds, time_string); | |
| 79 } | |
| 80 | |
| 81 } else if (delta < one_day - (cutoff < 24 ? half_hour : half_minute)) { | |
| 82 // Anything up to 23.5 hours (respectively 23:59:30.000 when |cutoff| | |
| 83 // permits two-value output) is formatted as hours (respectively hours and | |
| 84 // minutes). | |
| 85 if (delta >= cutoff * one_hour - half_minute) { | |
| 86 const int hours = (delta + half_hour).InHours(); | |
| 87 formatter->Format(Formatter::UNIT_HOUR, hours, time_string); | |
| 88 } else { | |
| 89 const int hours = (delta + half_minute).InHours(); | |
| 90 const int minutes = (delta + half_minute).InMinutes() % 60; | |
| 91 formatter->Format(Formatter::TWO_UNITS_HOUR_MIN, | |
| 92 hours, minutes, time_string); | |
| 93 } | |
| 94 | |
| 95 } else { | |
| 96 // Anything bigger is formatted as days (respectively days and hours). | |
| 97 if (delta >= cutoff * one_day - half_hour) { | |
| 98 const int days = (delta + half_day).InDays(); | |
| 99 formatter->Format(Formatter::UNIT_DAY, days, time_string); | |
| 100 } else { | |
| 101 const int days = (delta + half_hour).InDays(); | |
| 102 const int hours = (delta + half_hour).InHours() % 24; | |
| 103 formatter->Format(Formatter::TWO_UNITS_DAY_HOUR, | |
| 104 days, hours, time_string); | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 const int capacity = time_string.length() + 1; | |
| 109 DCHECK_GT(capacity, 1); | |
| 110 base::string16 result; | |
| 111 UErrorCode error = U_ZERO_ERROR; | |
| 112 time_string.extract(static_cast<UChar*>(WriteInto(&result, capacity)), | |
| 113 capacity, error); | |
| 114 DCHECK(U_SUCCESS(error)); | |
| 115 return result; | |
| 116 } | |
| 117 | |
| 118 // static | |
| 119 base::string16 TimeFormat::RelativeDate( | |
| 120 const Time& time, | |
| 121 const Time* optional_midnight_today) { | |
| 122 Time midnight_today = optional_midnight_today ? *optional_midnight_today : | |
| 123 Time::Now().LocalMidnight(); | |
| 124 TimeDelta day = TimeDelta::FromMicroseconds(Time::kMicrosecondsPerDay); | |
| 125 Time tomorrow = midnight_today + day; | |
| 126 Time yesterday = midnight_today - day; | |
| 127 if (time >= tomorrow) | |
| 128 return base::string16(); | |
| 129 else if (time >= midnight_today) | |
| 130 return l10n_util::GetStringUTF16(IDS_PAST_TIME_TODAY); | |
| 131 else if (time >= yesterday) | |
| 132 return l10n_util::GetStringUTF16(IDS_PAST_TIME_YESTERDAY); | |
| 133 return base::string16(); | |
| 134 } | |
| 135 | |
| 136 } // namespace ui | |
| OLD | NEW |