Skip to content

Commit

Permalink
Add support for z, zz, zzz in format_datetime (#11323)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #11323

This diff adds support for JODA's z, zz, zzz patterns (all equivalent) in Presto's
forma_datetime function.

This is used to format time zone abbreviations.

Differential Revision: D64774281
  • Loading branch information
Kevin Wilfong authored and facebook-github-bot committed Oct 22, 2024
1 parent 1f18e8f commit b59553f
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 13 deletions.
34 changes: 27 additions & 7 deletions velox/functions/lib/DateTimeFormatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1167,10 +1167,17 @@ uint32_t DateTimeFormatter::maxResultSize(const tz::TimeZone* timezone) const {
size += std::max((int)token.pattern.minRepresentDigits, 9);
break;
case DateTimeFormatSpecifier::TIMEZONE:
VELOX_NYI(
"Date format specifier is not yet implemented: {} ({})",
getSpecifierName(token.pattern.specifier),
token.pattern.minRepresentDigits);
if (token.pattern.minRepresentDigits <= 3) {
// The longest abbreviation according to here is 5, e.g. some time
// zones use the offset as the abbreviation, like +0530.
// https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
size += 5;
} else {
VELOX_NYI(
"Date format specifier is not yet implemented: {} ({})",
getSpecifierName(token.pattern.specifier),
token.pattern.minRepresentDigits);
}

break;
case DateTimeFormatSpecifier::TIMEZONE_OFFSET_ID:
Expand Down Expand Up @@ -1412,9 +1419,22 @@ int32_t DateTimeFormatter::format(
} break;

case DateTimeFormatSpecifier::TIMEZONE: {
// TODO: implement short name time zone, need a map from full name
// to short name
VELOX_UNSUPPORTED("time zone name is not yet supported");
VELOX_USER_CHECK_NOT_NULL(
timezone,
"The time zone cannot be formatted if it is not present.");
if (token.pattern.minRepresentDigits <= 3) {
const std::string& abbrev =
tz::locateZone(timezone->id())
->tz()
->get_info(date::local_seconds(
std::chrono::seconds(timestamp.getSeconds())))
.first.abbrev;
std::memcpy(result, abbrev.data(), abbrev.length());
result += abbrev.length();
} else {
// TODO: implement full name time zone
VELOX_NYI("full time zone name is not yet supported");
}
} break;

case DateTimeFormatSpecifier::TIMEZONE_OFFSET_ID: {
Expand Down
29 changes: 23 additions & 6 deletions velox/functions/prestosql/tests/DateTimeFunctionsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3269,6 +3269,24 @@ TEST_F(DateTimeFunctionsTest, formatDateTime) {
EXPECT_EQ("+05:30", formatDatetime(parseTimestamp("1970-01-01"), "ZZ"));
EXPECT_EQ("+0530", formatDatetime(parseTimestamp("1970-01-01"), "Z"));

EXPECT_EQ("IST", formatDatetime(parseTimestamp("1970-01-01"), "zzz"));
EXPECT_EQ("IST", formatDatetime(parseTimestamp("1970-01-01"), "zz"));
EXPECT_EQ("IST", formatDatetime(parseTimestamp("1970-01-01"), "z"));

// Test daylight savings.
setQueryTimeZone("America/Los_Angeles");
EXPECT_EQ("PST", formatDatetime(parseTimestamp("1970-01-01"), "z"));
EXPECT_EQ("PDT", formatDatetime(parseTimestamp("1970-10-01"), "z"));

// Test a long abbreviation.
setQueryTimeZone("Asia/Colombo");
EXPECT_EQ("+0530", formatDatetime(parseTimestamp("1970-10-01"), "z"));

setQueryTimeZone("Asia/Kolkata");
// We don't support more than 3 'z's yet.
EXPECT_THROW(
formatDatetime(parseTimestamp("1970-01-01"), "zzzz"), VeloxRuntimeError);

// Literal test cases.
EXPECT_EQ("hello", formatDatetime(parseTimestamp("1970-01-01"), "'hello'"));
EXPECT_EQ("'", formatDatetime(parseTimestamp("1970-01-01"), "''"));
Expand Down Expand Up @@ -3313,15 +3331,14 @@ TEST_F(DateTimeFunctionsTest, formatDateTime) {
EXPECT_THROW(
formatDatetime(parseTimestamp("1970-01-01"), "'abcd"), VeloxUserError);

// System errors for patterns we haven't implemented yet.
// Time zone name patterns aren't supported when there isn't a time zone
// available.
EXPECT_THROW(
formatDatetime(parseTimestamp("1970-01-01"), "z"), VeloxRuntimeError);
formatDatetime(parseTimestamp("1970-01-01"), "z"), VeloxUserError);
EXPECT_THROW(
formatDatetime(parseTimestamp("1970-01-01"), "zz"), VeloxRuntimeError);
formatDatetime(parseTimestamp("1970-01-01"), "zz"), VeloxUserError);
EXPECT_THROW(
formatDatetime(parseTimestamp("1970-01-01"), "zzz"), VeloxRuntimeError);
EXPECT_THROW(
formatDatetime(parseTimestamp("1970-01-01"), "zzzz"), VeloxRuntimeError);
formatDatetime(parseTimestamp("1970-01-01"), "zzz"), VeloxUserError);
}

TEST_F(DateTimeFunctionsTest, formatDateTimeTimezone) {
Expand Down

0 comments on commit b59553f

Please sign in to comment.