// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ui/base/l10n/time_format.h" #include #include "base/lazy_instance.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "base/time/time.h" #include "third_party/icu/source/common/unicode/unistr.h" #include "ui/base/l10n/formatter.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/ui_base_export.h" #include "ui/strings/grit/ui_strings.h" using base::Time; using base::TimeDelta; using ui::TimeFormat; namespace ui { UI_BASE_EXPORT base::LazyInstance g_container = LAZY_INSTANCE_INITIALIZER; // static base::string16 TimeFormat::Simple(TimeFormat::Format format, TimeFormat::Length length, const base::TimeDelta& delta) { return Detailed(format, length, 0, delta); } // static base::string16 TimeFormat::Detailed(TimeFormat::Format format, TimeFormat::Length length, int cutoff, const base::TimeDelta& delta) { if (delta < TimeDelta::FromSeconds(0)) { NOTREACHED() << "Negative duration"; return base::string16(); } // Negative cutoff: always use two-value format. if (cutoff < 0) cutoff = std::numeric_limits::max(); const TimeDelta one_minute(TimeDelta::FromMinutes(1)); const TimeDelta one_hour(TimeDelta::FromHours(1)); const TimeDelta one_day(TimeDelta::FromDays(1)); const TimeDelta half_second(TimeDelta::FromMilliseconds(500)); const TimeDelta half_minute(TimeDelta::FromSeconds(30)); const TimeDelta half_hour(TimeDelta::FromMinutes(30)); const TimeDelta half_day(TimeDelta::FromHours(12)); // Rationale: Start by determining major (first) unit, then add minor (second) // unit if mandated by |cutoff|. icu::UnicodeString time_string; const Formatter* formatter = g_container.Get().Get(format, length); if (delta < one_minute - half_second) { // Anything up to 59.500 seconds is formatted as seconds. const int seconds = static_cast((delta + half_second).InSeconds()); formatter->Format(Formatter::UNIT_SEC, seconds, &time_string); } else if (delta < one_hour - (cutoff < 60 ? half_minute : half_second)) { // Anything up to 59.5 minutes (respectively 59:59.500 when |cutoff| permits // two-value output) is formatted as minutes (respectively minutes and // seconds). if (delta >= cutoff * one_minute - half_second) { const int minutes = (delta + half_minute).InMinutes(); formatter->Format(Formatter::UNIT_MIN, minutes, &time_string); } else { const int minutes = (delta + half_second).InMinutes(); const int seconds = static_cast( (delta + half_second).InSeconds() % 60); formatter->Format(Formatter::TWO_UNITS_MIN_SEC, minutes, seconds, &time_string); } } else if (delta < one_day - (cutoff < 24 ? half_hour : half_minute)) { // Anything up to 23.5 hours (respectively 23:59:30.000 when |cutoff| // permits two-value output) is formatted as hours (respectively hours and // minutes). if (delta >= cutoff * one_hour - half_minute) { const int hours = (delta + half_hour).InHours(); formatter->Format(Formatter::UNIT_HOUR, hours, &time_string); } else { const int hours = (delta + half_minute).InHours(); const int minutes = (delta + half_minute).InMinutes() % 60; formatter->Format(Formatter::TWO_UNITS_HOUR_MIN, hours, minutes, &time_string); } } else { // Anything bigger is formatted as days (respectively days and hours). if (delta >= cutoff * one_day - half_hour) { const int days = (delta + half_day).InDays(); formatter->Format(Formatter::UNIT_DAY, days, &time_string); } else { const int days = (delta + half_hour).InDays(); const int hours = (delta + half_hour).InHours() % 24; formatter->Format(Formatter::TWO_UNITS_DAY_HOUR, days, hours, &time_string); } } const int capacity = time_string.length() + 1; DCHECK_GT(capacity, 1); base::string16 result; UErrorCode error = U_ZERO_ERROR; time_string.extract(static_cast(base::WriteInto(&result, capacity)), capacity, error); DCHECK(U_SUCCESS(error)); return result; } // static base::string16 TimeFormat::RelativeDate( const Time& time, const Time* optional_midnight_today) { Time midnight_today = optional_midnight_today ? *optional_midnight_today : Time::Now().LocalMidnight(); TimeDelta day = TimeDelta::FromMicroseconds(Time::kMicrosecondsPerDay); Time tomorrow = midnight_today + day; Time yesterday = midnight_today - day; if (time >= tomorrow) return base::string16(); else if (time >= midnight_today) return l10n_util::GetStringUTF16(IDS_PAST_TIME_TODAY); else if (time >= yesterday) return l10n_util::GetStringUTF16(IDS_PAST_TIME_YESTERDAY); return base::string16(); } } // namespace ui