LoginSignup
1
0

More than 1 year has passed since last update.

Happy new year.

Posted at

昨年末いまさらですが clickhouse-client を終了するときに変わった出力をしていることに気づきました。

> clickhouse-client
ClickHouse client version 21.12.2.17 (official build).
Connecting to localhost:9000 as user default.
Connected to ClickHouse server version 21.12.2 revision 54452.

:) exit
Happy new year.

Happy new year.

普段はBye.。年末年始仕様のメッセージが仕組まれています。クライアントのコードを追ってみます。

Client/ClientBase.cpp
    if (isNewYearMode())
        std::cout << "Happy new year." << std::endl;
    else if (isChineseNewYearMode(local_tz))
        std::cout << "Happy Chinese new year. 春节快乐!" << std::endl;
    else
        std::cout << "Bye." << std::endl;

この特殊演出は、 isNewYearModeisChineseNewYearMode の2パターン用意されているようです。
isNewYearModeから見ていきます。

Client/ClientBaseHelpers.cpp
bool isNewYearMode()
{
    time_t current_time = time(nullptr);

    /// It's bad to be intrusive.
    if (current_time % 3 != 0)
        return false;

    LocalDate now(current_time);
    return (now.month() == 12 && now.day() >= 20) || (now.month() == 1 && now.day() <= 5);
}

12/20 - 1/5まで出力されるようです。

続いてisChineseNewYearMode。名前からして中国の春節に対応するメソッドです。

Client/ClientBaseHelpers.cpp
bool isChineseNewYearMode(const String & local_tz)
{
    /// Days of Dec. 20 in Chinese calendar starting from year 2019 to year 2105
    static constexpr UInt16 chineseNewYearIndicators[]
        = {18275, 18659, 19014, 19368, 19752, 20107, 20491, 20845, 21199, 21583, 21937, 22292, 22676, 23030, 23414, 23768, 24122, 24506,
            24860, 25215, 25599, 25954, 26308, 26692, 27046, 27430, 27784, 28138, 28522, 28877, 29232, 29616, 29970, 30354, 30708, 31062,
            31446, 31800, 32155, 32539, 32894, 33248, 33632, 33986, 34369, 34724, 35078, 35462, 35817, 36171, 36555, 36909, 37293, 37647,
            38002, 38386, 38740, 39095, 39479, 39833, 40187, 40571, 40925, 41309, 41664, 42018, 42402, 42757, 43111, 43495, 43849, 44233,
            44587, 44942, 45326, 45680, 46035, 46418, 46772, 47126, 47510, 47865, 48249, 48604, 48958, 49342};

    /// All time zone names are acquired from https://www.iana.org/time-zones
    static constexpr const char * chineseNewYearTimeZoneIndicators[] = {
        /// Time zones celebrating Chinese new year.
        "Asia/Shanghai",
        "Asia/Chongqing",
        "Asia/Harbin",
        "Asia/Urumqi",
        "Asia/Hong_Kong",
        "Asia/Chungking",
        "Asia/Macao",
        "Asia/Macau",
        "Asia/Taipei",
        "Asia/Singapore",

        /// Time zones celebrating Chinese new year but with different festival names. Let's not print the message for now.
        // "Asia/Brunei",
        // "Asia/Ho_Chi_Minh",
        // "Asia/Hovd",
        // "Asia/Jakarta",
        // "Asia/Jayapura",
        // "Asia/Kashgar",
        // "Asia/Kuala_Lumpur",
        // "Asia/Kuching",
        // "Asia/Makassar",
        // "Asia/Pontianak",
        // "Asia/Pyongyang",
        // "Asia/Saigon",
        // "Asia/Seoul",
        // "Asia/Ujung_Pandang",
        // "Asia/Ulaanbaatar",
        // "Asia/Ulan_Bator",
    };
    static constexpr size_t M = sizeof(chineseNewYearTimeZoneIndicators) / sizeof(chineseNewYearTimeZoneIndicators[0]);

    time_t current_time = time(nullptr);

    if (chineseNewYearTimeZoneIndicators + M
        == std::find_if(chineseNewYearTimeZoneIndicators, chineseNewYearTimeZoneIndicators + M, [&local_tz](const char * tz)
                        {
                            return tz == local_tz;
                        }))
        return false;

    /// It's bad to be intrusive.
    if (current_time % 3 != 0)
        return false;

    auto days = DateLUT::instance().toDayNum(current_time).toUnderType();
    for (auto d : chineseNewYearIndicators)
    {
        /// Let's celebrate until Lantern Festival
        if (d <= days && d + 25 >= days)
            return true;
        else if (d > days)
            return false;
    }
    return false;
}

しっかり書いてる。。。C++はわからないので、調べ調べ読み進めます。

static constexpr size_t M = sizeof(chineseNewYearTimeZoneIndicators) / sizeof(chineseNewYearTimeZoneIndicators[0]);

配列の要素数を求めています。配列全体のサイズ / 要素1つのサイズ = 要素数 ということみたいです。要素を追加したときでも対応してくれる書き方のようです。

std::find_if(chineseNewYearTimeZoneIndicators, chineseNewYearTimeZoneIndicators + M, [&local_tz](const char * tz)
                        {
                            return tz == local_tz;
                        })

こメソッドの引数で渡されたタイムゾーンが、chineseNewYearTimeZoneIndicators内に存在するか検索し、見つかったポインタが戻ります。見つからなかった場合は、chineseNewYearTimeZoneIndicators + M(配列の終端のポインタ)が返ります。

auto days = DateLUT::instance().toDayNum(current_time).toUnderType();

ここでは現在の日数を求めています。日数は1925/01/01からの経過日数です。
起点はDateLUTのコードの以下の箇所にあります。

Common/DateLUTImpl.h
#define DATE_LUT_MIN_YEAR 1925 /// 1925 since wast majority of timezones changed to 15-minute aligned offsets somewhere in 1924 or earlier.

求めた現在の日数と、chineseNewYearIndicatorsのリストを比較して春節当日から25日間出力されます。リストは2015年まで用意されています。


最後に、2022年のClickHouseのロードマップを置いておきます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0