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 U_NAMESPACE_USE 29 30 31 static const URelativeDateTimeUnit kTimeUnitToRelativeDateTime[] = { 32 UDAT_REL_UNIT_YEAR, 33 UDAT_REL_UNIT_MONTH, 34 UDAT_REL_UNIT_WEEK, 35 UDAT_REL_UNIT_DAY, 36 UDAT_REL_UNIT_HOUR, 37 UDAT_REL_UNIT_MINUTE, 38 UDAT_REL_UNIT_SECOND, 39 }; 40 41 42 static const UCalendarDateFields kTimeUnitToICUDateField[] = { 43 UCAL_YEAR, 44 UCAL_MONTH, 45 UCAL_WEEK_OF_MONTH, 46 UCAL_DAY_OF_WEEK, 47 UCAL_HOUR_OF_DAY, 48 UCAL_MINUTE, 49 UCAL_SECOND, 50 }; 51 52 53 BRelativeDateTimeFormat::BRelativeDateTimeFormat() 54 : Inherited() 55 { 56 Locale icuLocale(fLanguage.Code()); 57 UErrorCode icuStatus = U_ZERO_ERROR; 58 59 fFormatter = new RelativeDateTimeFormatter(icuLocale, icuStatus); 60 if (fFormatter == NULL) { 61 fInitStatus = B_NO_MEMORY; 62 return; 63 } 64 65 fCalendar = new GregorianCalendar(icuStatus); 66 if (fCalendar == NULL) { 67 fInitStatus = B_NO_MEMORY; 68 return; 69 } 70 71 if (!U_SUCCESS(icuStatus)) 72 fInitStatus = B_ERROR; 73 } 74 75 76 BRelativeDateTimeFormat::BRelativeDateTimeFormat(const BLanguage& language, 77 const BFormattingConventions& conventions) 78 : Inherited(language, conventions) 79 { 80 Locale icuLocale(fLanguage.Code()); 81 UErrorCode icuStatus = U_ZERO_ERROR; 82 83 fFormatter = new RelativeDateTimeFormatter(icuLocale, icuStatus); 84 if (fFormatter == NULL) { 85 fInitStatus = B_NO_MEMORY; 86 return; 87 } 88 89 fCalendar = new GregorianCalendar(icuStatus); 90 if (fCalendar == NULL) { 91 fInitStatus = B_NO_MEMORY; 92 return; 93 } 94 95 if (!U_SUCCESS(icuStatus)) 96 fInitStatus = B_ERROR; 97 } 98 99 100 BRelativeDateTimeFormat::BRelativeDateTimeFormat(const BRelativeDateTimeFormat& other) 101 : Inherited(other), 102 fFormatter(other.fFormatter != NULL 103 ? new RelativeDateTimeFormatter(*other.fFormatter) : NULL), 104 fCalendar(other.fCalendar != NULL 105 ? new GregorianCalendar(*other.fCalendar) : NULL) 106 { 107 if ((fFormatter == NULL && other.fFormatter != NULL) 108 || (fCalendar == NULL && other.fCalendar != NULL)) 109 fInitStatus = B_NO_MEMORY; 110 } 111 112 113 BRelativeDateTimeFormat::~BRelativeDateTimeFormat() 114 { 115 delete fFormatter; 116 delete fCalendar; 117 } 118 119 120 status_t 121 BRelativeDateTimeFormat::Format(BString& string, 122 const time_t timeValue) const 123 { 124 if (fFormatter == NULL) 125 return B_NO_INIT; 126 127 time_t currentTime = time(NULL); 128 129 UErrorCode icuStatus = U_ZERO_ERROR; 130 fCalendar->setTime((UDate)currentTime * 1000, icuStatus); 131 if (!U_SUCCESS(icuStatus)) 132 return B_ERROR; 133 134 UDate UTimeValue = (UDate)timeValue * 1000; 135 136 int delta = 0; 137 int offset = 1; 138 URelativeDateTimeUnit unit = UDAT_REL_UNIT_SECOND; 139 140 for (int timeUnit = 0; timeUnit <= B_TIME_UNIT_LAST; ++timeUnit) { 141 delta = fCalendar->fieldDifference(UTimeValue, 142 kTimeUnitToICUDateField[timeUnit], icuStatus); 143 144 if (!U_SUCCESS(icuStatus)) 145 return B_ERROR; 146 147 if (abs(delta) >= offset) { 148 unit = kTimeUnitToRelativeDateTime[timeUnit]; 149 break; 150 } 151 } 152 153 UnicodeString unicodeResult; 154 155 // Note: icu::RelativeDateTimeFormatter::formatNumeric() is a part of ICU Draft API 156 // and may be changed in the future versions and was introduced in ICU 57. 157 fFormatter->formatNumeric(delta, unit, unicodeResult, icuStatus); 158 159 if (!U_SUCCESS(icuStatus)) 160 return B_ERROR; 161 162 BStringByteSink byteSink(&string); 163 unicodeResult.toUTF8(byteSink); 164 165 return B_OK; 166 } 167