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