blob: b04f44e95444c93b6bd35a01ca6f669c69c546e5 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
**/
#ifndef QUICKSTEP_TYPES_DATE_BINARY_OPERATORS_HPP_
#define QUICKSTEP_TYPES_DATE_BINARY_OPERATORS_HPP_
#include <cstdint>
#include <ctime>
#include "types/DatetimeLit.hpp"
#include "types/IntervalLit.hpp"
#include "types/port/gmtime_r.hpp"
#include "types/port/timegm.hpp"
#include "glog/logging.h"
namespace quickstep {
/** \addtogroup Types
* @{
*/
// Month arithmetic clamps to the actual last day of a given month.
inline int ClampDayOfMonth(const int year, const int month, const int day) {
DCHECK_LT(day, 32);
switch (month) {
case 2: {
const int days_in_february =
(year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
? 29
: 28;
return (day > days_in_february) ? days_in_february : day;
}
case 4:
case 6:
case 9:
case 11: {
return day == 31 ? 30 : day;
}
default:
return day;
}
}
// We have a separate function here because timeinfo's months begin from 0.
inline void ClampDayOfMonthStructTM(struct tm *timeinfo) {
DCHECK_LT(timeinfo->tm_mday, 32);
switch (timeinfo->tm_mon) {
case 1: {
const int days_in_february
= ((timeinfo->tm_year & 3) == 0 && ((timeinfo->tm_year % 25) != 0
|| ((timeinfo->tm_year + 1900) & 15) == 0))
? 29 : 28;
timeinfo->tm_mday = timeinfo->tm_mday > days_in_february
? days_in_february : timeinfo->tm_mday;
return;
}
case 3:
case 5:
case 8:
case 10: {
timeinfo->tm_mday = timeinfo->tm_mday == 31 ? 30 : timeinfo->tm_mday;
return;
}
default:
return;
}
}
// Overloaded operators for all date operations.
inline DatetimeLit operator+(const DatetimeLit &lhs, const DatetimeIntervalLit &rhs) {
DatetimeLit datetime;
datetime.ticks = lhs.ticks + rhs.interval_ticks;
return datetime;
}
inline DatetimeLit operator+(const DatetimeIntervalLit &lhs, const DatetimeLit &rhs) {
DatetimeLit datetime;
datetime.ticks = lhs.interval_ticks + rhs.ticks;
return datetime;
}
inline DatetimeLit operator+(const DatetimeLit &lhs, const YearMonthIntervalLit &rhs) {
std::time_t timestamp = lhs.epochTime();
struct tm timeinfo;
quickstep::gmtime_r(&timestamp, &timeinfo);
timeinfo.tm_year += rhs.months / 12;
timeinfo.tm_mon += rhs.months % 12;
if (timeinfo.tm_mon > 11) {
timeinfo.tm_mon -= 12;
++timeinfo.tm_year;
}
ClampDayOfMonthStructTM(&timeinfo);
DatetimeLit datetime(DatetimeLit::FromEpochTime(quickstep::timegm(&timeinfo)));
datetime.ticks += lhs.subseconds();
return datetime; // Datetime in GMT.
}
inline DatetimeLit operator+(const YearMonthIntervalLit &lhs, const DatetimeLit &rhs) {
return rhs + lhs;
}
inline DateLit operator+(const DateLit &lhs, const YearMonthIntervalLit &rhs) {
std::int32_t result_year = lhs.year + (rhs.months / 12);
std::uint8_t result_month = lhs.month + (rhs.months % 12);
if (result_month > 11) {
result_month -= 12;
++result_year;
}
const std::uint8_t result_day = static_cast<std::uint8_t>(
ClampDayOfMonth(result_year, result_month, lhs.day));
return DateLit::Create(result_year, result_month, result_day);
}
inline DateLit operator+(const YearMonthIntervalLit &lhs, const DateLit &rhs) {
return rhs + lhs;
}
inline DatetimeIntervalLit operator+(const DatetimeIntervalLit &lhs, const DatetimeIntervalLit &rhs) {
DatetimeIntervalLit interval(lhs);
interval += rhs;
return interval;
}
inline YearMonthIntervalLit operator+(const YearMonthIntervalLit &lhs, const YearMonthIntervalLit &rhs) {
YearMonthIntervalLit interval(lhs);
interval += rhs;
return interval;
}
// NOTE(zuyu): The result type of the Subtract between two Datetimes
// is DatetimeInterval, instead of YearMonthInterval.
inline DatetimeIntervalLit operator-(const DatetimeLit &lhs, const DatetimeLit &rhs) {
DatetimeIntervalLit interval;
interval.interval_ticks = lhs.ticks - rhs.ticks;
return interval;
}
inline DatetimeLit operator-(const DatetimeLit &lhs, const DatetimeIntervalLit &rhs) {
DatetimeLit datetime;
datetime.ticks = lhs.ticks - rhs.interval_ticks;
return datetime;
}
inline DatetimeLit operator-(const DatetimeLit &lhs, const YearMonthIntervalLit &rhs) {
std::time_t timestamp = lhs.epochTime();
struct tm timeinfo;
quickstep::gmtime_r(&timestamp, &timeinfo);
timeinfo.tm_year -= rhs.months / 12;
timeinfo.tm_mon -= rhs.months % 12;
if (timeinfo.tm_mon < 0) {
--timeinfo.tm_year;
timeinfo.tm_mon += 12;
}
ClampDayOfMonthStructTM(&timeinfo);
DatetimeLit datetime(DatetimeLit::FromEpochTime(quickstep::timegm(&timeinfo)));
datetime.ticks += lhs.subseconds();
return datetime; // Datetime in GMT.
}
inline DateLit operator-(const DateLit &lhs, const YearMonthIntervalLit &rhs) {
std::int32_t result_year = lhs.year - (rhs.months / 12);
std::int8_t result_month = lhs.month - (rhs.months % 12);
if (result_month < 0) {
--result_year;
result_month += 12;
}
const std::uint8_t result_day = static_cast<std::uint8_t>(
ClampDayOfMonth(result_year, result_month, lhs.day));
return DateLit::Create(result_year, result_month, result_day);
}
inline DatetimeIntervalLit operator-(const DatetimeIntervalLit &lhs, const DatetimeIntervalLit &rhs) {
DatetimeIntervalLit interval(lhs);
interval -= rhs;
return interval;
}
inline YearMonthIntervalLit operator-(const YearMonthIntervalLit &lhs, const YearMonthIntervalLit &rhs) {
YearMonthIntervalLit interval(lhs);
interval -= rhs;
return interval;
}
template <typename NumericCppType>
inline DatetimeIntervalLit operator*(const DatetimeIntervalLit &lhs, const NumericCppType &rhs) {
DatetimeIntervalLit interval(lhs);
interval *= rhs;
return interval;
}
template <typename NumericCppType>
inline DatetimeIntervalLit operator*(const NumericCppType &lhs, const DatetimeIntervalLit &rhs) {
DatetimeIntervalLit interval(rhs);
interval *= lhs;
return interval;
}
template <typename NumericCppType>
inline YearMonthIntervalLit operator*(const YearMonthIntervalLit &lhs, const NumericCppType &rhs) {
YearMonthIntervalLit interval(lhs);
interval *= rhs;
return interval;
}
template <typename NumericCppType>
inline YearMonthIntervalLit operator*(const NumericCppType &lhs, const YearMonthIntervalLit &rhs) {
YearMonthIntervalLit interval(rhs);
interval *= lhs;
return interval;
}
template <typename NumericCppType>
inline DatetimeIntervalLit operator/(const DatetimeIntervalLit &lhs, const NumericCppType &rhs) {
DatetimeIntervalLit interval(lhs);
interval /= rhs;
return interval;
}
template <typename NumericCppType>
inline YearMonthIntervalLit operator/(const YearMonthIntervalLit &lhs, const NumericCppType &rhs) {
YearMonthIntervalLit interval(lhs);
interval /= rhs;
return interval;
}
/** @} */
} // namespace quickstep
#endif // QUICKSTEP_TYPES_DATE_BINARY_OPERATORS_HPP_