mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-24 08:32:02 +00:00
add week(), yearweek()
This commit is contained in:
parent
cb3a371756
commit
365d85e1f9
@ -1,154 +0,0 @@
|
||||
#pragma once
|
||||
#include <regex>
|
||||
#include <Columns/ColumnString.h>
|
||||
#include <Columns/ColumnVector.h>
|
||||
#include <Core/Types.h>
|
||||
#include <Functions/FunctionHelpers.h>
|
||||
#include <Functions/extractTimeZoneFromFunctionArguments.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <common/DateLUTImpl.h>
|
||||
|
||||
/// Custom date defaults to January 1 ( 01-01 )
|
||||
#define DEFAULT_CUSTOM_MONTH 1
|
||||
#define DEFAULT_CUSTOM_DAY 1
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||
extern const int ILLEGAL_COLUMN;
|
||||
}
|
||||
|
||||
/** CustomDate Transformations.
|
||||
* Represents two functions - from datetime (UInt32) and from date (UInt16), both with custom_month and custom_day.
|
||||
*/
|
||||
|
||||
static inline UInt32 dateIsNotSupported(const char * name)
|
||||
{
|
||||
throw Exception("Illegal type Date of argument for function " + std::string(name), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||
}
|
||||
|
||||
/// This factor transformation will say that the function is monotone everywhere.
|
||||
struct ZeroTransform
|
||||
{
|
||||
static inline UInt16 execute(UInt32, UInt8, UInt8, const DateLUTImpl &) { return 0; }
|
||||
static inline UInt16 execute(UInt16, UInt8, UInt8, const DateLUTImpl &) { return 0; }
|
||||
};
|
||||
|
||||
struct ToStartOfCustomYearImpl
|
||||
{
|
||||
static constexpr auto name = "toStartOfCustomYear";
|
||||
|
||||
static inline UInt16 execute(UInt32 t, UInt8 custom_month, UInt8 custom_day, const DateLUTImpl & time_zone)
|
||||
{
|
||||
return time_zone.toFirstDayNumOfCustomYear(time_zone.toDayNum(t), custom_month, custom_day);
|
||||
}
|
||||
static inline UInt16 execute(UInt16 d, UInt8 custom_month, UInt8 custom_day, const DateLUTImpl & time_zone)
|
||||
{
|
||||
return time_zone.toFirstDayNumOfCustomYear(DayNum(d), custom_month, custom_day);
|
||||
}
|
||||
|
||||
using FactorTransform = ZeroTransform;
|
||||
};
|
||||
|
||||
struct ToCustomYearImpl
|
||||
{
|
||||
static constexpr auto name = "toCustomYear";
|
||||
|
||||
static inline UInt16 execute(UInt32 t, UInt8 custom_month, UInt8 custom_day, const DateLUTImpl & time_zone)
|
||||
{
|
||||
return time_zone.toCustomYear(time_zone.toDayNum(t), custom_month, custom_day);
|
||||
}
|
||||
static inline UInt16 execute(UInt16 d, UInt8 custom_month, UInt8 custom_day, const DateLUTImpl & time_zone)
|
||||
{
|
||||
return time_zone.toCustomYear(DayNum(d), custom_month, custom_day);
|
||||
}
|
||||
|
||||
using FactorTransform = ZeroTransform;
|
||||
};
|
||||
|
||||
struct ToCustomWeekImpl
|
||||
{
|
||||
static constexpr auto name = "toCustomWeek";
|
||||
|
||||
static inline UInt8 execute(UInt32 t, UInt8 custom_month, UInt8 custom_day, const DateLUTImpl & time_zone)
|
||||
{
|
||||
return time_zone.toCustomWeek(time_zone.toDayNum(t), custom_month, custom_day);
|
||||
}
|
||||
static inline UInt8 execute(UInt16 d, UInt8 custom_month, UInt8 custom_day, const DateLUTImpl & time_zone)
|
||||
{
|
||||
return time_zone.toCustomWeek(DayNum(d), custom_month, custom_day);
|
||||
}
|
||||
|
||||
using FactorTransform = ToCustomYearImpl;
|
||||
};
|
||||
|
||||
template <typename FromType, typename ToType, typename Transform>
|
||||
struct Transformer
|
||||
{
|
||||
static void vector(
|
||||
const PaddedPODArray<FromType> & vec_from,
|
||||
PaddedPODArray<ToType> & vec_to,
|
||||
UInt8 custom_month,
|
||||
UInt8 custom_day,
|
||||
const DateLUTImpl & time_zone)
|
||||
{
|
||||
size_t size = vec_from.size();
|
||||
vec_to.resize(size);
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
vec_to[i] = Transform::execute(vec_from[i], custom_month, custom_day, time_zone);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename FromType, typename ToType, typename Transform>
|
||||
struct CustomDateTransformImpl
|
||||
{
|
||||
static void execute(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/)
|
||||
{
|
||||
using Op = Transformer<FromType, ToType, Transform>;
|
||||
|
||||
UInt8 custom_month = DEFAULT_CUSTOM_MONTH;
|
||||
UInt8 custom_day = DEFAULT_CUSTOM_DAY;
|
||||
// With custom date parameter, fommat: MM-DD
|
||||
if (arguments.size() > 1)
|
||||
{
|
||||
auto * custom_date_column = checkAndGetColumnConst<ColumnString>(block.getByPosition(arguments[1]).column.get());
|
||||
if (custom_date_column)
|
||||
{
|
||||
String custom_date = custom_date_column->getValue<String>();
|
||||
std::regex regex_mmdd("((1[0-2])|(0[1-9]))-(([12][0-9])|(3[01])|(0[1-9]))");
|
||||
if (custom_date.length() == 5 && std::regex_match(custom_date, regex_mmdd))
|
||||
{
|
||||
custom_month = std::stoi(custom_date.substr(0, 2));
|
||||
custom_day = std::stoi(custom_date.substr(3, 2));
|
||||
}
|
||||
else
|
||||
throw Exception(
|
||||
String("The second argument for function ") + Transform::name
|
||||
+ " must be a constant string with custom date(MM-DD)",
|
||||
ErrorCodes::ILLEGAL_COLUMN);
|
||||
}
|
||||
}
|
||||
|
||||
const DateLUTImpl & time_zone = extractTimeZoneFromFunctionArguments(block, arguments, 2, 0);
|
||||
const ColumnPtr source_col = block.getByPosition(arguments[0]).column;
|
||||
if (const auto * sources = checkAndGetColumn<ColumnVector<FromType>>(source_col.get()))
|
||||
{
|
||||
auto col_to = ColumnVector<ToType>::create();
|
||||
Op::vector(sources->getData(), col_to->getData(), custom_month, custom_day, time_zone);
|
||||
block.getByPosition(result).column = std::move(col_to);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Exception(
|
||||
"Illegal column " + block.getByPosition(arguments[0]).column->getName() + " of first argument of function "
|
||||
+ Transform::name,
|
||||
ErrorCodes::ILLEGAL_COLUMN);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
119
dbms/src/Functions/CustomWeekTransforms.h
Normal file
119
dbms/src/Functions/CustomWeekTransforms.h
Normal file
@ -0,0 +1,119 @@
|
||||
#pragma once
|
||||
#include <regex>
|
||||
#include <Columns/ColumnVector.h>
|
||||
#include <Columns/ColumnsNumber.h>
|
||||
#include <Core/Types.h>
|
||||
#include <Functions/FunctionHelpers.h>
|
||||
#include <Functions/extractTimeZoneFromFunctionArguments.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <common/DateLUTImpl.h>
|
||||
|
||||
/// The default mode value to use for the WEEK() function
|
||||
#define DEFAULT_WEEK_MODE 0
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||
extern const int ILLEGAL_COLUMN;
|
||||
}
|
||||
|
||||
/**
|
||||
* CustomWeek Transformations.
|
||||
*/
|
||||
|
||||
static inline UInt32 dateIsNotSupported(const char * name)
|
||||
{
|
||||
throw Exception("Illegal type Date of argument for function " + std::string(name), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||
}
|
||||
|
||||
/// This factor transformation will say that the function is monotone everywhere.
|
||||
struct ZeroTransform
|
||||
{
|
||||
static inline UInt16 execute(UInt32, UInt8, const DateLUTImpl &) { return 0; }
|
||||
static inline UInt16 execute(UInt16, UInt8, const DateLUTImpl &) { return 0; }
|
||||
};
|
||||
|
||||
struct WeekImpl
|
||||
{
|
||||
static constexpr auto name = "week";
|
||||
|
||||
static inline UInt8 execute(UInt32 t, UInt8 week_mode, const DateLUTImpl & time_zone)
|
||||
{
|
||||
UInt32 year = 0;
|
||||
return time_zone.calc_week(time_zone.toDayNum(t), week_mode, &year);
|
||||
}
|
||||
static inline UInt8 execute(UInt16 d, UInt8 week_mode, const DateLUTImpl & time_zone)
|
||||
{
|
||||
UInt32 year = 0;
|
||||
return time_zone.calc_week(DayNum(d), week_mode, &year);
|
||||
}
|
||||
|
||||
using FactorTransform = ZeroTransform;
|
||||
};
|
||||
|
||||
struct YearWeekImpl
|
||||
{
|
||||
static constexpr auto name = "yearWeek";
|
||||
|
||||
static inline UInt32 execute(UInt32 t, UInt8 week_mode, const DateLUTImpl & time_zone)
|
||||
{
|
||||
return time_zone.calc_yearWeek(time_zone.toDayNum(t), week_mode);
|
||||
}
|
||||
static inline UInt32 execute(UInt16 d, UInt8 week_mode, const DateLUTImpl & time_zone)
|
||||
{
|
||||
return time_zone.calc_yearWeek(DayNum(d), week_mode);
|
||||
}
|
||||
|
||||
using FactorTransform = ZeroTransform;
|
||||
};
|
||||
|
||||
template <typename FromType, typename ToType, typename Transform>
|
||||
struct Transformer
|
||||
{
|
||||
static void
|
||||
vector(const PaddedPODArray<FromType> & vec_from, PaddedPODArray<ToType> & vec_to, UInt8 week_mode, const DateLUTImpl & time_zone)
|
||||
{
|
||||
size_t size = vec_from.size();
|
||||
vec_to.resize(size);
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
vec_to[i] = Transform::execute(vec_from[i], week_mode, time_zone);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename FromType, typename ToType, typename Transform>
|
||||
struct CustomWeekTransformImpl
|
||||
{
|
||||
static void execute(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/)
|
||||
{
|
||||
using Op = Transformer<FromType, ToType, Transform>;
|
||||
|
||||
UInt8 week_mode = DEFAULT_WEEK_MODE;
|
||||
if (arguments.size() > 1)
|
||||
{
|
||||
if (const auto week_mode_column = checkAndGetColumnConst<ColumnUInt8>(block.getByPosition(arguments[1]).column.get()))
|
||||
week_mode = week_mode_column->getValue<UInt8>();
|
||||
}
|
||||
|
||||
const DateLUTImpl & time_zone = extractTimeZoneFromFunctionArguments(block, arguments, 2, 0);
|
||||
const ColumnPtr source_col = block.getByPosition(arguments[0]).column;
|
||||
if (const auto * sources = checkAndGetColumn<ColumnVector<FromType>>(source_col.get()))
|
||||
{
|
||||
auto col_to = ColumnVector<ToType>::create();
|
||||
Op::vector(sources->getData(), col_to->getData(), week_mode, time_zone);
|
||||
block.getByPosition(result).column = std::move(col_to);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Exception(
|
||||
"Illegal column " + block.getByPosition(arguments[0]).column->getName() + " of first argument of function "
|
||||
+ Transform::name,
|
||||
ErrorCodes::ILLEGAL_COLUMN);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
#include <DataTypes/DataTypeDate.h>
|
||||
#include <DataTypes/DataTypeDateTime.h>
|
||||
#include <Functions/CustomDateTransforms.h>
|
||||
#include <Functions/CustomWeekTransforms.h>
|
||||
#include <Functions/IFunction.h>
|
||||
#include <Functions/extractTimeZoneFromFunctionArguments.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
@ -15,13 +15,13 @@ namespace ErrorCodes
|
||||
}
|
||||
|
||||
|
||||
/// See DateTimeTransforms.h
|
||||
/// See CustomWeekTransforms.h
|
||||
template <typename ToDataType, typename Transform>
|
||||
class FunctionCustomDateToSomething : public IFunction
|
||||
class FunctionCustomWeekToSomething : public IFunction
|
||||
{
|
||||
public:
|
||||
static constexpr auto name = Transform::name;
|
||||
static FunctionPtr create(const Context &) { return std::make_shared<FunctionCustomDateToSomething>(); }
|
||||
static FunctionPtr create(const Context &) { return std::make_shared<FunctionCustomWeekToSomething>(); }
|
||||
|
||||
String getName() const override { return name; }
|
||||
|
||||
@ -45,12 +45,12 @@ public:
|
||||
"Illegal type " + arguments[0].type->getName() + " of argument of function " + getName()
|
||||
+ ". Should be a date or a date with time",
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||
if (!isString(arguments[1].type))
|
||||
if (!isUInt8(arguments[1].type))
|
||||
throw Exception(
|
||||
"Function " + getName()
|
||||
+ " supports 1 or 2 or 3 arguments. The 1st argument "
|
||||
"must be of type Date or DateTime. The 2nd argument (optional) must be "
|
||||
"a constant string with custom date(MM-DD). The 3nd argument (optional) must be "
|
||||
"a constant UInt8 with week mode. The 3nd argument (optional) must be "
|
||||
"a constant string with timezone name",
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||
}
|
||||
@ -61,12 +61,12 @@ public:
|
||||
"Illegal type " + arguments[0].type->getName() + " of argument of function " + getName()
|
||||
+ ". Should be a date or a date with time",
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||
if (!isString(arguments[1].type))
|
||||
if (!isUInt8(arguments[1].type))
|
||||
throw Exception(
|
||||
"Function " + getName()
|
||||
+ " supports 1 or 2 or 3 arguments. The 1st argument "
|
||||
"must be of type Date or DateTime. The 2nd argument (optional) must be "
|
||||
"a constant string with custom date(MM-DD). The 3nd argument (optional) must be "
|
||||
"a constant UInt8 with week mode. The 3nd argument (optional) must be "
|
||||
"a constant string with timezone name",
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||
if (!isString(arguments[2].type))
|
||||
@ -74,7 +74,7 @@ public:
|
||||
"Function " + getName()
|
||||
+ " supports 1 or 2 or 3 arguments. The 1st argument "
|
||||
"must be of type Date or DateTime. The 2nd argument (optional) must be "
|
||||
"a constant string with custom date(MM-DD). The 3nd argument (optional) must be "
|
||||
"a constant UInt8 with week mode. The 3nd argument (optional) must be "
|
||||
"a constant string with timezone name",
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||
if (isDate(arguments[0].type) && std::is_same_v<ToDataType, DataTypeDate>)
|
||||
@ -104,10 +104,10 @@ public:
|
||||
WhichDataType which(from_type);
|
||||
|
||||
if (which.isDate())
|
||||
CustomDateTransformImpl<DataTypeDate::FieldType, typename ToDataType::FieldType, Transform>::execute(
|
||||
CustomWeekTransformImpl<DataTypeDate::FieldType, typename ToDataType::FieldType, Transform>::execute(
|
||||
block, arguments, result, input_rows_count);
|
||||
else if (which.isDateTime())
|
||||
CustomDateTransformImpl<DataTypeDateTime::FieldType, typename ToDataType::FieldType, Transform>::execute(
|
||||
CustomWeekTransformImpl<DataTypeDateTime::FieldType, typename ToDataType::FieldType, Transform>::execute(
|
||||
block, arguments, result, input_rows_count);
|
||||
else
|
||||
throw Exception(
|
||||
@ -139,15 +139,15 @@ public:
|
||||
|
||||
if (checkAndGetDataType<DataTypeDate>(&type))
|
||||
{
|
||||
return Transform::FactorTransform::execute(UInt16(left.get<UInt64>()), DEFAULT_CUSTOM_MONTH, DEFAULT_CUSTOM_DAY, date_lut)
|
||||
== Transform::FactorTransform::execute(UInt16(right.get<UInt64>()), DEFAULT_CUSTOM_MONTH, DEFAULT_CUSTOM_DAY, date_lut)
|
||||
return Transform::FactorTransform::execute(UInt16(left.get<UInt64>()), DEFAULT_WEEK_MODE, date_lut)
|
||||
== Transform::FactorTransform::execute(UInt16(right.get<UInt64>()), DEFAULT_WEEK_MODE, date_lut)
|
||||
? is_monotonic
|
||||
: is_not_monotonic;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Transform::FactorTransform::execute(UInt32(left.get<UInt64>()), DEFAULT_CUSTOM_MONTH, DEFAULT_CUSTOM_DAY, date_lut)
|
||||
== Transform::FactorTransform::execute(UInt32(right.get<UInt64>()), DEFAULT_CUSTOM_MONTH, DEFAULT_CUSTOM_DAY, date_lut)
|
||||
return Transform::FactorTransform::execute(UInt32(left.get<UInt64>()), DEFAULT_WEEK_MODE, date_lut)
|
||||
== Transform::FactorTransform::execute(UInt32(right.get<UInt64>()), DEFAULT_WEEK_MODE, date_lut)
|
||||
? is_monotonic
|
||||
: is_not_monotonic;
|
||||
}
|
@ -17,7 +17,6 @@ void registerFunctionToMonday(FunctionFactory &);
|
||||
void registerFunctionToISOWeek(FunctionFactory &);
|
||||
void registerFunctionToISOYear(FunctionFactory &);
|
||||
void registerFunctionToCustomWeek(FunctionFactory &);
|
||||
void registerFunctionToCustomYear(FunctionFactory &);
|
||||
void registerFunctionToStartOfMonth(FunctionFactory &);
|
||||
void registerFunctionToStartOfQuarter(FunctionFactory &);
|
||||
void registerFunctionToStartOfYear(FunctionFactory &);
|
||||
@ -28,7 +27,6 @@ void registerFunctionToStartOfFifteenMinutes(FunctionFactory &);
|
||||
void registerFunctionToStartOfHour(FunctionFactory &);
|
||||
void registerFunctionToStartOfInterval(FunctionFactory &);
|
||||
void registerFunctionToStartOfISOYear(FunctionFactory &);
|
||||
void registerFunctionToStartOfCustomYear(FunctionFactory &);
|
||||
void registerFunctionToRelativeYearNum(FunctionFactory &);
|
||||
void registerFunctionToRelativeQuarterNum(FunctionFactory &);
|
||||
void registerFunctionToRelativeMonthNum(FunctionFactory &);
|
||||
@ -83,7 +81,6 @@ void registerFunctionsDateTime(FunctionFactory & factory)
|
||||
registerFunctionToISOWeek(factory);
|
||||
registerFunctionToISOYear(factory);
|
||||
registerFunctionToCustomWeek(factory);
|
||||
registerFunctionToCustomYear(factory);
|
||||
registerFunctionToStartOfMonth(factory);
|
||||
registerFunctionToStartOfQuarter(factory);
|
||||
registerFunctionToStartOfYear(factory);
|
||||
@ -94,7 +91,6 @@ void registerFunctionsDateTime(FunctionFactory & factory)
|
||||
registerFunctionToStartOfHour(factory);
|
||||
registerFunctionToStartOfInterval(factory);
|
||||
registerFunctionToStartOfISOYear(factory);
|
||||
registerFunctionToStartOfCustomYear(factory);
|
||||
registerFunctionToRelativeYearNum(factory);
|
||||
registerFunctionToRelativeQuarterNum(factory);
|
||||
registerFunctionToRelativeMonthNum(factory);
|
||||
|
@ -1,17 +1,19 @@
|
||||
#include <DataTypes/DataTypesNumber.h>
|
||||
#include <Functions/CustomDateTransforms.h>
|
||||
#include <Functions/FunctionCustomDateToSomething.h>
|
||||
#include <Functions/CustomWeekTransforms.h>
|
||||
#include <Functions/FunctionCustomWeekToSomething.h>
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/IFunction.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
using FunctionToCustomWeek = FunctionCustomDateToSomething<DataTypeUInt8, ToCustomWeekImpl>;
|
||||
using FunctionWeek = FunctionCustomWeekToSomething<DataTypeUInt8, WeekImpl>;
|
||||
using FunctionYearWeek = FunctionCustomWeekToSomething<DataTypeUInt32, YearWeekImpl>;
|
||||
|
||||
void registerFunctionToCustomWeek(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionToCustomWeek>();
|
||||
factory.registerFunction<FunctionWeek>();
|
||||
factory.registerFunction<FunctionYearWeek>();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
#include <Functions/IFunction.h>
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/CustomDateTransforms.h>
|
||||
#include <Functions/FunctionCustomDateToSomething.h>
|
||||
#include <DataTypes/DataTypesNumber.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
using FunctionToCustomYear = FunctionCustomDateToSomething<DataTypeUInt16, ToCustomYearImpl>;
|
||||
|
||||
void registerFunctionToCustomYear(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionToCustomYear>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,20 +0,0 @@
|
||||
#include <Functions/IFunction.h>
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/CustomDateTransforms.h>
|
||||
#include <Functions/FunctionCustomDateToSomething.h>
|
||||
#include <DataTypes/DataTypesNumber.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
using FunctionToStartOfCustomYear = FunctionCustomDateToSomething<DataTypeDate, ToStartOfCustomYearImpl>;
|
||||
|
||||
void registerFunctionToStartOfCustomYear(FunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<FunctionToStartOfCustomYear>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,45 +1,63 @@
|
||||
2016-12-22 52 2016 2015-12-28
|
||||
2016-12-23 52 2016 2015-12-28
|
||||
2016-12-24 52 2016 2015-12-28
|
||||
2016-12-25 52 2016 2015-12-28
|
||||
2016-12-26 1 2017 2016-12-26
|
||||
2016-12-27 1 2017 2016-12-26
|
||||
2016-12-28 1 2017 2016-12-26
|
||||
2016-12-29 1 2017 2016-12-26
|
||||
2016-12-30 1 2017 2016-12-26
|
||||
2016-12-31 1 2017 2016-12-26
|
||||
2017-01-01 1 2017 2016-12-26
|
||||
2017-01-02 2 2017 2016-12-26
|
||||
2017-01-03 2 2017 2016-12-26
|
||||
2017-01-04 2 2017 2016-12-26
|
||||
2017-01-05 2 2017 2016-12-26
|
||||
2017-01-20 00:00:00 52 2016 2016-01-25
|
||||
2017-01-21 00:00:00 52 2016 2016-01-25
|
||||
2017-01-22 00:00:00 52 2016 2016-01-25
|
||||
2017-01-23 00:00:00 1 2017 2017-01-23
|
||||
2017-01-24 00:00:00 1 2017 2017-01-23
|
||||
2017-01-25 00:00:00 1 2017 2017-01-23
|
||||
2017-01-26 00:00:00 1 2017 2017-01-23
|
||||
2017-01-27 00:00:00 1 2017 2017-01-23
|
||||
2017-01-28 00:00:00 1 2017 2017-01-23
|
||||
2017-01-29 00:00:00 1 2017 2017-01-23
|
||||
2017-01-30 00:00:00 2 2017 2017-01-23
|
||||
2017-01-31 00:00:00 2 2017 2017-01-23
|
||||
2017-02-01 00:00:00 2 2017 2017-01-23
|
||||
2017-02-02 00:00:00 2 2017 2017-01-23
|
||||
2017-02-03 00:00:00 2 2017 2017-01-23
|
||||
2017-01-20 00:00:00 52 2016 2016-01-25
|
||||
2017-01-21 00:00:00 52 2016 2016-01-25
|
||||
2017-01-22 00:00:00 52 2016 2016-01-25
|
||||
2017-01-23 00:00:00 1 2017 2017-01-23
|
||||
2017-01-24 00:00:00 1 2017 2017-01-23
|
||||
2017-01-25 00:00:00 1 2017 2017-01-23
|
||||
2017-01-26 00:00:00 1 2017 2017-01-23
|
||||
2017-01-27 00:00:00 1 2017 2017-01-23
|
||||
2017-01-28 00:00:00 1 2017 2017-01-23
|
||||
2017-01-29 00:00:00 1 2017 2017-01-23
|
||||
2017-01-30 00:00:00 2 2017 2017-01-23
|
||||
2017-01-31 00:00:00 2 2017 2017-01-23
|
||||
2017-02-01 00:00:00 2 2017 2017-01-23
|
||||
2017-02-02 00:00:00 2 2017 2017-01-23
|
||||
2017-02-03 00:00:00 2 2017 2017-01-23
|
||||
0 0 1 1
|
||||
52 52 53 53
|
||||
1 0
|
||||
198153 198153 198252 198252
|
||||
198701 198652
|
||||
0 0 0 0 0 0 1
|
||||
1 0 1 1 1 1 1
|
||||
0 1 1 1 1 0 0
|
||||
1 1 1 2 2 1 1
|
||||
199952 200053 200152 200252 200352 200452 200601
|
||||
200001 200053 200201 200301 200401 200501 200601
|
||||
199952 200101 200201 200301 200401 200453 200552
|
||||
200001 200101 200201 200302 200402 200501 200601
|
||||
52 53 52 52
|
||||
53 52
|
||||
52 53 52 53 52 52 52 52
|
||||
0 0 52 52 0 0 52 52
|
||||
1 1 1 1 1 1 1 1
|
||||
53 52 53 52 53 52 1 52
|
||||
0 1 53 1 1 1 1 1
|
||||
200053 200052 200053 200052 200101 200052 200101 200052
|
||||
2016-12-21 52 52 201652 201652
|
||||
2016-12-22 52 52 201652 201652
|
||||
2016-12-23 52 52 201652 201652
|
||||
2016-12-24 52 52 201652 201652
|
||||
2016-12-25 53 52 201653 201652
|
||||
2016-12-26 53 1 201653 201701
|
||||
2016-12-27 53 1 201653 201701
|
||||
2016-12-28 53 1 201653 201701
|
||||
2016-12-29 53 1 201653 201701
|
||||
2016-12-30 53 1 201653 201701
|
||||
2016-12-31 53 1 201653 201701
|
||||
2017-01-01 1 1 201701 201701
|
||||
2017-01-02 1 2 201701 201702
|
||||
2017-01-03 1 2 201701 201702
|
||||
2017-01-04 1 2 201701 201702
|
||||
2017-01-05 1 2 201701 201702
|
||||
2017-01-06 1 2 201701 201702
|
||||
2017-01-07 1 2 201701 201702
|
||||
2017-01-08 2 2 201702 201702
|
||||
2017-01-09 2 3 201702 201703
|
||||
2017-01-10 2 3 201702 201703
|
||||
2016-12-22 00:00:00 52 52 201652 201652
|
||||
2016-12-23 00:00:00 52 52 201652 201652
|
||||
2016-12-24 00:00:00 52 52 201652 201652
|
||||
2016-12-25 00:00:00 53 52 201653 201652
|
||||
2016-12-26 00:00:00 53 1 201653 201701
|
||||
2016-12-27 00:00:00 53 1 201653 201701
|
||||
2016-12-28 00:00:00 53 1 201653 201701
|
||||
2016-12-29 00:00:00 53 1 201653 201701
|
||||
2016-12-30 00:00:00 53 1 201653 201701
|
||||
2016-12-31 00:00:00 53 1 201653 201701
|
||||
2017-01-01 00:00:00 1 1 201701 201701
|
||||
2017-01-02 00:00:00 1 2 201701 201702
|
||||
2017-01-03 00:00:00 1 2 201701 201702
|
||||
2017-01-04 00:00:00 1 2 201701 201702
|
||||
2017-01-05 00:00:00 1 2 201701 201702
|
||||
2017-01-06 00:00:00 1 2 201701 201702
|
||||
2017-01-07 00:00:00 1 2 201701 201702
|
||||
2017-01-08 00:00:00 2 2 201702 201702
|
||||
2017-01-09 00:00:00 2 3 201702 201703
|
||||
2017-01-10 00:00:00 2 3 201702 201703
|
||||
2017-01-11 00:00:00 2 3 201702 201703
|
||||
|
@ -1,6 +1,42 @@
|
||||
-- By default, the week contains January 1 is the first week:
|
||||
SELECT toDate('2016-12-22') + number AS d, toCustomWeek(d) as week, toCustomYear(d) AS year, toStartOfCustomYear(d) AS startday FROM numbers(15);
|
||||
-- The week contains January 28 is the first week:
|
||||
SELECT toDateTime(toDate('2017-01-20') + number, 'Europe/Moscow' ) AS d, toCustomWeek(d,'01-28') as week, toCustomYear(d,'01-28') AS year, toStartOfCustomYear(d,'01-28') AS startday FROM numbers(15);
|
||||
-- and with timezone
|
||||
SELECT toDateTime(toDate('2017-01-20') + number, 'Europe/Moscow' ) AS d, toCustomWeek(d,'01-28','Europe/Moscow') as week, toCustomYear(d,'01-28','Europe/Moscow') AS year, toStartOfCustomYear(d,'01-28','Europe/Moscow') AS startday FROM numbers(15);
|
||||
-- week mode [0,7], week test case. refer to the mysql test case
|
||||
SELECT week(toDate('1998-01-01')), week(toDate('1997-01-01')), week(toDate('1998-01-01'), 1), week(toDate('1997-01-01'), 1);
|
||||
SELECT week(toDate('1998-12-31')), week(toDate('1997-12-31')), week(toDate('1998-12-31'), 1), week(toDate('1997-12-31'), 1);
|
||||
SELECT week(toDate('1995-01-01')), week(toDate('1995-01-01'), 1);
|
||||
SELECT yearWeek(toDate('1981-12-31'), 1), yearWeek(toDate('1982-01-01'), 1), yearWeek(toDate('1982-12-31'), 1), yearWeek(toDate('1983-01-01'), 1);
|
||||
SELECT yearWeek(toDate('1987-01-01'), 1), yearWeek(toDate('1987-01-01'));
|
||||
|
||||
SELECT week(toDate('2000-01-01'),0) AS w2000, week(toDate('2001-01-01'),0) AS w2001, week(toDate('2002-01-01'),0) AS w2002,week(toDate('2003-01-01'),0) AS w2003, week(toDate('2004-01-01'),0) AS w2004, week(toDate('2005-01-01'),0) AS w2005, week(toDate('2006-01-01'),0) AS w2006;
|
||||
SELECT week(toDate('2000-01-06'),0) AS w2000, week(toDate('2001-01-06'),0) AS w2001, week(toDate('2002-01-06'),0) AS w2002,week(toDate('2003-01-06'),0) AS w2003, week(toDate('2004-01-06'),0) AS w2004, week(toDate('2005-01-06'),0) AS w2005, week(toDate('2006-01-06'),0) AS w2006;
|
||||
SELECT week(toDate('2000-01-01'),1) AS w2000, week(toDate('2001-01-01'),1) AS w2001, week(toDate('2002-01-01'),1) AS w2002,week(toDate('2003-01-01'),1) AS w2003, week(toDate('2004-01-01'),1) AS w2004, week(toDate('2005-01-01'),1) AS w2005, week(toDate('2006-01-01'),1) AS w2006;
|
||||
SELECT week(toDate('2000-01-06'),1) AS w2000, week(toDate('2001-01-06'),1) AS w2001, week(toDate('2002-01-06'),1) AS w2002,week(toDate('2003-01-06'),1) AS w2003, week(toDate('2004-01-06'),1) AS w2004, week(toDate('2005-01-06'),1) AS w2005, week(toDate('2006-01-06'),1) AS w2006;
|
||||
SELECT yearWeek(toDate('2000-01-01'),0) AS w2000, yearWeek(toDate('2001-01-01'),0) AS w2001, yearWeek(toDate('2002-01-01'),0) AS w2002,yearWeek(toDate('2003-01-01'),0) AS w2003, yearWeek(toDate('2004-01-01'),0) AS w2004, yearWeek(toDate('2005-01-01'),0) AS w2005, yearWeek(toDate('2006-01-01'),0) AS w2006;
|
||||
SELECT yearWeek(toDate('2000-01-06'),0) AS w2000, yearWeek(toDate('2001-01-06'),0) AS w2001, yearWeek(toDate('2002-01-06'),0) AS w2002,yearWeek(toDate('2003-01-06'),0) AS w2003, yearWeek(toDate('2004-01-06'),0) AS w2004, yearWeek(toDate('2005-01-06'),0) AS w2005, yearWeek(toDate('2006-01-06'),0) AS w2006;
|
||||
SELECT yearWeek(toDate('2000-01-01'),1) AS w2000, yearWeek(toDate('2001-01-01'),1) AS w2001, yearWeek(toDate('2002-01-01'),1) AS w2002,yearWeek(toDate('2003-01-01'),1) AS w2003, yearWeek(toDate('2004-01-01'),1) AS w2004, yearWeek(toDate('2005-01-01'),1) AS w2005, yearWeek(toDate('2006-01-01'),1) AS w2006;
|
||||
SELECT yearWeek(toDate('2000-01-06'),1) AS w2000, yearWeek(toDate('2001-01-06'),1) AS w2001, yearWeek(toDate('2002-01-06'),1) AS w2002,yearWeek(toDate('2003-01-06'),1) AS w2003, yearWeek(toDate('2004-01-06'),1) AS w2004, yearWeek(toDate('2005-01-06'),1) AS w2005, yearWeek(toDate('2006-01-06'),1) AS w2006;
|
||||
SELECT week(toDate('1998-12-31'),2),week(toDate('1998-12-31'),3), week(toDate('2000-01-01'),2), week(toDate('2000-01-01'),3);
|
||||
SELECT week(toDate('2000-12-31'),2),week(toDate('2000-12-31'),3);
|
||||
|
||||
SELECT week(toDate('1998-12-31'),0) AS w0, week(toDate('1998-12-31'),1) AS w1, week(toDate('1998-12-31'),2) AS w2, week(toDate('1998-12-31'),3) AS w3, week(toDate('1998-12-31'),4) AS w4, week(toDate('1998-12-31'),5) AS w5, week(toDate('1998-12-31'),6) AS w6, week(toDate('1998-12-31'),7) AS w7;
|
||||
SELECT week(toDate('2000-01-01'),0) AS w0, week(toDate('2000-01-01'),1) AS w1, week(toDate('2000-01-01'),2) AS w2, week(toDate('2000-01-01'),3) AS w3, week(toDate('2000-01-01'),4) AS w4, week(toDate('2000-01-01'),5) AS w5, week(toDate('2000-01-01'),6) AS w6, week(toDate('2000-01-01'),7) AS w7;
|
||||
SELECT week(toDate('2000-01-06'),0) AS w0, week(toDate('2000-01-06'),1) AS w1, week(toDate('2000-01-06'),2) AS w2, week(toDate('2000-01-06'),3) AS w3, week(toDate('2000-01-06'),4) AS w4, week(toDate('2000-01-06'),5) AS w5, week(toDate('2000-01-06'),6) AS w6, week(toDate('2000-01-06'),7) AS w7;
|
||||
SELECT week(toDate('2000-12-31'),0) AS w0, week(toDate('2000-12-31'),1) AS w1, week(toDate('2000-12-31'),2) AS w2, week(toDate('2000-12-31'),3) AS w3, week(toDate('2000-12-31'),4) AS w4, week(toDate('2000-12-31'),5) AS w5, week(toDate('2000-12-31'),6) AS w6, week(toDate('2000-12-31'),7) AS w7;
|
||||
SELECT week(toDate('2001-01-01'),0) AS w0, week(toDate('2001-01-01'),1) AS w1, week(toDate('2001-01-01'),2) AS w2, week(toDate('2001-01-01'),3) AS w3, week(toDate('2001-01-01'),4) AS w4, week(toDate('2001-01-01'),5) AS w5, week(toDate('2001-01-01'),6) AS w6, week(toDate('2001-01-01'),7) AS w7;
|
||||
|
||||
SELECT yearWeek(toDate('2000-12-31'),0), yearWeek(toDate('2000-12-31'),1), yearWeek(toDate('2000-12-31'),2), yearWeek(toDate('2000-12-31'),3), yearWeek(toDate('2000-12-31'),4), yearWeek(toDate('2000-12-31'),5), yearWeek(toDate('2000-12-31'),6), yearWeek(toDate('2000-12-31'),7);
|
||||
|
||||
-- week mode 8,9
|
||||
SELECT
|
||||
toDate('2016-12-21') + number AS d,
|
||||
week(d, 8) AS week8,
|
||||
week(d, 9) AS week9,
|
||||
yearWeek(d, 8) AS yearWeek8,
|
||||
yearWeek(d, 9) AS yearWeek9
|
||||
FROM numbers(21);
|
||||
|
||||
SELECT toDateTime(toDate('2016-12-22') + number, 'Europe/Moscow' ) AS d,
|
||||
week(d, 8, 'Europe/Moscow') AS week8,
|
||||
week(d, 9, 'Europe/Moscow') AS week9,
|
||||
yearWeek(d, 8, 'Europe/Moscow') AS yearWeek8,
|
||||
yearWeek(d, 9, 'Europe/Moscow') AS yearWeek9
|
||||
FROM numbers(21);
|
||||
|
||||
|
@ -76,14 +76,6 @@ Returns the date.
|
||||
Rounds down a date or date with time to the first day of ISO year.
|
||||
Returns the date.
|
||||
|
||||
## toStartOfCustomYear
|
||||
|
||||
Rounds down a date or date with time to the first day of Custom year.
|
||||
Returns the date.
|
||||
```
|
||||
toStartOfCustomYear(DateTime1, [, CustomDate][, Timezone])
|
||||
```
|
||||
|
||||
## toStartOfQuarter
|
||||
|
||||
Rounds down a date or date with time to the first day of the quarter.
|
||||
@ -184,46 +176,70 @@ Converts a date or date with time to a UInt16 number containing the Custom Year
|
||||
toCustomYear(DateTime, [, CustomDate][, Timezone])
|
||||
```
|
||||
|
||||
## toCustomWeek
|
||||
## week(date[,mode])
|
||||
This function returns the week number for date or datetime. The two-argument form of week() enables you to specify whether the week starts on Sunday or Monday and whether the return value should be in the range from 0 to 53 or from 1 to 53. If the mode argument is omitted, the default mode is 0.
|
||||
The following table describes how the mode argument works.
|
||||
|
||||
| Mode | First day of week | Range | Week 1 is the first week … |
|
||||
| ----------- | -------- | -------- | ------------------ |
|
||||
|0|Sunday|0-53|with a Sunday in this year
|
||||
|1|Monday|0-53|with 4 or more days this year
|
||||
|2|Sunday|1-53|with a Sunday in this year
|
||||
|3|Monday|1-53|with 4 or more days this year
|
||||
|4|Sunday|0-53|with 4 or more days this year
|
||||
|5|Monday|0-53|with a Monday in this year
|
||||
|6|Sunday|1-53|with 4 or more days this year
|
||||
|7|Monday|1-53|with a Monday in this year
|
||||
|8|Sunday|1-53|contains January 1
|
||||
|9|Monday|1-53|contains January 1
|
||||
|
||||
For mode values with a meaning of “with 4 or more days this year,” weeks are numbered according to ISO 8601:1988:
|
||||
|
||||
- If the week containing January 1 has 4 or more days in the new year, it is week 1.
|
||||
|
||||
- Otherwise, it is the last week of the previous year, and the next week is week 1.
|
||||
|
||||
For mode values with a meaning of “contains January 1”, the week contains January 1 is week 1. It doesn't matter how many days in the new year the week contained, even if it contained only one day.
|
||||
|
||||
Converts a date or date with time to a UInt8 number containing the Custom Week number.
|
||||
The week number 1 is the first week in year that contains some day, which default to January 1, it can be modify by parameter of function.
|
||||
Week begins at monday.
|
||||
```
|
||||
toCustomWeek(DateTime1, [, CustomDate][, Timezone])
|
||||
week(DateTime1, [, mode][, Timezone])
|
||||
|
||||
```
|
||||
**Parameters**
|
||||
|
||||
- `DateTime1` – Date or DateTime.
|
||||
- `CustomDate` – Optional parameter, default is January 1, format: MM-DD.
|
||||
- `mode` – Optional parameter, Range of values is [0,9], default is 0.
|
||||
- `Timezone` – Optional parameter, it behaves like any other conversion function.
|
||||
|
||||
**Example**
|
||||
By default, the week contains January 1 is the first week:
|
||||
|
||||
``` sql
|
||||
SELECT toDate('2016-12-27') AS date, toCustomYear(date) AS year, toCustomWeek(date) AS week, toStartOfCustomYear(date) AS startday;
|
||||
SELECT toDate('2016-12-27') AS date, week(date) AS week0, week(date,1) AS week1, week(date,9) AS week9;
|
||||
```
|
||||
|
||||
```
|
||||
┌───────date─┬─year─┬─week─┬───startday─┐
|
||||
│ 2016-12-27 │ 2017 │ 1 │ 2016-12-26 │
|
||||
└───────────┴─────┴──────┴─────────┘
|
||||
┌───────date─┬─week0─┬─week1─┬─week9─┐
|
||||
│ 2016-12-27 │ 52 │ 52 │ 1 │
|
||||
└────────────┴───────┴───────┴───────┘
|
||||
```
|
||||
|
||||
The week contains January 28 is the first week:
|
||||
## yearWeek(date[,mode])
|
||||
Returns year and week for a date. The year in the result may be different from the year in the date argument for the first and the last week of the year.
|
||||
|
||||
The mode argument works exactly like the mode argument to week(). For the single-argument syntax, a mode value of 0 is used.
|
||||
|
||||
**Example**
|
||||
|
||||
``` sql
|
||||
SELECT toDate('2016-12-27') AS date, toCustomYear(date, '01-28') AS year, toCustomWeek(date,'01-28') AS week, toStartOfCustomYear(date,'01-28') AS startday;
|
||||
SELECT toDate('2016-12-27') AS date, yearWeek(date) AS yearWeek0, yearWeek(date,1) AS yearWeek1, yearWeek(date,9) AS yearWeek9;
|
||||
```
|
||||
|
||||
```
|
||||
┌───────date─┬─year─┬─week─┬───startday─┐
|
||||
│ 2016-12-27 │ 2016 │ 49 │ 2016-01-25 │
|
||||
└───────────┴─────┴──────┴─────────┘
|
||||
┌───────date─┬─yearWeek0─┬─yearWeek1─┬─yearWeek9─┐
|
||||
│ 2016-12-27 │ 201652 │ 201652 │ 201701 │
|
||||
└────────────┴───────────┴───────────┴───────────┘
|
||||
```
|
||||
|
||||
|
||||
## now
|
||||
|
||||
Accepts zero arguments and returns the current time at one of the moments of request execution.
|
||||
|
@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/Types.h>
|
||||
#include <common/DayNum.h>
|
||||
#include <common/likely.h>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <common/DayNum.h>
|
||||
#include <common/Types.h>
|
||||
#include <common/likely.h>
|
||||
|
||||
#define DATE_LUT_MAX (0xFFFFFFFFU - 86400)
|
||||
#define DATE_LUT_MAX_DAY_NUM (0xFFFFFFFFU / 86400)
|
||||
@ -14,6 +14,13 @@
|
||||
#define DATE_LUT_MAX_YEAR 2105 /// Last supported year
|
||||
#define DATE_LUT_YEARS (1 + DATE_LUT_MAX_YEAR - DATE_LUT_MIN_YEAR) /// Number of years in lookup table
|
||||
|
||||
/// Flags for calc_week() function.
|
||||
#define WEEK_MONDAY_FIRST 1
|
||||
#define WEEK_YEAR 2
|
||||
#define WEEK_FIRST_WEEKDAY 4
|
||||
#define WEEK_NEWYEAR_DAY 8
|
||||
|
||||
|
||||
#if defined(__PPC__)
|
||||
# if !__clang__
|
||||
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
@ -93,10 +100,7 @@ private:
|
||||
return DayNum(guess - 1);
|
||||
}
|
||||
|
||||
inline const Values & find(time_t t) const
|
||||
{
|
||||
return lut[findIndex(t)];
|
||||
}
|
||||
inline const Values & find(time_t t) const { return lut[findIndex(t)]; }
|
||||
|
||||
public:
|
||||
const std::string & getTimeZone() const { return time_zone; }
|
||||
@ -117,15 +121,9 @@ public:
|
||||
return lut[DayNum(index - (lut[index].day_of_week - 1))].date;
|
||||
}
|
||||
|
||||
inline DayNum toFirstDayNumOfWeek(DayNum d) const
|
||||
{
|
||||
return DayNum(d - (lut[d].day_of_week - 1));
|
||||
}
|
||||
inline DayNum toFirstDayNumOfWeek(DayNum d) const { return DayNum(d - (lut[d].day_of_week - 1)); }
|
||||
|
||||
inline DayNum toFirstDayNumOfWeek(time_t t) const
|
||||
{
|
||||
return toFirstDayNumOfWeek(toDayNum(t));
|
||||
}
|
||||
inline DayNum toFirstDayNumOfWeek(time_t t) const { return toFirstDayNumOfWeek(toDayNum(t)); }
|
||||
|
||||
/// Round down to start of month.
|
||||
inline time_t toFirstDayOfMonth(time_t t) const
|
||||
@ -134,15 +132,9 @@ public:
|
||||
return lut[index - (lut[index].day_of_month - 1)].date;
|
||||
}
|
||||
|
||||
inline DayNum toFirstDayNumOfMonth(DayNum d) const
|
||||
{
|
||||
return DayNum(d - (lut[d].day_of_month - 1));
|
||||
}
|
||||
inline DayNum toFirstDayNumOfMonth(DayNum d) const { return DayNum(d - (lut[d].day_of_month - 1)); }
|
||||
|
||||
inline DayNum toFirstDayNumOfMonth(time_t t) const
|
||||
{
|
||||
return toFirstDayNumOfMonth(toDayNum(t));
|
||||
}
|
||||
inline DayNum toFirstDayNumOfMonth(time_t t) const { return toFirstDayNumOfMonth(toDayNum(t)); }
|
||||
|
||||
/// Round down to start of quarter.
|
||||
inline DayNum toFirstDayNumOfQuarter(DayNum d) const
|
||||
@ -160,31 +152,16 @@ public:
|
||||
return DayNum(index + 1);
|
||||
}
|
||||
|
||||
inline DayNum toFirstDayNumOfQuarter(time_t t) const
|
||||
{
|
||||
return toFirstDayNumOfQuarter(toDayNum(t));
|
||||
}
|
||||
inline DayNum toFirstDayNumOfQuarter(time_t t) const { return toFirstDayNumOfQuarter(toDayNum(t)); }
|
||||
|
||||
inline time_t toFirstDayOfQuarter(time_t t) const
|
||||
{
|
||||
return fromDayNum(toFirstDayNumOfQuarter(t));
|
||||
}
|
||||
inline time_t toFirstDayOfQuarter(time_t t) const { return fromDayNum(toFirstDayNumOfQuarter(t)); }
|
||||
|
||||
/// Round down to start of year.
|
||||
inline time_t toFirstDayOfYear(time_t t) const
|
||||
{
|
||||
return lut[years_lut[lut[findIndex(t)].year - DATE_LUT_MIN_YEAR]].date;
|
||||
}
|
||||
inline time_t toFirstDayOfYear(time_t t) const { return lut[years_lut[lut[findIndex(t)].year - DATE_LUT_MIN_YEAR]].date; }
|
||||
|
||||
inline DayNum toFirstDayNumOfYear(DayNum d) const
|
||||
{
|
||||
return years_lut[lut[d].year - DATE_LUT_MIN_YEAR];
|
||||
}
|
||||
inline DayNum toFirstDayNumOfYear(DayNum d) const { return years_lut[lut[d].year - DATE_LUT_MIN_YEAR]; }
|
||||
|
||||
inline DayNum toFirstDayNumOfYear(time_t t) const
|
||||
{
|
||||
return toFirstDayNumOfYear(toDayNum(t));
|
||||
}
|
||||
inline DayNum toFirstDayNumOfYear(time_t t) const { return toFirstDayNumOfYear(toDayNum(t)); }
|
||||
|
||||
inline time_t toFirstDayOfNextMonth(time_t t) const
|
||||
{
|
||||
@ -200,15 +177,9 @@ public:
|
||||
return lut[index - (lut[index].day_of_month - 1)].date;
|
||||
}
|
||||
|
||||
inline UInt8 daysInMonth(DayNum d) const
|
||||
{
|
||||
return lut[d].days_in_month;
|
||||
}
|
||||
inline UInt8 daysInMonth(DayNum d) const { return lut[d].days_in_month; }
|
||||
|
||||
inline UInt8 daysInMonth(time_t t) const
|
||||
{
|
||||
return find(t).days_in_month;
|
||||
}
|
||||
inline UInt8 daysInMonth(time_t t) const { return find(t).days_in_month; }
|
||||
|
||||
inline UInt8 daysInMonth(UInt16 year, UInt8 month) const
|
||||
{
|
||||
@ -219,10 +190,7 @@ public:
|
||||
|
||||
/** Round to start of day, then shift for specified amount of days.
|
||||
*/
|
||||
inline time_t toDateAndShift(time_t t, Int32 days) const
|
||||
{
|
||||
return lut[DayNum(findIndex(t) + days)].date;
|
||||
}
|
||||
inline time_t toDateAndShift(time_t t, Int32 days) const { return lut[DayNum(findIndex(t) + days)].date; }
|
||||
|
||||
inline time_t toTime(time_t t) const
|
||||
{
|
||||
@ -324,10 +292,7 @@ public:
|
||||
return (d + 8 - toDayOfWeek(d)) / 7;
|
||||
}
|
||||
|
||||
inline unsigned toRelativeWeekNum(time_t t) const
|
||||
{
|
||||
return toRelativeWeekNum(toDayNum(t));
|
||||
}
|
||||
inline unsigned toRelativeWeekNum(time_t t) const { return toRelativeWeekNum(toDayNum(t)); }
|
||||
|
||||
/// Get year that contains most of the current week. Week begins at monday.
|
||||
inline unsigned toISOYear(DayNum d) const
|
||||
@ -336,10 +301,7 @@ public:
|
||||
return toYear(DayNum(d + 4 - toDayOfWeek(d)));
|
||||
}
|
||||
|
||||
inline unsigned toISOYear(time_t t) const
|
||||
{
|
||||
return toISOYear(toDayNum(t));
|
||||
}
|
||||
inline unsigned toISOYear(time_t t) const { return toISOYear(toDayNum(t)); }
|
||||
|
||||
/// ISO year begins with a monday of the week that is contained more than by half in the corresponding calendar year.
|
||||
/// Example: ISO year 2019 begins at 2018-12-31. And ISO year 2017 begins at 2017-01-02.
|
||||
@ -351,100 +313,204 @@ public:
|
||||
DayNum first_day_of_year = years_lut[iso_year - DATE_LUT_MIN_YEAR];
|
||||
auto first_day_of_week_of_year = lut[first_day_of_year].day_of_week;
|
||||
|
||||
return DayNum(first_day_of_week_of_year <= 4
|
||||
? first_day_of_year + 1 - first_day_of_week_of_year
|
||||
return DayNum(
|
||||
first_day_of_week_of_year <= 4 ? first_day_of_year + 1 - first_day_of_week_of_year
|
||||
: first_day_of_year + 8 - first_day_of_week_of_year);
|
||||
}
|
||||
|
||||
inline DayNum toFirstDayNumOfISOYear(time_t t) const
|
||||
{
|
||||
return toFirstDayNumOfISOYear(toDayNum(t));
|
||||
}
|
||||
inline DayNum toFirstDayNumOfISOYear(time_t t) const { return toFirstDayNumOfISOYear(toDayNum(t)); }
|
||||
|
||||
inline time_t toFirstDayOfISOYear(time_t t) const
|
||||
{
|
||||
return fromDayNum(toFirstDayNumOfISOYear(t));
|
||||
}
|
||||
inline time_t toFirstDayOfISOYear(time_t t) const { return fromDayNum(toFirstDayNumOfISOYear(t)); }
|
||||
|
||||
/// ISO 8601 week number. Week begins at monday.
|
||||
/// The week number 1 is the first week in year that contains 4 or more days (that's more than half).
|
||||
inline unsigned toISOWeek(DayNum d) const
|
||||
inline unsigned toISOWeek(DayNum d) const { return 1 + DayNum(toFirstDayNumOfWeek(d) - toFirstDayNumOfISOYear(d)) / 7; }
|
||||
|
||||
inline unsigned toISOWeek(time_t t) const { return toISOWeek(toDayNum(t)); }
|
||||
|
||||
/*
|
||||
The bits in week_mode has the following meaning:
|
||||
WEEK_MONDAY_FIRST (0) If not set Sunday is first day of week
|
||||
If set Monday is first day of week
|
||||
WEEK_YEAR (1) If not set Week is in range 0-53
|
||||
|
||||
Week 0 is returned for the the last week of the previous year (for
|
||||
a date at start of january) In this case one can get 53 for the
|
||||
first week of next year. This flag ensures that the week is
|
||||
relevant for the given year. Note that this flag is only
|
||||
releveant if WEEK_JANUARY is not set.
|
||||
|
||||
If set Week is in range 1-53.
|
||||
|
||||
In this case one may get week 53 for a date in January (when
|
||||
the week is that last week of previous year) and week 1 for a
|
||||
date in December.
|
||||
|
||||
WEEK_FIRST_WEEKDAY (2) If not set Weeks are numbered according
|
||||
to ISO 8601:1988
|
||||
If set The week that contains the first
|
||||
'first-day-of-week' is week 1.
|
||||
|
||||
WEEK_NEWYEAR_DAY (3)
|
||||
If set The week that contains the January 1 is week 1.
|
||||
Week is in range 1-53.
|
||||
And ignore WEEK_YEAR, WEEK_FIRST_WEEKDAY
|
||||
|
||||
ISO 8601:1988 means that if the week containing January 1 has
|
||||
four or more days in the new year, then it is week 1;
|
||||
Otherwise it is the last week of the previous year, and the
|
||||
next week is week 1.
|
||||
*/
|
||||
inline unsigned calc_week(DayNum d, UInt32 week_mode, UInt32 * year) const
|
||||
{
|
||||
return 1 + DayNum(toFirstDayNumOfWeek(d) - toFirstDayNumOfISOYear(d)) / 7;
|
||||
bool newyear_day_mode = week_mode & WEEK_NEWYEAR_DAY;
|
||||
|
||||
week_mode = check_week_mode(week_mode);
|
||||
bool monday_first_mode = week_mode & WEEK_MONDAY_FIRST;
|
||||
bool week_year_mode = week_mode & WEEK_YEAR;
|
||||
bool first_weekday_mode = week_mode & WEEK_FIRST_WEEKDAY;
|
||||
|
||||
// Calculate week number of WEEK_NEWYEAR_DAY mode
|
||||
if (newyear_day_mode)
|
||||
{
|
||||
return calc_newyear_week(d, monday_first_mode, year);
|
||||
}
|
||||
|
||||
inline unsigned toISOWeek(time_t t) const
|
||||
UInt32 days = 0;
|
||||
UInt64 daynr = calc_daynr(toYear(d), toMonth(d), toDayOfMonth(d));
|
||||
UInt64 first_daynr = calc_daynr(toYear(d), 1, 1);
|
||||
|
||||
// 0 for monday, 1 for tuesday ...
|
||||
// get weekday from first day in year.
|
||||
UInt32 weekday = calc_weekday(first_daynr, !monday_first_mode);
|
||||
*year = toYear(d);
|
||||
|
||||
if (toMonth(d) == 1 && toDayOfMonth(d) <= 7 - weekday)
|
||||
{
|
||||
return toISOWeek(toDayNum(t));
|
||||
if (!week_year_mode && ((first_weekday_mode && weekday != 0) || (!first_weekday_mode && weekday >= 4)))
|
||||
return 0;
|
||||
week_year_mode = 1;
|
||||
(*year)--;
|
||||
first_daynr -= (days = calc_days_in_year(*year));
|
||||
weekday = (weekday + 53 * 7 - days) % 7;
|
||||
}
|
||||
|
||||
/// Get year that contains the custom week.
|
||||
inline unsigned toCustomYear(DayNum d, UInt8 custom_month, UInt8 custom_day) const
|
||||
if ((first_weekday_mode && weekday != 0) || (!first_weekday_mode && weekday >= 4))
|
||||
days = daynr - (first_daynr + (7 - weekday));
|
||||
else
|
||||
days = daynr - (first_daynr - weekday);
|
||||
|
||||
if (week_year_mode && days >= 52 * 7)
|
||||
{
|
||||
// Checking the week across the year
|
||||
auto year = toYear(DayNum(d + 7 - toDayOfWeek(d)));
|
||||
auto day_of_year = makeDayNum(year, custom_month, custom_day);
|
||||
// Checking greater than or equal to Monday, If true take current year, else take last year.
|
||||
return toFirstDayNumOfWeek(day_of_year) <= d ? year : year - 1;
|
||||
weekday = (weekday + calc_days_in_year(*year)) % 7;
|
||||
if ((!first_weekday_mode && weekday < 4) || (first_weekday_mode && weekday == 0))
|
||||
{
|
||||
(*year)++;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return days / 7 + 1;
|
||||
}
|
||||
|
||||
inline unsigned toCustomYear(time_t t, UInt8 custom_month, UInt8 custom_day) const
|
||||
inline unsigned calc_yearWeek(DayNum d, UInt32 week_mode) const
|
||||
{
|
||||
return toCustomYear(toDayNum(t),custom_month,custom_day);
|
||||
UInt32 year = 0;
|
||||
UInt8 week = calc_week(d, week_mode | WEEK_YEAR, &year);
|
||||
return week + year * 100;
|
||||
}
|
||||
|
||||
/// Custom year begins with a monday of the week that is contained January 1,
|
||||
/// which day can be modified through custom_month and custom_day of parameters.
|
||||
/// Example: Custom year 2019 begins at 2018-12-31. And Custom year 2017 begins at 2016-12-26.
|
||||
inline DayNum toFirstDayNumOfCustomYear(DayNum d, UInt8 custom_month, UInt8 custom_day) const
|
||||
{
|
||||
auto custom_year = toCustomYear(d, custom_month, custom_day);
|
||||
return toFirstDayNumOfWeek(makeDayNum(custom_year, custom_month, custom_day));
|
||||
}
|
||||
|
||||
inline DayNum toFirstDayNumOfCustomYear(time_t t, UInt8 custom_month, UInt8 custom_day) const
|
||||
{
|
||||
return toFirstDayNumOfCustomYear(toDayNum(t), custom_month, custom_day);
|
||||
}
|
||||
|
||||
inline time_t toFirstDayOfCustomYear(time_t t, UInt8 custom_month, UInt8 custom_day) const
|
||||
{
|
||||
return fromDayNum(toFirstDayNumOfCustomYear(t, custom_month, custom_day));
|
||||
}
|
||||
|
||||
/// Custom week number. Week begins at monday.
|
||||
/// Calculate week number of WEEK_NEWYEAR_DAY mode
|
||||
/// The week number 1 is the first week in year that contains January 1,
|
||||
/// which day can be modified through custom_month and custom_day of parameters.
|
||||
inline unsigned toCustomWeek(DayNum d, UInt8 custom_month, UInt8 custom_day) const
|
||||
inline unsigned calc_newyear_week(DayNum d, bool monday_first_mode, UInt32 * year) const
|
||||
{
|
||||
return 1 + (toFirstDayNumOfWeek(d) - toFirstDayNumOfCustomYear(d, custom_month, custom_day)) / 7;
|
||||
UInt16 offset_day = monday_first_mode ? 0U : 1U;
|
||||
|
||||
// Checking the week across the year
|
||||
*year = toYear(DayNum(d + 7 - toDayOfWeek(DayNum(d + offset_day))));
|
||||
|
||||
DayNum first_day = makeDayNum(*year, 1, 1);
|
||||
DayNum this_day = d;
|
||||
|
||||
if (monday_first_mode)
|
||||
{
|
||||
// Rounds down a date to the nearest Monday.
|
||||
first_day = toFirstDayNumOfWeek(first_day);
|
||||
this_day = toFirstDayNumOfWeek(d);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Rounds down a date to the nearest Sunday.
|
||||
if (toDayOfWeek(first_day) != 7)
|
||||
first_day = DayNum(first_day - toDayOfWeek(first_day));
|
||||
if (toDayOfWeek(d) != 7)
|
||||
this_day = DayNum(d - toDayOfWeek(d));
|
||||
}
|
||||
return (this_day - first_day) / 7 + 1;
|
||||
}
|
||||
|
||||
inline unsigned toCustomWeek(time_t t, UInt8 custom_month, UInt8 custom_day) const
|
||||
inline unsigned check_week_mode(UInt32 mode) const
|
||||
{
|
||||
return toCustomWeek(toDayNum(t), custom_month, custom_day);
|
||||
UInt32 week_format = (mode & 7);
|
||||
if (!(week_format & WEEK_MONDAY_FIRST))
|
||||
week_format ^= WEEK_FIRST_WEEKDAY;
|
||||
return week_format;
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate nr of day since year 0 in new date-system (from 1615)
|
||||
SYNOPSIS
|
||||
calc_daynr()
|
||||
year Year (exact 4 digit year, no year conversions)
|
||||
month Month
|
||||
day Day
|
||||
|
||||
NOTES: 0000-00-00 is a valid date, and will return 0
|
||||
|
||||
RETURN
|
||||
Days since 0000-00-00
|
||||
*/
|
||||
inline UInt64 calc_daynr(UInt32 year, UInt32 month, UInt32 day) const
|
||||
{
|
||||
UInt64 delsum;
|
||||
int temp;
|
||||
int y = year; /* may be < 0 temporarily */
|
||||
|
||||
if (y == 0 && month == 0)
|
||||
return 0; /* Skip errors */
|
||||
/* Cast to int to be able to handle month == 0 */
|
||||
delsum = static_cast<UInt64>(365 * y + 31 * (month - 1) + day);
|
||||
delsum = static_cast<UInt64>(365 * y + 31 * (static_cast<int>(month) - 1) + static_cast<int>(day));
|
||||
if (month <= 2)
|
||||
y--;
|
||||
else
|
||||
delsum -= static_cast<UInt64>(static_cast<int>(month) * 4 + 23) / 10;
|
||||
temp = ((y / 100 + 1) * 3) / 4;
|
||||
return delsum + y / 4 - temp;
|
||||
} /* calc_daynr */
|
||||
|
||||
/*
|
||||
Calc weekday from daynr
|
||||
Returns 0 for monday, 1 for tuesday ...
|
||||
*/
|
||||
inline unsigned calc_weekday(UInt64 daynr, bool sunday_first_day_of_week) const
|
||||
{
|
||||
return (static_cast<UInt32>((daynr + 5L + (sunday_first_day_of_week ? 1L : 0L)) % 7));
|
||||
}
|
||||
|
||||
/* Calc days in one year. */
|
||||
inline unsigned calc_days_in_year(UInt32 year) const
|
||||
{
|
||||
return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)) ? 366 : 365);
|
||||
}
|
||||
|
||||
/// Number of month from some fixed moment in the past (year * 12 + month)
|
||||
inline unsigned toRelativeMonthNum(DayNum d) const
|
||||
{
|
||||
return lut[d].year * 12 + lut[d].month;
|
||||
}
|
||||
inline unsigned toRelativeMonthNum(DayNum d) const { return lut[d].year * 12 + lut[d].month; }
|
||||
|
||||
inline unsigned toRelativeMonthNum(time_t t) const
|
||||
{
|
||||
return toRelativeMonthNum(toDayNum(t));
|
||||
}
|
||||
inline unsigned toRelativeMonthNum(time_t t) const { return toRelativeMonthNum(toDayNum(t)); }
|
||||
|
||||
inline unsigned toRelativeQuarterNum(DayNum d) const
|
||||
{
|
||||
return lut[d].year * 4 + (lut[d].month - 1) / 3;
|
||||
}
|
||||
inline unsigned toRelativeQuarterNum(DayNum d) const { return lut[d].year * 4 + (lut[d].month - 1) / 3; }
|
||||
|
||||
inline unsigned toRelativeQuarterNum(time_t t) const
|
||||
{
|
||||
return toRelativeQuarterNum(toDayNum(t));
|
||||
}
|
||||
inline unsigned toRelativeQuarterNum(time_t t) const { return toRelativeQuarterNum(toDayNum(t)); }
|
||||
|
||||
/// We count all hour-length intervals, unrelated to offset changes.
|
||||
inline time_t toRelativeHourNum(time_t t) const
|
||||
@ -457,20 +523,11 @@ public:
|
||||
return (t + 86400 - offset_at_start_of_epoch) / 3600;
|
||||
}
|
||||
|
||||
inline time_t toRelativeHourNum(DayNum d) const
|
||||
{
|
||||
return toRelativeHourNum(lut[d].date);
|
||||
}
|
||||
inline time_t toRelativeHourNum(DayNum d) const { return toRelativeHourNum(lut[d].date); }
|
||||
|
||||
inline time_t toRelativeMinuteNum(time_t t) const
|
||||
{
|
||||
return t / 60;
|
||||
}
|
||||
inline time_t toRelativeMinuteNum(time_t t) const { return t / 60; }
|
||||
|
||||
inline time_t toRelativeMinuteNum(DayNum d) const
|
||||
{
|
||||
return toRelativeMinuteNum(lut[d].date);
|
||||
}
|
||||
inline time_t toRelativeMinuteNum(DayNum d) const { return toRelativeMinuteNum(lut[d].date); }
|
||||
|
||||
inline DayNum toStartOfYearInterval(DayNum d, UInt64 years) const
|
||||
{
|
||||
@ -540,16 +597,14 @@ public:
|
||||
/// Create DayNum from year, month, day of month.
|
||||
inline DayNum makeDayNum(UInt16 year, UInt8 month, UInt8 day_of_month) const
|
||||
{
|
||||
if (unlikely(year < DATE_LUT_MIN_YEAR || year > DATE_LUT_MAX_YEAR || month < 1 || month > 12 || day_of_month < 1 || day_of_month > 31))
|
||||
if (unlikely(
|
||||
year < DATE_LUT_MIN_YEAR || year > DATE_LUT_MAX_YEAR || month < 1 || month > 12 || day_of_month < 1 || day_of_month > 31))
|
||||
return DayNum(0);
|
||||
|
||||
return DayNum(years_months_lut[(year - DATE_LUT_MIN_YEAR) * 12 + month - 1] + day_of_month - 1);
|
||||
}
|
||||
|
||||
inline time_t makeDate(UInt16 year, UInt8 month, UInt8 day_of_month) const
|
||||
{
|
||||
return lut[makeDayNum(year, month, day_of_month)].date;
|
||||
}
|
||||
inline time_t makeDate(UInt16 year, UInt8 month, UInt8 day_of_month) const { return lut[makeDayNum(year, month, day_of_month)].date; }
|
||||
|
||||
/** Does not accept daylight saving time as argument: in case of ambiguity, it choose greater timestamp.
|
||||
*/
|
||||
@ -591,38 +646,21 @@ public:
|
||||
return values.year * 10000 + values.month * 100 + values.day_of_month;
|
||||
}
|
||||
|
||||
inline time_t YYYYMMDDToDate(UInt32 num) const
|
||||
{
|
||||
return makeDate(num / 10000, num / 100 % 100, num % 100);
|
||||
}
|
||||
inline time_t YYYYMMDDToDate(UInt32 num) const { return makeDate(num / 10000, num / 100 % 100, num % 100); }
|
||||
|
||||
inline DayNum YYYYMMDDToDayNum(UInt32 num) const
|
||||
{
|
||||
return makeDayNum(num / 10000, num / 100 % 100, num % 100);
|
||||
}
|
||||
inline DayNum YYYYMMDDToDayNum(UInt32 num) const { return makeDayNum(num / 10000, num / 100 % 100, num % 100); }
|
||||
|
||||
|
||||
inline UInt64 toNumYYYYMMDDhhmmss(time_t t) const
|
||||
{
|
||||
const Values & values = find(t);
|
||||
return
|
||||
toSecond(t)
|
||||
+ toMinute(t) * 100
|
||||
+ toHour(t) * 10000
|
||||
+ UInt64(values.day_of_month) * 1000000
|
||||
+ UInt64(values.month) * 100000000
|
||||
+ UInt64(values.year) * 10000000000;
|
||||
return toSecond(t) + toMinute(t) * 100 + toHour(t) * 10000 + UInt64(values.day_of_month) * 1000000
|
||||
+ UInt64(values.month) * 100000000 + UInt64(values.year) * 10000000000;
|
||||
}
|
||||
|
||||
inline time_t YYYYMMDDhhmmssToTime(UInt64 num) const
|
||||
{
|
||||
return makeDateTime(
|
||||
num / 10000000000,
|
||||
num / 100000000 % 100,
|
||||
num / 1000000 % 100,
|
||||
num / 10000 % 100,
|
||||
num / 100 % 100,
|
||||
num % 100);
|
||||
return makeDateTime(num / 10000000000, num / 100000000 % 100, num / 1000000 % 100, num / 10000 % 100, num / 100 % 100, num % 100);
|
||||
}
|
||||
|
||||
/// Adding calendar intervals.
|
||||
@ -641,10 +679,7 @@ public:
|
||||
return lut[index].date + time_offset;
|
||||
}
|
||||
|
||||
inline time_t addWeeks(time_t t, Int64 delta) const
|
||||
{
|
||||
return addDays(t, delta * 7);
|
||||
}
|
||||
inline time_t addWeeks(time_t t, Int64 delta) const { return addDays(t, delta * 7); }
|
||||
|
||||
inline UInt8 saturateDayOfMonth(UInt16 year, UInt8 month, UInt8 day_of_month) const
|
||||
{
|
||||
@ -697,15 +732,9 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
inline time_t addQuarters(time_t t, Int64 delta) const
|
||||
{
|
||||
return addMonths(t, delta * 3);
|
||||
}
|
||||
inline time_t addQuarters(time_t t, Int64 delta) const { return addMonths(t, delta * 3); }
|
||||
|
||||
inline DayNum addQuarters(DayNum d, Int64 delta) const
|
||||
{
|
||||
return addMonths(d, delta * 3);
|
||||
}
|
||||
inline DayNum addQuarters(DayNum d, Int64 delta) const { return addMonths(d, delta * 3); }
|
||||
|
||||
/// Saturation can occur if 29 Feb is mapped to non-leap year.
|
||||
inline time_t addYears(time_t t, Int64 delta) const
|
||||
|
Loading…
Reference in New Issue
Block a user