Skip to content

Commit

Permalink
add a date type DateStdT implementation using only std::chrono types
Browse files Browse the repository at this point in the history
  • Loading branch information
vsian committed Sep 4, 2024
1 parent 715e745 commit be4af9d
Show file tree
Hide file tree
Showing 6 changed files with 378 additions and 61 deletions.
11 changes: 8 additions & 3 deletions src/common/stl.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -192,16 +192,21 @@ export namespace std {
using std::chrono::steady_clock;
using std::chrono::time_point;

using std::chrono::year_month_day;
using std::chrono::sys_days;
using std::chrono::system_clock;

using std::chrono::ceil;
using std::chrono::days;
using std::tm;
using std::time_t;
using std::mktime;
using std::format;

using std::chrono::year;
using std::chrono::month;
using std::chrono::day;

using std::chrono::year_month_day;
using std::chrono::sys_days;
using std::chrono::system_clock;
} // namespace chrono

using std::cout;
Expand Down
270 changes: 212 additions & 58 deletions src/parser/type/datetime/date_type_std.cpp
Original file line number Diff line number Diff line change
@@ -1,60 +1,214 @@
#pragma once

#include "interval_type.h"
#include <string>

namespace infinity {

struct DateTypeStd {
friend struct DateTimeType;

DateType() = default;

explicit constexpr DateType(int32_t date_value) : value(date_value){};

inline int32_t GetValue() const { return value; }

operator int32_t() const { return value; }

inline void FromString(const std::string_view &date_str) { FromString(date_str.data(), date_str.size()); }

void FromString(const char *date, size_t length);

void FromString(const char *date, size_t length, size_t &end_length);

[[nodiscard]] std::string ToString() const;

int32_t value{0};

private:
static bool ConvertFromString(const char *date_ptr, size_t length, DateType &date, size_t &end_length);

static bool YMD2Date(int32_t year, int32_t month, int32_t day, DateType &date);

static bool Date2YMD(int32_t days, int32_t &year, int32_t &month, int32_t &day);

inline static bool IsLeapYear(int32_t year) { return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); }

static bool IsDateValid(int32_t year, int32_t month, int32_t day);

public:
inline bool operator==(const DateType &other) const { return this->value == other.value; }

inline bool operator>=(const DateType &other) const { return this->value >= other.value; }

inline bool operator>(const DateType &other) const { return this->value > other.value; }

inline bool operator<=(const DateType &other) const { return this->value <= other.value; }

inline bool operator<(const DateType &other) const { return this->value < other.value; }

public:
// Operation
static bool Add(DateType input, IntervalType interval, DateType &output);

static bool Subtract(DateType input, IntervalType interval, DateType &output);

static int64_t GetDatePart(DateType input, TimeUnit unit);
};
#include "date_type_std.h"
#include "parser_assert.h"
#include <format>
#include <chrono>

constexpr static int32_t DAY_HOUR = 24;
constexpr static int32_t DAY_MINUTE = DAY_HOUR * 60;
constexpr static int32_t DAY_SECOND = DAY_MINUTE * 60;

namespace infinity{

void DateTypeStd::FromString(const char *date_ptr, size_t length) {
size_t end_length_unused;
if (!ConvertFromString(date_ptr, length, *this, end_length_unused)) {
ParserError("Invalid date format (YYYY-MM-DD or YYYY/MM/DD).");
}
}

void DateTypeStd::FromString(const char *date_ptr, size_t length, size_t &end_length) {
if (!ConvertFromString(date_ptr, length, *this, end_length)) {
ParserError("Invalid date format (YYYY-MM-DD or YYYY/MM/DD).");
}
}

std::string DateTypeStd::ToString() const {
int32_t year{0}, month{0}, day{0};
if (!Date2YMD(value, year, month, day)) {
ParserError(std::format("Invalid date: {}-{}-{}", year, month, day));
}
// TODO: format for negative year?
return std::format("{:04d}-{:02d}-{:02d}", year, month, day);
}

bool DateTypeStd::ConvertFromString(const char *date_ptr, size_t length, DateTypeStd &date, size_t &end_length) {
// trim the string
size_t pos{0};

// skip spaces
while (pos < length && std::isspace(date_ptr[pos])) {
++pos;
}

// Get year
int32_t year{0};
bool negative_year{false};
if (date_ptr[pos] == '-') {
negative_year = true;
++pos;
}
while (pos < length && std::isdigit(date_ptr[pos])) {
if (std::isspace(date_ptr[pos])) {
++pos;
continue;
}
if (std::isdigit(date_ptr[pos])) {
year = year * 10 + (date_ptr[pos] - '0');
++pos;
// if (year > 9999)
// return false;
continue;
}
break;
}
if (negative_year) {
year = -year;
}
if (date_ptr[pos] != '-' && date_ptr[pos] != '/') {
return false;
}
++pos; // skip - and /

// Get month
int32_t month{0};
while (pos < length && std::isdigit(date_ptr[pos])) {
if (std::isspace(date_ptr[pos])) {
++pos;
continue;
}
if (std::isdigit(date_ptr[pos])) {
month = month * 10 + (date_ptr[pos] - '0');
++pos;
// if (month > 12)
// return false;
continue;
}
break;
}
if (date_ptr[pos] != '-' && date_ptr[pos] != '/') {
return false;
}
++pos; // skip - and /

// Get day
int32_t day{0};
while (pos < length && std::isdigit(date_ptr[pos])) {
if (std::isspace(date_ptr[pos])) {
++pos;
continue;
}
if (std::isdigit(date_ptr[pos])) {
day = day * 10 + (date_ptr[pos] - '0');
++pos;
// if (day > 31)
// return false;
continue;
}
break;
}
end_length = pos;

return YMD2Date(year, month, day, date);
}

bool DateTypeStd::YMD2Date(int32_t year, int32_t month, int32_t day, DateTypeStd &date) {
std::chrono::year_month_day ymd (
std::chrono::year{year},
std::chrono::month{static_cast<unsigned int>(month)},
std::chrono::day{static_cast<unsigned int>(day)}
);
auto sd = std::chrono::sys_days{ymd};
date.value = sd.time_since_epoch().count();
return ymd.ok();
}

bool DateTypeStd::Date2YMD(int32_t days, int32_t &year, int32_t &month, int32_t &day) {
auto sd = std::chrono::sys_days{std::chrono::days{days}};
auto ymd = std::chrono::year_month_day{sd};

year = static_cast<int>(ymd.year());
month = static_cast<unsigned>(ymd.month());
day = static_cast<unsigned>(ymd.day());
return IsDateValid(year, month, day);
}

bool DateTypeStd::IsDateValid(int32_t year, int32_t month, int32_t day) {
DateTypeStd date;
return YMD2Date(year, month, day, date);
}

bool DateTypeStd::Add(DateTypeStd input, IntervalType interval, DateTypeStd &output) {
int32_t year{0}, month{0}, day{0};
if (!Date2YMD(input.value, year, month, day)) {
return false;
}
switch (interval.unit) {
case kYear: {
std::chrono::sys_days output_sd(std::chrono::days{input.value} + std::chrono::duration_cast<std::chrono::days>(std::chrono::years{interval.value}));
output.value = output_sd.time_since_epoch().count();
return true;
}
case kMonth: {
std::chrono::sys_days output_sd(std::chrono::days{input.value} + std::chrono::duration_cast<std::chrono::days>(std::chrono::months{interval.value}));
output.value = output_sd.time_since_epoch().count();
return true;
}
case kDay: {
output.value = input.value + interval.value;
return true;
}
case kHour: {
output.value = input.value + (interval.value / DAY_HOUR);
return true;
}
case kMinute: {
output.value = input.value + (interval.value / DAY_MINUTE);
return true;
}
case kSecond: {
output.value = input.value + (interval.value / DAY_SECOND);
return true;
}
case kInvalidUnit: {
ParserError("Invalid interval unit.");
}
}
return false;
}

bool DateTypeStd::Subtract(DateTypeStd input, IntervalType interval, DateTypeStd &output) {
interval.value = -interval.value;
return Add(input, interval, output);
}

int64_t DateTypeStd::GetDatePart(DateTypeStd input, TimeUnit unit) {
int32_t year{}, month{}, day{};
auto result = Date2YMD(input.value, year, month, day);
ParserAssert(result, "Invalid date value");
switch (unit) {
case TimeUnit::kYear: {
return year;
}
case TimeUnit::kMonth: {
return month;
}
case TimeUnit::kDay: {
return day;
}
case TimeUnit::kHour: {
ParserError("Can't extract hour from date");
}
case TimeUnit::kMinute: {
ParserError("Can't extract minute from date");
}
case TimeUnit::kSecond: {
ParserError("Can't extract second from date");
}
default: {
ParserError("Invalid time unit");
}
}
return -1;
}

}
60 changes: 60 additions & 0 deletions src/parser/type/datetime/date_type_std.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#pragma once

#include "interval_type.h"
#include <string>

namespace infinity {

struct DateTypeStd {
friend struct DateTimeType;

DateTypeStd() = default;

explicit constexpr DateTypeStd(int32_t date_value) : value(date_value){};

inline int32_t GetValue() const { return value; }

operator int32_t() const { return value; }

inline void FromString(const std::string_view &date_str) { FromString(date_str.data(), date_str.size()); }

void FromString(const char *date, size_t length);

void FromString(const char *date, size_t length, size_t &end_length);

[[nodiscard]] std::string ToString() const;

int32_t value{0};

private:
static bool ConvertFromString(const char *date_ptr, size_t length, DateTypeStd &date, size_t &end_length);

static bool YMD2Date(int32_t year, int32_t month, int32_t day, DateTypeStd &date);

static bool Date2YMD(int32_t days, int32_t &year, int32_t &month, int32_t &day);

inline static bool IsLeapYear(int32_t year) { return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); }

static bool IsDateValid(int32_t year, int32_t month, int32_t day);

public:
inline bool operator==(const DateTypeStd &other) const { return this->value == other.value; }

inline bool operator>=(const DateTypeStd &other) const { return this->value >= other.value; }

inline bool operator>(const DateTypeStd &other) const { return this->value > other.value; }

inline bool operator<=(const DateTypeStd &other) const { return this->value <= other.value; }

inline bool operator<(const DateTypeStd &other) const { return this->value < other.value; }

public:
// Operation
static bool Add(DateTypeStd input, IntervalType interval, DateTypeStd &output);

static bool Subtract(DateTypeStd input, IntervalType interval, DateTypeStd &output);

static int64_t GetDatePart(DateTypeStd input, TimeUnit unit);
};

}
1 change: 1 addition & 0 deletions src/parser/type/internal_types.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export using infinity::DateT;

export using infinity::TimeT;
export using infinity::DateTimeT;
export using infinity::DateStdT;
export using infinity::TimestampT;
export using infinity::IntervalT;

Expand Down
2 changes: 2 additions & 0 deletions src/parser/type/internal_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#pragma once


#include "type/datetime/date_type_std.h"
#include "type/number/float16.h"
#include "type/number/bfloat16.h"
#include "type/number/huge_int.h"
Expand Down Expand Up @@ -64,6 +65,7 @@ using VarcharT = Varchar;

// Date and Time
using DateT = DateType;
using DateStdT = DateTypeStd;
using TimeT = TimeType;
using DateTimeT = DateTimeType;
using TimestampT = TimestampType;
Expand Down
Loading

0 comments on commit be4af9d

Please sign in to comment.