diff --git a/app/node/factory.cpp b/app/node/factory.cpp
index dd82a0805..41d6f55a5 100644
--- a/app/node/factory.cpp
+++ b/app/node/factory.cpp
@@ -62,6 +62,7 @@
#include "project/folder/folder.h"
#include "project/footage/footage.h"
#include "project/sequence/sequence.h"
+#include "time/timeformat/timeformat.h"
#include "time/timeoffset/timeoffsetnode.h"
#include "time/timeremap/timeremap.h"
@@ -291,6 +292,8 @@ Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id)
return new MaskDistortNode();
case kDropShadowFilter:
return new DropShadowFilter();
+ case kTimeFormat:
+ return new TimeFormatNode();
case kInternalNodeCount:
break;
diff --git a/app/node/factory.h b/app/node/factory.h
index d7ca955ff..b6f6037f0 100644
--- a/app/node/factory.h
+++ b/app/node/factory.h
@@ -75,6 +75,7 @@ public:
kChromaKey,
kMaskDistort,
kDropShadowFilter,
+ kTimeFormat,
// Count value
kInternalNodeCount
diff --git a/app/node/time/CMakeLists.txt b/app/node/time/CMakeLists.txt
index e23a85367..9f3aa1dc5 100644
--- a/app/node/time/CMakeLists.txt
+++ b/app/node/time/CMakeLists.txt
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
+add_subdirectory(timeformat)
add_subdirectory(timeoffset)
add_subdirectory(timeremap)
diff --git a/app/node/time/timeformat/CMakeLists.txt b/app/node/time/timeformat/CMakeLists.txt
new file mode 100644
index 000000000..552649a6d
--- /dev/null
+++ b/app/node/time/timeformat/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Olive - Non-Linear Video Editor
+# Copyright (C) 2022 Olive Team
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+set(OLIVE_SOURCES
+ ${OLIVE_SOURCES}
+ node/time/timeformat/timeformat.cpp
+ node/time/timeformat/timeformat.h
+ PARENT_SCOPE
+)
diff --git a/app/node/time/timeformat/timeformat.cpp b/app/node/time/timeformat/timeformat.cpp
new file mode 100644
index 000000000..50a870a86
--- /dev/null
+++ b/app/node/time/timeformat/timeformat.cpp
@@ -0,0 +1,79 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2022 Olive Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+***/
+
+#include "timeformat.h"
+
+#include
+
+namespace olive {
+
+#define super Node
+
+const QString TimeFormatNode::kTimeInput = QStringLiteral("time_in");
+const QString TimeFormatNode::kFormatInput = QStringLiteral("format_in");
+const QString TimeFormatNode::kLocalTimeInput = QStringLiteral("localtime_in");
+
+TimeFormatNode::TimeFormatNode()
+{
+ AddInput(kTimeInput, NodeValue::kFloat);
+ AddInput(kFormatInput, NodeValue::kText, QStringLiteral("hh:mm:ss"));
+ AddInput(kLocalTimeInput, NodeValue::kBoolean);
+}
+
+QString TimeFormatNode::Name() const
+{
+ return tr("Time Format");
+}
+
+QString TimeFormatNode::id() const
+{
+ return QStringLiteral("org.olivevideoeditor.Olive.timeformat");
+}
+
+QVector TimeFormatNode::Category() const
+{
+ return {kCategoryGenerator};
+}
+
+QString TimeFormatNode::Description() const
+{
+ return tr("Format time (in Unix epoch seconds) into a string.");
+}
+
+void TimeFormatNode::Retranslate()
+{
+ super::Retranslate();
+
+ SetInputName(kTimeInput, tr("Time"));
+ SetInputName(kFormatInput, tr("Format"));
+ SetInputName(kLocalTimeInput, tr("Interpret time as local time"));
+}
+
+void TimeFormatNode::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
+{
+ qint64 ms_since_epoch = value[kTimeInput].toDouble()*1000;
+ bool time_is_local = value[kLocalTimeInput].toBool();
+ QDateTime dt = QDateTime::fromMSecsSinceEpoch(ms_since_epoch, time_is_local ? Qt::LocalTime : Qt::UTC);
+ QString format = value[kFormatInput].toString();
+ QString output = dt.toString(format);
+ table->Push(NodeValue(NodeValue::kText, output, this));
+}
+
+}
diff --git a/app/node/time/timeformat/timeformat.h b/app/node/time/timeformat/timeformat.h
new file mode 100644
index 000000000..ddc7ac8c1
--- /dev/null
+++ b/app/node/time/timeformat/timeformat.h
@@ -0,0 +1,53 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2022 Olive Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+***/
+
+#ifndef TIMEFORMAT_H
+#define TIMEFORMAT_H
+
+#include "node/node.h"
+
+namespace olive {
+
+class TimeFormatNode : public Node
+{
+ Q_OBJECT
+public:
+ TimeFormatNode();
+
+ NODE_DEFAULT_FUNCTIONS(TimeFormatNode)
+
+ virtual QString Name() const override;
+ virtual QString id() const override;
+ virtual QVector Category() const override;
+ virtual QString Description() const override;
+
+ virtual void Retranslate() override;
+
+ virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override;
+
+ static const QString kTimeInput;
+ static const QString kFormatInput;
+ static const QString kLocalTimeInput;
+
+};
+
+}
+
+#endif // TIMEFORMAT_H