1 /* 2 * Copyright 2017, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Akshay Agarwal <agarwal.akshay.akshay8@gmail.com> 7 */ 8 9 10 #include <unicode/uversion.h> 11 #include <RelativeDateTimeFormat.h> 12 13 #include <stdlib.h> 14 #include <time.h> 15 16 #include <unicode/gregocal.h> 17 #include <unicode/reldatefmt.h> 18 #include <unicode/utypes.h> 19 20 #include <ICUWrapper.h> 21 22 #include <Language.h> 23 #include <Locale.h> 24 #include <LocaleRoster.h> 25 #include <TimeUnitFormat.h> 26 27 28 static const URelativeDateTimeUnit kTimeUnitToRelativeDateTime[] = { 29 UDAT_REL_UNIT_YEAR, 30 UDAT_REL_UNIT_MONTH, 31 UDAT_REL_UNIT_WEEK, 32 UDAT_REL_UNIT_DAY, 33 UDAT_REL_UNIT_HOUR, 34 UDAT_REL_UNIT_MINUTE, 35 UDAT_REL_UNIT_SECOND, 36 }; 37 38 39 static const UCalendarDateFields kTimeUnitToICUDateField[] = { 40 UCAL_YEAR, 41 UCAL_MONTH, 42 UCAL_WEEK_OF_MONTH, 43 UCAL_DAY_OF_WEEK, 44 UCAL_HOUR_OF_DAY, 45 UCAL_MINUTE, 46 UCAL_SECOND, 47 }; 48 49 50 BRelativeDateTimeFormat::BRelativeDateTimeFormat() 51 : Inherited() 52 { 53 Locale icuLocale(fLanguage.Code()); 54 UErrorCode icuStatus = U_ZERO_ERROR; 55 56 fFormatter = new RelativeDateTimeFormatter(icuLocale, icuStatus); 57 if (fFormatter == NULL) { 58 fInitStatus = B_NO_MEMORY; 59 return; 60 } 61 62 fCalendar = new GregorianCalendar(icuStatus); 63 if (fCalendar == NULL) { 64 fInitStatus = B_NO_MEMORY; 65 return; 66 } 67 68 if (!U_SUCCESS(icuStatus)) 69 fInitStatus = B_ERROR; 70 } 71 72 73 BRelativeDateTimeFormat::BRelativeDateTimeFormat(const BLanguage& language, 74 const BFormattingConventions& conventions) 75 : Inherited(language, conventions) 76 { 77 Locale icuLocale(fLanguage.Code()); 78 UErrorCode icuStatus = U_ZERO_ERROR; 79 80 fFormatter = new RelativeDateTimeFormatter(icuLocale, icuStatus); 81 if (fFormatter == NULL) { 82 fInitStatus = B_NO_MEMORY; 83 return; 84 } 85 86 fCalendar = new GregorianCalendar(icuStatus); 87 if (fCalendar == NULL) { 88 fInitStatus = B_NO_MEMORY; 89 return; 90 } 91 92 if (!U_SUCCESS(icuStatus)) 93 fInitStatus = B_ERROR; 94 } 95 96 97 BRelativeDateTimeFormat::BRelativeDateTimeFormat(const BRelativeDateTimeFormat& other) 98 : Inherited(other), 99 fFormatter(other.fFormatter != NULL 100 ? new RelativeDateTimeFormatter(*other.fFormatter) : NULL), 101 fCalendar(other.fCalendar != NULL 102 ? new GregorianCalendar(*other.fCalendar) : NULL) 103 { 104 if ((fFormatter == NULL && other.fFormatter != NULL) 105 || (fCalendar == NULL && other.fCalendar != NULL)) 106 fInitStatus = B_NO_MEMORY; 107 } 108 109 110 BRelativeDateTimeFormat::~BRelativeDateTimeFormat() 111 { 112 delete fFormatter; 113 delete fCalendar; 114 } 115 116 117 status_t 118 BRelativeDateTimeFormat::Format(BString& string, 119 const time_t timeValue) const 120 { 121 if (fFormatter == NULL) 122 return B_NO_INIT; 123 124 time_t currentTime = time(NULL); 125 126 UErrorCode icuStatus = U_ZERO_ERROR; 127 fCalendar->setTime((UDate)currentTime * 1000, icuStatus); 128 if (!U_SUCCESS(icuStatus)) 129 return B_ERROR; 130 131 UDate UTimeValue = (UDate)timeValue * 1000; 132 133 int delta = 0; 134 int offset = 1; 135 URelativeDateTimeUnit unit = UDAT_REL_UNIT_SECOND; 136 137 for (int timeUnit = 0; timeUnit <= B_TIME_UNIT_LAST; ++timeUnit) { 138 delta = fCalendar->fieldDifference(UTimeValue, 139 kTimeUnitToICUDateField[timeUnit], icuStatus); 140 141 if (!U_SUCCESS(icuStatus)) 142 return B_ERROR; 143 144 if (abs(delta) >= offset) { 145 unit = kTimeUnitToRelativeDateTime[timeUnit]; 146 break; 147 } 148 } 149 150 UnicodeString unicodeResult; 151 152 // Note: icu::RelativeDateTimeFormatter::formatNumeric() is a part of ICU Draft API 153 // and may be changed in the future versions and was introduced in ICU 57. 154 fFormatter->formatNumeric(delta, unit, unicodeResult, icuStatus); 155 156 if (!U_SUCCESS(icuStatus)) 157 return B_ERROR; 158 159 BStringByteSink byteSink(&string); 160 unicodeResult.toUTF8(byteSink); 161 162 return B_OK; 163 } 164