spacing with correct cooldowns and updates

This commit is contained in:
jorenchik
2024-10-19 17:21:19 +03:00
parent 2f2818b44b
commit 2d1589c94d
5 changed files with 234 additions and 117 deletions

14
src/include/main.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include <vector>
#include "parser.h"
void update();
void saveMdem();
struct MdemBuffer {
std::vector<Question*> questions = std::vector<Question*>();
time_t trainedAt = 0;
};

View File

@@ -2,6 +2,7 @@
#include <QMainWindow> #include <QMainWindow>
#include "main.h"
#include "parser.h" #include "parser.h"
extern QMainWindow *trainWindow; extern QMainWindow *trainWindow;
@@ -15,7 +16,6 @@ enum PracticeAlgorithm {
void initTrainWindow(); void initTrainWindow();
void initiatePractice( void initiatePractice(
std::vector<Question*> questions, MdemBuffer *mdemBuffer,
PracticeAlgorithm algorithm, PracticeAlgorithm algorithm
time_t *trainedAt
); );

View File

@@ -58,6 +58,7 @@
#include <QPushButton> #include <QPushButton>
#include <QStandardPaths> #include <QStandardPaths>
#include "main.h"
#include "api.h" #include "api.h"
#include "parser.h" #include "parser.h"
#include "qscilexer.h" #include "qscilexer.h"
@@ -86,11 +87,6 @@ struct Mdem {
Question *question; Question *question;
}; };
struct MdemBuffer {
std::vector<Question*> questions = std::vector<Question*>();
time_t trainedAt = 0;
};
struct ErrorView { struct ErrorView {
QWidget box; QWidget box;
QVBoxLayout layout; QVBoxLayout layout;
@@ -164,6 +160,8 @@ std::string outputMdem(std::vector<Question*> questions, time_t time = 0) {
std::stringstream ss; std::stringstream ss;
if (time > 0) { if (time > 0) {
auto timezoneOffset = settings->value("timezone").toInt();
/*time = time + 3600 * timezoneOffset;*/
std::tm* tm = std::localtime(&time); std::tm* tm = std::localtime(&time);
char buffer[100]; char buffer[100];
std::strftime(buffer, sizeof(buffer), "%d.%m.%Y %H\\:%M", tm); std::strftime(buffer, sizeof(buffer), "%d.%m.%Y %H\\:%M", tm);
@@ -242,8 +240,13 @@ void makePages() {
void setupMdem(Mdem *mdem, Question *question) { void setupMdem(Mdem *mdem, Question *question) {
if (MultiElementQuestion* mw = dynamic_cast<MultiElementQuestion*>(question)) { if (MultiElementQuestion* mw = dynamic_cast<MultiElementQuestion*>(question)) {
std::stringstream ss;
if (mw->Cooldown > 0) {
ss << std::format("[{:.2f}] ", question->Cooldown);
}
ss << mw->QuestionText;
mdem->wFrontText.setText( mdem->wFrontText.setText(
QString::fromStdString(mw->QuestionText) QString::fromStdString(ss.str())
); );
auto choices = mw->Choices; auto choices = mw->Choices;
for (size_t k = 0; k < choices.size(); ++k) { for (size_t k = 0; k < choices.size(); ++k) {
@@ -444,7 +447,35 @@ void CreateMdems(std::vector<Question*>& questions) {
hMdemScroll->addItem(mdemSpacer); hMdemScroll->addItem(mdemSpacer);
} }
void updateMdemInfo(std::string filename, bool isChanged = false) {
if (filename.length() > 0) {
std::stringstream ss;
ss << std::format("mdem: {}", filename);
if (isChanged) {
ss << "*";
}
if (mdemBuffer->trainedAt > 0) {
std::tm* tm = std::localtime(&mdemBuffer->trainedAt);
char buffer[100];
std::strftime(buffer, sizeof(buffer), "%d.%m.%Y %H:%M", tm);
ss << std::endl << "Last practiced: " << std::string(buffer);
}
deckListLabel->setText(QString::fromStdString(ss.str()));
} else {
deckListLabel->setText("");
}
}
std::string getFilename(std::string path) {
std::smatch matches;
auto filenameMatched = std::regex_search(path, matches, lastPathElementExp);
return matches[2].str();
}
void update() {
SwitchPage(currentPage);
updateMdemInfo(getFilename(currentMdem));
}
void SwitchPage(int pageIdx) { void SwitchPage(int pageIdx) {
currentPage = pageIdx; currentPage = pageIdx;
@@ -560,29 +591,6 @@ void releaseError(ErrorView** item) {
std::cout << std::format("Released, current pool size: {}\n", errorPool.size()); std::cout << std::format("Released, current pool size: {}\n", errorPool.size());
} }
std::string getFilename(std::string path) {
std::smatch matches;
auto filenameMatched = std::regex_search(path, matches, lastPathElementExp);
return matches[2].str();
}
void updateMdemInfo(std::string filename) {
if (filename.length() > 0) {
std::stringstream ss;
ss << std::format("mdem: {}", filename);
if (mdemBuffer->trainedAt > 0) {
std::tm* tm = std::localtime(&mdemBuffer->trainedAt);
char buffer[100];
std::strftime(buffer, sizeof(buffer), "%d.%m.%Y %H:%M", tm);
ss << std::endl << "Last practiced: " << std::string(buffer);
}
deckListLabel->setText(QString::fromStdString(ss.str()));
} else {
deckListLabel->setText("");
}
}
void reloadMdem() { void reloadMdem() {
auto file = std::ifstream(currentMdem); auto file = std::ifstream(currentMdem);
std::string content; std::string content;
@@ -616,7 +624,7 @@ void reloadMdem() {
mdemBuffer->trainedAt = 0; mdemBuffer->trainedAt = 0;
} else { } else {
auto timezoneOffset = settings->value("timezone").toInt(); auto timezoneOffset = settings->value("timezone").toInt();
mdemBuffer->trainedAt = res.value.lastTrainedAt + 3600 * timezoneOffset; mdemBuffer->trainedAt = res.value.lastTrainedAt - 3600 * timezoneOffset;
} }
std::cout << std::format("Last trained at: {}", mdemBuffer->trainedAt) << std::endl; std::cout << std::format("Last trained at: {}", mdemBuffer->trainedAt) << std::endl;
@@ -705,13 +713,13 @@ void setupEditorSave(bool checked) {
for (int i = 0; i < mdemBuffer->questions.size(); ++i) { for (int i = 0; i < mdemBuffer->questions.size(); ++i) {
if (mdemBuffer->questions[i] == oldQuestion) { if (mdemBuffer->questions[i] == oldQuestion) {
mdemBuffer->questions.erase(mdemBuffer->questions.begin() + i); mdemBuffer->questions.erase(mdemBuffer->questions.begin() + i);
delete mdemBuffer->questions[i]; delete oldQuestion;
mdemBuffer->questions[i] = editMdem->question; mdemBuffer->questions.insert(mdemBuffer->questions.begin() + i, res.value.questions[0]);
break; break;
} }
} }
/*setupMdem(editMdem, res.value.questions[0]);*/ setupMdem(editMdem, res.value.questions[0]);
/*showBacklabels(editMdem);*/ showBacklabels(editMdem);
editorWindow->hide(); editorWindow->hide();
} else { } else {
QMessageBox::information( QMessageBox::information(
@@ -741,6 +749,12 @@ void setupEditorSave(bool checked) {
} }
}; };
void saveMdem() {
auto filename = getFilename(currentMdem);
std::ofstream out(currentMdem);
out << outputMdem(mdemBuffer->questions, mdemBuffer->trainedAt);
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
mdemBuffer = new MdemBuffer; mdemBuffer = new MdemBuffer;
QApplication app(argc, argv); QApplication app(argc, argv);
@@ -952,9 +966,9 @@ int main(int argc, char *argv[]) {
hlButtonsTop->addWidget(add); hlButtonsTop->addWidget(add);
hlButtonsTop->addWidget(save); hlButtonsTop->addWidget(save);
hlButtonsTop->addWidget(load); hlButtonsTop->addWidget(load);
cbAlgorithm->addItem("Primary", PRIMARY);
cbAlgorithm->addItem("Random", RANDOM);
cbAlgorithm->addItem("Spaced", SPACED); cbAlgorithm->addItem("Spaced", SPACED);
cbAlgorithm->addItem("Random", RANDOM);
cbAlgorithm->addItem("Primary", PRIMARY);
practice->setText("Practice"); practice->setText("Practice");
hlButtonsBottom->addWidget(cbAlgorithm); hlButtonsBottom->addWidget(cbAlgorithm);
hlButtonsBottom->addWidget(practice); hlButtonsBottom->addWidget(practice);
@@ -972,9 +986,7 @@ int main(int argc, char *argv[]) {
}); });
QObject::connect(load, &QToolButton::clicked, &reloadMdem); QObject::connect(load, &QToolButton::clicked, &reloadMdem);
QObject::connect(save, &QToolButton::clicked, []() { QObject::connect(save, &QToolButton::clicked, []() {
auto filename = getFilename(currentMdem); saveMdem();
std::ofstream out(currentMdem);
out << outputMdem(mdemBuffer->questions, mdemBuffer->trainedAt);
}); });
QObject::connect( QObject::connect(
practice, practice,
@@ -983,9 +995,8 @@ int main(int argc, char *argv[]) {
trainWindow->show(); trainWindow->show();
trainWindow->resize(600, 300); trainWindow->resize(600, 300);
initiatePractice( initiatePractice(
mdemBuffer->questions, mdemBuffer,
static_cast<PracticeAlgorithm>(cbAlgorithm->currentData().toInt()), static_cast<PracticeAlgorithm>(cbAlgorithm->currentData().toInt())
&mdemBuffer->trainedAt
); );
} }
); );

View File

@@ -2,14 +2,14 @@
#include <QWidget> #include <QWidget>
#include <QToolButton> #include <QToolButton>
#include <algorithm> #include <algorithm>
#include <atomic>
#include <cstdint> #include <cstdint>
#include <ctime>
#include <format> #include <format>
#include <cstdlib> #include <cstdlib>
#include <exception>
#include <format> #include <format>
#include <qabstractitemview.h> #include <qabstractitemview.h>
#include <qboxlayout.h> #include <qboxlayout.h>
#include <qchar.h>
#include <qcoreevent.h> #include <qcoreevent.h>
#include <qlabel.h> #include <qlabel.h>
#include <qlayoutitem.h> #include <qlayoutitem.h>
@@ -17,6 +17,7 @@
#include <qnamespace.h> #include <qnamespace.h>
#include <qscrollarea.h> #include <qscrollarea.h>
#include <qstandarditemmodel.h> #include <qstandarditemmodel.h>
#include <qstringalgorithms.h>
#include <qstringlistmodel.h> #include <qstringlistmodel.h>
#include <qtoolbutton.h> #include <qtoolbutton.h>
#include <Qt> #include <Qt>
@@ -29,6 +30,7 @@
#include <QStyledItemDelegate> #include <QStyledItemDelegate>
#include <QPainter> #include <QPainter>
#include "main.h"
#include "trainWindow.h" #include "trainWindow.h"
#include "parser.h" #include "parser.h"
@@ -204,7 +206,6 @@ QLabel *lQuestionText;
QVBoxLayout *vButtonBox; QVBoxLayout *vButtonBox;
QWidget *actionButtons; QWidget *actionButtons;
QHBoxLayout *hButtons; QHBoxLayout *hButtons;
QToolButton *btnPrev;
QSpacerItem *leftSpacer; QSpacerItem *leftSpacer;
QToolButton *btnTriggerAnswer; QToolButton *btnTriggerAnswer;
QSpacerItem *rightSpacer; QSpacerItem *rightSpacer;
@@ -229,10 +230,12 @@ QVBoxLayout *vGroups;
std::vector<QStandardItemModel*> groupModels; std::vector<QStandardItemModel*> groupModels;
// Questions & State // Questions & State
std::vector<Question*> trainQuestions = std::vector<Question*>(); MdemBuffer *currentBuffer;
int32_t currentQuestionIndex = -1; int32_t currentQuestionIndex = -1;
std::vector<GroupView*> groupViews; std::vector<GroupView*> groupViews;
PracticeAlgorithm practiceAlgoritm; PracticeAlgorithm practiceAlgoritm;
time_t lastTrainedAt;
std::default_random_engine rng; std::default_random_engine rng;
std::vector<QStandardItem*> itemPool; std::vector<QStandardItem*> itemPool;
@@ -285,6 +288,11 @@ void hideQuestionElements() {
orderList->hide(); orderList->hide();
multiChoiceList->hide(); multiChoiceList->hide();
wGroupQuestion->hide(); wGroupQuestion->hide();
btnNotRemembered->hide();
btnHard->hide();
btnMedium->hide();
btnEasy->hide();
btnTriggerAnswer->hide();
} }
void setupAnswerQuestion(MultiElementQuestion *question) { void setupAnswerQuestion(MultiElementQuestion *question) {
@@ -308,6 +316,10 @@ void setupAnswerQuestion(MultiElementQuestion *question) {
[](bool checked) { [](bool checked) {
answerText->show(); answerText->show();
btnTriggerAnswer->hide(); btnTriggerAnswer->hide();
btnNotRemembered->show();
btnHard->show();
btnMedium->show();
btnEasy->show();
} }
); );
btnTriggerAnswer->show(); btnTriggerAnswer->show();
@@ -491,63 +503,132 @@ void setupQuestion(Question *question) {
hideQuestionElements(); hideQuestionElements();
releaseAllItems(); releaseAllItems();
QObject::disconnect(btnTriggerAnswer, 0, 0, 0); QObject::disconnect(btnTriggerAnswer, 0, 0, 0);
if (auto *question = dynamic_cast<MultiElementQuestion*>(trainQuestions[currentQuestionIndex])) { if (auto *q = dynamic_cast<MultiElementQuestion*>(question)) {
btnNotRemembered->hide(); switch (q->type) {
btnHard->hide();
btnMedium->hide();
btnEasy->hide();
switch (question->type) {
case MultiElementType::Order: case MultiElementType::Order:
setupOrderQuestion(question); setupOrderQuestion(q);
break; break;
case MultiElementType::MultiChoice: case MultiElementType::MultiChoice:
setupMultiChoiceQuestion(question); setupMultiChoiceQuestion(q);
break; break;
case MultiElementType::Regular: case MultiElementType::Regular:
setupAnswerQuestion(question); setupAnswerQuestion(q);
break; break;
} }
} else if (auto *question = dynamic_cast<GroupQuestion*>(trainQuestions[currentQuestionIndex])) { } else if (auto *question = dynamic_cast<GroupQuestion*>(
currentBuffer->questions[currentQuestionIndex])
) {
setupGroupQuestion(question); setupGroupQuestion(question);
} }
} }
void updatePaginationVisibility() { void updatePaginationVisibility() {
if (currentQuestionIndex == 0) { if (currentQuestionIndex == currentBuffer->questions.size() - 1) {
btnPrev->hide();
} else {
btnPrev->show();
}
if (currentQuestionIndex == trainQuestions.size() - 1) {
btnNext->hide(); btnNext->hide();
} else { } else {
btnNext->show(); btnNext->show();
} }
} }
void initiatePractice( template <typename T>
std::vector<Question*> questions, int randomIndex(std::vector<T> *vec) {
PracticeAlgorithm algorithm, srand(time(NULL));
time_t *trainedAt return rand() % vec->size();
) { }
time_t getTime() {
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
time_t unix_timestamp = std::chrono::duration_cast<std::chrono::seconds>( return std::chrono::duration_cast<std::chrono::seconds>(
now.time_since_epoch() now.time_since_epoch()
).count(); ).count();
}
trainQuestions = questions; void setupNextQuestion() {
if (questions.size() <= 0) { if (currentBuffer->questions.size() <= 0) {
return; return;
} }
currentQuestionIndex = 0; switch (practiceAlgoritm) {
updatePaginationVisibility(); case PRIMARY: {
setupQuestion(trainQuestions[currentQuestionIndex]); currentQuestionIndex++;
practiceAlgoritm = algorithm; if (currentQuestionIndex < currentBuffer->questions.size()) {
setupQuestion(currentBuffer->questions[currentQuestionIndex]);
}
updatePaginationVisibility();
} break;
case RANDOM: {
auto questionCandidates = currentBuffer->questions;
if (currentQuestionIndex > -1) {
questionCandidates.erase(questionCandidates.begin() + currentQuestionIndex);
}
if (questionCandidates.size() > 0) {
auto i = randomIndex(&questionCandidates);
setupQuestion(questionCandidates[i]);
for (int k = 0; k < currentBuffer->questions.size(); ++k) {
if (currentBuffer->questions[k] == questionCandidates[i]) {
currentQuestionIndex = k;
break;
}
}
}
} break;
case SPACED: {
auto questionCandidates = std::vector<Question*>();
time_t time = getTime();
auto lastTrainedAt = currentBuffer->trainedAt;
currentBuffer->trainedAt = time;
for (int i = 0; i < currentBuffer->questions.size(); ++i) {
auto cooldownSeconds = currentBuffer->questions[i]->Cooldown * 3600;
auto cooldownEndsAt = lastTrainedAt + cooldownSeconds;
if (i != currentQuestionIndex && cooldownEndsAt <= time) {
questionCandidates.push_back(currentBuffer->questions[i]);
}
auto newCooldown = cooldownEndsAt - time;
if (newCooldown < 0) {
newCooldown = 0;
}
currentBuffer->questions[i]->Cooldown = (double)newCooldown / 3600;
}
if (questionCandidates.size() > 0) {
auto i = randomIndex(&questionCandidates);
setupQuestion(questionCandidates[i]);
setupQuestion(
questionCandidates[randomIndex(&questionCandidates)]
);
for (int k = 0; k < currentBuffer->questions.size(); ++k) {
if (currentBuffer->questions[k] == questionCandidates[i]) {
currentQuestionIndex = k;
break;
}
}
}
update();
} break;
}
}
btnNotRemembered->hide(); void initiatePractice(
btnHard->hide(); MdemBuffer *mdemBuffer,
btnMedium->hide(); PracticeAlgorithm algorithm
btnEasy->hide(); ) {
practiceAlgoritm = algorithm;
currentBuffer = mdemBuffer;
if (currentBuffer->questions.size() <= 0) {
return;
}
currentQuestionIndex = -1;
hideQuestionElements();
updatePaginationVisibility();
setupNextQuestion();
}
void setCooldownHours(int cooldown) {
time_t time = getTime();
currentBuffer->trainedAt = time;
auto question = currentBuffer->questions[currentQuestionIndex];
question->Cooldown = cooldown;
update();
} }
void initTrainWindow() { void initTrainWindow() {
@@ -566,6 +647,25 @@ void initTrainWindow() {
itemDelegate = new CustomItemDelegate(multiChoiceList); itemDelegate = new CustomItemDelegate(multiChoiceList);
{ // Top button menu.
auto hTopButtons = new QHBoxLayout();
auto topButtons = new QWidget();
topButtons->setLayout(hTopButtons);
auto topLeftSpacer = new QSpacerItem(50, 50, QSizePolicy::Expanding, QSizePolicy::Minimum);
auto btnSaveProgress = new QToolButton();
btnSaveProgress->setText("Save progress");
hTopButtons->addItem(topLeftSpacer);
hTopButtons->addWidget(btnSaveProgress);
vTrainWidget->addWidget(topButtons);
QObject::connect(btnSaveProgress, &QToolButton::clicked, []() {
saveMdem();
});
}
{ // Make the question box. { // Make the question box.
questionBox = new QWidget(); questionBox = new QWidget();
vQuestionBox = new QVBoxLayout(); vQuestionBox = new QVBoxLayout();
@@ -639,16 +739,26 @@ void initTrainWindow() {
vButtonBox = new QVBoxLayout(); vButtonBox = new QVBoxLayout();
actionButtons = new QWidget(); actionButtons = new QWidget();
hButtons = new QHBoxLayout(); hButtons = new QHBoxLayout();
btnPrev = new QToolButton();
leftSpacer = new QSpacerItem(50, 50, QSizePolicy::Expanding, QSizePolicy::Minimum); leftSpacer = new QSpacerItem(50, 50, QSizePolicy::Expanding, QSizePolicy::Minimum);
btnTriggerAnswer = new QToolButton(); btnTriggerAnswer = new QToolButton();
btnNotRemembered = new QToolButton(); btnNotRemembered = new QToolButton();
QObject::connect(btnNotRemembered, &QToolButton::clicked, []() {
setCooldownHours(0);
});
btnHard = new QToolButton(); btnHard = new QToolButton();
QObject::connect(btnHard, &QToolButton::clicked, []() {
setCooldownHours(12);
});
btnMedium = new QToolButton(); btnMedium = new QToolButton();
QObject::connect(btnMedium, &QToolButton::clicked, []() {
setCooldownHours(48);
});
btnEasy = new QToolButton(); btnEasy = new QToolButton();
QObject::connect(btnEasy, &QToolButton::clicked, []() {
setCooldownHours(72);
});
btnNotRemembered->setText("Not remembered"); btnNotRemembered->setText("Not remembered");
btnHard->setText("Hard"); btnHard->setText("Hard");
btnMedium->setText("Medium"); btnMedium->setText("Medium");
@@ -659,17 +769,10 @@ void initTrainWindow() {
rightSpacer = new QSpacerItem(50, 50, QSizePolicy::Expanding, QSizePolicy::Minimum); rightSpacer = new QSpacerItem(50, 50, QSizePolicy::Expanding, QSizePolicy::Minimum);
btnNext = new QToolButton(); btnNext = new QToolButton();
hButtons->addWidget(btnPrev);
hButtons->addItem(leftSpacer); hButtons->addItem(leftSpacer);
hButtons->addWidget(btnTriggerAnswer); hButtons->addWidget(btnTriggerAnswer);
hButtons->addWidget(btnNotRemembered); hButtons->addWidget(btnNotRemembered);
hButtons->addWidget(btnHard); hButtons->addWidget(btnHard);
QObject::connect(btnHard, &QToolButton::clicked, []() {
const double hourCooldown = 25.0;
auto question = trainQuestions[currentQuestionIndex];
question->Cooldown = hourCooldown;
});
hButtons->addWidget(btnMedium); hButtons->addWidget(btnMedium);
hButtons->addWidget(btnEasy); hButtons->addWidget(btnEasy);
@@ -677,34 +780,13 @@ void initTrainWindow() {
hButtons->addWidget(btnNext); hButtons->addWidget(btnNext);
vButtonBox->addWidget(actionButtons); vButtonBox->addWidget(actionButtons);
actionButtons->setLayout(hButtons); actionButtons->setLayout(hButtons);
btnPrev->setText("Previous");
QObject::connect(btnPrev, &QToolButton::clicked, []() {
currentQuestionIndex--;
if (currentQuestionIndex > -1) {
setupQuestion(trainQuestions[currentQuestionIndex]);
}
updatePaginationVisibility();
});
btnTriggerAnswer->setText("Show answer"); btnTriggerAnswer->setText("Show answer");
btnTriggerAnswer->hide();
btnNext->setText("Next"); btnNext->setText("Next");
QObject::connect(btnNext, &QToolButton::clicked, []() { QObject::connect(btnNext, &QToolButton::clicked, []() {
switch (practiceAlgoritm) { setupNextQuestion();
case PRIMARY:
currentQuestionIndex++;
if (currentQuestionIndex < trainQuestions.size()) {
setupQuestion(trainQuestions[currentQuestionIndex]);
}
updatePaginationVisibility();
break;
case RANDOM:
// TODO: implement
break;
case SPACED:
// TODO: implement
break;
}
}); });
questionBox->setObjectName("question-box"); questionBox->setObjectName("question-box");
actionButtons->setStyleSheet(QString( actionButtons->setStyleSheet(QString(

View File

@@ -141,6 +141,18 @@ Result<NoneType> ValidateGrammar(const std::vector<Token>& tokens) {
return {}; return {};
} }
time_t parseToUTCTime(const std::string datetime, std::string format) {
std::tm tm = {};
std::istringstream ss(datetime);
ss >> std::get_time(&tm, format.c_str());
if (ss.fail()) {
throw std::runtime_error("Failed to parse datetime string");
}
std::time_t time = timegm(&tm);
return time;
}
Result<ParseInfo> parseQuestions(const std::vector<Token>& tokens) { Result<ParseInfo> parseQuestions(const std::vector<Token>& tokens) {
auto questions = std::vector<Question*>(); auto questions = std::vector<Question*>();
time_t time = 0; time_t time = 0;
@@ -178,16 +190,14 @@ Result<ParseInfo> parseQuestions(const std::vector<Token>& tokens) {
}; };
if (isInBounds(i) && tokens[i].tokenType == TokenType::TextFragment) { if (isInBounds(i) && tokens[i].tokenType == TokenType::TextFragment) {
std::tm tm = {};
try { try {
strptime(tokens[i].content.c_str(), "%d.%m.%Y %H:%M", &tm); time = parseToUTCTime(tokens[i].content.c_str(), "%d.%m.%Y %H:%M");
} catch (std::exception e) { } catch (std::exception e) {
return makeResult( return makeResult(
std::format("cannot parse the time - {}", e.what()), std::format("cannot parse the time - {}", e.what()),
tokens[i] tokens[i]
); );
} }
time = mktime(&tm);
i++; i++;
} }