aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Common/LocalDateTime.h
blob: 1aa4f421ea1cfc3e3caccea2da92a145ee3bce18 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#pragma once

#include <string>
#include <iomanip>
#include <exception>
#include <Common/DateLUT.h>
#include <Common/LocalDate.h>


/** Stores calendar date and time in broken-down form.
  * Could be initialized from date and time in text form like '2011-01-01 00:00:00' or from time_t.
  * Could be implicitly casted to time_t.
  * NOTE: Transforming between time_t and LocalDate is done in local time zone!
  *
  * When local time was shifted backwards (due to daylight saving time or whatever reason)
  *  - then to resolve the ambiguity of transforming to time_t, lowest of two possible values is selected.
  */
class LocalDateTime
{
private:
    unsigned short m_year; /// NOLINT
    unsigned char m_month;
    unsigned char m_day;
    unsigned char m_hour;
    unsigned char m_minute;
    unsigned char m_second;

    /// For struct to fill 8 bytes and for safe invocation of memcmp.
    /// NOTE We may use attribute packed instead, but it is less portable.
    unsigned char pad = 0;

    void init(time_t time, const DateLUTImpl & time_zone)
    {
        DateLUTImpl::DateTimeComponents components = time_zone.toDateTimeComponents(static_cast<DateLUTImpl::Time>(time));

        m_year = components.date.year;
        m_month = components.date.month;
        m_day = components.date.day;
        m_hour = components.time.hour;
        m_minute = components.time.minute;
        m_second = components.time.second;

        (void)pad;  /// Suppress unused private field warning.
    }

    void init(const char * s, size_t length)
    {
        if (length < 19)
            throw std::runtime_error("Cannot parse LocalDateTime: " + std::string(s, length));

        m_year = (s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + (s[3] - '0');
        m_month = (s[5] - '0') * 10 + (s[6] - '0');
        m_day = (s[8] - '0') * 10 + (s[9] - '0');

        m_hour = (s[11] - '0') * 10 + (s[12] - '0');
        m_minute = (s[14] - '0') * 10 + (s[15] - '0');
        m_second = (s[17] - '0') * 10 + (s[18] - '0');

        (void)pad;
    }

public:
    explicit LocalDateTime(time_t time, const DateLUTImpl & time_zone = DateLUT::instance())
    {
        init(time, time_zone);
    }

    LocalDateTime(unsigned short year_, unsigned char month_, unsigned char day_, /// NOLINT
        unsigned char hour_, unsigned char minute_, unsigned char second_)
        : m_year(year_), m_month(month_), m_day(day_), m_hour(hour_), m_minute(minute_), m_second(second_)
    {
    }

    explicit LocalDateTime(const std::string & s)
    {
        if (s.size() < 19)
            throw std::runtime_error("Cannot parse LocalDateTime: " + s);

        init(s.data(), s.size());
    }

    LocalDateTime() : m_year(0), m_month(0), m_day(0), m_hour(0), m_minute(0), m_second(0)
    {
    }

    LocalDateTime(const char * data, size_t length)
    {
        init(data, length);
    }

    LocalDateTime(const LocalDateTime &) noexcept = default;
    LocalDateTime & operator= (const LocalDateTime &) noexcept = default;

    unsigned short year() const { return m_year; } /// NOLINT
    unsigned char month() const { return m_month; }
    unsigned char day() const { return m_day; }
    unsigned char hour() const { return m_hour; }
    unsigned char minute() const { return m_minute; }
    unsigned char second() const { return m_second; }

    void year(unsigned short x) { m_year = x; } /// NOLINT
    void month(unsigned char x) { m_month = x; }
    void day(unsigned char x) { m_day = x; }
    void hour(unsigned char x) { m_hour = x; }
    void minute(unsigned char x) { m_minute = x; }
    void second(unsigned char x) { m_second = x; }

    LocalDate toDate() const { return LocalDate(m_year, m_month, m_day); }
    LocalDateTime toStartOfDate() const { return LocalDateTime(m_year, m_month, m_day, 0, 0, 0); }

    time_t to_time_t(const DateLUTImpl & time_zone = DateLUT::instance()) const /// NOLINT
    {
        return time_zone.makeDateTime(m_year, m_month, m_day, m_hour, m_minute, m_second);
    }

    std::string toString() const
    {
        std::string s{"0000-00-00 00:00:00"};

        s[0] += m_year / 1000;
        s[1] += (m_year / 100) % 10;
        s[2] += (m_year / 10) % 10;
        s[3] += m_year % 10;
        s[5] += m_month / 10;
        s[6] += m_month % 10;
        s[8] += m_day / 10;
        s[9] += m_day % 10;

        s[11] += m_hour / 10;
        s[12] += m_hour % 10;
        s[14] += m_minute / 10;
        s[15] += m_minute % 10;
        s[17] += m_second / 10;
        s[18] += m_second % 10;

        return s;
    }

    bool operator< (const LocalDateTime & other) const
    {
        return 0 > memcmp(this, &other, sizeof(*this));
    }

    bool operator> (const LocalDateTime & other) const
    {
        return 0 < memcmp(this, &other, sizeof(*this));
    }

    bool operator<= (const LocalDateTime & other) const
    {
        return 0 >= memcmp(this, &other, sizeof(*this));
    }

    bool operator>= (const LocalDateTime & other) const
    {
        return 0 <= memcmp(this, &other, sizeof(*this));
    }

    bool operator== (const LocalDateTime & other) const
    {
        return 0 == memcmp(this, &other, sizeof(*this));
    }

    bool operator!= (const LocalDateTime & other) const
    {
        return !(*this == other);
    }
};

static_assert(sizeof(LocalDateTime) == 8);