1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4 * Copyright (c) 2008-2016, International Business Machines Corporation and
5 * others. All Rights Reserved.
6 ********************************************************************/
8 #include "unicode/utypes.h"
10 #if !UCONFIG_NO_FORMATTING
12 #include "unicode/decimfmt.h"
13 #include "unicode/tmunit.h"
14 #include "unicode/tmutamt.h"
15 #include "unicode/tmutfmt.h"
16 #include "unicode/ustring.h"
20 //TODO: put as compilation flag
21 //#define TUFMTTS_DEBUG 1
27 class TimeUnitTest : public IntlTest {
28 void runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/ ) {
29 if (exec) logln("TestSuite TimeUnitTest");
31 TESTCASE_AUTO(testBasic);
32 TESTCASE_AUTO(testAPI);
33 TESTCASE_AUTO(testGreekWithFallback);
34 TESTCASE_AUTO(testGreekWithSanitization);
35 TESTCASE_AUTO(test10219Plurals);
36 TESTCASE_AUTO(TestBritishShortHourFallback);
42 * Performs basic tests
52 * Performs tests for Greek
53 * This tests that requests for short unit names correctly fall back
54 * to long unit names for a locale where the locale data does not
55 * provide short unit names. As of CLDR 1.9, Greek is one such language.
57 void testGreekWithFallback();
60 * Performs tests for Greek
61 * This tests that if the plural count listed in time unit format does not
62 * match those in the plural rules for the locale, those plural count in
63 * time unit format will be ingored and subsequently, fall back will kick in
64 * which is tested above.
65 * Without data sanitization, setNumberFormat() would crash.
66 * As of CLDR shiped in ICU4.8, Greek is one such language.
68 void testGreekWithSanitization();
71 * Performs unit test for ticket 10219 making sure that plurals work
72 * correctly with rounding.
74 void test10219Plurals();
76 void TestBritishShortHourFallback();
79 extern IntlTest *createTimeUnitTest() {
80 return new TimeUnitTest();
83 // This function is more lenient than equals operator as it considers integer 3 hours and
84 // double 3.0 hours to be equal
85 static UBool tmaEqual(const TimeUnitAmount& left, const TimeUnitAmount& right) {
86 if (left.getTimeUnitField() != right.getTimeUnitField()) {
89 UErrorCode status = U_ZERO_ERROR;
90 if (!left.getNumber().isNumeric() || !right.getNumber().isNumeric()) {
93 UBool result = left.getNumber().getDouble(status) == right.getNumber().getDouble(status);
94 if (U_FAILURE(status)) {
103 void TimeUnitTest::testBasic() {
104 const char* locales[] = {"en", "sl", "fr", "zh", "ar", "ru", "zh_Hant", "pa"};
105 for ( unsigned int locIndex = 0;
106 locIndex < UPRV_LENGTHOF(locales);
108 UErrorCode status = U_ZERO_ERROR;
109 Locale loc(locales[locIndex]);
110 TimeUnitFormat** formats = new TimeUnitFormat*[2];
111 formats[UTMUTFMT_FULL_STYLE] = new TimeUnitFormat(loc, status);
112 if (!assertSuccess("TimeUnitFormat(full)", status, TRUE)) return;
113 formats[UTMUTFMT_ABBREVIATED_STYLE] = new TimeUnitFormat(loc, UTMUTFMT_ABBREVIATED_STYLE, status);
114 if (!assertSuccess("TimeUnitFormat(short)", status)) return;
116 std::cout << "locale: " << locales[locIndex] << "\n";
118 for (int style = UTMUTFMT_FULL_STYLE;
119 style <= UTMUTFMT_ABBREVIATED_STYLE;
121 for (TimeUnit::UTimeUnitFields j = TimeUnit::UTIMEUNIT_YEAR;
122 j < TimeUnit::UTIMEUNIT_FIELD_COUNT;
123 j = (TimeUnit::UTimeUnitFields)(j+1)) {
125 std::cout << "time unit: " << j << "\n";
127 double tests[] = {0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 5, 10, 100, 101.35};
128 for (unsigned int i = 0; i < UPRV_LENGTHOF(tests); ++i) {
130 std::cout << "number: " << tests[i] << "\n";
132 TimeUnitAmount* source = new TimeUnitAmount(tests[i], j, status);
133 if (!assertSuccess("TimeUnitAmount()", status)) return;
134 UnicodeString formatted;
135 Formattable formattable;
136 formattable.adoptObject(source);
137 formatted = ((Format*)formats[style])->format(formattable, formatted, status);
138 if (!assertSuccess("format()", status)) return;
140 char formatResult[1000];
141 formatted.extract(0, formatted.length(), formatResult, "UTF-8");
142 std::cout << "format result: " << formatResult << "\n";
145 ((Format*)formats[style])->parseObject(formatted, result, status);
146 if (!assertSuccess("parseObject()", status)) return;
147 if (!tmaEqual(*((TimeUnitAmount *)result.getObject()), *((TimeUnitAmount *) formattable.getObject()))) {
148 dataerrln("No round trip: ");
150 // other style parsing
151 Formattable result_1;
152 ((Format*)formats[1-style])->parseObject(formatted, result_1, status);
153 if (!assertSuccess("parseObject()", status)) return;
154 if (!tmaEqual(*((TimeUnitAmount *)result_1.getObject()), *((TimeUnitAmount *) formattable.getObject()))) {
155 dataerrln("No round trip: ");
160 delete formats[UTMUTFMT_FULL_STYLE];
161 delete formats[UTMUTFMT_ABBREVIATED_STYLE];
167 void TimeUnitTest::testAPI() {
168 //================= TimeUnit =================
169 UErrorCode status = U_ZERO_ERROR;
171 TimeUnit* tmunit = TimeUnit::createInstance(TimeUnit::UTIMEUNIT_YEAR, status);
172 if (!assertSuccess("TimeUnit::createInstance", status)) return;
174 TimeUnit* another = (TimeUnit*)tmunit->clone();
175 TimeUnit third(*tmunit);
176 TimeUnit fourth = third;
178 assertTrue("orig and clone are equal", (*tmunit == *another));
179 assertTrue("copied and assigned are equal", (third == fourth));
181 TimeUnit* tmunit_m = TimeUnit::createInstance(TimeUnit::UTIMEUNIT_MONTH, status);
182 assertTrue("year != month", (*tmunit != *tmunit_m));
184 TimeUnit::UTimeUnitFields field = tmunit_m->getTimeUnitField();
185 assertTrue("field of month time unit is month", (field == TimeUnit::UTIMEUNIT_MONTH));
187 //===== Interoperability with MeasureUnit ======
188 MeasureUnit **ptrs = new MeasureUnit *[TimeUnit::UTIMEUNIT_FIELD_COUNT];
190 ptrs[TimeUnit::UTIMEUNIT_YEAR] = MeasureUnit::createYear(status);
191 ptrs[TimeUnit::UTIMEUNIT_MONTH] = MeasureUnit::createMonth(status);
192 ptrs[TimeUnit::UTIMEUNIT_DAY] = MeasureUnit::createDay(status);
193 ptrs[TimeUnit::UTIMEUNIT_WEEK] = MeasureUnit::createWeek(status);
194 ptrs[TimeUnit::UTIMEUNIT_HOUR] = MeasureUnit::createHour(status);
195 ptrs[TimeUnit::UTIMEUNIT_MINUTE] = MeasureUnit::createMinute(status);
196 ptrs[TimeUnit::UTIMEUNIT_SECOND] = MeasureUnit::createSecond(status);
197 if (!assertSuccess("TimeUnit::createInstance", status)) return;
199 for (TimeUnit::UTimeUnitFields j = TimeUnit::UTIMEUNIT_YEAR;
200 j < TimeUnit::UTIMEUNIT_FIELD_COUNT;
201 j = (TimeUnit::UTimeUnitFields)(j+1)) {
202 MeasureUnit *ptr = TimeUnit::createInstance(j, status);
203 if (!assertSuccess("TimeUnit::createInstance", status)) return;
204 // We have to convert *ptr to a MeasureUnit or else == will fail over
205 // differing types (TimeUnit vs. MeasureUnit).
207 "Time unit should be equal to corresponding MeasureUnit",
208 MeasureUnit(*ptr) == *ptrs[j]);
214 for (int i = 0; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; ++i) {
220 //================= TimeUnitAmount =================
222 Formattable formattable((int32_t)2);
223 TimeUnitAmount tma_long(formattable, TimeUnit::UTIMEUNIT_DAY, status);
224 if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return;
226 formattable.setDouble(2);
227 TimeUnitAmount tma_double(formattable, TimeUnit::UTIMEUNIT_DAY, status);
228 if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return;
230 formattable.setDouble(3);
231 TimeUnitAmount tma_double_3(formattable, TimeUnit::UTIMEUNIT_DAY, status);
232 if (!assertSuccess("TimeUnitAmount(formattable...)", status)) return;
234 TimeUnitAmount tma(2, TimeUnit::UTIMEUNIT_DAY, status);
235 if (!assertSuccess("TimeUnitAmount(number...)", status)) return;
237 TimeUnitAmount tma_h(2, TimeUnit::UTIMEUNIT_HOUR, status);
238 if (!assertSuccess("TimeUnitAmount(number...)", status)) return;
240 TimeUnitAmount second(tma);
241 TimeUnitAmount third_tma = tma;
242 TimeUnitAmount* fourth_tma = (TimeUnitAmount*)tma.clone();
244 assertTrue("orig and copy are equal", (second == tma));
245 assertTrue("clone and assigned are equal", (third_tma == *fourth_tma));
246 assertTrue("different if number diff", (tma_double != tma_double_3));
247 assertTrue("different if number type diff", (tma_double != tma_long));
248 assertTrue("different if time unit diff", (tma != tma_h));
249 assertTrue("same even different constructor", (tma_double == tma));
251 assertTrue("getTimeUnitField", (tma.getTimeUnitField() == TimeUnit::UTIMEUNIT_DAY));
254 //================= TimeUnitFormat =================
256 TimeUnitFormat* tmf_en = new TimeUnitFormat(Locale("en"), status);
257 if (!assertSuccess("TimeUnitFormat(en...)", status, TRUE)) return;
258 TimeUnitFormat tmf_fr(Locale("fr"), status);
259 if (!assertSuccess("TimeUnitFormat(fr...)", status)) return;
261 assertTrue("TimeUnitFormat: en and fr diff", (*tmf_en != tmf_fr));
263 TimeUnitFormat tmf_assign = *tmf_en;
264 assertTrue("TimeUnitFormat: orig and assign are equal", (*tmf_en == tmf_assign));
266 TimeUnitFormat tmf_copy(tmf_fr);
267 assertTrue("TimeUnitFormat: orig and copy are equal", (tmf_fr == tmf_copy));
269 TimeUnitFormat* tmf_clone = (TimeUnitFormat*)tmf_en->clone();
270 assertTrue("TimeUnitFormat: orig and clone are equal", (*tmf_en == *tmf_clone));
273 tmf_en->setLocale(Locale("fr"), status);
274 if (!assertSuccess("setLocale(fr...)", status)) return;
276 NumberFormat* numberFmt = NumberFormat::createInstance(
277 Locale("fr"), status);
278 if (!assertSuccess("NumberFormat::createInstance()", status)) return;
279 tmf_en->setNumberFormat(*numberFmt, status);
280 if (!assertSuccess("setNumberFormat(en...)", status)) return;
281 assertTrue("TimeUnitFormat: setLocale", (*tmf_en == tmf_fr));
285 TimeUnitFormat* en_long = new TimeUnitFormat(Locale("en"), UTMUTFMT_FULL_STYLE, status);
286 if (!assertSuccess("TimeUnitFormat(en...)", status)) return;
289 TimeUnitFormat* en_short = new TimeUnitFormat(Locale("en"), UTMUTFMT_ABBREVIATED_STYLE, status);
290 if (!assertSuccess("TimeUnitFormat(en...)", status)) return;
293 TimeUnitFormat* format = new TimeUnitFormat(status);
294 format->setLocale(Locale("zh"), status);
295 format->setNumberFormat(*numberFmt, status);
296 if (!assertSuccess("TimeUnitFormat(en...)", status)) return;
302 * Tests for Greek Language.
303 * This tests that requests for short unit names correctly fall back
304 * to long unit names for a locale where the locale data does not
305 * provide short unit names. As of CLDR 1.9, Greek is one such language.
307 void TimeUnitTest::testGreekWithFallback() {
308 UErrorCode status = U_ZERO_ERROR;
310 const char* locales[] = {"el-GR", "el"};
311 TimeUnit::UTimeUnitFields tunits[] = {TimeUnit::UTIMEUNIT_SECOND, TimeUnit::UTIMEUNIT_MINUTE, TimeUnit::UTIMEUNIT_HOUR, TimeUnit::UTIMEUNIT_DAY, TimeUnit::UTIMEUNIT_MONTH, TimeUnit::UTIMEUNIT_YEAR};
312 UTimeUnitFormatStyle styles[] = {UTMUTFMT_FULL_STYLE, UTMUTFMT_ABBREVIATED_STYLE};
313 const int numbers[] = {1, 7};
315 const UChar oneSecond[] = {0x0031, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x03b5, 0x03c1, 0x03cc, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03bf, 0};
316 const UChar oneSecondShort[] = {0x0031, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x002e, 0};
317 const UChar oneMinute[] = {0x0031, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03cc, 0};
318 const UChar oneMinuteShort[] = {0x0031, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x002e, 0};
319 const UChar oneHour[] = {0x0031, 0x0020, 0x03ce, 0x03c1, 0x03b1, 0};
320 const UChar oneDay[] = {0x0031, 0x0020, 0x03b7, 0x03bc, 0x03ad, 0x03c1, 0x03b1, 0};
321 const UChar oneMonth[] = {0x0031, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x03b1, 0x03c2, 0};
322 const UChar oneMonthShort[] = {0x0031, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x002e, 0};
323 const UChar oneYear[] = {0x0031, 0x0020, 0x03ad, 0x03c4, 0x03bf, 0x03c2, 0};
324 const UChar oneYearShort[] = {0x0031, 0x0020, 0x03ad, 0x03c4, 0x002e, 0};
325 const UChar sevenSeconds[] = {0x0037, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x03b5, 0x03c1, 0x03cc, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03b1, 0};
326 const UChar sevenSecondsShort[] = {0x0037, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x002e, 0};
327 const UChar sevenMinutes[] = {0x0037, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03ac, 0};
328 const UChar sevenMinutesShort[] = {0x0037, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x002e, 0};
329 const UChar sevenHours[] = {0x0037, 0x0020, 0x03ce, 0x03c1, 0x03b5, 0x03c2, 0};
330 const UChar sevenHoursShort[] = {0x0037, 0x0020, 0x03ce, 0x03c1, 0x002e, 0};
331 const UChar sevenDays[] = {0x0037, 0x0020, 0x03b7, 0x03bc, 0x03ad, 0x03c1, 0x03b5, 0x03c2, 0};
332 const UChar sevenMonths[] = {0x0037, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x03b5, 0x3c2, 0};
333 const UChar sevenMonthsShort[] = {0x0037, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x002e, 0};
334 const UChar sevenYears[] = {0x0037, 0x0020, 0x03ad, 0x03c4, 0x03b7, 0};
335 const UChar sevenYearsShort[] = {0x0037, 0x0020, 0x03ad, 0x03c4, 0x002e, 0};
337 const UnicodeString oneSecondStr(oneSecond);
338 const UnicodeString oneSecondShortStr(oneSecondShort);
339 const UnicodeString oneMinuteStr(oneMinute);
340 const UnicodeString oneMinuteShortStr(oneMinuteShort);
341 const UnicodeString oneHourStr(oneHour);
342 const UnicodeString oneDayStr(oneDay);
343 const UnicodeString oneMonthStr(oneMonth);
344 const UnicodeString oneMonthShortStr(oneMonthShort);
345 const UnicodeString oneYearStr(oneYear);
346 const UnicodeString oneYearShortStr(oneYearShort);
347 const UnicodeString sevenSecondsStr(sevenSeconds);
348 const UnicodeString sevenSecondsShortStr(sevenSecondsShort);
349 const UnicodeString sevenMinutesStr(sevenMinutes);
350 const UnicodeString sevenMinutesShortStr(sevenMinutesShort);
351 const UnicodeString sevenHoursStr(sevenHours);
352 const UnicodeString sevenHoursShortStr(sevenHoursShort);
353 const UnicodeString sevenDaysStr(sevenDays);
354 const UnicodeString sevenMonthsStr(sevenMonths);
355 const UnicodeString sevenMonthsShortStr(sevenMonthsShort);
356 const UnicodeString sevenYearsStr(sevenYears);
357 const UnicodeString sevenYearsShortStr(sevenYearsShort);
359 const UnicodeString expected[] = {
360 oneSecondStr, oneMinuteStr, oneHourStr, oneDayStr, oneMonthStr, oneYearStr,
361 oneSecondShortStr, oneMinuteShortStr, oneHourStr, oneDayStr, oneMonthShortStr, oneYearShortStr,
362 sevenSecondsStr, sevenMinutesStr, sevenHoursStr, sevenDaysStr, sevenMonthsStr, sevenYearsStr,
363 sevenSecondsShortStr, sevenMinutesShortStr, sevenHoursShortStr, sevenDaysStr, sevenMonthsShortStr, sevenYearsShortStr,
365 oneSecondStr, oneMinuteStr, oneHourStr, oneDayStr, oneMonthStr, oneYearStr,
366 oneSecondShortStr, oneMinuteShortStr, oneHourStr, oneDayStr, oneMonthShortStr, oneYearShortStr,
367 sevenSecondsStr, sevenMinutesStr, sevenHoursStr, sevenDaysStr, sevenMonthsStr, sevenYearsStr,
368 sevenSecondsShortStr, sevenMinutesShortStr, sevenHoursShortStr, sevenDaysStr, sevenMonthsShortStr, sevenYearsShortStr};
371 for ( unsigned int locIndex = 0;
372 locIndex < UPRV_LENGTHOF(locales);
375 Locale l = Locale::createFromName(locales[locIndex]);
377 for ( unsigned int numberIndex = 0;
378 numberIndex < UPRV_LENGTHOF(numbers);
381 for ( unsigned int styleIndex = 0;
382 styleIndex < UPRV_LENGTHOF(styles);
385 for ( unsigned int unitIndex = 0;
386 unitIndex < UPRV_LENGTHOF(tunits);
389 TimeUnitAmount *tamt = new TimeUnitAmount(numbers[numberIndex], tunits[unitIndex], status);
390 if (U_FAILURE(status)) {
391 dataerrln("generating TimeUnitAmount Object failed.");
393 std::cout << "Failed to get TimeUnitAmount for " << tunits[unitIndex] << "\n";
398 TimeUnitFormat *tfmt = new TimeUnitFormat(l, styles[styleIndex], status);
399 if (U_FAILURE(status)) {
400 dataerrln("generating TimeUnitAmount Object failed.");
402 std::cout << "Failed to get TimeUnitFormat for " << locales[locIndex] << "\n";
410 fmt.adoptObject(tamt);
411 str = ((Format *)tfmt)->format(fmt, str, status);
412 if (!assertSuccess("formatting relative time failed", status)) {
415 std::cout << "Failed to format" << "\n";
421 char tmp[128]; //output
422 char tmp1[128]; //expected
424 u_strToUTF8(tmp, 128, &len, str.getTerminatedBuffer(), str.length(), &status);
425 u_strToUTF8(tmp1, 128, &len, expected[counter].unescape().getTerminatedBuffer(), expected[counter].unescape().length(), &status);
426 std::cout << "Formatted string : " << tmp << " expected : " << tmp1 << "\n";
428 if (!assertEquals("formatted time string is not expected, locale: " + UnicodeString(locales[locIndex]) + " style: " + (int)styles[styleIndex] + " units: " + (int)tunits[unitIndex], expected[counter], str)) {
443 void TimeUnitTest::testGreekWithSanitization() {
445 UErrorCode status = U_ZERO_ERROR;
447 NumberFormat* numberFmt = NumberFormat::createInstance(Locale("el"), status);
448 if (!assertSuccess("NumberFormat::createInstance for el locale", status, TRUE)) return;
449 numberFmt->setMaximumFractionDigits(1);
451 TimeUnitFormat* timeUnitFormat = new TimeUnitFormat(elLoc, status);
452 if (!assertSuccess("TimeUnitFormat::TimeUnitFormat for el locale", status)) return;
454 timeUnitFormat->setNumberFormat(*numberFmt, status);
457 delete timeUnitFormat;
460 void TimeUnitTest::test10219Plurals() {
461 Locale usLocale("en_US");
462 double values[2] = {1.588, 1.011};
463 UnicodeString expected[2][3] = {
464 {"1 minute", "1.5 minutes", "1.58 minutes"},
465 {"1 minute", "1.0 minutes", "1.01 minutes"}
467 UErrorCode status = U_ZERO_ERROR;
468 TimeUnitFormat tuf(usLocale, status);
469 if (U_FAILURE(status)) {
470 dataerrln("generating TimeUnitFormat Object failed: %s", u_errorName(status));
473 LocalPointer<DecimalFormat> nf((DecimalFormat *) NumberFormat::createInstance(usLocale, status));
474 if (U_FAILURE(status)) {
475 dataerrln("generating NumberFormat Object failed: %s", u_errorName(status));
478 for (int32_t j = 0; j < UPRV_LENGTHOF(values); ++j) {
479 for (int32_t i = 0; i < UPRV_LENGTHOF(expected[j]); ++i) {
480 nf->setMinimumFractionDigits(i);
481 nf->setMaximumFractionDigits(i);
482 nf->setRoundingMode(DecimalFormat::kRoundDown);
483 tuf.setNumberFormat(*nf, status);
484 if (U_FAILURE(status)) {
485 dataerrln("setting NumberFormat failed: %s", u_errorName(status));
488 UnicodeString actual;
490 LocalPointer<TimeUnitAmount> tamt(
491 new TimeUnitAmount(values[j], TimeUnit::UTIMEUNIT_MINUTE, status), status);
492 if (U_FAILURE(status)) {
493 dataerrln("generating TimeUnitAmount Object failed: %s", u_errorName(status));
496 fmt.adoptObject(tamt.orphan());
497 tuf.format(fmt, actual, status);
498 if (U_FAILURE(status)) {
499 dataerrln("Actual formatting failed: %s", u_errorName(status));
502 if (expected[j][i] != actual) {
503 errln("Expected " + expected[j][i] + ", got " + actual);
511 UnicodeString formattedString = "1 minutes";
512 tuf.parseObject(formattedString, result, pos);
513 if (formattedString.length() != pos.getIndex()) {
514 errln("Expect parsing to go all the way to the end of the string.");
518 void TimeUnitTest::TestBritishShortHourFallback() {
519 // See ticket #11986 "incomplete fallback in MeasureFormat".
520 UErrorCode status = U_ZERO_ERROR;
521 Formattable oneHour(new TimeUnitAmount(1, TimeUnit::UTIMEUNIT_HOUR, status));
522 Locale en_GB("en_GB");
523 TimeUnitFormat formatter(en_GB, UTMUTFMT_ABBREVIATED_STYLE, status);
524 UnicodeString result;
525 formatter.format(oneHour, result, status);
526 assertSuccess("TestBritishShortHourFallback()", status);
527 assertEquals("TestBritishShortHourFallback()", UNICODE_STRING_SIMPLE("1 hr"), result, TRUE);