diff --git a/src/audit/log.cpp b/src/audit/log.cpp
index 2102f2862..4680bee1f 100644
--- a/src/audit/log.cpp
+++ b/src/audit/log.cpp
@@ -5,6 +5,7 @@
 #include <fmt/format.h>
 #include <json/json.hpp>
 
+#include "storage/v2/temporal.hpp"
 #include "utils/logging.hpp"
 #include "utils/string.hpp"
 
@@ -42,6 +43,14 @@ inline nlohmann::json PropertyValueToJson(const storage::PropertyValue &pv) {
       }
       break;
     }
+    case storage::PropertyValue::Type::TemporalData: {
+      ret = nlohmann::json::object();
+      const auto temporal_data = pv.ValueTemporalData();
+      // TODO (antonio2368): Maybe we want to have custom format for each type
+      ret.emplace("type", storage::TemporalTypeTostring(temporal_data.type));
+      ret.emplace("microseconds", temporal_data.microseconds);
+      break;
+    }
   }
   return ret;
 }
diff --git a/src/glue/communication.cpp b/src/glue/communication.cpp
index 464b5237c..ef69f642f 100644
--- a/src/glue/communication.cpp
+++ b/src/glue/communication.cpp
@@ -216,6 +216,8 @@ Value ToBoltValue(const storage::PropertyValue &value) {
       }
       return Value(std::move(dv_map));
     }
+    case storage::PropertyValue::Type::TemporalData:
+      LOG_FATAL("Unsupported type");
   }
 }
 
diff --git a/src/query/dump.cpp b/src/query/dump.cpp
index a47c9b174..2476e67e4 100644
--- a/src/query/dump.cpp
+++ b/src/query/dump.cpp
@@ -12,6 +12,7 @@
 #include "query/exceptions.hpp"
 #include "query/stream.hpp"
 #include "query/typed_value.hpp"
+#include "storage/v2/property_value.hpp"
 #include "storage/v2/storage.hpp"
 #include "utils/algorithm.hpp"
 #include "utils/logging.hpp"
@@ -88,6 +89,10 @@ void DumpPropertyValue(std::ostream *os, const storage::PropertyValue &value) {
       *os << "}";
       return;
     }
+    case storage::PropertyValue::Type::TemporalData: {
+      // TODO(antonio2368): Define dump command for temporal data
+      return;
+    }
   }
 }
 
diff --git a/src/query/frontend/ast/pretty_print.cpp b/src/query/frontend/ast/pretty_print.cpp
index 9b2ec186d..a57351cb3 100644
--- a/src/query/frontend/ast/pretty_print.cpp
+++ b/src/query/frontend/ast/pretty_print.cpp
@@ -141,6 +141,9 @@ void PrintObject(std::ostream *out, const storage::PropertyValue &value) {
     case storage::PropertyValue::Type::Map:
       PrintObject(out, value.ValueMap());
       break;
+    case storage::PropertyValue::Type::TemporalData:
+      // TODO (antonio2368): Print out the temporal data based on the type
+      LOG_FATAL("Not implemented!");
   }
 }
 
diff --git a/src/query/plan/operator.cpp b/src/query/plan/operator.cpp
index 72b2a51d2..926f42163 100644
--- a/src/query/plan/operator.cpp
+++ b/src/query/plan/operator.cpp
@@ -491,6 +491,7 @@ UniqueCursorPtr ScanAllByLabelPropertyRange::MakeCursor(utils::MemoryResource *m
           case storage::PropertyValue::Type::Int:
           case storage::PropertyValue::Type::Double:
           case storage::PropertyValue::Type::String:
+          case storage::PropertyValue::Type::TemporalData:
             // These are all fine, there's also Point, Date and Time data types
             // which were added to Cypher, but we don't have support for those
             // yet.
diff --git a/src/query/procedure/mg_procedure_impl.cpp b/src/query/procedure/mg_procedure_impl.cpp
index abd453e4c..0cfd151e3 100644
--- a/src/query/procedure/mg_procedure_impl.cpp
+++ b/src/query/procedure/mg_procedure_impl.cpp
@@ -477,6 +477,10 @@ mgp_value::mgp_value(const storage::PropertyValue &pv, utils::MemoryResource *m)
       map_v = allocator.new_object<mgp_map>(std::move(items));
       break;
     }
+    case storage::PropertyValue::Type::TemporalData: {
+      // TODO (antonio2368): Add support for temporala data types
+      LOG_FATAL("Unsupported type");
+    }
   }
 }
 
diff --git a/src/query/serialization/property_value.cpp b/src/query/serialization/property_value.cpp
index 262ff3cf0..46158d852 100644
--- a/src/query/serialization/property_value.cpp
+++ b/src/query/serialization/property_value.cpp
@@ -4,6 +4,10 @@
 
 namespace query::serialization {
 
+namespace {
+enum class ObjectType : uint8_t { MAP, TEMPORAL_DATA };
+}  // namespace
+
 nlohmann::json SerializePropertyValue(const storage::PropertyValue &property_value) {
   using Type = storage::PropertyValue::Type;
   switch (property_value.type()) {
@@ -21,6 +25,13 @@ nlohmann::json SerializePropertyValue(const storage::PropertyValue &property_val
       return SerializePropertyValueVector(property_value.ValueList());
     case Type::Map:
       return SerializePropertyValueMap(property_value.ValueMap());
+    case Type::TemporalData:
+      const auto temporal_data = property_value.ValueTemporalData();
+      auto data = nlohmann::json::object();
+      data.emplace("type", static_cast<uint64_t>(ObjectType::TEMPORAL_DATA));
+      data.emplace("value", nlohmann::json::object({{"type", static_cast<uint64_t>(temporal_data.type)},
+                                                    {"microseconds", temporal_data.microseconds}}));
+      return data;
   }
 }
 
@@ -34,9 +45,11 @@ nlohmann::json SerializePropertyValueVector(const std::vector<storage::PropertyV
 
 nlohmann::json SerializePropertyValueMap(const std::map<std::string, storage::PropertyValue> &parameters) {
   nlohmann::json data = nlohmann::json::object();
+  data.emplace("type", static_cast<uint64_t>(ObjectType::MAP));
+  data.emplace("value", nlohmann::json::object());
 
   for (const auto &[key, value] : parameters) {
-    data[key] = SerializePropertyValue(value);
+    data["value"][key] = SerializePropertyValue(value);
   }
 
   return data;
@@ -68,7 +81,14 @@ storage::PropertyValue DeserializePropertyValue(const nlohmann::json &data) {
   }
 
   MG_ASSERT(data.is_object(), "Unknown type found in the trigger storage");
-  return storage::PropertyValue(DeserializePropertyValueMap(data));
+
+  switch (data["type"].get<ObjectType>()) {
+    case ObjectType::MAP:
+      return storage::PropertyValue(DeserializePropertyValueMap(data));
+    case ObjectType::TEMPORAL_DATA:
+      return storage::PropertyValue(storage::TemporalData{data["value"]["type"].get<storage::TemporalType>(),
+                                                          data["value"]["microseconds"].get<int64_t>()});
+  }
 }
 
 std::vector<storage::PropertyValue> DeserializePropertyValueList(const nlohmann::json::array_t &data) {
@@ -82,9 +102,11 @@ std::vector<storage::PropertyValue> DeserializePropertyValueList(const nlohmann:
 }
 
 std::map<std::string, storage::PropertyValue> DeserializePropertyValueMap(const nlohmann::json::object_t &data) {
+  MG_ASSERT(data.at("type").get<ObjectType>() == ObjectType::MAP, "Invalid map serialization");
   std::map<std::string, storage::PropertyValue> property_values;
 
-  for (const auto &[key, value] : data) {
+  const nlohmann::json::object_t &values = data.at("value");
+  for (const auto &[key, value] : values) {
     property_values.emplace(key, DeserializePropertyValue(value));
   }
 
diff --git a/src/query/typed_value.cpp b/src/query/typed_value.cpp
index cdf51952c..573467e5b 100644
--- a/src/query/typed_value.cpp
+++ b/src/query/typed_value.cpp
@@ -52,6 +52,9 @@ TypedValue::TypedValue(const storage::PropertyValue &value, utils::MemoryResourc
       for (const auto &kv : map) map_v.emplace(kv.first, kv.second);
       return;
     }
+    case storage::PropertyValue::Type::TemporalData:
+      // TODO (antonio2368): Add support for Temporal types in TypedValues
+      break;
   }
   LOG_FATAL("Unsupported type");
 }
@@ -96,6 +99,9 @@ TypedValue::TypedValue(storage::PropertyValue &&other, utils::MemoryResource *me
       for (auto &kv : map) map_v.emplace(kv.first, std::move(kv.second));
       break;
     }
+    case storage::PropertyValue::Type::TemporalData:
+      // TODO (antonio2368): Add support for Temporal types in TypedValues
+      LOG_FATAL("Unsupported type");
   }
 
   other = storage::PropertyValue();
diff --git a/src/storage/v2/CMakeLists.txt b/src/storage/v2/CMakeLists.txt
index a997fb496..5de28e244 100644
--- a/src/storage/v2/CMakeLists.txt
+++ b/src/storage/v2/CMakeLists.txt
@@ -1,6 +1,7 @@
 set(storage_v2_src_files
     commit_log.cpp
     constraints.cpp
+    temporal.cpp
     durability/durability.cpp
     durability/serialization.cpp
     durability/snapshot.cpp
diff --git a/src/storage/v2/durability/marker.hpp b/src/storage/v2/durability/marker.hpp
index 856ee99bf..c9929e6eb 100644
--- a/src/storage/v2/durability/marker.hpp
+++ b/src/storage/v2/durability/marker.hpp
@@ -16,6 +16,7 @@ enum class Marker : uint8_t {
   TYPE_LIST = 0x15,
   TYPE_MAP = 0x16,
   TYPE_PROPERTY_VALUE = 0x17,
+  TYPE_TEMPORAL_DATA = 0x18,
 
   SECTION_VERTEX = 0x20,
   SECTION_EDGE = 0x21,
@@ -59,6 +60,7 @@ static const Marker kMarkersAll[] = {
     Marker::TYPE_STRING,
     Marker::TYPE_LIST,
     Marker::TYPE_MAP,
+    Marker::TYPE_TEMPORAL_DATA,
     Marker::TYPE_PROPERTY_VALUE,
     Marker::SECTION_VERTEX,
     Marker::SECTION_EDGE,
diff --git a/src/storage/v2/durability/serialization.cpp b/src/storage/v2/durability/serialization.cpp
index f9ce966ff..b9d7ffe95 100644
--- a/src/storage/v2/durability/serialization.cpp
+++ b/src/storage/v2/durability/serialization.cpp
@@ -1,5 +1,6 @@
 #include "storage/v2/durability/serialization.hpp"
 
+#include "storage/v2/temporal.hpp"
 #include "utils/endian.hpp"
 
 namespace storage::durability {
@@ -109,6 +110,13 @@ void Encoder::WritePropertyValue(const PropertyValue &value) {
       }
       break;
     }
+    case PropertyValue::Type::TemporalData: {
+      const auto temporal_data = value.ValueTemporalData();
+      WriteMarker(Marker::TYPE_TEMPORAL_DATA);
+      WriteUint(static_cast<uint64_t>(temporal_data.type));
+      WriteUint(utils::MemcpyCast<uint64_t>(temporal_data.microseconds));
+      break;
+    }
   }
 }
 
@@ -222,6 +230,21 @@ std::optional<std::string> Decoder::ReadString() {
   return value;
 }
 
+namespace {
+std::optional<TemporalData> ReadTemporalData(Decoder &decoder) {
+  const auto inner_marker = decoder.ReadMarker();
+  if (!inner_marker || *inner_marker != Marker::TYPE_TEMPORAL_DATA) return std::nullopt;
+
+  const auto type = decoder.ReadUint();
+  if (!type) return std::nullopt;
+
+  const auto microseconds = decoder.ReadUint();
+  if (!microseconds) return std::nullopt;
+
+  return TemporalData{static_cast<TemporalType>(*type), utils::MemcpyCast<int64_t>(*microseconds)};
+}
+}  // namespace
+
 std::optional<PropertyValue> Decoder::ReadPropertyValue() {
   auto pv_marker = ReadMarker();
   if (!pv_marker || *pv_marker != Marker::TYPE_PROPERTY_VALUE) return std::nullopt;
@@ -283,6 +306,11 @@ std::optional<PropertyValue> Decoder::ReadPropertyValue() {
       }
       return PropertyValue(std::move(value));
     }
+    case Marker::TYPE_TEMPORAL_DATA: {
+      const auto maybe_temporal_data = ReadTemporalData(*this);
+      if (!maybe_temporal_data) return std::nullopt;
+      return PropertyValue(*maybe_temporal_data);
+    }
 
     case Marker::TYPE_PROPERTY_VALUE:
     case Marker::SECTION_VERTEX:
@@ -379,6 +407,9 @@ bool Decoder::SkipPropertyValue() {
       }
       return true;
     }
+    case Marker::TYPE_TEMPORAL_DATA: {
+      return !!ReadTemporalData(*this);
+    }
 
     case Marker::TYPE_PROPERTY_VALUE:
     case Marker::SECTION_VERTEX:
diff --git a/src/storage/v2/durability/wal.cpp b/src/storage/v2/durability/wal.cpp
index 9f4bc46e7..04ce72c0b 100644
--- a/src/storage/v2/durability/wal.cpp
+++ b/src/storage/v2/durability/wal.cpp
@@ -158,6 +158,7 @@ WalDeltaData::Type MarkerToWalDeltaDataType(Marker marker) {
     case Marker::TYPE_STRING:
     case Marker::TYPE_LIST:
     case Marker::TYPE_MAP:
+    case Marker::TYPE_TEMPORAL_DATA:
     case Marker::TYPE_PROPERTY_VALUE:
     case Marker::SECTION_VERTEX:
     case Marker::SECTION_EDGE:
diff --git a/src/storage/v2/indices.cpp b/src/storage/v2/indices.cpp
index f7bd634fd..4408e5cb0 100644
--- a/src/storage/v2/indices.cpp
+++ b/src/storage/v2/indices.cpp
@@ -1,6 +1,8 @@
 #include "indices.hpp"
 
 #include "storage/v2/mvcc.hpp"
+#include "storage/v2/property_value.hpp"
+#include "utils/bound.hpp"
 #include "utils/logging.hpp"
 #include "utils/memory_tracker.hpp"
 
@@ -519,6 +521,7 @@ const PropertyValue kSmallestNumber = PropertyValue(-std::numeric_limits<double>
 const PropertyValue kSmallestString = PropertyValue("");
 const PropertyValue kSmallestList = PropertyValue(std::vector<PropertyValue>());
 const PropertyValue kSmallestMap = PropertyValue(std::map<std::string, PropertyValue>());
+const PropertyValue kSmallestTemporalData = PropertyValue(TemporalData{static_cast<TemporalType>(0), 0});
 
 LabelPropertyIndex::Iterable::Iterable(utils::SkipList<Entry>::Accessor index_accessor, LabelId label,
                                        PropertyId property,
@@ -590,6 +593,9 @@ LabelPropertyIndex::Iterable::Iterable(utils::SkipList<Entry>::Accessor index_ac
         upper_bound_ = utils::MakeBoundExclusive(kSmallestMap);
         break;
       case PropertyValue::Type::Map:
+        upper_bound_ = utils::MakeBoundExclusive(kSmallestTemporalData);
+        break;
+      case PropertyValue::Type::TemporalData:
         // This is the last type in the order so we leave the upper bound empty.
         break;
     }
@@ -619,7 +625,9 @@ LabelPropertyIndex::Iterable::Iterable(utils::SkipList<Entry>::Accessor index_ac
         break;
       case PropertyValue::Type::Map:
         lower_bound_ = utils::MakeBoundInclusive(kSmallestMap);
-        // This is the last type in the order so we leave the upper bound empty.
+        break;
+      case PropertyValue::Type::TemporalData:
+        lower_bound_ = utils::MakeBoundInclusive(kSmallestTemporalData);
         break;
     }
   }
diff --git a/src/storage/v2/property_store.cpp b/src/storage/v2/property_store.cpp
index b7ea25a4f..99b21eaab 100644
--- a/src/storage/v2/property_store.cpp
+++ b/src/storage/v2/property_store.cpp
@@ -7,6 +7,7 @@
 #include <type_traits>
 #include <utility>
 
+#include "storage/v2/temporal.hpp"
 #include "utils/cast.hpp"
 #include "utils/logging.hpp"
 
@@ -90,6 +91,7 @@ enum class Type : uint8_t {
   STRING = 0x50,
   LIST = 0x60,
   MAP = 0x70,
+  TEMPORAL_DATA = 0x80
 };
 
 const uint8_t kMaskType = 0xf0;
@@ -141,6 +143,16 @@ const uint8_t kShiftIdSize = 2;
 //       + encoded key data
 //       + encoded value size
 //       + encoded value data
+//   * TEMPORAL_DATE
+//     - type; payload size isn't used
+//     - encoded property ID
+//     - value saved as Metadata
+//       + type; id size is used to indicate whether the temporal data type is encoded
+//         as `uint8_t`, `uint16_t`, `uint32_t` or `uint64_t`; payload size used to
+//         indicate whether the microseconds are encoded as `uint8_t`, `uint16_t, `uint32_t
+//         or `uint64_t`
+//       + encoded temporal data type value
+//       + encoded microseconds value
 
 struct Metadata {
   Type type{Type::EMPTY};
@@ -428,9 +440,40 @@ std::optional<std::pair<Type, Size>> EncodePropertyValue(Writer *writer, const P
       }
       return {{Type::MAP, *size}};
     }
+    case PropertyValue::Type::TemporalData: {
+      auto metadata = writer->WriteMetadata();
+      if (!metadata) return std::nullopt;
+
+      const auto temporal_data = value.ValueTemporalData();
+      auto type_size = writer->WriteUint(utils::UnderlyingCast(temporal_data.type));
+      if (!type_size) return std::nullopt;
+
+      auto microseconds_size = writer->WriteInt(temporal_data.microseconds);
+      if (!microseconds_size) return std::nullopt;
+      metadata->Set({Type::TEMPORAL_DATA, *type_size, *microseconds_size});
+
+      // We don't need payload size so we set it to a random value
+      return {{Type::TEMPORAL_DATA, Size::INT8}};
+    }
   }
 }
 
+namespace {
+std::optional<TemporalData> DecodeTemporalData(Reader &reader) {
+  auto metadata = reader.ReadMetadata();
+  if (!metadata || metadata->type != Type::TEMPORAL_DATA) return std::nullopt;
+
+  auto type_value = reader.ReadUint(metadata->id_size);
+  if (!type_value) return std::nullopt;
+
+  auto microseconds_value = reader.ReadInt(metadata->payload_size);
+  if (!microseconds_value) return std::nullopt;
+
+  return TemporalData{static_cast<TemporalType>(*type_value), *microseconds_value};
+}
+
+}  // namespace
+
 // Function used to decode a PropertyValue from a byte stream. It can either
 // decode or skip the encoded PropertyValue, depending on the supplied value
 // pointer.
@@ -537,6 +580,18 @@ std::optional<std::pair<Type, Size>> EncodePropertyValue(Writer *writer, const P
       }
       return true;
     }
+
+    case Type::TEMPORAL_DATA: {
+      const auto maybe_temporal_data = DecodeTemporalData(*reader);
+
+      if (!maybe_temporal_data) return false;
+
+      if (value) {
+        *value = PropertyValue(*maybe_temporal_data);
+      }
+
+      return true;
+    }
   }
 }
 
@@ -627,6 +682,16 @@ std::optional<std::pair<Type, Size>> EncodePropertyValue(Writer *writer, const P
       }
       return true;
     }
+    case Type::TEMPORAL_DATA: {
+      if (!value.IsTemporalData()) return false;
+
+      const auto maybe_temporal_data = DecodeTemporalData(*reader);
+      if (!maybe_temporal_data) {
+        return false;
+      }
+
+      return *maybe_temporal_data == value.ValueTemporalData();
+    }
   }
 }
 
diff --git a/src/storage/v2/property_value.hpp b/src/storage/v2/property_value.hpp
index 18de7052f..91a1024eb 100644
--- a/src/storage/v2/property_value.hpp
+++ b/src/storage/v2/property_value.hpp
@@ -5,6 +5,7 @@
 #include <string>
 #include <vector>
 
+#include "storage/v2/temporal.hpp"
 #include "utils/algorithm.hpp"
 #include "utils/exceptions.hpp"
 
@@ -33,6 +34,7 @@ class PropertyValue {
     String = 4,
     List = 5,
     Map = 6,
+    TemporalData = 7
   };
 
   static bool AreComparableTypes(Type a, Type b) {
@@ -43,10 +45,11 @@ class PropertyValue {
   PropertyValue() : type_(Type::Null) {}
 
   // constructors for primitive types
-  explicit PropertyValue(bool value) : type_(Type::Bool) { bool_v = value; }
-  explicit PropertyValue(int value) : type_(Type::Int) { int_v = value; }
-  explicit PropertyValue(int64_t value) : type_(Type::Int) { int_v = value; }
-  explicit PropertyValue(double value) : type_(Type::Double) { double_v = value; }
+  explicit PropertyValue(const bool value) : type_(Type::Bool) { bool_v = value; }
+  explicit PropertyValue(const int value) : type_(Type::Int) { int_v = value; }
+  explicit PropertyValue(const int64_t value) : type_(Type::Int) { int_v = value; }
+  explicit PropertyValue(const double value) : type_(Type::Double) { double_v = value; }
+  explicit PropertyValue(const TemporalData value) : type_{Type::TemporalData} { temporal_data_v = value; }
 
   // copy constructors for non-primitive types
   /// @throw std::bad_alloc
@@ -103,6 +106,7 @@ class PropertyValue {
   bool IsString() const { return type_ == Type::String; }
   bool IsList() const { return type_ == Type::List; }
   bool IsMap() const { return type_ == Type::Map; }
+  bool IsTemporalData() const { return type_ == Type::TemporalData; }
 
   // value getters for primitive types
   /// @throw PropertyValueException if value isn't of correct type.
@@ -127,6 +131,15 @@ class PropertyValue {
     return double_v;
   }
 
+  /// @throw PropertyValueException if value isn't of correct type.
+  TemporalData ValueTemporalData() const {
+    if (type_ != Type::TemporalData) {
+      throw PropertyValueException("The value isn't a temporal data!");
+    }
+
+    return temporal_data_v;
+  }
+
   // const value getters for non-primitive types
   /// @throw PropertyValueException if value isn't of correct type.
   const std::string &ValueString() const {
@@ -187,6 +200,7 @@ class PropertyValue {
     std::string string_v;
     std::vector<PropertyValue> list_v;
     std::map<std::string, PropertyValue> map_v;
+    TemporalData temporal_data_v;
   };
 
   Type type_;
@@ -210,6 +224,8 @@ inline std::ostream &operator<<(std::ostream &os, const PropertyValue::Type type
       return os << "list";
     case PropertyValue::Type::Map:
       return os << "map";
+    case PropertyValue::Type::TemporalData:
+      return os << "temporal data";
   }
 }
 /// @throw anything std::ostream::operator<< may throw.
@@ -234,6 +250,9 @@ inline std::ostream &operator<<(std::ostream &os, const PropertyValue &value) {
       utils::PrintIterable(os, value.ValueMap(), ", ",
                            [](auto &stream, const auto &pair) { stream << pair.first << ": " << pair.second; });
       return os << "}";
+    case PropertyValue::Type::TemporalData:
+      return os << fmt::format("type: {}, microseconds: {}", TemporalTypeTostring(value.ValueTemporalData().type),
+                               value.ValueTemporalData().microseconds);
   }
 }
 
@@ -265,6 +284,8 @@ inline bool operator==(const PropertyValue &first, const PropertyValue &second)
       return first.ValueList() == second.ValueList();
     case PropertyValue::Type::Map:
       return first.ValueMap() == second.ValueMap();
+    case PropertyValue::Type::TemporalData:
+      return first.ValueTemporalData() == second.ValueTemporalData();
   }
 }
 
@@ -293,6 +314,8 @@ inline bool operator<(const PropertyValue &first, const PropertyValue &second) n
       return first.ValueList() < second.ValueList();
     case PropertyValue::Type::Map:
       return first.ValueMap() < second.ValueMap();
+    case PropertyValue::Type::TemporalData:
+      return first.ValueTemporalData() < second.ValueTemporalData();
   }
 }
 
@@ -318,6 +341,9 @@ inline PropertyValue::PropertyValue(const PropertyValue &other) : type_(other.ty
     case Type::Map:
       new (&map_v) std::map<std::string, PropertyValue>(other.map_v);
       return;
+    case Type::TemporalData:
+      this->temporal_data_v = other.temporal_data_v;
+      return;
   }
 }
 
@@ -343,6 +369,9 @@ inline PropertyValue::PropertyValue(PropertyValue &&other) noexcept : type_(othe
     case Type::Map:
       new (&map_v) std::map<std::string, PropertyValue>(std::move(other.map_v));
       break;
+    case Type::TemporalData:
+      this->temporal_data_v = other.temporal_data_v;
+      break;
   }
 
   // reset the type of other
@@ -377,6 +406,9 @@ inline PropertyValue &PropertyValue::operator=(const PropertyValue &other) {
     case Type::Map:
       new (&map_v) std::map<std::string, PropertyValue>(other.map_v);
       break;
+    case Type::TemporalData:
+      this->temporal_data_v = other.temporal_data_v;
+      break;
   }
 
   return *this;
@@ -409,6 +441,9 @@ inline PropertyValue &PropertyValue::operator=(PropertyValue &&other) noexcept {
     case Type::Map:
       new (&map_v) std::map<std::string, PropertyValue>(std::move(other.map_v));
       break;
+    case Type::TemporalData:
+      this->temporal_data_v = other.temporal_data_v;
+      break;
   }
 
   // reset the type of other
@@ -425,20 +460,18 @@ inline void PropertyValue::DestroyValue() noexcept {
     case Type::Bool:
     case Type::Int:
     case Type::Double:
+    case Type::TemporalData:
       return;
 
     // destructor for non primitive types since we used placement new
     case Type::String:
-      // Clang fails to compile ~std::string. It seems it is a bug in some
-      // versions of clang. Using namespace std statement solves the issue.
-      using namespace std;
-      string_v.~string();
+      std::destroy_at(&string_v);
       return;
     case Type::List:
-      list_v.~vector();
+      std::destroy_at(&list_v);
       return;
     case Type::Map:
-      map_v.~map();
+      std::destroy_at(&map_v);
       return;
   }
 }
diff --git a/src/storage/v2/replication/slk.cpp b/src/storage/v2/replication/slk.cpp
index e8bf1dd3a..65cafaa8a 100644
--- a/src/storage/v2/replication/slk.cpp
+++ b/src/storage/v2/replication/slk.cpp
@@ -2,6 +2,8 @@
 
 #include <type_traits>
 
+#include "storage/v2/property_value.hpp"
+#include "storage/v2/temporal.hpp"
 #include "utils/cast.hpp"
 
 namespace slk {
@@ -14,10 +16,6 @@ void Load(storage::Gid *gid, slk::Reader *reader) {
   *gid = storage::Gid::FromUint(value);
 }
 
-void Save(const storage::PropertyValue::Type &type, slk::Builder *builder) {
-  slk::Save(utils::UnderlyingCast(type), builder);
-}
-
 void Load(storage::PropertyValue::Type *type, slk::Reader *reader) {
   using PVTypeUnderlyingType = std::underlying_type_t<storage::PropertyValue::Type>;
   PVTypeUnderlyingType value;
@@ -31,6 +29,7 @@ void Load(storage::PropertyValue::Type *type, slk::Reader *reader) {
     case utils::UnderlyingCast(storage::PropertyValue::Type::String):
     case utils::UnderlyingCast(storage::PropertyValue::Type::List):
     case utils::UnderlyingCast(storage::PropertyValue::Type::Map):
+    case utils::UnderlyingCast(storage::PropertyValue::Type::TemporalData):
       valid = true;
       break;
     default:
@@ -82,6 +81,13 @@ void Save(const storage::PropertyValue &value, slk::Builder *builder) {
       }
       return;
     }
+    case storage::PropertyValue::Type::TemporalData: {
+      slk::Save(storage::PropertyValue::Type::TemporalData, builder);
+      const auto temporal_data = value.ValueTemporalData();
+      slk::Save(temporal_data.type, builder);
+      slk::Save(temporal_data.microseconds, builder);
+      return;
+    }
   }
 }
 
@@ -138,18 +144,15 @@ void Load(storage::PropertyValue *value, slk::Reader *reader) {
       *value = storage::PropertyValue(std::move(map));
       return;
     }
+    case storage::PropertyValue::Type::TemporalData: {
+      storage::TemporalType temporal_type;
+      slk::Load(&temporal_type, reader);
+      int64_t microseconds{0};
+      slk::Load(&microseconds, reader);
+      *value = storage::PropertyValue(storage::TemporalData{temporal_type, microseconds});
+      return;
+    }
   }
 }
 
-void Save(const storage::durability::Marker &marker, slk::Builder *builder) {
-  slk::Save(utils::UnderlyingCast(marker), builder);
-}
-
-void Load(storage::durability::Marker *marker, slk::Reader *reader) {
-  using PVTypeUnderlyingType = std::underlying_type_t<storage::PropertyValue::Type>;
-  PVTypeUnderlyingType value;
-  slk::Load(&value, reader);
-  *marker = static_cast<storage::durability::Marker>(value);
-}
-
 }  // namespace slk
diff --git a/src/storage/v2/replication/slk.hpp b/src/storage/v2/replication/slk.hpp
index 0652ae211..964a0d5cc 100644
--- a/src/storage/v2/replication/slk.hpp
+++ b/src/storage/v2/replication/slk.hpp
@@ -4,6 +4,7 @@
 #include "storage/v2/durability/marker.hpp"
 #include "storage/v2/id_types.hpp"
 #include "storage/v2/property_value.hpp"
+#include "utils/concepts.hpp"
 
 namespace slk {
 
@@ -13,7 +14,17 @@ void Load(storage::Gid *gid, slk::Reader *reader);
 void Save(const storage::PropertyValue &value, slk::Builder *builder);
 void Load(storage::PropertyValue *value, slk::Reader *reader);
 
-void Save(const storage::durability::Marker &marker, slk::Builder *builder);
-void Load(storage::durability::Marker *marker, slk::Reader *reader);
+template <utils::Enum T>
+void Save(const T &enum_value, slk::Builder *builder) {
+  slk::Save(utils::UnderlyingCast(enum_value), builder);
+}
+
+template <utils::Enum T>
+void Load(T *enum_value, slk::Reader *reader) {
+  using UnderlyingType = std::underlying_type_t<T>;
+  UnderlyingType value;
+  slk::Load(&value, reader);
+  *enum_value = static_cast<T>(value);
+}
 
 }  // namespace slk
diff --git a/src/storage/v2/temporal.cpp b/src/storage/v2/temporal.cpp
new file mode 100644
index 000000000..7f83e7cae
--- /dev/null
+++ b/src/storage/v2/temporal.cpp
@@ -0,0 +1,6 @@
+#include "storage/v2/temporal.hpp"
+
+namespace storage {
+TemporalData::TemporalData(TemporalType type, int64_t microseconds) : type{type}, microseconds{microseconds} {}
+
+}  // namespace storage
diff --git a/src/storage/v2/temporal.hpp b/src/storage/v2/temporal.hpp
new file mode 100644
index 000000000..6fe37b8ea
--- /dev/null
+++ b/src/storage/v2/temporal.hpp
@@ -0,0 +1,31 @@
+#pragma once
+#include <cstdint>
+#include <string_view>
+
+namespace storage {
+
+enum class TemporalType : uint8_t { Date = 0, LocalTime, LocalDateTime, Duration };
+
+constexpr std::string_view TemporalTypeTostring(const TemporalType type) {
+  switch (type) {
+    case TemporalType::Date:
+      return "Date";
+    case TemporalType::LocalTime:
+      return "LocalTime";
+    case TemporalType::LocalDateTime:
+      return "LocalDateTime";
+    case TemporalType::Duration:
+      return "Duration";
+  }
+}
+
+struct TemporalData {
+  explicit TemporalData(TemporalType type, int64_t microseconds);
+
+  auto operator<=>(const TemporalData &) const = default;
+
+  TemporalType type;
+  int64_t microseconds;
+};
+
+}  // namespace storage
diff --git a/src/utils/concepts.hpp b/src/utils/concepts.hpp
index 37365fe98..0469bc07d 100644
--- a/src/utils/concepts.hpp
+++ b/src/utils/concepts.hpp
@@ -4,4 +4,7 @@
 namespace utils {
 template <typename T, typename... Args>
 concept SameAsAnyOf = (std::same_as<T, Args> || ...);
+
+template <typename T>
+concept Enum = std::is_enum_v<T>;
 }  // namespace utils
diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt
index 94bebd8d3..d0cff86ce 100644
--- a/tests/unit/CMakeLists.txt
+++ b/tests/unit/CMakeLists.txt
@@ -282,7 +282,7 @@ add_unit_test(commit_log_v2.cpp)
 target_link_libraries(${test_prefix}commit_log_v2 gflags mg-utils mg-storage-v2)
 
 add_unit_test(property_value_v2.cpp)
-target_link_libraries(${test_prefix}property_value_v2 mg-utils)
+target_link_libraries(${test_prefix}property_value_v2 mg-storage-v2 mg-utils)
 
 add_unit_test(storage_v2.cpp)
 target_link_libraries(${test_prefix}storage_v2 mg-storage-v2 storage_test_utils)
diff --git a/tests/unit/property_value_v2.cpp b/tests/unit/property_value_v2.cpp
index 069d7da45..f4ffbc913 100644
--- a/tests/unit/property_value_v2.cpp
+++ b/tests/unit/property_value_v2.cpp
@@ -3,6 +3,7 @@
 #include <sstream>
 
 #include "storage/v2/property_value.hpp"
+#include "storage/v2/temporal.hpp"
 
 // NOLINTNEXTLINE(hicpp-special-member-functions)
 TEST(PropertyValue, Null) {
@@ -496,10 +497,16 @@ TEST(PropertyValue, MapMove) {
 TEST(PropertyValue, CopyConstructor) {
   std::vector<storage::PropertyValue> vec{storage::PropertyValue(true), storage::PropertyValue(123)};
   std::map<std::string, storage::PropertyValue> map{{"nandare", storage::PropertyValue(false)}};
-  std::vector<storage::PropertyValue> data{storage::PropertyValue(),          storage::PropertyValue(true),
-                                           storage::PropertyValue(123),       storage::PropertyValue(123.5),
-                                           storage::PropertyValue("nandare"), storage::PropertyValue(vec),
-                                           storage::PropertyValue(map)};
+  std::vector<storage::PropertyValue> data{
+      storage::PropertyValue(),
+      storage::PropertyValue(true),
+      storage::PropertyValue(123),
+      storage::PropertyValue(123.5),
+      storage::PropertyValue("nandare"),
+      storage::PropertyValue(vec),
+      storage::PropertyValue(map),
+      storage::PropertyValue(storage::TemporalData(storage::TemporalType::Date, 23))};
+
   for (const auto &item : data) {
     storage::PropertyValue pv(item);
     ASSERT_EQ(pv.type(), item.type());
@@ -525,6 +532,8 @@ TEST(PropertyValue, CopyConstructor) {
       case storage::PropertyValue::Type::Map:
         ASSERT_EQ(pv.ValueMap(), item.ValueMap());
         break;
+      case storage::PropertyValue::Type::TemporalData:
+        ASSERT_EQ(pv.ValueTemporalData(), item.ValueTemporalData());
     }
   }
 }
@@ -533,10 +542,16 @@ TEST(PropertyValue, CopyConstructor) {
 TEST(PropertyValue, MoveConstructor) {
   std::vector<storage::PropertyValue> vec{storage::PropertyValue(true), storage::PropertyValue(123)};
   std::map<std::string, storage::PropertyValue> map{{"nandare", storage::PropertyValue(false)}};
-  std::vector<storage::PropertyValue> data{storage::PropertyValue(),          storage::PropertyValue(true),
-                                           storage::PropertyValue(123),       storage::PropertyValue(123.5),
-                                           storage::PropertyValue("nandare"), storage::PropertyValue(vec),
-                                           storage::PropertyValue(map)};
+  std::vector<storage::PropertyValue> data{
+      storage::PropertyValue(),
+      storage::PropertyValue(true),
+      storage::PropertyValue(123),
+      storage::PropertyValue(123.5),
+      storage::PropertyValue("nandare"),
+      storage::PropertyValue(vec),
+      storage::PropertyValue(map),
+      storage::PropertyValue(storage::TemporalData(storage::TemporalType::Date, 23))};
+
   for (auto &item : data) {
     storage::PropertyValue copy(item);
     storage::PropertyValue pv(std::move(item));
@@ -564,6 +579,9 @@ TEST(PropertyValue, MoveConstructor) {
       case storage::PropertyValue::Type::Map:
         ASSERT_EQ(pv.ValueMap(), copy.ValueMap());
         break;
+      case storage::PropertyValue::Type::TemporalData:
+        ASSERT_EQ(pv.ValueTemporalData(), copy.ValueTemporalData());
+        break;
     }
   }
 }
@@ -572,10 +590,16 @@ TEST(PropertyValue, MoveConstructor) {
 TEST(PropertyValue, CopyAssignment) {
   std::vector<storage::PropertyValue> vec{storage::PropertyValue(true), storage::PropertyValue(123)};
   std::map<std::string, storage::PropertyValue> map{{"nandare", storage::PropertyValue(false)}};
-  std::vector<storage::PropertyValue> data{storage::PropertyValue(),          storage::PropertyValue(true),
-                                           storage::PropertyValue(123),       storage::PropertyValue(123.5),
-                                           storage::PropertyValue("nandare"), storage::PropertyValue(vec),
-                                           storage::PropertyValue(map)};
+  std::vector<storage::PropertyValue> data{
+      storage::PropertyValue(),
+      storage::PropertyValue(true),
+      storage::PropertyValue(123),
+      storage::PropertyValue(123.5),
+      storage::PropertyValue("nandare"),
+      storage::PropertyValue(vec),
+      storage::PropertyValue(map),
+      storage::PropertyValue(storage::TemporalData(storage::TemporalType::Date, 23))};
+
   for (const auto &item : data) {
     storage::PropertyValue pv(123);
     pv = item;
@@ -602,6 +626,9 @@ TEST(PropertyValue, CopyAssignment) {
       case storage::PropertyValue::Type::Map:
         ASSERT_EQ(pv.ValueMap(), item.ValueMap());
         break;
+      case storage::PropertyValue::Type::TemporalData:
+        ASSERT_EQ(pv.ValueTemporalData(), item.ValueTemporalData());
+        break;
     }
   }
 }
@@ -610,10 +637,16 @@ TEST(PropertyValue, CopyAssignment) {
 TEST(PropertyValue, MoveAssignment) {
   std::vector<storage::PropertyValue> vec{storage::PropertyValue(true), storage::PropertyValue(123)};
   std::map<std::string, storage::PropertyValue> map{{"nandare", storage::PropertyValue(false)}};
-  std::vector<storage::PropertyValue> data{storage::PropertyValue(),          storage::PropertyValue(true),
-                                           storage::PropertyValue(123),       storage::PropertyValue(123.5),
-                                           storage::PropertyValue("nandare"), storage::PropertyValue(vec),
-                                           storage::PropertyValue(map)};
+  std::vector<storage::PropertyValue> data{
+      storage::PropertyValue(),
+      storage::PropertyValue(true),
+      storage::PropertyValue(123),
+      storage::PropertyValue(123.5),
+      storage::PropertyValue("nandare"),
+      storage::PropertyValue(vec),
+      storage::PropertyValue(map),
+      storage::PropertyValue(storage::TemporalData(storage::TemporalType::Date, 23))};
+
   for (auto &item : data) {
     storage::PropertyValue copy(item);
     storage::PropertyValue pv(123);
@@ -642,6 +675,9 @@ TEST(PropertyValue, MoveAssignment) {
       case storage::PropertyValue::Type::Map:
         ASSERT_EQ(pv.ValueMap(), copy.ValueMap());
         break;
+      case storage::PropertyValue::Type::TemporalData:
+        ASSERT_EQ(pv.ValueTemporalData(), copy.ValueTemporalData());
+        break;
     }
   }
 }
diff --git a/tests/unit/query_serialization_property_value.cpp b/tests/unit/query_serialization_property_value.cpp
index 569d13ec2..78b2a1b9a 100644
--- a/tests/unit/query_serialization_property_value.cpp
+++ b/tests/unit/query_serialization_property_value.cpp
@@ -1,6 +1,7 @@
 #include <gtest/gtest.h>
 
 #include "query/serialization/property_value.hpp"
+#include "storage/v2/temporal.hpp"
 #include "utils/logging.hpp"
 
 namespace {
@@ -39,6 +40,16 @@ TEST(PropertyValueSerializationTest, String) {
   CheckJsonConversion(storage::PropertyValue{""});
 }
 
+TEST(PropertyValueSerializationTest, TemporalData) {
+  const auto test_temporal_data_conversion = [](const auto type, const auto microseconds) {
+    CheckJsonConversion(storage::PropertyValue{storage::TemporalData{type, microseconds}});
+  };
+
+  test_temporal_data_conversion(storage::TemporalType::Date, 20);
+  test_temporal_data_conversion(storage::TemporalType::LocalDateTime, -20);
+  test_temporal_data_conversion(storage::TemporalType::Duration, 10000);
+}
+
 namespace {
 
 std::vector<storage::PropertyValue> GetPropertyValueListWithBasicTypes() {
@@ -59,27 +70,39 @@ std::map<std::string, storage::PropertyValue> GetPropertyValueMapWithBasicTypes(
 TEST(PropertyValueSerializationTest, List) {
   storage::PropertyValue list = storage::PropertyValue{GetPropertyValueListWithBasicTypes()};
 
-  SPDLOG_DEBUG("Basic list");
-  CheckJsonConversion(list);
+  {
+    SCOPED_TRACE("Basic list");
+    CheckJsonConversion(list);
+  }
 
-  SPDLOG_DEBUG("Nested list");
-  CheckJsonConversion(storage::PropertyValue{std::vector<storage::PropertyValue>{list, list}});
+  {
+    SCOPED_TRACE("Nested list");
+    CheckJsonConversion(storage::PropertyValue{std::vector<storage::PropertyValue>{list, list}});
+  }
 
-  SPDLOG_DEBUG("List with map");
-  list.ValueList().emplace_back(GetPropertyValueMapWithBasicTypes());
-  CheckJsonConversion(list);
+  {
+    SCOPED_TRACE("List with map");
+    list.ValueList().emplace_back(GetPropertyValueMapWithBasicTypes());
+    CheckJsonConversion(list);
+  }
 }
 
 TEST(PropertyValueSerializationTest, Map) {
   auto map = GetPropertyValueMapWithBasicTypes();
-  SPDLOG_DEBUG("Basic map");
-  CheckJsonConversion(storage::PropertyValue{map});
+  {
+    SCOPED_TRACE("Basic map");
+    CheckJsonConversion(storage::PropertyValue{map});
+  }
 
-  SPDLOG_DEBUG("Nested map");
-  map.emplace("map", storage::PropertyValue{map});
-  CheckJsonConversion(storage::PropertyValue{map});
+  {
+    SCOPED_TRACE("Nested map");
+    map.emplace("map", storage::PropertyValue{map});
+    CheckJsonConversion(storage::PropertyValue{map});
+  }
 
-  SPDLOG_DEBUG("Map with list");
-  map.emplace("list", storage::PropertyValue{GetPropertyValueListWithBasicTypes()});
-  CheckJsonConversion(storage::PropertyValue{map});
+  {
+    SCOPED_TRACE("Map with list");
+    map.emplace("list", storage::PropertyValue{GetPropertyValueListWithBasicTypes()});
+    CheckJsonConversion(storage::PropertyValue{map});
+  }
 }
diff --git a/tests/unit/slk_advanced.cpp b/tests/unit/slk_advanced.cpp
index 8afabf30b..343214160 100644
--- a/tests/unit/slk_advanced.cpp
+++ b/tests/unit/slk_advanced.cpp
@@ -1,18 +1,25 @@
 #include <gtest/gtest.h>
 
+#include "storage/v2/property_value.hpp"
 #include "storage/v2/replication/slk.hpp"
 
 #include "slk_common.hpp"
+#include "storage/v2/temporal.hpp"
 
 TEST(SlkAdvanced, PropertyValueList) {
-  std::vector<storage::PropertyValue> original{storage::PropertyValue("hello world!"), storage::PropertyValue(5),
-                                               storage::PropertyValue(1.123423), storage::PropertyValue(true),
-                                               storage::PropertyValue()};
+  std::vector<storage::PropertyValue> original{
+      storage::PropertyValue("hello world!"),
+      storage::PropertyValue(5),
+      storage::PropertyValue(1.123423),
+      storage::PropertyValue(true),
+      storage::PropertyValue(),
+      storage::PropertyValue(storage::TemporalData(storage::TemporalType::Date, 23))};
   ASSERT_EQ(original[0].type(), storage::PropertyValue::Type::String);
   ASSERT_EQ(original[1].type(), storage::PropertyValue::Type::Int);
   ASSERT_EQ(original[2].type(), storage::PropertyValue::Type::Double);
   ASSERT_EQ(original[3].type(), storage::PropertyValue::Type::Bool);
   ASSERT_EQ(original[4].type(), storage::PropertyValue::Type::Null);
+  ASSERT_EQ(original[5].type(), storage::PropertyValue::Type::TemporalData);
 
   slk::Loopback loopback;
   auto builder = loopback.GetBuilder();
@@ -26,16 +33,19 @@ TEST(SlkAdvanced, PropertyValueList) {
 }
 
 TEST(SlkAdvanced, PropertyValueMap) {
-  std::map<std::string, storage::PropertyValue> original{{"hello", storage::PropertyValue("world")},
-                                                         {"number", storage::PropertyValue(5)},
-                                                         {"real", storage::PropertyValue(1.123423)},
-                                                         {"truth", storage::PropertyValue(true)},
-                                                         {"nothing", storage::PropertyValue()}};
+  std::map<std::string, storage::PropertyValue> original{
+      {"hello", storage::PropertyValue("world")},
+      {"number", storage::PropertyValue(5)},
+      {"real", storage::PropertyValue(1.123423)},
+      {"truth", storage::PropertyValue(true)},
+      {"nothing", storage::PropertyValue()},
+      {"date", storage::PropertyValue(storage::TemporalData(storage::TemporalType::Date, 23))}};
   ASSERT_EQ(original["hello"].type(), storage::PropertyValue::Type::String);
   ASSERT_EQ(original["number"].type(), storage::PropertyValue::Type::Int);
   ASSERT_EQ(original["real"].type(), storage::PropertyValue::Type::Double);
   ASSERT_EQ(original["truth"].type(), storage::PropertyValue::Type::Bool);
   ASSERT_EQ(original["nothing"].type(), storage::PropertyValue::Type::Null);
+  ASSERT_EQ(original["date"].type(), storage::PropertyValue::Type::TemporalData);
 
   slk::Loopback loopback;
   auto builder = loopback.GetBuilder();
@@ -49,25 +59,33 @@ TEST(SlkAdvanced, PropertyValueMap) {
 }
 
 TEST(SlkAdvanced, PropertyValueComplex) {
-  std::vector<storage::PropertyValue> vec_v{storage::PropertyValue("hello world!"), storage::PropertyValue(5),
-                                            storage::PropertyValue(1.123423), storage::PropertyValue(true),
-                                            storage::PropertyValue()};
+  std::vector<storage::PropertyValue> vec_v{
+      storage::PropertyValue("hello world!"),
+      storage::PropertyValue(5),
+      storage::PropertyValue(1.123423),
+      storage::PropertyValue(true),
+      storage::PropertyValue(),
+      storage::PropertyValue(storage::TemporalData(storage::TemporalType::Date, 23))};
   ASSERT_EQ(vec_v[0].type(), storage::PropertyValue::Type::String);
   ASSERT_EQ(vec_v[1].type(), storage::PropertyValue::Type::Int);
   ASSERT_EQ(vec_v[2].type(), storage::PropertyValue::Type::Double);
   ASSERT_EQ(vec_v[3].type(), storage::PropertyValue::Type::Bool);
   ASSERT_EQ(vec_v[4].type(), storage::PropertyValue::Type::Null);
+  ASSERT_EQ(vec_v[5].type(), storage::PropertyValue::Type::TemporalData);
 
-  std::map<std::string, storage::PropertyValue> map_v{{"hello", storage::PropertyValue("world")},
-                                                      {"number", storage::PropertyValue(5)},
-                                                      {"real", storage::PropertyValue(1.123423)},
-                                                      {"truth", storage::PropertyValue(true)},
-                                                      {"nothing", storage::PropertyValue()}};
+  std::map<std::string, storage::PropertyValue> map_v{
+      {"hello", storage::PropertyValue("world")},
+      {"number", storage::PropertyValue(5)},
+      {"real", storage::PropertyValue(1.123423)},
+      {"truth", storage::PropertyValue(true)},
+      {"nothing", storage::PropertyValue()},
+      {"date", storage::PropertyValue(storage::TemporalData(storage::TemporalType::Date, 23))}};
   ASSERT_EQ(map_v["hello"].type(), storage::PropertyValue::Type::String);
   ASSERT_EQ(map_v["number"].type(), storage::PropertyValue::Type::Int);
   ASSERT_EQ(map_v["real"].type(), storage::PropertyValue::Type::Double);
   ASSERT_EQ(map_v["truth"].type(), storage::PropertyValue::Type::Bool);
   ASSERT_EQ(map_v["nothing"].type(), storage::PropertyValue::Type::Null);
+  ASSERT_EQ(map_v["date"].type(), storage::PropertyValue::Type::TemporalData);
 
   storage::PropertyValue original(
       std::vector<storage::PropertyValue>{storage::PropertyValue(vec_v), storage::PropertyValue(map_v)});
diff --git a/tests/unit/storage_v2_decoder_encoder.cpp b/tests/unit/storage_v2_decoder_encoder.cpp
index b217a4030..caeffddd3 100644
--- a/tests/unit/storage_v2_decoder_encoder.cpp
+++ b/tests/unit/storage_v2_decoder_encoder.cpp
@@ -4,6 +4,8 @@
 #include <limits>
 
 #include "storage/v2/durability/serialization.hpp"
+#include "storage/v2/property_value.hpp"
+#include "storage/v2/temporal.hpp"
 
 static const std::string kTestMagic{"MGtest"};
 static const uint64_t kTestVersion{1};
@@ -118,7 +120,8 @@ GENERATE_READ_TEST(PropertyValue, storage::PropertyValue, storage::PropertyValue
                    storage::PropertyValue(std::vector<storage::PropertyValue>{storage::PropertyValue("nandare"),
                                                                               storage::PropertyValue(123L)}),
                    storage::PropertyValue(std::map<std::string, storage::PropertyValue>{
-                       {"nandare", storage::PropertyValue(123)}}));
+                       {"nandare", storage::PropertyValue(123)}}),
+                   storage::PropertyValue(storage::TemporalData(storage::TemporalType::Date, 23)));
 
 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
 #define GENERATE_SKIP_TEST(name, type, ...)                        \
@@ -162,7 +165,8 @@ GENERATE_SKIP_TEST(PropertyValue, storage::PropertyValue, storage::PropertyValue
                    storage::PropertyValue(std::vector<storage::PropertyValue>{storage::PropertyValue("nandare"),
                                                                               storage::PropertyValue(123L)}),
                    storage::PropertyValue(std::map<std::string, storage::PropertyValue>{
-                       {"nandare", storage::PropertyValue(123)}}));
+                       {"nandare", storage::PropertyValue(123)}}),
+                   storage::PropertyValue(storage::TemporalData(storage::TemporalType::Date, 23)));
 
 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
 #define GENERATE_PARTIAL_READ_TEST(name, value)                                \
@@ -225,8 +229,9 @@ GENERATE_PARTIAL_READ_TEST(PropertyValue,
                            storage::PropertyValue(std::vector<storage::PropertyValue>{
                                storage::PropertyValue(), storage::PropertyValue(true), storage::PropertyValue(123L),
                                storage::PropertyValue(123.5), storage::PropertyValue("nandare"),
-                               storage::PropertyValue{std::map<std::string, storage::PropertyValue>{
-                                   {"haihai", storage::PropertyValue()}}}}));
+                               storage::PropertyValue{
+                                   std::map<std::string, storage::PropertyValue>{{"haihai", storage::PropertyValue()}}},
+                               storage::PropertyValue(storage::TemporalData(storage::TemporalType::Date, 23))}));
 
 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
 #define GENERATE_PARTIAL_SKIP_TEST(name, value)                                \
@@ -275,8 +280,9 @@ GENERATE_PARTIAL_SKIP_TEST(PropertyValue,
                            storage::PropertyValue(std::vector<storage::PropertyValue>{
                                storage::PropertyValue(), storage::PropertyValue(true), storage::PropertyValue(123L),
                                storage::PropertyValue(123.5), storage::PropertyValue("nandare"),
-                               storage::PropertyValue{std::map<std::string, storage::PropertyValue>{
-                                   {"haihai", storage::PropertyValue()}}}}));
+                               storage::PropertyValue{
+                                   std::map<std::string, storage::PropertyValue>{{"haihai", storage::PropertyValue()}}},
+                               storage::PropertyValue(storage::TemporalData(storage::TemporalType::Date, 23))}));
 
 // NOLINTNEXTLINE(hicpp-special-member-functions)
 TEST_F(DecoderEncoderTest, PropertyValueInvalidMarker) {
@@ -299,6 +305,7 @@ TEST_F(DecoderEncoderTest, PropertyValueInvalidMarker) {
         case storage::durability::Marker::TYPE_STRING:
         case storage::durability::Marker::TYPE_LIST:
         case storage::durability::Marker::TYPE_MAP:
+        case storage::durability::Marker::TYPE_TEMPORAL_DATA:
         case storage::durability::Marker::TYPE_PROPERTY_VALUE:
           valid_marker = true;
           break;
diff --git a/tests/unit/storage_v2_indices.cpp b/tests/unit/storage_v2_indices.cpp
index 8b0a3fc36..3bf874b78 100644
--- a/tests/unit/storage_v2_indices.cpp
+++ b/tests/unit/storage_v2_indices.cpp
@@ -1,7 +1,9 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include "storage/v2/property_value.hpp"
 #include "storage/v2/storage.hpp"
+#include "storage/v2/temporal.hpp"
 
 // NOLINTNEXTLINE(google-build-using-namespace)
 using namespace storage;
@@ -614,6 +616,9 @@ TEST_F(IndexTest, LabelPropertyIndexCountEstimate) {
 TEST_F(IndexTest, LabelPropertyIndexMixedIteration) {
   storage.CreateIndex(label1, prop_val);
 
+  const std::array temporals{TemporalData{TemporalType::Date, 23}, TemporalData{TemporalType::Date, 28},
+                             TemporalData{TemporalType::LocalDateTime, 20}};
+
   std::vector<PropertyValue> values = {
       PropertyValue(false),
       PropertyValue(true),
@@ -638,6 +643,9 @@ TEST_F(IndexTest, LabelPropertyIndexMixedIteration) {
       PropertyValue(std::map<std::string, PropertyValue>()),
       PropertyValue(std::map<std::string, PropertyValue>{{"id", PropertyValue(5)}}),
       PropertyValue(std::map<std::string, PropertyValue>{{"id", PropertyValue(10)}}),
+      PropertyValue(temporals[0]),
+      PropertyValue(temporals[1]),
+      PropertyValue(temporals[2]),
   };
 
   // Create vertices, each with one of the values above.
@@ -735,6 +743,17 @@ TEST_F(IndexTest, LabelPropertyIndexMixedIteration) {
          {PropertyValue(std::map<std::string, PropertyValue>{{"id", PropertyValue(5)}}),
           PropertyValue(std::map<std::string, PropertyValue>{{"id", PropertyValue(10)}})});
 
+  verify(utils::MakeBoundExclusive(PropertyValue(temporals[0])),
+         utils::MakeBoundInclusive(PropertyValue(TemporalData{TemporalType::Date, 200})),
+         // LocalDateTime has a "higher" type number so it is not part of the range
+         {PropertyValue(temporals[1])});
+  verify(utils::MakeBoundExclusive(PropertyValue(temporals[0])), utils::MakeBoundInclusive(PropertyValue(temporals[2])),
+         {PropertyValue(temporals[1]), PropertyValue(temporals[2])});
+  verify(utils::MakeBoundInclusive(PropertyValue(temporals[0])), utils::MakeBoundExclusive(PropertyValue(temporals[2])),
+         {PropertyValue(temporals[0]), PropertyValue(temporals[1])});
+  verify(utils::MakeBoundInclusive(PropertyValue(temporals[0])), utils::MakeBoundInclusive(PropertyValue(temporals[2])),
+         {PropertyValue(temporals[0]), PropertyValue(temporals[1]), PropertyValue(temporals[2])});
+
   // Range iteration with one unspecified bound should only yield items that
   // have the same type as the specified bound.
   verify(utils::MakeBoundInclusive(PropertyValue(false)), std::nullopt, {PropertyValue(false), PropertyValue(true)});
@@ -760,6 +779,10 @@ TEST_F(IndexTest, LabelPropertyIndexMixedIteration) {
          utils::MakeBoundExclusive(PropertyValue(std::map<std::string, PropertyValue>{{"id", PropertyValue(7.5)}})),
          {PropertyValue(std::map<std::string, PropertyValue>()),
           PropertyValue(std::map<std::string, PropertyValue>{{"id", PropertyValue(5)}})});
+  verify(utils::MakeBoundInclusive(PropertyValue(TemporalData(TemporalType::Date, 10))), std::nullopt,
+         {PropertyValue(temporals[0]), PropertyValue(temporals[1]), PropertyValue(temporals[2])});
+  verify(std::nullopt, utils::MakeBoundExclusive(PropertyValue(TemporalData(TemporalType::Duration, 0))),
+         {PropertyValue(temporals[0]), PropertyValue(temporals[1]), PropertyValue(temporals[2])});
 
   // Range iteration with two specified bounds that don't have the same type
   // should yield no items.
diff --git a/tests/unit/storage_v2_property_store.cpp b/tests/unit/storage_v2_property_store.cpp
index 2f0f82299..b4180dc81 100644
--- a/tests/unit/storage_v2_property_store.cpp
+++ b/tests/unit/storage_v2_property_store.cpp
@@ -4,6 +4,8 @@
 #include <limits>
 
 #include "storage/v2/property_store.hpp"
+#include "storage/v2/property_value.hpp"
+#include "storage/v2/temporal.hpp"
 
 using testing::UnorderedElementsAre;
 
@@ -37,6 +39,7 @@ const storage::PropertyValue kSampleValues[] = {
         std::map<std::string, storage::PropertyValue>{{"test", storage::PropertyValue(33)},
                                                       {"map", storage::PropertyValue(std::string("sample"))},
                                                       {"item", storage::PropertyValue(-33.33)}}),
+    storage::PropertyValue(storage::TemporalData(storage::TemporalType::Date, 23)),
 };
 
 void TestIsPropertyEqual(const storage::PropertyStore &store, storage::PropertyId property,
@@ -71,12 +74,22 @@ TEST(PropertyStore, Simple) {
 TEST(PropertyStore, SimpleLarge) {
   storage::PropertyStore props;
   auto prop = storage::PropertyId::FromInt(42);
-  auto value = storage::PropertyValue(std::string(10000, 'a'));
-  ASSERT_TRUE(props.SetProperty(prop, value));
-  ASSERT_EQ(props.GetProperty(prop), value);
-  ASSERT_TRUE(props.HasProperty(prop));
-  TestIsPropertyEqual(props, prop, value);
-  ASSERT_THAT(props.Properties(), UnorderedElementsAre(std::pair(prop, value)));
+  {
+    auto value = storage::PropertyValue(std::string(10000, 'a'));
+    ASSERT_TRUE(props.SetProperty(prop, value));
+    ASSERT_EQ(props.GetProperty(prop), value);
+    ASSERT_TRUE(props.HasProperty(prop));
+    TestIsPropertyEqual(props, prop, value);
+    ASSERT_THAT(props.Properties(), UnorderedElementsAre(std::pair(prop, value)));
+  }
+  {
+    auto value = storage::PropertyValue(storage::TemporalData(storage::TemporalType::Date, 23));
+    ASSERT_FALSE(props.SetProperty(prop, value));
+    ASSERT_EQ(props.GetProperty(prop), value);
+    ASSERT_TRUE(props.HasProperty(prop));
+    TestIsPropertyEqual(props, prop, value);
+    ASSERT_THAT(props.Properties(), UnorderedElementsAre(std::pair(prop, value)));
+  }
 
   ASSERT_FALSE(props.SetProperty(prop, storage::PropertyValue()));
   ASSERT_TRUE(props.GetProperty(prop).IsNull());
@@ -227,9 +240,11 @@ TEST(PropertyStore, EmptySet) {
   std::vector<storage::PropertyValue> vec{storage::PropertyValue(true), storage::PropertyValue(123),
                                           storage::PropertyValue()};
   std::map<std::string, storage::PropertyValue> map{{"nandare", storage::PropertyValue(false)}};
-  std::vector<storage::PropertyValue> data{storage::PropertyValue(true),  storage::PropertyValue(123),
-                                           storage::PropertyValue(123.5), storage::PropertyValue("nandare"),
-                                           storage::PropertyValue(vec),   storage::PropertyValue(map)};
+  const storage::TemporalData temporal{storage::TemporalType::LocalDateTime, 23};
+  std::vector<storage::PropertyValue> data{storage::PropertyValue(true),    storage::PropertyValue(123),
+                                           storage::PropertyValue(123.5),   storage::PropertyValue("nandare"),
+                                           storage::PropertyValue(vec),     storage::PropertyValue(map),
+                                           storage::PropertyValue(temporal)};
 
   auto prop = storage::PropertyId::FromInt(42);
   for (const auto &value : data) {
@@ -262,13 +277,15 @@ TEST(PropertyStore, FullSet) {
   std::vector<storage::PropertyValue> vec{storage::PropertyValue(true), storage::PropertyValue(123),
                                           storage::PropertyValue()};
   std::map<std::string, storage::PropertyValue> map{{"nandare", storage::PropertyValue(false)}};
+  const storage::TemporalData temporal{storage::TemporalType::LocalDateTime, 23};
   std::map<storage::PropertyId, storage::PropertyValue> data{
       {storage::PropertyId::FromInt(1), storage::PropertyValue(true)},
       {storage::PropertyId::FromInt(2), storage::PropertyValue(123)},
       {storage::PropertyId::FromInt(3), storage::PropertyValue(123.5)},
       {storage::PropertyId::FromInt(4), storage::PropertyValue("nandare")},
       {storage::PropertyId::FromInt(5), storage::PropertyValue(vec)},
-      {storage::PropertyId::FromInt(6), storage::PropertyValue(map)}};
+      {storage::PropertyId::FromInt(6), storage::PropertyValue(map)},
+      {storage::PropertyId::FromInt(7), storage::PropertyValue(temporal)}};
 
   std::vector<storage::PropertyValue> alt{storage::PropertyValue(),
                                           storage::PropertyValue(std::string()),
@@ -585,3 +602,19 @@ TEST(PropertyStore, IsPropertyEqualMap) {
                                                {"sdf", storage::PropertyValue(true)},
                                                {"zyx", storage::PropertyValue("test")}})));
 }
+
+TEST(PropertyStore, IsPropertyEqualTemporalData) {
+  storage::PropertyStore props;
+  auto prop = storage::PropertyId::FromInt(42);
+  const storage::TemporalData temporal{storage::TemporalType::Date, 23};
+  ASSERT_TRUE(props.SetProperty(prop, storage::PropertyValue(temporal)));
+  ASSERT_TRUE(props.IsPropertyEqual(prop, storage::PropertyValue(temporal)));
+
+  // Different type.
+  ASSERT_FALSE(
+      props.IsPropertyEqual(prop, storage::PropertyValue(storage::TemporalData{storage::TemporalType::Duration, 23})));
+
+  // Same type, different value.
+  ASSERT_FALSE(
+      props.IsPropertyEqual(prop, storage::PropertyValue(storage::TemporalData{storage::TemporalType::Date, 30})));
+}