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 27U_NAMESPACE_USE 28 29 30BTimeFormat::BTimeFormat() 31 : BFormat() 32{ 33} 34 35 36BTimeFormat::BTimeFormat(const BLanguage& language, 37 const BFormattingConventions& conventions) 38 : BFormat(language, conventions) 39{ 40} 41 42 43BTimeFormat::BTimeFormat(const BTimeFormat &other) 44 : BFormat(other) 45{ 46} 47 48 49BTimeFormat::~BTimeFormat() 50{ 51} 52 53 54void 55BTimeFormat::SetTimeFormat(BTimeFormatStyle style, 56 const BString& format) 57{ 58 fConventions.SetExplicitTimeFormat(style, format); 59} 60 61 62// #pragma mark - Formatting 63 64 65ssize_t 66BTimeFormat::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 86status_t 87BTimeFormat::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 113status_t 114BTimeFormat::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 153status_t 154BTimeFormat::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 209status_t 210BTimeFormat::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 230DateFormat* 231BTimeFormat::_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