in velox/functions/lib/DateTimeFormatter.cpp [132:305]
std::string DateTimeFormatter::format(
const Timestamp& timestamp,
const date::time_zone* timezone) const {
const std::chrono::
time_point<std::chrono::system_clock, std::chrono::milliseconds>
timePoint(std::chrono::milliseconds(timestamp.toMillis()));
validateTimePoint(timePoint);
const auto daysTimePoint = date::floor<date::days>(timePoint);
const auto durationInTheDay = date::make_time(timePoint - daysTimePoint);
const date::year_month_day calDate(daysTimePoint);
const date::weekday weekday(daysTimePoint);
std::string result;
for (auto& token : tokens_) {
if (token.type == DateTimeToken::Type::kLiteral) {
result += token.literal;
} else {
switch (token.pattern.specifier) {
case DateTimeFormatSpecifier::ERA:
result += static_cast<signed>(calDate.year()) >= 0 ? "AD" : "BC";
break;
case DateTimeFormatSpecifier::CENTURY_OF_ERA: {
auto year = static_cast<signed>(calDate.year());
if (year < 0) {
VELOX_USER_FAIL(
"With century of era in format, year should be greater than 0.")
} else {
auto century = year / 100;
result +=
padContent(century, '0', token.pattern.minRepresentDigits);
}
} break;
case DateTimeFormatSpecifier::YEAR_OF_ERA:
result += padContent(
std::abs(static_cast<signed>(calDate.year())),
'0',
token.pattern.minRepresentDigits);
break;
case DateTimeFormatSpecifier::DAY_OF_WEEK_0_BASED:
case DateTimeFormatSpecifier::DAY_OF_WEEK_1_BASED: {
auto weekdayNum = weekday.c_encoding();
if (weekdayNum == 0 &&
token.pattern.specifier ==
DateTimeFormatSpecifier::DAY_OF_WEEK_1_BASED) {
weekdayNum = 7;
}
result +=
padContent(weekdayNum, '0', token.pattern.minRepresentDigits);
} break;
case DateTimeFormatSpecifier::DAY_OF_WEEK_TEXT: {
auto weekdayNum = weekday.c_encoding();
if (token.pattern.minRepresentDigits <= 3) {
result += weekdaysShort[weekdayNum];
} else {
result += weekdaysFull[weekdayNum];
}
} break;
case DateTimeFormatSpecifier::YEAR:
result += padContent(
static_cast<signed>(calDate.year()),
'0',
token.pattern.minRepresentDigits);
break;
case DateTimeFormatSpecifier::DAY_OF_YEAR: {
auto firstDayOfTheYear = date::year_month_day(
calDate.year(), date::month(1), date::day(1));
auto delta =
(date::sys_days{calDate} - date::sys_days{firstDayOfTheYear})
.count();
delta += 1;
result += padContent(delta, '0', token.pattern.minRepresentDigits);
} break;
case DateTimeFormatSpecifier::MONTH_OF_YEAR:
result += padContent(
static_cast<unsigned>(calDate.month()),
'0',
token.pattern.minRepresentDigits);
break;
case DateTimeFormatSpecifier::MONTH_OF_YEAR_TEXT:
if (token.pattern.minRepresentDigits <= 3) {
result += monthsShort[static_cast<unsigned>(calDate.month()) - 1];
} else {
result += monthsFull[static_cast<unsigned>(calDate.month()) - 1];
}
break;
case DateTimeFormatSpecifier::DAY_OF_MONTH:
result += padContent(
static_cast<unsigned>(calDate.day()),
'0',
token.pattern.minRepresentDigits);
break;
case DateTimeFormatSpecifier::HALFDAY_OF_DAY:
result += durationInTheDay.hours().count() < 12 ? "AM" : "PM";
break;
case DateTimeFormatSpecifier::HOUR_OF_HALFDAY:
case DateTimeFormatSpecifier::CLOCK_HOUR_OF_HALFDAY:
case DateTimeFormatSpecifier::HOUR_OF_DAY:
case DateTimeFormatSpecifier::CLOCK_HOUR_OF_DAY: {
auto hourNum = durationInTheDay.hours().count();
if (token.pattern.specifier ==
DateTimeFormatSpecifier::CLOCK_HOUR_OF_HALFDAY) {
hourNum = (hourNum + 11) % 12 + 1;
} else if (
token.pattern.specifier ==
DateTimeFormatSpecifier::HOUR_OF_HALFDAY) {
hourNum = hourNum % 12;
} else if (
token.pattern.specifier ==
DateTimeFormatSpecifier::CLOCK_HOUR_OF_DAY) {
hourNum = (hourNum + 23) % 24 + 1;
}
result += padContent(hourNum, '0', token.pattern.minRepresentDigits);
} break;
case DateTimeFormatSpecifier::MINUTE_OF_HOUR:
result += padContent(
durationInTheDay.minutes().count() % 60,
'0',
token.pattern.minRepresentDigits);
break;
case DateTimeFormatSpecifier::SECOND_OF_MINUTE:
result += padContent(
durationInTheDay.seconds().count() % 60,
'0',
token.pattern.minRepresentDigits);
break;
case DateTimeFormatSpecifier::FRACTION_OF_SECOND:
result += padContent(
durationInTheDay.subseconds().count(),
'0',
token.pattern.minRepresentDigits,
false)
.substr(0, token.pattern.minRepresentDigits);
break;
case DateTimeFormatSpecifier::TIMEZONE:
// TODO: implement short name time zone, need a map from full name to
// short name
if (token.pattern.minRepresentDigits <= 3) {
VELOX_UNSUPPORTED("short name time zone is not yet supported")
}
if (timezone == nullptr) {
VELOX_USER_FAIL("Timezone unknown")
}
result += timezone->name();
break;
case DateTimeFormatSpecifier::TIMEZONE_OFFSET_ID:
// TODO: implement timezone offset id formatting, need a map from full
// name to offset time
case DateTimeFormatSpecifier::WEEK_YEAR:
case DateTimeFormatSpecifier::WEEK_OF_WEEK_YEAR:
default:
VELOX_UNSUPPORTED(
"format is not supported for specifier {}",
token.pattern.specifier);
}
}
}
return result;
}