Skip to content

Commit 2a08e0c

Browse files
committed
Make datetime more flexible rather than fixed
Signed-off-by: Andrew Sasmito <asasmito1920@gmail.com>
1 parent 0f73997 commit 2a08e0c

5 files changed

Lines changed: 72 additions & 49 deletions

File tree

cpp/csp/adapters/csv/CsvInputAdapterManager.cpp

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,53 @@
1818

1919
namespace csp::adapters::csv {
2020

21-
// Parses exactly "YYYY-MM-DD HH::MM::SS"
22-
DateTime parseFixed_YmdHMS(std::string_view date) {
23-
if (date.size() < 19)
24-
CSP_THROW(ValueError, "Timestamp too short");
21+
// Build parser at runtime for extracting date time
22+
std::function<DateTime(std::string_view)>
23+
createParser(std::string_view format) {
2524

26-
auto d2 = [&](size_t i) {
27-
return (date[i] - '0') * 10 + (date[i + 1] - '0');
28-
};
25+
constexpr std::array<std::string_view, 6> date_format = {"YYYY", "MM", "DD",
26+
"hh", "mm", "ss"};
27+
28+
std::array<int, 6> date_indices;
2929

30-
int year = d2(0) * 100 + d2(2);
31-
int month = d2(5);
32-
int day = d2(8);
30+
for (int i = 0; i < 6; ++i) {
31+
auto pos = format.find(date_format[i]);
3332

34-
int hour = d2(11);
35-
int minute = d2(14);
36-
int second = d2(17);
33+
date_indices[i] =
34+
pos == std::string_view::npos ? -1 : static_cast<int>(pos);
35+
}
3736

38-
return DateTime(year, month, day, hour, minute, second);
37+
return [date_indices](std::string_view date) -> DateTime {
38+
std::array<int, 6> data = {
39+
0, // year
40+
0, // month
41+
1, // day
42+
0, // hour
43+
0, // minute
44+
0 // second
45+
};
46+
47+
auto d2 = [&](int idx) {
48+
return (date[idx] - '0') * 10 + (date[idx + 1] - '0');
49+
};
50+
51+
auto d4 = [&](int idx) {
52+
return (date[idx] - '0') * 1000 + (date[idx + 1] - '0') * 100 +
53+
(date[idx + 2] - '0') * 10 + (date[idx + 3] - '0');
54+
};
55+
56+
for (int i = 0; i < 6; ++i) {
57+
if (date_indices[i] == -1)
58+
continue;
59+
60+
if (i == 0)
61+
data[i] = d4(date_indices[i]);
62+
else
63+
data[i] = d2(date_indices[i]);
64+
}
65+
66+
return DateTime(data[0], data[1], data[2], data[3], data[4], data[5]);
67+
};
3968
}
4069

4170
CsvInputAdapterManager::CsvInputAdapterManager(csp::Engine *engine,
@@ -61,12 +90,10 @@ CsvInputAdapterManager::CsvInputAdapterManager(csp::Engine *engine,
6190
properties.tryGet("time_format", m_timeFormat);
6291

6392
if (m_timeFormat.empty()) {
64-
dateParser = parseFixed_YmdHMS;
65-
} else if (m_timeFormat == "YYYY-MM-DD HH::MM::SS") {
66-
dateParser = parseFixed_YmdHMS;
67-
} else {
68-
CSP_THROW(ValueError, "Time format not supported");
93+
CSP_THROW(ValueError, "Time format must be provided");
6994
}
95+
96+
dateParser = createParser(m_timeFormat);
7097
}
7198

7299
CsvInputAdapterManager::~CsvInputAdapterManager() = default;
@@ -299,24 +326,21 @@ void CsvInputAdapterManager::bindSubscriberDispatchers() {
299326

300327
auto col = colIndex.find(csvColumn);
301328

302-
CSP_TRUE_OR_THROW_RUNTIME(
303-
col != colIndex.end(),
304-
"Column '" << csvColumn << "' not found in CSV header");
329+
CSP_TRUE_OR_THROW_RUNTIME(col != colIndex.end(),
330+
"Column '" << csvColumn
331+
<< "' not found in CSV header");
305332

306333
auto field = meta->field(structField);
307334

308-
CSP_TRUE_OR_THROW_RUNTIME(
309-
field,
310-
"Field '" << structField << "' not found in struct");
335+
CSP_TRUE_OR_THROW_RUNTIME(field, "Field '" << structField
336+
<< "' not found in struct");
311337

312338
size_t idx = col->second;
313339

314340
subscription.m_fieldSetters.push_back(
315341
[idx, field](StructPtr &s,
316342
const std::vector<std::string_view> &cols) {
317-
field->setValue<std::string>(
318-
s.get(),
319-
std::string(cols[idx]));
343+
field->setValue<std::string>(s.get(), std::string(cols[idx]));
320344
});
321345
}
322346

cpp/csp/adapters/csv/CsvInputAdapterManager.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,6 @@
1616

1717
namespace csp::adapters::csv {
1818

19-
// Manages all csv input adapters for a single engine run.
20-
//
21-
// Lifecycle:
22-
// 1. Registration: getInputAdapter() called per subscription (before engine
23-
// starts)
24-
// 2. start(): create processors → wire adapters → read first row
25-
// 3. processNextSimTimeSlice(): skip/dispatch loop per engine tick
26-
// 4. stop(): tear down all state
2719
class CsvInputAdapterManager final : public csp::AdapterManager {
2820
public:
2921
CsvInputAdapterManager(csp::Engine *engine, const Dictionary &properties);
@@ -80,7 +72,7 @@ class CsvInputAdapterManager final : public csp::AdapterManager {
8072
// populated.
8173
void bindSubscriberDispatchers();
8274

83-
using dateTimeParserfn = DateTime (*)(std::string_view);
75+
using dateTimeParserfn = std::function<DateTime(std::string_view)>;
8476

8577
// Registration-phase state (populated by getInputAdapter before start)
8678
std::vector<Subscriber> m_subscribers;

csp/adapters/csv.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ def subscribe(
4444
push_mode=push_mode,
4545
)
4646

47+
def subscribe_all(
48+
self,
49+
ts_type,
50+
field_map=None,
51+
symbol=None,
52+
push_mode=PushMode.LAST_VALUE,
53+
):
54+
return self.subscribe(ts_type, field_map, symbol, push_mode) # Legacy API
55+
4756
def _create(self, engine, memo):
4857
return _csvadapterimpl._csv_adapter_manager(engine, self._properties)
4958

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
TIME|SYMBOL|PRICE|SIZE|SIDE
2-
2020-03-03 09:30:00|AAPL|500.00|100|BUY
3-
2020-03-03 09:30:01|IBM|100.00|200|BUY
4-
2020-03-03 09:30:02|AAPL|400.00|100|BUY
5-
2020-03-03 09:30:03|IBM|200.00|300|SELL
6-
2020-03-03 09:30:04|AAPL|300.00|200|SELL
7-
2020-03-03 09:30:05|AAPL|200.00|400|BUY
8-
2020-03-03 09:30:06|GM|2.00|1|BUY
2+
20200303 09:30:00|AAPL|500.00|100|BUY
3+
20200303 09:30:01|IBM|100.00|200|BUY
4+
20200303 09:30:02|AAPL|400.00|100|BUY
5+
20200303 09:30:03|IBM|200.00|300|SELL
6+
20200303 09:30:04|AAPL|300.00|200|SELL
7+
20200303 09:30:05|AAPL|200.00|400|BUY
8+
20200303 09:30:06|GM|2.00|1|BUY

csp/tests/adapters/test_csv.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ def graph():
3030
time_column="TIME",
3131
symbol_column="SYMBOL",
3232
delimiter="|",
33+
time_format="YYYYMMDD hh:mm:ss",
3334
)
3435

3536
# Struct
@@ -47,7 +48,7 @@ def graph():
4748
aapl_price = reader.subscribe(str, symbol="AAPL", field_map="PRICE")
4849

4950
# all data
50-
all = reader.subscribe(PriceQuantity)
51+
all = reader.subscribe_all(PriceQuantity)
5152

5253
csp.add_graph_output("aapl", aapl)
5354
csp.add_graph_output("ibm", ibm)
@@ -92,10 +93,7 @@ def graph():
9293

9394
def test_starttime(self):
9495
reader = CsvAdapterManager(
95-
self._filename,
96-
time_column="TIME",
97-
symbol_column="SYMBOL",
98-
delimiter="|",
96+
self._filename, time_column="TIME", symbol_column="SYMBOL", delimiter="|", time_format="YYYYMMDD hh:mm:ss"
9997
)
10098
aapl = reader.subscribe(str, symbol="AAPL", field_map="PRICE")
10199

0 commit comments

Comments
 (0)