1 /* 2 * Copyright 2010-2014, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Oliver Tappe <zooey@hirschkaefer.de> 7 */ 8 9 #include <unicode/uversion.h> 10 #include <TimeFormat.h> 11 12 #include <AutoDeleter.h> 13 #include <Autolock.h> 14 #include <DateTime.h> 15 #include <FormattingConventionsPrivate.h> 16 #include <LanguagePrivate.h> 17 #include <TimeZone.h> 18 19 #include <ICUWrapper.h> 20 21 #include <unicode/datefmt.h> 22 #include <unicode/smpdtfmt.h> 23 24 #include <vector> 25 26 27 BTimeFormat::BTimeFormat() 28 : BFormat() 29 { 30 } 31 32 33 BTimeFormat::BTimeFormat(const BLanguage& language, 34 const BFormattingConventions& conventions) 35 : BFormat(language, conventions) 36 { 37 } 38 39 40 BTimeFormat::BTimeFormat(const BTimeFormat &other) 41 : BFormat(other) 42 { 43 } 44 45 46 BTimeFormat::~BTimeFormat() 47 { 48 } 49 50 51 void 52 BTimeFormat::SetTimeFormat(BTimeFormatStyle style, 53 const BString& format) 54 { 55 fConventions.SetExplicitTimeFormat(style, format); 56 } 57 58 59 // #pragma mark - Formatting 60 61 62 ssize_t 63 BTimeFormat::Format(char* string, size_t maxSize, time_t time, 64 BTimeFormatStyle style) const 65 { 66 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 67 if (timeFormatter.Get() == NULL) 68 return B_NO_MEMORY; 69 70 UnicodeString icuString; 71 timeFormatter->format((UDate)time * 1000, icuString); 72 73 CheckedArrayByteSink stringConverter(string, maxSize); 74 icuString.toUTF8(stringConverter); 75 76 if (stringConverter.Overflowed()) 77 return B_BAD_VALUE; 78 79 return stringConverter.NumberOfBytesWritten(); 80 } 81 82 83 status_t 84 BTimeFormat::Format(BString& string, const time_t time, 85 const BTimeFormatStyle style, const BTimeZone* timeZone) const 86 { 87 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 88 if (timeFormatter.Get() == NULL) 89 return B_NO_MEMORY; 90 91 if (timeZone != NULL) { 92 ObjectDeleter<TimeZone> icuTimeZone( 93 TimeZone::createTimeZone(timeZone->ID().String())); 94 if (icuTimeZone.Get() == NULL) 95 return B_NO_MEMORY; 96 timeFormatter->setTimeZone(*icuTimeZone.Get()); 97 } 98 99 UnicodeString icuString; 100 timeFormatter->format((UDate)time * 1000, icuString); 101 102 string.Truncate(0); 103 BStringByteSink stringConverter(&string); 104 icuString.toUTF8(stringConverter); 105 106 return B_OK; 107 } 108 109 110 status_t 111 BTimeFormat::Format(BString& string, int*& fieldPositions, int& fieldCount, 112 time_t time, BTimeFormatStyle style) const 113 { 114 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 115 if (timeFormatter.Get() == NULL) 116 return B_NO_MEMORY; 117 118 fieldPositions = NULL; 119 UErrorCode error = U_ZERO_ERROR; 120 icu::FieldPositionIterator positionIterator; 121 UnicodeString icuString; 122 timeFormatter->format((UDate)time * 1000, icuString, &positionIterator, 123 error); 124 125 if (error != U_ZERO_ERROR) 126 return B_BAD_VALUE; 127 128 icu::FieldPosition field; 129 std::vector<int> fieldPosStorage; 130 fieldCount = 0; 131 while (positionIterator.next(field)) { 132 fieldPosStorage.push_back(field.getBeginIndex()); 133 fieldPosStorage.push_back(field.getEndIndex()); 134 fieldCount += 2; 135 } 136 137 fieldPositions = (int*) malloc(fieldCount * sizeof(int)); 138 139 for (int i = 0 ; i < fieldCount ; i++ ) 140 fieldPositions[i] = fieldPosStorage[i]; 141 142 string.Truncate(0); 143 BStringByteSink stringConverter(&string); 144 icuString.toUTF8(stringConverter); 145 146 return B_OK; 147 } 148 149 150 status_t 151 BTimeFormat::GetTimeFields(BDateElement*& fields, int& fieldCount, 152 BTimeFormatStyle style) const 153 { 154 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 155 if (timeFormatter.Get() == NULL) 156 return B_NO_MEMORY; 157 158 fields = NULL; 159 UErrorCode error = U_ZERO_ERROR; 160 icu::FieldPositionIterator positionIterator; 161 UnicodeString icuString; 162 time_t now; 163 timeFormatter->format((UDate)time(&now) * 1000, icuString, 164 &positionIterator, error); 165 166 if (error != U_ZERO_ERROR) 167 return B_BAD_VALUE; 168 169 icu::FieldPosition field; 170 std::vector<int> fieldPosStorage; 171 fieldCount = 0; 172 while (positionIterator.next(field)) { 173 fieldPosStorage.push_back(field.getField()); 174 fieldCount ++; 175 } 176 177 fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement)); 178 179 for (int i = 0 ; i < fieldCount ; i++ ) { 180 switch (fieldPosStorage[i]) { 181 case UDAT_HOUR_OF_DAY1_FIELD: 182 case UDAT_HOUR_OF_DAY0_FIELD: 183 case UDAT_HOUR1_FIELD: 184 case UDAT_HOUR0_FIELD: 185 fields[i] = B_DATE_ELEMENT_HOUR; 186 break; 187 case UDAT_MINUTE_FIELD: 188 fields[i] = B_DATE_ELEMENT_MINUTE; 189 break; 190 case UDAT_SECOND_FIELD: 191 fields[i] = B_DATE_ELEMENT_SECOND; 192 break; 193 case UDAT_AM_PM_FIELD: 194 fields[i] = B_DATE_ELEMENT_AM_PM; 195 break; 196 default: 197 fields[i] = B_DATE_ELEMENT_INVALID; 198 break; 199 } 200 } 201 202 return B_OK; 203 } 204 205 206 status_t 207 BTimeFormat::Parse(BString source, BTimeFormatStyle style, BTime& output) 208 { 209 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(style)); 210 if (timeFormatter.Get() == NULL) 211 return B_NO_MEMORY; 212 213 // If no timezone is specified in the time string, assume GMT 214 timeFormatter->setTimeZone(*icu::TimeZone::getGMT()); 215 216 ParsePosition p(0); 217 UDate date = timeFormatter->parse(UnicodeString::fromUTF8(source.String()), 218 p); 219 220 output.SetTime(0, 0, 0); 221 output.AddMilliseconds(date); 222 223 return B_OK; 224 } 225 226 227 DateFormat* 228 BTimeFormat::_CreateTimeFormatter(const BTimeFormatStyle style) const 229 { 230 Locale* icuLocale 231 = fConventions.UseStringsFromPreferredLanguage() 232 ? BLanguage::Private(&fLanguage).ICULocale() 233 : BFormattingConventions::Private(&fConventions).ICULocale(); 234 235 icu::DateFormat* timeFormatter 236 = icu::DateFormat::createTimeInstance(DateFormat::kShort, *icuLocale); 237 if (timeFormatter == NULL) 238 return NULL; 239 240 SimpleDateFormat* timeFormatterImpl 241 = static_cast<SimpleDateFormat*>(timeFormatter); 242 243 BString format; 244 fConventions.GetTimeFormat(style, format); 245 246 UnicodeString pattern(format.String()); 247 timeFormatterImpl->applyPattern(pattern); 248 249 return timeFormatter; 250 } 251