|
32 | 32 | #include "unicode/stringpiece.h"
|
33 | 33 | #include "unicode/timezone.h"
|
34 | 34 | #include "unicode/ucol.h"
|
| 35 | +#include "icu-helpers.hpp" |
35 | 36 |
|
36 | 37 | #include <cassert>
|
37 | 38 |
|
@@ -210,41 +211,63 @@ static ScalarFunction GetICUCollateFunction(const string &collation, const strin
|
210 | 211 | return result;
|
211 | 212 | }
|
212 | 213 |
|
213 |
| -static void SetICUTimeZone(ClientContext &context, SetScope scope, Value ¶meter) { |
214 |
| - auto str = StringValue::Get(parameter); |
215 |
| - icu::StringPiece utf8(str); |
216 |
| - const auto uid = icu::UnicodeString::fromUTF8(utf8); |
| 214 | +unique_ptr<icu::TimeZone> GetTimeZoneInternal(string &tz_str, vector<string> &candidates) { |
| 215 | + icu::StringPiece tz_name_utf8(tz_str); |
| 216 | + const auto uid = icu::UnicodeString::fromUTF8(tz_name_utf8); |
217 | 217 | duckdb::unique_ptr<icu::TimeZone> tz(icu::TimeZone::createTimeZone(uid));
|
218 | 218 | if (*tz != icu::TimeZone::getUnknown()) {
|
219 |
| - return; |
| 219 | + return tz; |
220 | 220 | }
|
221 | 221 |
|
222 |
| - // Try to be friendlier |
223 |
| - // Go through all the zone names and look for a case insensitive match |
224 |
| - // If we don't find one, make a suggestion |
| 222 | + // Try to be friendlier |
| 223 | + // Go through all the zone names and look for a case insensitive match |
| 224 | + // If we don't find one, make a suggestion |
| 225 | + // FIXME: this is very inefficient |
225 | 226 | UErrorCode status = U_ZERO_ERROR;
|
226 | 227 | duckdb::unique_ptr<icu::Calendar> calendar(icu::Calendar::createInstance(status));
|
227 | 228 | duckdb::unique_ptr<icu::StringEnumeration> tzs(icu::TimeZone::createEnumeration());
|
228 |
| - vector<string> candidates; |
229 | 229 | for (;;) {
|
230 | 230 | auto long_id = tzs->snext(status);
|
231 | 231 | if (U_FAILURE(status) || !long_id) {
|
232 | 232 | break;
|
233 | 233 | }
|
234 |
| - std::string utf8; |
235 |
| - long_id->toUTF8String(utf8); |
236 |
| - if (StringUtil::CIEquals(utf8, str)) { |
237 |
| - parameter = Value(utf8); |
238 |
| - return; |
| 234 | + std::string candidate_tz_name; |
| 235 | + long_id->toUTF8String(candidate_tz_name); |
| 236 | + if (StringUtil::CIEquals(candidate_tz_name, tz_str)) { |
| 237 | + // case insensitive match - return this timezone instead |
| 238 | + tz_str = candidate_tz_name; |
| 239 | + icu::StringPiece utf8(tz_str); |
| 240 | + const auto tz_unicode_str = icu::UnicodeString::fromUTF8(utf8); |
| 241 | + duckdb::unique_ptr<icu::TimeZone> insensitive_tz(icu::TimeZone::createTimeZone(tz_unicode_str)); |
| 242 | + return insensitive_tz; |
239 | 243 | }
|
240 | 244 |
|
241 |
| - candidates.emplace_back(utf8); |
| 245 | + candidates.emplace_back(candidate_tz_name); |
242 | 246 | }
|
| 247 | + return nullptr; |
| 248 | +} |
243 | 249 |
|
| 250 | +unique_ptr<icu::TimeZone> ICUHelpers::TryGetTimeZone(string &tz_str) { |
| 251 | + vector<string> candidates; |
| 252 | + return GetTimeZoneInternal(tz_str, candidates); |
| 253 | +} |
| 254 | + |
| 255 | +unique_ptr<icu::TimeZone> ICUHelpers::GetTimeZone(string &tz_str) { |
| 256 | + vector<string> candidates; |
| 257 | + auto tz = GetTimeZoneInternal(tz_str, candidates); |
| 258 | + if (tz) { |
| 259 | + return tz; |
| 260 | + } |
244 | 261 | string candidate_str =
|
245 |
| - StringUtil::CandidatesMessage(StringUtil::TopNJaroWinkler(candidates, str), "Candidate time zones"); |
| 262 | + StringUtil::CandidatesMessage(StringUtil::TopNJaroWinkler(candidates, tz_str), "Candidate time zones"); |
| 263 | + |
| 264 | + throw NotImplementedException("Unknown TimeZone '%s'!\n%s", tz_str, candidate_str); |
| 265 | +} |
246 | 266 |
|
247 |
| - throw NotImplementedException("Unknown TimeZone '%s'!\n%s", str, candidate_str); |
| 267 | +static void SetICUTimeZone(ClientContext &context, SetScope scope, Value ¶meter) { |
| 268 | + auto tz_str = StringValue::Get(parameter); |
| 269 | + ICUHelpers::GetTimeZone(tz_str); |
| 270 | + parameter = Value(tz_str); |
248 | 271 | }
|
249 | 272 |
|
250 | 273 | struct ICUCalendarData : public GlobalTableFunctionState {
|
|
0 commit comments