DatetimeProperties#

class pandas::DatetimeProperties#

pandas C++ class.

Example#

#include <pandas/pandas.h>
using namespace pandas;

// Use DatetimeProperties
DatetimeProperties obj;
// ... operations ...

Indexing / Selection#

Signature

Return Type

Location

Example

static int64_t get_freq_nanoseconds(const std::string& freq)

static int64_t

pd_datetime_accessor.h:720

Statistics#

Signature

Return Type

Location

Example

std::vector<int64_t> minute() const

std::vector<int64_t>

pd_datetime_accessor.h:114

View

Time Series#

Signature

Return Type

Location

Example

PeriodArray to_period(const std::string& freq = "D") const

PeriodArray

pd_datetime_accessor.h:625

View

std::vector<numpy::datetime64> tz_convert(const std::string& tz) const

std::vector<numpy::datetime64>

pd_datetime_accessor.h:641

View

std::vector<numpy::datetime64> tz_localize(const std::string& tz, const std::string& ambiguous = "raise", const std::string& nonexistent = "raise") const

std::vector<numpy::datetime64>

pd_datetime_accessor.h:667

View

I/O#

Signature

Return Type

Location

Example

std::vector<numpy::datetime64> to_pydatetime() const

std::vector<numpy::datetime64>

pd_datetime_accessor.h:700

View

Type Checking#

Signature

Return Type

Location

Example

std::vector<bool> is_leap_year() const

std::vector<bool>

pd_datetime_accessor.h:305

View

std::vector<bool> is_month_end() const

std::vector<bool>

pd_datetime_accessor.h:223

View

std::vector<bool> is_month_start() const

std::vector<bool>

pd_datetime_accessor.h:208

View

std::vector<bool> is_quarter_end() const

std::vector<bool>

pd_datetime_accessor.h:257

View

std::vector<bool> is_quarter_start() const

std::vector<bool>

pd_datetime_accessor.h:241

View

std::vector<bool> is_year_end() const

std::vector<bool>

pd_datetime_accessor.h:290

View

std::vector<bool> is_year_start() const

std::vector<bool>

pd_datetime_accessor.h:275

View

Other Methods#

Signature

Return Type

Location

Example

std::vector<numpy::datetime64> as_unit(const std::string& unit_str) const

std::vector<numpy::datetime64>

pd_datetime_accessor.h:690

View

std::vector<numpy::datetime64> ceil(const std::string& freq, const std::string& ambiguous = "raise", const std::string& nonexistent = "raise") const

std::vector<numpy::datetime64>

pd_datetime_accessor.h:608

View

static numpy::datetime64 ceil_datetime(const numpy::datetime64& dt, const std::string& freq)

static numpy::datetime64

pd_datetime_accessor.h:753

std::vector<std::string> date() const

std::vector<std::string>

pd_datetime_accessor.h:339

View

std::vector<int64_t> day() const

std::vector<int64_t>

pd_datetime_accessor.h:84

View

std::vector<std::string> day_name(const std::string& locale = "") const

std::vector<std::string>

pd_datetime_accessor.h:430

View

std::vector<int64_t> dayofweek() const

std::vector<int64_t>

pd_datetime_accessor.h:144

View

std::vector<int64_t> dayofyear() const

std::vector<int64_t>

pd_datetime_accessor.h:160

View

static int days_in_month(int year, int month)

static int

pd_datetime_accessor.h:710

View

std::vector<int64_t> days_in_month_prop() const

std::vector<int64_t>

pd_datetime_accessor.h:359

View

DatetimeArray dta(data, src_tz)

DatetimeArray

pd_datetime_accessor.h:654

DatetimeArray dta(data, nullptr)

DatetimeArray

pd_datetime_accessor.h:677

std::vector<numpy::datetime64> floor(const std::string& freq, const std::string& ambiguous = "raise", const std::string& nonexistent = "raise") const

std::vector<numpy::datetime64>

pd_datetime_accessor.h:591

View

static numpy::datetime64 floor_datetime(const numpy::datetime64& dt, const std::string& freq)

static numpy::datetime64

pd_datetime_accessor.h:744

std::string freq() const

std::string

pd_datetime_accessor.h:410

View

bool has_nat() const

bool

pd_datetime_accessor.h:37

View

std::vector<int64_t> hour() const

std::vector<int64_t>

pd_datetime_accessor.h:99

View

IsoCalendar isocalendar() const

IsoCalendar

pd_datetime_accessor.h:496

View

DataFrame isocalendar_to_dataframe() const

DataFrame

pd_datetime_accessor.h:494

std::vector<int64_t> microsecond() const

std::vector<int64_t>

pd_datetime_accessor.h:376

View

std::vector<int64_t> month() const

std::vector<int64_t>

pd_datetime_accessor.h:69

View

std::vector<std::string> month_name(const std::string& locale = "") const

std::vector<std::string>

pd_datetime_accessor.h:448

View

std::vector<int64_t> nanosecond() const

std::vector<int64_t>

pd_datetime_accessor.h:393

View

std::vector<numpy::datetime64> normalize() const

std::vector<numpy::datetime64>

pd_datetime_accessor.h:466

View

const ParentType& parent() const

const ParentType&

pd_datetime_accessor.h:35

explicit DatetimeProperties(const ParentType& parent) : parent_(parent)

explicit DatetimeProperties(const ParentType& parent) :

pd_datetime_accessor.h:31

std::vector<int64_t> quarter() const

std::vector<int64_t>

pd_datetime_accessor.h:175

View

std::vector<numpy::datetime64> round(const std::string& freq, const std::string& ambiguous = "raise", const std::string& nonexistent = "raise") const

std::vector<numpy::datetime64>

pd_datetime_accessor.h:574

View

static numpy::datetime64 round_datetime(const numpy::datetime64& dt, const std::string& freq)

static numpy::datetime64

pd_datetime_accessor.h:764

pandas::Series<T> s(std::move(data))

pandas::Series<T>

pd_datetime_accessor.h:46

View

std::vector<int64_t> second() const

std::vector<int64_t>

pd_datetime_accessor.h:129

View

void set_tz_override(const std::string& tz)

void

pd_datetime_accessor.h:33

std::vector<std::string> strftime(const std::string& format) const

std::vector<std::string>

pd_datetime_accessor.h:322

View

std::vector<std::string> time() const

std::vector<std::string>

pd_datetime_accessor.h:343

View

std::vector<std::string> timetz() const

std::vector<std::string>

pd_datetime_accessor.h:422

View

std::string tz() const

std::string

pd_datetime_accessor.h:414

View

std::string unit() const

std::string

pd_datetime_accessor.h:418

View

std::vector<int64_t> week() const

std::vector<int64_t>

pd_datetime_accessor.h:191

View

pandas::Series<T> wrap_int_result(std::vector<T>&& data) const

pandas::Series<T>

pd_datetime_accessor.h:45

View

std::vector<int64_t> year() const

std::vector<int64_t>

pd_datetime_accessor.h:54

View

Code Examples#

The following examples are extracted from the test suite.

minute (pd_test_1_all.cpp:7505)
7495    std::cout << "========= minute property =============================";
7496
7497    std::vector<std::optional<numpy::datetime64>> values = {
7498        make_dt(0),                    // Minute 0
7499        make_dt(30 * NS_PER_MIN),      // Minute 30
7500        make_dt(59 * NS_PER_MIN)       // Minute 59
7501    };
7502    pandas::DatetimeArray arr(values);
7503    pandas::DatetimeIndex idx(arr);
7504
7505    auto minutes = idx.minute();
7506
7507    bool passed = (minutes.size() == 3);
7508    auto m0 = minutes[0];
7509    auto m1 = minutes[1];
7510    auto m2 = minutes[2];
7511    passed = passed && m0.has_value() && *m0 == 0;
7512    passed = passed && m1.has_value() && *m1 == 30;
7513    passed = passed && m2.has_value() && *m2 == 59;
7514
7515    if (!passed) {
to_period (pd_test_2_all.cpp:14554)
14544        std::cout << "====================================== [OK] pd_test_to_parquet test suite ========================" << std::endl;
14545        return 0;
14546    }
14547
14548} // namespace dataframe_tests
14549// ------------------- pd_test_to_parquet.cpp (end) -----------------------------
14550
14551// ------------------- pd_test_to_period.cpp (start) -----------------------------
14552// dataframe_tests/pd_test_to_period.cpp
14553// Test suite for DataFrame.to_period() method
14554
14555#include <iostream>
14556#include <stdexcept>
14557#include <vector>
14558#include <string>
14559#include <map>
14560
14561#include "../pandas/pd_dataframe.h"
14562
14563// CRITICAL: No using namespace directives
tz_convert (pd_test_2_all.cpp:17874)
17864        std::cout << "====================================== [OK] pd_test_transform test suite ========================== " << std::endl;
17865        return 0;
17866    }
17867
17868} // namespace dataframe_tests
17869// ------------------- pd_test_transform.cpp (end) -----------------------------
17870
17871// ------------------- pd_test_tz_convert.cpp (start) -----------------------------
17872// dataframe_tests/pd_test_tz_convert.cpp
17873// Test for DataFrame.tz_convert() method
17874
17875#include <iostream>
17876#include <stdexcept>
17877#include <cmath>
17878#include "../pandas/pd_dataframe.h"
17879
17880namespace dataframe_tests {
17881    namespace dataframe_tests_tz_convert {
17882
17883        void pd_test_tz_convert_basic() {
tz_localize (pd_test_1_all.cpp:1431)
1421            "2023-06-15"
1422        });
1423
1424        // Initially should be timezone-naive
1425        if (arr.is_tz_aware()) {
1426            std::cout << "  [FAIL] : array should be timezone-naive initially" << std::endl;
1427            throw std::runtime_error("pd_test_datetime_array_timezone failed: naive");
1428        }
1429
1430        // Localize to UTC
1431        auto localized = arr.tz_localize("UTC");
1432        if (!localized.is_tz_aware()) {
1433            std::cout << "  [FAIL] : localized array should be timezone-aware" << std::endl;
1434            throw std::runtime_error("pd_test_datetime_array_timezone failed: localize");
1435        }
1436
1437        // Verify timezone name in dtype
1438        auto dt = localized.dtype();
1439        if (!dt.is_tz_aware()) {
1440            std::cout << "  [FAIL] : dtype should be timezone-aware" << std::endl;
1441            throw std::runtime_error("pd_test_datetime_array_timezone failed: dtype tz");
to_pydatetime (pd_test_timestamp_scalar.cpp:519)
509      // asm8 alias
510      numpy::datetime64 asm8 = ts.asm8();
511      if (asm8.isNaT()) { pass = false; fail_msg = "asm8 should not return NaT"; }
512
513      // to_numpy
514      int64_t value = ts.to_numpy();
515      if (value == 0) { pass = false; fail_msg = "to_numpy should return non-zero"; }
516
517      // to_pydatetime
518      std::tm tm = ts.to_pydatetime();
519      if (tm.tm_year != 124) { pass = false; fail_msg = "tm_year should be 124 (2024-1900)"; }
520      if (tm.tm_mon != 5) { pass = false; fail_msg = "tm_mon should be 5 (June)"; }
521
522      // timestamp
523      double posix = ts.timestamp();
524      if (posix <= 0) { pass = false; fail_msg = "POSIX timestamp should be positive"; }
525
526      // timetuple
527      auto [y, mo, d, h, mi, s] = ts.timetuple();
528      if (y != 2024 || mo != 6) { pass = false; fail_msg = "timetuple values incorrect"; }
is_leap_year (pd_test_1_all.cpp:1280)
1270        }
1271
1272        // is_month_end
1273        auto me = arr.is_month_end();
1274        if (!me[1].has_value() || !me[1].value()) {
1275            std::cout << "  [FAIL] : 2023-03-31 should be month end" << std::endl;
1276            throw std::runtime_error("pd_test_datetime_array_boolean_props failed: month end");
1277        }
1278
1279        // is_leap_year
1280        auto ly = arr.is_leap_year();
1281        if (!ly[2].has_value() || !ly[2].value()) {
1282            std::cout << "  [FAIL] : 2024 should be leap year" << std::endl;
1283            throw std::runtime_error("pd_test_datetime_array_boolean_props failed: leap year");
1284        }
1285        if (!ly[0].has_value() || ly[0].value()) {
1286            std::cout << "  [FAIL] : 2023 should not be leap year" << std::endl;
1287            throw std::runtime_error("pd_test_datetime_array_boolean_props failed: not leap year");
1288        }
1289
1290        std::cout << " -> tests passed" << std::endl;
is_month_end (pd_test_1_all.cpp:1273)
1263        }
1264
1265        // is_month_start
1266        auto ms = arr.is_month_start();
1267        if (!ms[0].has_value() || !ms[0].value()) {
1268            std::cout << "  [FAIL] : 2023-01-01 should be month start" << std::endl;
1269            throw std::runtime_error("pd_test_datetime_array_boolean_props failed: month start");
1270        }
1271
1272        // is_month_end
1273        auto me = arr.is_month_end();
1274        if (!me[1].has_value() || !me[1].value()) {
1275            std::cout << "  [FAIL] : 2023-03-31 should be month end" << std::endl;
1276            throw std::runtime_error("pd_test_datetime_array_boolean_props failed: month end");
1277        }
1278
1279        // is_leap_year
1280        auto ly = arr.is_leap_year();
1281        if (!ly[2].has_value() || !ly[2].value()) {
1282            std::cout << "  [FAIL] : 2024 should be leap year" << std::endl;
1283            throw std::runtime_error("pd_test_datetime_array_boolean_props failed: leap year");
is_month_start (pd_test_1_all.cpp:1266)
1256        if (!ys[0].has_value() || !ys[0].value()) {
1257            std::cout << "  [FAIL] : 2023-01-01 should be year start" << std::endl;
1258            throw std::runtime_error("pd_test_datetime_array_boolean_props failed: year start");
1259        }
1260        if (!ys[1].has_value() || ys[1].value()) {
1261            std::cout << "  [FAIL] : 2023-03-31 should not be year start" << std::endl;
1262            throw std::runtime_error("pd_test_datetime_array_boolean_props failed: not year start");
1263        }
1264
1265        // is_month_start
1266        auto ms = arr.is_month_start();
1267        if (!ms[0].has_value() || !ms[0].value()) {
1268            std::cout << "  [FAIL] : 2023-01-01 should be month start" << std::endl;
1269            throw std::runtime_error("pd_test_datetime_array_boolean_props failed: month start");
1270        }
1271
1272        // is_month_end
1273        auto me = arr.is_month_end();
1274        if (!me[1].has_value() || !me[1].value()) {
1275            std::cout << "  [FAIL] : 2023-03-31 should be month end" << std::endl;
1276            throw std::runtime_error("pd_test_datetime_array_boolean_props failed: month end");
is_quarter_end (pd_test_3_all.cpp:25056)
25046    };
25047    pandas::Series<numpy::datetime64> s(dates);
25048    pandas::DatetimeProperties<pandas::Series<numpy::datetime64>> dt(s);
25049    if (dt.has_nat()) throw std::runtime_error("has_nat should be false for clean series");
25050    auto ms = dt.is_month_start();
25051    if (ms[0] != true || ms[1] != false) throw std::runtime_error("is_month_start failed");
25052    auto me = dt.is_month_end();
25053    if (me[1] != true || me[0] != false) throw std::runtime_error("is_month_end failed");
25054    auto qs = dt.is_quarter_start();
25055    if (qs[0] != true || qs[1] != false) throw std::runtime_error("is_quarter_start failed");
25056    auto qe = dt.is_quarter_end();
25057    if (qe[2] != true || qe[0] != false) throw std::runtime_error("is_quarter_end failed");
25058    auto ys = dt.is_year_start();
25059    if (ys[0] != true || ys[1] != false) throw std::runtime_error("is_year_start failed");
25060    auto ye = dt.is_year_end();
25061    if (ye[3] != true || ye[0] != false) throw std::runtime_error("is_year_end failed");
25062    std::cout << " -> tests passed" << std::endl;
25063}
25064
25065void pd_test_dt_bool_na_with_nat() {
25066    std::cout << "========= pd_test_dt_bool_na: series with NaT ==========";
is_quarter_start (pd_test_3_all.cpp:25054)
25044        numpy::datetime64("2024-03-31"),
25045        numpy::datetime64("2024-12-31")
25046    };
25047    pandas::Series<numpy::datetime64> s(dates);
25048    pandas::DatetimeProperties<pandas::Series<numpy::datetime64>> dt(s);
25049    if (dt.has_nat()) throw std::runtime_error("has_nat should be false for clean series");
25050    auto ms = dt.is_month_start();
25051    if (ms[0] != true || ms[1] != false) throw std::runtime_error("is_month_start failed");
25052    auto me = dt.is_month_end();
25053    if (me[1] != true || me[0] != false) throw std::runtime_error("is_month_end failed");
25054    auto qs = dt.is_quarter_start();
25055    if (qs[0] != true || qs[1] != false) throw std::runtime_error("is_quarter_start failed");
25056    auto qe = dt.is_quarter_end();
25057    if (qe[2] != true || qe[0] != false) throw std::runtime_error("is_quarter_end failed");
25058    auto ys = dt.is_year_start();
25059    if (ys[0] != true || ys[1] != false) throw std::runtime_error("is_year_start failed");
25060    auto ye = dt.is_year_end();
25061    if (ye[3] != true || ye[0] != false) throw std::runtime_error("is_year_end failed");
25062    std::cout << " -> tests passed" << std::endl;
25063}
is_year_end (pd_test_3_all.cpp:25060)
25050    auto ms = dt.is_month_start();
25051    if (ms[0] != true || ms[1] != false) throw std::runtime_error("is_month_start failed");
25052    auto me = dt.is_month_end();
25053    if (me[1] != true || me[0] != false) throw std::runtime_error("is_month_end failed");
25054    auto qs = dt.is_quarter_start();
25055    if (qs[0] != true || qs[1] != false) throw std::runtime_error("is_quarter_start failed");
25056    auto qe = dt.is_quarter_end();
25057    if (qe[2] != true || qe[0] != false) throw std::runtime_error("is_quarter_end failed");
25058    auto ys = dt.is_year_start();
25059    if (ys[0] != true || ys[1] != false) throw std::runtime_error("is_year_start failed");
25060    auto ye = dt.is_year_end();
25061    if (ye[3] != true || ye[0] != false) throw std::runtime_error("is_year_end failed");
25062    std::cout << " -> tests passed" << std::endl;
25063}
25064
25065void pd_test_dt_bool_na_with_nat() {
25066    std::cout << "========= pd_test_dt_bool_na: series with NaT ==========";
25067    std::vector<numpy::datetime64> dates = {
25068        numpy::datetime64("2024-01-01"),
25069        numpy::datetime64(),  // NaT
25070        numpy::datetime64("2024-12-31")
is_year_start (pd_test_1_all.cpp:1255)
1245        std::cout << "========= DatetimeArray: boolean properties ======================= ";
1246
1247        pandas::DatetimeArray arr(std::vector<std::string>{
1248            "2023-01-01",   // year start, month start
1249            "2023-03-31",   // quarter end, month end
1250            "2024-02-29",   // leap year (2024 is leap year)
1251            "2023-12-31"    // year end, month end
1252        });
1253
1254        // is_year_start
1255        auto ys = arr.is_year_start();
1256        if (!ys[0].has_value() || !ys[0].value()) {
1257            std::cout << "  [FAIL] : 2023-01-01 should be year start" << std::endl;
1258            throw std::runtime_error("pd_test_datetime_array_boolean_props failed: year start");
1259        }
1260        if (!ys[1].has_value() || ys[1].value()) {
1261            std::cout << "  [FAIL] : 2023-03-31 should not be year start" << std::endl;
1262            throw std::runtime_error("pd_test_datetime_array_boolean_props failed: not year start");
1263        }
1264
1265        // is_month_start
as_unit (pd_test_1_all.cpp:9361)
9351    data.setElementAt({1}, numpy::datetime64(2000000000LL, numpy::DateTimeUnit::Nanosecond));  // 2 seconds in ns
9352
9353    numpy::NDArray<numpy::bool_> mask(std::vector<size_t>{2});
9354    mask.setElementAt({0}, numpy::bool_(false));
9355    mask.setElementAt({1}, numpy::bool_(false));
9356
9357    pandas::DatetimeArray arr(data, mask);
9358    pandas::DatetimeTDMixin idx(arr, "test");
9359
9360    // Convert to microseconds
9361    pandas::DatetimeTDMixin us_idx = idx.as_unit("us");
9362
9363    // Convert to same unit (should return identical)
9364    pandas::DatetimeTDMixin same_idx = idx.as_unit("ns");
9365
9366    bool passed = (us_idx.size() == 2 && same_idx.size() == 2 &&
9367                   us_idx.name().has_value() && *us_idx.name() == "test");
9368    if (!passed) {
9369        std::cout << "  [FAIL] : in pd_test_datetime_as_unit() : as_unit check failed" << std::endl;
9370        throw std::runtime_error("pd_test_datetime_as_unit failed");
9371    }
ceil (pd_test_1_all.cpp:4949)
4939                throw std::runtime_error("pd_test_arithmetic_series_round failed: round failed");
4940            }
4941
4942            auto f = a.floor();
4943            passed = std::abs(f[0] - 1.0) < 0.001 && std::abs(f[2] - 3.0) < 0.001 && std::abs(f[3] - (-2.0)) < 0.001;
4944            if (!passed) {
4945                std::cout << "  [FAIL] : in pd_test_arithmetic_series_round() : floor failed" << std::endl;
4946                throw std::runtime_error("pd_test_arithmetic_series_round failed: floor failed");
4947            }
4948
4949            auto c = a.ceil();
4950            passed = std::abs(c[0] - 2.0) < 0.001 && std::abs(c[2] - 4.0) < 0.001 && std::abs(c[3] - (-1.0)) < 0.001;
4951            if (!passed) {
4952                std::cout << "  [FAIL] : in pd_test_arithmetic_series_round() : ceil failed" << std::endl;
4953                throw std::runtime_error("pd_test_arithmetic_series_round failed: ceil failed");
4954            }
4955
4956            // Round with decimals
4957            pandas::Series<double> b({1.234, 2.567, 3.891});
4958            auto r2 = b.round(2);
4959            passed = std::abs(r2[0] - 1.23) < 0.001 && std::abs(r2[1] - 2.57) < 0.001;
date (pd_test_2_all.cpp:21549)
21539    std::cout << "  -- test_pivot_grouper_mixed_plain --" << std::endl;
21540
21541    // Mix plain column and grouper
21542    auto df = make_df(
21543        {"date", "region", "product", "sales"},
21544        {{"2023-01-15", "2023-01-20", "2023-02-10", "2023-02-25"},
21545         {"East", "West", "East", "West"},
21546         {"A", "B", "A", "B"},
21547         {"100", "200", "150", "250"}});
21548
21549    // index: region (plain) + date (grouper with freq)
21550    std::vector<std::pair<std::string, std::string>> idx_groupers = {
21551        {"region", ""},    // plain column (empty freq)
21552        {"date", "ME"}     // grouper with monthly freq
21553    };
21554    std::vector<std::pair<std::string, std::string>> col_groupers = {};
21555
21556    auto result = pandas::detail::pivot_table_with_grouper(
21557        df, {"sales"}, idx_groupers, col_groupers, "sum");
21558
21559    check(result.nrows() > 0, "has_rows");
day (pd_test_1_all.cpp:1193)
1183            std::cout << "  [FAIL] : month[0] should be 3" << std::endl;
1184            throw std::runtime_error("pd_test_datetime_array_component_month_day failed: month[0]");
1185        }
1186        auto m1 = months[1];
1187        if (!m1.has_value() || m1.value() != 12) {
1188            std::cout << "  [FAIL] : month[1] should be 12" << std::endl;
1189            throw std::runtime_error("pd_test_datetime_array_component_month_day failed: month[1]");
1190        }
1191
1192        // Day
1193        auto days = arr.day();
1194        auto d0 = days[0];
1195        if (!d0.has_value() || d0.value() != 15) {
1196            std::cout << "  [FAIL] : day[0] should be 15" << std::endl;
1197            throw std::runtime_error("pd_test_datetime_array_component_month_day failed: day[0]");
1198        }
1199        auto d1 = days[1];
1200        if (!d1.has_value() || d1.value() != 25) {
1201            std::cout << "  [FAIL] : day[1] should be 25" << std::endl;
1202            throw std::runtime_error("pd_test_datetime_array_component_month_day failed: day[1]");
1203        }
day_name (pd_test_1_all.cpp:8474)
8464void pd_test_datetime_mixin_day_name() {
8465    std::cout << "========= day_name ====================================";
8466
8467    std::vector<std::optional<numpy::datetime64>> values = {
8468        numpy::datetime64(0LL, numpy::DateTimeUnit::Nanosecond)  // 1970-01-01 = Thursday
8469    };
8470    pandas::DatetimeArray arr(values);
8471    pandas::DatetimeMixinIndex idx(arr);
8472
8473    std::vector<std::string> names = idx.day_name();
8474
8475    bool passed = (names.size() == 1 && names[0] == "Thursday");
8476    if (!passed) {
8477        std::cout << "  [FAIL] : in pd_test_datetime_mixin_day_name() got: " << names[0] << std::endl;
8478        throw std::runtime_error("pd_test_datetime_mixin_day_name failed");
8479    }
8480
8481    std::cout << " -> tests passed" << std::endl;
8482}
dayofweek (pd_test_1_all.cpp:7565)
7555    // 1970-01-01 was a Thursday (day 3)
7556    std::vector<std::optional<numpy::datetime64>> values = {
7557        make_dt(0),                // Thursday (3)
7558        make_dt(NS_PER_DAY),       // Friday (4)
7559        make_dt(2 * NS_PER_DAY),   // Saturday (5)
7560        make_dt(3 * NS_PER_DAY)    // Sunday (6)
7561    };
7562    pandas::DatetimeArray arr(values);
7563    pandas::DatetimeIndex idx(arr);
7564
7565    auto dow = idx.dayofweek();
7566
7567    bool passed = (dow.size() == 4);
7568    if (!passed) {
7569        std::cout << "  [FAIL] : in pd_test_datetime_index_dayofweek()" << std::endl;
7570        throw std::runtime_error("pd_test_datetime_index_dayofweek failed");
7571    }
7572
7573    std::cout << " -> tests passed" << std::endl;
7574}
dayofyear (pd_test_3_all.cpp:18582)
18572    auto seconds = s.dt().second();
18573    if (seconds[0] != 45 || seconds[1] != 30 || seconds[2] != 59) {
18574        std::cout << "  [FAIL] : second() failed" << std::endl;
18575        throw std::runtime_error("pd_test_dt_time_components: second() failed");
18576    }
18577
18578    std::cout << " -> tests passed" << std::endl;
18579}
18580
18581// ============================================================================
18582// Test dt().dayofweek(), dt().dayofyear(), dt().quarter()
18583// ============================================================================
18584
18585void pd_test_dt_derived_properties() {
18586    std::cout << "========= Series.dt().dayofweek/dayofyear/quarter() ======";
18587
18588    // 2020-01-01 is a Wednesday (dayofweek=2), dayofyear=1, Q1
18589    // 2020-07-04 is a Saturday (dayofweek=5), dayofyear=186, Q3
18590    pandas::Series<std::string> s({"2020-01-01", "2020-07-04"});
18591
18592    auto dow = s.dt().dayofweek();
days_in_month (pd_test_1_all.cpp:2766)
2756            std::cout << "  [FAIL] : day[0] should be 15" << std::endl;
2757            throw std::runtime_error("pd_test_period_array_day_components failed: day[0]");
2758        }
2759        auto d1 = days[1];
2760        if (!d1.has_value() || d1.value() != 25) {
2761            std::cout << "  [FAIL] : day[1] should be 25" << std::endl;
2762            throw std::runtime_error("pd_test_period_array_day_components failed: day[1]");
2763        }
2764
2765        // Days in month
2766        auto dim = arr.days_in_month();
2767        auto dim0 = dim[0];
2768        if (!dim0.has_value() || dim0.value() != 31) {
2769            std::cout << "  [FAIL] : days_in_month[0] should be 31 (March)" << std::endl;
2770            throw std::runtime_error("pd_test_period_array_day_components failed: days_in_month[0]");
2771        }
2772        auto dim1 = dim[1];
2773        if (!dim1.has_value() || dim1.value() != 31) {
2774            std::cout << "  [FAIL] : days_in_month[1] should be 31 (December)" << std::endl;
2775            throw std::runtime_error("pd_test_period_array_day_components failed: days_in_month[1]");
2776        }
days_in_month_prop (pd_test_3_all.cpp:22045)
22035void test_dt_days_in_month() {
22036    std::cout << "========= dt.days_in_month ======================";
22037
22038    std::vector<numpy::datetime64> dates = {
22039        numpy::datetime64("2023-01-15"),  // Jan = 31
22040        numpy::datetime64("2023-02-15"),  // Feb 2023 = 28
22041        numpy::datetime64("2024-02-15")   // Feb 2024 (leap) = 29
22042    };
22043    pandas::Series<numpy::datetime64> s(dates);
22044
22045    auto result = s.dt().days_in_month_prop();
22046    if (result[0] != 31 || result[1] != 28 || result[2] != 29) {
22047        throw std::runtime_error("dt.days_in_month: wrong values");
22048    }
22049
22050    // Also test alias
22051    auto alias = s.dt().daysinmonth();
22052    if (alias[0] != 31) {
22053        throw std::runtime_error("dt.daysinmonth: wrong values");
22054    }
floor (pd_test_1_all.cpp:4942)
4932            pandas::Series<double> a({1.4, 2.5, 3.6, -1.4, -2.5});
4933
4934            auto r = a.round();
4935            bool passed = std::abs(r[0] - 1.0) < 0.001 && std::abs(r[2] - 4.0) < 0.001;
4936            if (!passed) {
4937                std::cout << "  [FAIL] : in pd_test_arithmetic_series_round() : round failed" << std::endl;
4938                throw std::runtime_error("pd_test_arithmetic_series_round failed: round failed");
4939            }
4940
4941            auto f = a.floor();
4942            passed = std::abs(f[0] - 1.0) < 0.001 && std::abs(f[2] - 3.0) < 0.001 && std::abs(f[3] - (-2.0)) < 0.001;
4943            if (!passed) {
4944                std::cout << "  [FAIL] : in pd_test_arithmetic_series_round() : floor failed" << std::endl;
4945                throw std::runtime_error("pd_test_arithmetic_series_round failed: floor failed");
4946            }
4947
4948            auto c = a.ceil();
4949            passed = std::abs(c[0] - 2.0) < 0.001 && std::abs(c[2] - 4.0) < 0.001 && std::abs(c[3] - (-1.0)) < 0.001;
4950            if (!passed) {
4951                std::cout << "  [FAIL] : in pd_test_arithmetic_series_round() : ceil failed" << std::endl;
freq (pd_test_1_all.cpp:8233)
8223    std::cout << "========= freq property ===============================";
8224
8225    std::vector<std::optional<numpy::datetime64>> values = {
8226        numpy::datetime64(0LL, numpy::DateTimeUnit::Nanosecond),
8227        numpy::datetime64(86400000000000LL, numpy::DateTimeUnit::Nanosecond)  // 1 day
8228    };
8229    pandas::DatetimeArray arr(values);
8230    pandas::DatetimeMixinIndex idx(arr);
8231
8232    // Default freq is nullopt or inferred
8233    auto f = idx.freq();
8234    std::string fs = idx.freqstr();
8235
8236    bool passed = true;  // freq may or may not be set
8237    if (!passed) {
8238        std::cout << "  [FAIL] : in pd_test_datetime_mixin_freq()" << std::endl;
8239        throw std::runtime_error("pd_test_datetime_mixin_freq failed");
8240    }
8241
8242    std::cout << " -> tests passed" << std::endl;
8243}
has_nat (pd_test_3_all.cpp:25049)
25039void pd_test_dt_bool_na_clean() {
25040    std::cout << "========= pd_test_dt_bool_na: clean series =============";
25041    std::vector<numpy::datetime64> dates = {
25042        numpy::datetime64("2024-01-01"),
25043        numpy::datetime64("2024-01-31"),
25044        numpy::datetime64("2024-03-31"),
25045        numpy::datetime64("2024-12-31")
25046    };
25047    pandas::Series<numpy::datetime64> s(dates);
25048    pandas::DatetimeProperties<pandas::Series<numpy::datetime64>> dt(s);
25049    if (dt.has_nat()) throw std::runtime_error("has_nat should be false for clean series");
25050    auto ms = dt.is_month_start();
25051    if (ms[0] != true || ms[1] != false) throw std::runtime_error("is_month_start failed");
25052    auto me = dt.is_month_end();
25053    if (me[1] != true || me[0] != false) throw std::runtime_error("is_month_end failed");
25054    auto qs = dt.is_quarter_start();
25055    if (qs[0] != true || qs[1] != false) throw std::runtime_error("is_quarter_start failed");
25056    auto qe = dt.is_quarter_end();
25057    if (qe[2] != true || qe[0] != false) throw std::runtime_error("is_quarter_end failed");
25058    auto ys = dt.is_year_start();
25059    if (ys[0] != true || ys[1] != false) throw std::runtime_error("is_year_start failed");
hour (pd_test_1_all.cpp:7476)
7466    std::cout << "========= hour property ===============================";
7467
7468    std::vector<std::optional<numpy::datetime64>> values = {
7469        make_dt(0),                    // Hour 0
7470        make_dt(6 * NS_PER_HOUR),      // Hour 6
7471        make_dt(23 * NS_PER_HOUR)      // Hour 23
7472    };
7473    pandas::DatetimeArray arr(values);
7474    pandas::DatetimeIndex idx(arr);
7475
7476    auto hours = idx.hour();
7477
7478    bool passed = (hours.size() == 3);
7479    auto h0 = hours[0];
7480    auto h1 = hours[1];
7481    auto h2 = hours[2];
7482    passed = passed && h0.has_value() && *h0 == 0;
7483    passed = passed && h1.has_value() && *h1 == 6;
7484    passed = passed && h2.has_value() && *h2 == 23;
7485
7486    if (!passed) {
isocalendar (pd_test_3_all.cpp:22134)
22124}
22125
22126void test_dt_isocalendar() {
22127    std::cout << "========= dt.isocalendar =========================";
22128
22129    std::vector<numpy::datetime64> dates = {
22130        numpy::datetime64("2023-01-15")
22131    };
22132    pandas::Series<numpy::datetime64> s(dates);
22133
22134    auto iso = s.dt().isocalendar();
22135    if (iso.year.size() != 1 || iso.week.size() != 1 || iso.day.size() != 1) {
22136        throw std::runtime_error("dt.isocalendar: wrong size");
22137    }
22138    if (iso.year[0] != 2023) {
22139        throw std::runtime_error("dt.isocalendar: wrong year");
22140    }
22141
22142    std::cout << " -> tests passed" << std::endl;
22143}
microsecond (pd_test_timestamp_scalar.cpp:45)
35      // Component constructor
36      pandas::Timestamp ts1(2024, 6, 15, 14, 30, 45);
37      if (ts1.year() != 2024 || ts1.month() != 6 || ts1.day() != 15 ||
38          ts1.hour() != 14 || ts1.minute() != 30 || ts1.second() != 45) {
39        pass = false;
40        fail_msg = "Component constructor values incorrect";
41      }
42
43      // With microseconds and nanoseconds
44      pandas::Timestamp ts2(2024, 1, 1, 12, 0, 0, 123456, 789);
45      if (ts2.microsecond() != 123456 || ts2.nanosecond() != 789) {
46        pass = false;
47        fail_msg = "Microsecond/nanosecond values incorrect";
48      }
49
50      // String constructor - ISO format
51      pandas::Timestamp ts3("2024-06-15T14:30:45");
52      if (ts3.year() != 2024 || ts3.month() != 6 || ts3.day() != 15) {
53        pass = false;
54        fail_msg = "String constructor parse failed";
55      }
month (pd_test_1_all.cpp:1180)
1170    void pd_test_datetime_array_component_month_day() {
1171        std::cout << "========= DatetimeArray: month/day components ======================= ";
1172
1173        pandas::DatetimeArray arr(std::vector<std::string>{
1174            "2023-03-15",
1175            "2023-12-25",
1176            "NaT"
1177        });
1178
1179        // Month
1180        auto months = arr.month();
1181        auto m0 = months[0];
1182        if (!m0.has_value() || m0.value() != 3) {
1183            std::cout << "  [FAIL] : month[0] should be 3" << std::endl;
1184            throw std::runtime_error("pd_test_datetime_array_component_month_day failed: month[0]");
1185        }
1186        auto m1 = months[1];
1187        if (!m1.has_value() || m1.value() != 12) {
1188            std::cout << "  [FAIL] : month[1] should be 12" << std::endl;
1189            throw std::runtime_error("pd_test_datetime_array_component_month_day failed: month[1]");
1190        }
month_name (pd_test_1_all.cpp:8454)
8444void pd_test_datetime_mixin_month_name() {
8445    std::cout << "========= month_name ==================================";
8446
8447    std::vector<std::optional<numpy::datetime64>> values = {
8448        numpy::datetime64(0LL, numpy::DateTimeUnit::Nanosecond)  // 1970-01-01 = January
8449    };
8450    pandas::DatetimeArray arr(values);
8451    pandas::DatetimeMixinIndex idx(arr);
8452
8453    std::vector<std::string> names = idx.month_name();
8454
8455    bool passed = (names.size() == 1 && names[0] == "January");
8456    if (!passed) {
8457        std::cout << "  [FAIL] : in pd_test_datetime_mixin_month_name() got: " << names[0] << std::endl;
8458        throw std::runtime_error("pd_test_datetime_mixin_month_name failed");
8459    }
8460
8461    std::cout << " -> tests passed" << std::endl;
8462}
nanosecond (pd_test_timestamp_scalar.cpp:45)
35      // Component constructor
36      pandas::Timestamp ts1(2024, 6, 15, 14, 30, 45);
37      if (ts1.year() != 2024 || ts1.month() != 6 || ts1.day() != 15 ||
38          ts1.hour() != 14 || ts1.minute() != 30 || ts1.second() != 45) {
39        pass = false;
40        fail_msg = "Component constructor values incorrect";
41      }
42
43      // With microseconds and nanoseconds
44      pandas::Timestamp ts2(2024, 1, 1, 12, 0, 0, 123456, 789);
45      if (ts2.microsecond() != 123456 || ts2.nanosecond() != 789) {
46        pass = false;
47        fail_msg = "Microsecond/nanosecond values incorrect";
48      }
49
50      // String constructor - ISO format
51      pandas::Timestamp ts3("2024-06-15T14:30:45");
52      if (ts3.year() != 2024 || ts3.month() != 6 || ts3.day() != 15) {
53        pass = false;
54        fail_msg = "String constructor parse failed";
55      }
normalize (pd_test_1_all.cpp:8723)
8713void pd_test_datetime_mixin_normalize() {
8714    std::cout << "========= normalize ===================================";
8715
8716    // Create datetime with time component
8717    std::vector<std::optional<numpy::datetime64>> values = {
8718        numpy::datetime64(86400000000000LL + 3600000000000LL, numpy::DateTimeUnit::Nanosecond)  // 1 day + 1 hour
8719    };
8720    pandas::DatetimeArray arr(values);
8721    pandas::DatetimeMixinIndex idx(arr);
8722
8723    pandas::DatetimeMixinIndex normalized = idx.normalize();
8724
8725    bool passed = (normalized.size() == 1);
8726    if (!passed) {
8727        std::cout << "  [FAIL] : in pd_test_datetime_mixin_normalize()" << std::endl;
8728        throw std::runtime_error("pd_test_datetime_mixin_normalize failed");
8729    }
8730
8731    std::cout << " -> tests passed" << std::endl;
8732}
quarter (pd_test_1_all.cpp:1218)
1208    void pd_test_datetime_array_quarter() {
1209        std::cout << "========= DatetimeArray: quarter ======================= ";
1210
1211        pandas::DatetimeArray arr(std::vector<std::string>{
1212            "2023-01-15",  // Q1
1213            "2023-05-20",  // Q2
1214            "2023-09-10",  // Q3
1215            "2023-11-25"   // Q4
1216        });
1217
1218        auto quarters = arr.quarter();
1219
1220        auto q0 = quarters[0];
1221        if (!q0.has_value() || q0.value() != 1) {
1222            std::cout << "  [FAIL] : quarter[0] should be 1" << std::endl;
1223            throw std::runtime_error("pd_test_datetime_array_quarter failed: quarter[0]");
1224        }
1225        auto q1 = quarters[1];
1226        if (!q1.has_value() || q1.value() != 2) {
1227            std::cout << "  [FAIL] : quarter[1] should be 2" << std::endl;
1228            throw std::runtime_error("pd_test_datetime_array_quarter failed: quarter[1]");
round (pd_test_1_all.cpp:1688)
1678    void pd_test_floating_array_rounding() {
1679        std::cout << "========= FloatingArray: rounding ======================= ";
1680
1681        pandas::FloatingArray<double> arr({
1682            std::optional<double>(1.234),
1683            std::optional<double>(2.567),
1684            std::nullopt
1685        });
1686
1687        auto rounded = arr.round(2);
1688        if (std::abs(rounded[0].value() - 1.23) > 0.001 ||
1689            std::abs(rounded[1].value() - 2.57) > 0.001) {
1690            std::cout << "  [FAIL] : in pd_test_floating_array_rounding() : round(2)" << std::endl;
1691            throw std::runtime_error("pd_test_floating_array_rounding failed: round(2)");
1692        }
1693
1694        if (!rounded.is_na(2)) {
1695            std::cout << "  [FAIL] : in pd_test_floating_array_rounding() : round should preserve NA" << std::endl;
1696            throw std::runtime_error("pd_test_floating_array_rounding failed: NA preservation");
1697        }
s (pd_test_1_all.cpp:4524)
4514#include <vector>
4515#include "../pandas/pd_dataframe.h"
4516#include "../pandas/pd_series.h"
4517
4518namespace dataframe_tests {
4519    namespace dataframe_tests_aggregation {
4520
4521        void pd_test_aggregation_series_sem() {
4522            std::cout << "========= Series sem ============================";
4523
4524            pandas::Series<double> s({1.0, 2.0, 3.0, 4.0, 5.0});
4525            auto sem_val = s.sem();
4526            // std(ddof=1) = sqrt(2.5), sem = sqrt(2.5)/sqrt(5) ≈ 0.707
4527            bool passed = sem_val.has_value() && std::abs(*sem_val - 0.707) < 0.01;
4528            if (!passed) {
4529                std::cout << "  [FAIL] : in pd_test_aggregation_series_sem() : sem value incorrect" << std::endl;
4530                throw std::runtime_error("pd_test_aggregation_series_sem failed: sem value incorrect");
4531            }
4532
4533            std::cout << " -> tests passed" << std::endl;
4534        }
second (pd_test_1_all.cpp:7534)
7524    std::cout << "========= second property =============================";
7525
7526    std::vector<std::optional<numpy::datetime64>> values = {
7527        make_dt(0),                    // Second 0
7528        make_dt(30 * NS_PER_SEC),      // Second 30
7529        make_dt(59 * NS_PER_SEC)       // Second 59
7530    };
7531    pandas::DatetimeArray arr(values);
7532    pandas::DatetimeIndex idx(arr);
7533
7534    auto seconds = idx.second();
7535
7536    bool passed = (seconds.size() == 3);
7537    auto s0 = seconds[0];
7538    auto s1 = seconds[1];
7539    auto s2 = seconds[2];
7540    passed = passed && s0.has_value() && *s0 == 0;
7541    passed = passed && s1.has_value() && *s1 == 30;
7542    passed = passed && s2.has_value() && *s2 == 59;
7543
7544    if (!passed) {
strftime (pd_test_1_all.cpp:8434)
8424void pd_test_datetime_mixin_strftime() {
8425    std::cout << "========= strftime ====================================";
8426
8427    std::vector<std::optional<numpy::datetime64>> values = {
8428        numpy::datetime64(0LL, numpy::DateTimeUnit::Nanosecond),  // 1970-01-01
8429        numpy::datetime64(86400000000000LL, numpy::DateTimeUnit::Nanosecond)  // 1970-01-02
8430    };
8431    pandas::DatetimeArray arr(values);
8432    pandas::DatetimeMixinIndex idx(arr);
8433
8434    std::vector<std::string> formatted = idx.strftime("%Y-%m-%d");
8435
8436    bool passed = (formatted.size() == 2 && !formatted[0].empty() && !formatted[1].empty());
8437    if (!passed) {
8438        std::cout << "  [FAIL] : in pd_test_datetime_mixin_strftime()" << std::endl;
8439        throw std::runtime_error("pd_test_datetime_mixin_strftime failed");
8440    }
8441
8442    std::cout << " -> tests passed" << std::endl;
8443}
time (pd_test_timestamp_scalar.cpp:535)
525      if (posix <= 0) { pass = false; fail_msg = "POSIX timestamp should be positive"; }
526
527      // timetuple
528      auto [y, mo, d, h, mi, s] = ts.timetuple();
529      if (y != 2024 || mo != 6) { pass = false; fail_msg = "timetuple values incorrect"; }
530
531      // date/time tuples
532      auto [dy, dm, dd] = ts.date();
533      if (dy != 2024) { pass = false; fail_msg = "date tuple year"; }
534
535      auto [th, tmi, ts2, tus] = ts.time();
536      if (th != 12) { pass = false; fail_msg = "time tuple hour"; }
537
538      // Julian date
539      double jd = ts.to_julian_date();
540      if (jd < 2400000) { pass = false; fail_msg = "Julian date should be reasonable"; }
541
542      // Ordinal
543      int ord = ts.toordinal();
544      if (ord <= 0) { pass = false; fail_msg = "Ordinal should be positive"; }
timetz (pd_test_timestamp_scalar.cpp:1042)
1032      // Test 3: utctimetuple() - returns (year, month, day, hour, minute, second) in UTC
1033      pandas::Timestamp ts_utc(2024, 6, 15, 14, 30, 45, 0, 0, "UTC");
1034      auto utc_tuple = ts_utc.utctimetuple();
1035      if (pass && std::get<0>(utc_tuple) != 2024) { pass = false; fail_msg = "utctimetuple year mismatch"; }
1036      if (pass && std::get<1>(utc_tuple) != 6) { pass = false; fail_msg = "utctimetuple month mismatch"; }
1037      if (pass && std::get<2>(utc_tuple) != 15) { pass = false; fail_msg = "utctimetuple day mismatch"; }
1038      if (pass && std::get<3>(utc_tuple) != 14) { pass = false; fail_msg = "utctimetuple hour mismatch"; }
1039      if (pass && std::get<4>(utc_tuple) != 30) { pass = false; fail_msg = "utctimetuple minute mismatch"; }
1040      if (pass && std::get<5>(utc_tuple) != 45) { pass = false; fail_msg = "utctimetuple second mismatch"; }
1041
1042      // Test 4: timetz() - returns (hour, minute, second, microsecond, tz_offset_seconds)
1043      pandas::Timestamp ts_tz(2024, 6, 15, 14, 30, 45, 123456, 0, "UTC");
1044      auto time_tuple = ts_tz.timetz();
1045      if (pass && std::get<0>(time_tuple) != 14) { pass = false; fail_msg = "timetz hour mismatch"; }
1046      if (pass && std::get<1>(time_tuple) != 30) { pass = false; fail_msg = "timetz minute mismatch"; }
1047      if (pass && std::get<2>(time_tuple) != 45) { pass = false; fail_msg = "timetz second mismatch"; }
1048      if (pass && std::get<3>(time_tuple) != 123456) { pass = false; fail_msg = "timetz microsecond mismatch"; }
1049      // UTC offset should be 0 for UTC timezone
1050      if (pass && std::get<4>(time_tuple) != 0) { pass = false; fail_msg = "timetz UTC offset should be 0, got " + std::to_string(std::get<4>(time_tuple)); }
1051
1052      if (!pass) {
tz (pd_test_2_all.cpp:17914)
17904            pandas::DataFrame df(data);
17905            df.set_index(std::make_unique<pandas::DatetimeIndex>(tz_aware_idx));
17906
17907            // Verify the index is timezone-aware
17908            const pandas::DatetimeIndex* original_idx = dynamic_cast<const pandas::DatetimeIndex*>(&df.index());
17909            if (!original_idx) {
17910                std::cout << "  [FAIL] : in pd_test_tz_convert_basic() : index is not DatetimeIndex" << std::endl;
17911                throw std::runtime_error("pd_test_tz_convert_basic failed: index is not DatetimeIndex");
17912            }
17913
17914            std::string original_tz = original_idx->tz();
17915            if (original_tz.empty()) {
17916                std::cout << "  [FAIL] : in pd_test_tz_convert_basic() : original index is not timezone-aware" << std::endl;
17917                throw std::runtime_error("pd_test_tz_convert_basic failed: original index is not timezone-aware");
17918            }
17919
17920            // Convert to Asia/Shanghai timezone
17921            pandas::DataFrame df_shanghai = df.tz_convert("Asia/Shanghai");
17922
17923            // Verify result has a DatetimeIndex
17924            const pandas::DatetimeIndex* converted_idx = dynamic_cast<const pandas::DatetimeIndex*>(&df_shanghai.index());
unit (pd_test_1_all.cpp:9284)
9274    data.setElementAt({0}, numpy::datetime64(1000LL, numpy::DateTimeUnit::Nanosecond));
9275    data.setElementAt({1}, numpy::datetime64(2000LL, numpy::DateTimeUnit::Nanosecond));
9276
9277    numpy::NDArray<numpy::bool_> mask(std::vector<size_t>{2});
9278    mask.setElementAt({0}, numpy::bool_(false));
9279    mask.setElementAt({1}, numpy::bool_(false));
9280
9281    pandas::DatetimeArray arr(data, mask);
9282    pandas::DatetimeTDMixin idx(arr);
9283
9284    std::string unit = idx.unit();
9285
9286    bool passed = (unit == "ns");  // nanosecond
9287    if (!passed) {
9288        std::cout << "  [FAIL] : in pd_test_datetime_unit_property() : unit property check failed, got '" << unit << "'" << std::endl;
9289        throw std::runtime_error("pd_test_datetime_unit_property failed");
9290    }
9291
9292    std::cout << " -> tests passed" << std::endl;
9293}
week (pd_test_timestamp_scalar.cpp:406)
396      // 2024-06-15 is a Saturday
397      pandas::Timestamp ts(2024, 6, 15);
398
399      if (ts.dayofweek() != 5) { pass = false; fail_msg = "2024-06-15 should be Saturday (5)"; }
400      if (ts.day_of_week() != 5) { pass = false; fail_msg = "day_of_week alias"; }
401      if (ts.dayofyear() != 167) { pass = false; fail_msg = "2024-06-15 should be day 167"; }
402      if (ts.day_of_year() != 167) { pass = false; fail_msg = "day_of_year alias"; }
403      if (ts.quarter() != 2) { pass = false; fail_msg = "June is Q2"; }
404      if (ts.days_in_month() != 30) { pass = false; fail_msg = "June has 30 days"; }
405
406      int week = ts.week();
407      if (week < 1 || week > 53) { pass = false; fail_msg = "week should be 1-53"; }
408
409      if (!pass) {
410        std::cout << "  [FAIL] : in np_test_timestamp_derived() : " << fail_msg;
411        throw std::runtime_error("np_test_timestamp_derived failed: " + fail_msg);
412      }
413
414      std::cout << " -> tests passed" << std::endl;
415    }
wrap_int_result (pd_test_3_all.cpp:25102)
25092void pd_test_dt_bool_na_name_preserve() {
25093    std::cout << "========= pd_test_dt_bool_na: name preservation ========";
25094    std::vector<numpy::datetime64> dates = {
25095        numpy::datetime64("2024-01-01"),
25096        numpy::datetime64("2024-06-15")
25097    };
25098    pandas::Series<numpy::datetime64> s(dates);
25099    s.set_name("test_dates");
25100    pandas::DatetimeProperties<pandas::Series<numpy::datetime64>> dt(s);
25101    auto year_series = dt.wrap_int_result(dt.year());
25102    if (!year_series.name().has_value() || year_series.name().value() != "test_dates")
25103        throw std::runtime_error("name not preserved through wrap_int_result");
25104    std::cout << " -> tests passed" << std::endl;
25105}
25106
25107int pd_test_dt_bool_na_main() {
25108    std::cout << "====================================== running pd_test_dt_bool_na ==================================== " << std::endl;
25109    try {
25110        pd_test_dt_bool_na_clean();
25111        pd_test_dt_bool_na_with_nat();
year (pd_test_1_all.cpp:1147)
1137    void pd_test_datetime_array_component_year() {
1138        std::cout << "========= DatetimeArray: year component ======================= ";
1139
1140        pandas::DatetimeArray arr(std::vector<std::string>{
1141            "2020-01-15",
1142            "NaT",
1143            "2025-06-20"
1144        });
1145
1146        auto years = arr.year();
1147
1148        auto y0 = years[0];
1149        if (!y0.has_value() || y0.value() != 2020) {
1150            std::cout << "  [FAIL] : year[0] should be 2020" << std::endl;
1151            throw std::runtime_error("pd_test_datetime_array_component_year failed: year[0]");
1152        }
1153
1154        auto y1 = years[1];
1155        if (y1.has_value()) {
1156            std::cout << "  [FAIL] : year[1] should be NA (NaT)" << std::endl;