diff --git a/source/RobotAPI/components/ArticulatedObjectLocalizerExample/ArticulatedObjectLocalizerExample.cpp b/source/RobotAPI/components/ArticulatedObjectLocalizerExample/ArticulatedObjectLocalizerExample.cpp
index d5c7d69917c8cbba5fafee284b18229f351ea9de..8e172a97d95ed3ce515743a877c8c5bb3ed168d1 100644
--- a/source/RobotAPI/components/ArticulatedObjectLocalizerExample/ArticulatedObjectLocalizerExample.cpp
+++ b/source/RobotAPI/components/ArticulatedObjectLocalizerExample/ArticulatedObjectLocalizerExample.cpp
@@ -87,7 +87,7 @@ namespace armarx::articulated_object
         articulatedObjectReader->connect();
 
         ARMARX_IMPORTANT << "Running example.";
-        start = armem::Time::now();
+        start = armem::Time::Now();
 
         task = new PeriodicTask<ArticulatedObjectLocalizerExample>(
             this, &ArticulatedObjectLocalizerExample::run,
@@ -108,7 +108,7 @@ namespace armarx::articulated_object
     {
         const std::string dishwasherName = "Kitchen/mobile-dishwasher";
 
-        const auto descriptions = articulatedObjectReader->queryDescriptions(IceUtil::Time::now());
+        const auto descriptions = articulatedObjectReader->queryDescriptions(armem::Time::Now());
 
         ARMARX_INFO << "Found " << descriptions.size() << " articulated object descriptions";
 
@@ -155,20 +155,22 @@ namespace armarx::articulated_object
 
         ARMARX_DEBUG << "Reporting articulated objects";
 
-        const IceUtil::Time now = TimeUtil::GetTime();
-        const float t           = float((now - start).toSecondsDouble());
+        const armem::Time now = armem::Time::Now();
+        const float t = float((now - start).toSecondsDouble());
 
         // move joints at certain frequency
         const float k = (1 + std::sin(t / (M_2_PIf32))) / 2; // in [0,1]
 
-        const std::map<std::string, float> jointValues{{"dishwasher_door_joint", M_PIf32 / 2 * k},
-            {"drawer_joint", 350 * k}};
+        const std::map<std::string, float> jointValues
+        {
+            {"dishwasher_door_joint", M_PIf32 / 2 * k},
+            {"drawer_joint", 350 * k}
+        };
 
         dishwasher->setGlobalPose(simox::math::pose(Eigen::Vector3f(1000, 0, 0)));
         dishwasher->setJointValues(jointValues);
 
-
-        articulatedObjectWriter->storeArticulatedObject(dishwasher, IceUtil::Time::now());
+        articulatedObjectWriter->storeArticulatedObject(dishwasher, now);
     }
 
 } // namespace armarx::articulated_object
diff --git a/source/RobotAPI/components/ObjectPoseProviderExample/ObjectPoseProviderExample.cpp b/source/RobotAPI/components/ObjectPoseProviderExample/ObjectPoseProviderExample.cpp
index adab12c7d13d5a4e9e032b0e964f9fea6e324c73..bbf6438cb32566dae0436d22770f8f89dd7d43c9 100644
--- a/source/RobotAPI/components/ObjectPoseProviderExample/ObjectPoseProviderExample.cpp
+++ b/source/RobotAPI/components/ObjectPoseProviderExample/ObjectPoseProviderExample.cpp
@@ -195,7 +195,7 @@ namespace armarx
                 }
 
                 pose.confidence = 0.75 + 0.25 * std::sin(t - i);
-                pose.timestamp = TimeUtil::GetTime();
+                pose.timestamp = DateTime::Now();
 
                 i++;
             }
diff --git a/source/RobotAPI/components/armem/addon/LegacyRobotStateMemoryAdapter/LegacyRobotStateMemoryAdapter.cpp b/source/RobotAPI/components/armem/addon/LegacyRobotStateMemoryAdapter/LegacyRobotStateMemoryAdapter.cpp
index cdc049a27ad64057d179096185a2a5968f34d0d0..b8ab1db644a6228974453e648271c5b7975283fe 100644
--- a/source/RobotAPI/components/armem/addon/LegacyRobotStateMemoryAdapter/LegacyRobotStateMemoryAdapter.cpp
+++ b/source/RobotAPI/components/armem/addon/LegacyRobotStateMemoryAdapter/LegacyRobotStateMemoryAdapter.cpp
@@ -20,14 +20,14 @@
  *             GNU General Public License
  */
 
-// Header
 #include "LegacyRobotStateMemoryAdapter.h"
 
-// ArmarX
+#include <RobotAPI/libraries/aron/common/aron_conversions.h>
 #include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h>
 #include <RobotAPI/libraries/armem_robot_state/aron/Transform.aron.generated.h>
 #include <RobotAPI/libraries/armem_robot/aron/RobotDescription.aron.generated.h>
 
+
 namespace armarx::armem
 {
 
@@ -87,7 +87,7 @@ namespace armarx::armem
 
         // is this corect??
         prop.platform.acceleration = Eigen::Vector3f();
-        prop.platform.relativePosition = Eigen::Vector3f(update.platformPose.x, // this should be globasl AFAIK
+        prop.platform.relativePosition = Eigen::Vector3f(update.platformPose.x,  // this should be globasl AFAIK
                                                          update.platformPose.y,
                                                          update.platformPose.rotationAroundZ);
         prop.platform.velocity = Eigen::Vector3f(std::get<0>(update.platformVelocity),
@@ -96,7 +96,7 @@ namespace armarx::armem
 
         armem::EntityUpdate entityUpdate;
         entityUpdate.entityID = propEntityID;
-        entityUpdate.timeCreated = IceUtil::Time::microSeconds(_timestampUpdateFirstModifiedInUs); // we take the oldest timestamp
+        entityUpdate.timeCreated = Time(Duration::MicroSeconds(_timestampUpdateFirstModifiedInUs));  // we take the oldest timestamp
 
         entityUpdate.instancesData =
         {
@@ -128,7 +128,7 @@ namespace armarx::armem
 
             armem::EntityUpdate locUpdate;
             locUpdate.entityID = locEntityID;
-            locUpdate.timeCreated = IceUtil::Time::microSeconds(_timestampUpdateFirstModifiedInUs);
+            locUpdate.timeCreated = Time(Duration::MicroSeconds(_timestampUpdateFirstModifiedInUs));
             locUpdate.instancesData =
             {
                transform.toAron()
@@ -247,7 +247,7 @@ namespace armarx::armem
         ARMARX_IMPORTANT << "Commiting Armar3 to descriptions";
         armem::arondto::RobotDescription desc;
         desc.name = "Armar3";
-        desc.timestamp = armem::Time::now();
+        toAron(desc.timestamp, armem::Time::Now());
         desc.xml.package = "RobotAPI";
         desc.xml.path = "RobotAPI/robots/Armar3/ArmarIII.xml";
 
@@ -261,7 +261,7 @@ namespace armarx::armem
         entityUpdate.entityID.entityName = "Armar3";
 
         entityUpdate.instancesData = { desc.toAron() };
-        entityUpdate.timeCreated = armem::Time::now();
+        entityUpdate.timeCreated = armem::Time::Now();
         auto res = memoryWriter.commit(c);
         if (!res.allSuccess())
         {
diff --git a/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp b/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp
index db3fb7ee4c04b359d97ca606e54fe2961750043c..05bb57827346342762bf482f906d6a6e10b83d5a 100644
--- a/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp
+++ b/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp
@@ -34,7 +34,6 @@
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
 #include <ArmarXCore/core/time/CycleUtil.h>
 
-
 #include <RobotAPI/libraries/armem/client/MemoryNameSystem.h>
 #include <RobotAPI/libraries/armem/server/MemoryRemoteGui.h>
 #include <RobotAPI/libraries/armem/client/query/Builder.h>
@@ -146,7 +145,7 @@ namespace armarx
     void ExampleMemoryClient::run()
     {
         ARMARX_IMPORTANT << "Running example.";
-        run_started = IceUtil::Time::now();
+        runStarted = armem::Time::Now();
 
         armem::MemoryID snapshotID = commitSingleSnapshot(exampleEntityID);
         if (true)
@@ -167,6 +166,10 @@ namespace armarx
             queryExampleData();
         }
         if (true)
+        {
+            commitExamplesWithIDs();
+        }
+        if (true)
         {
             commitExamplesWithLinks();
         }
@@ -210,9 +213,9 @@ namespace armarx
         // Prepare the update with some empty instances.
         armem::EntityUpdate update;
         update.entityID = entityID;
-        update.timeCreated = armem::Time::now();
+        update.timeCreated = armem::Time::Now();
 
-        double diff = (update.timeCreated - run_started).toMilliSecondsDouble() / 1000;
+        double diff = (update.timeCreated - runStarted).toMilliSecondsDouble() / 1000;
 
         auto dict1 = std::make_shared<aron::data::Dict>();
         auto dict2 = std::make_shared<aron::data::Dict>();
@@ -257,7 +260,7 @@ namespace armarx
         {
             armem::EntityUpdate& update = commit.add();
             update.entityID = entityID;
-            update.timeCreated = armem::Time::now() + armem::Time::seconds(i);
+            update.timeCreated = armem::Time::Now() + armem::Duration::Seconds(i);
             for (int j = 0; j < i; ++j)
             {
                 update.instancesData.push_back(std::make_shared<aron::data::Dict>());
@@ -364,7 +367,15 @@ namespace armarx
         }
         exampleDataProviderID = armem::MemoryID(addSegmentResult.segmentID);
 
-        const armem::Time time = armem::Time::now();
+        addSegmentResult = memoryWriter.addSegment("LinkedData", getName());
+        if (!addSegmentResult.success)
+        {
+            ARMARX_ERROR << addSegmentResult.errorMessage;
+            return;
+        }
+        linkedDataProviderID = armem::MemoryID(addSegmentResult.segmentID);
+
+        const armem::Time time = armem::Time::Now();
         armem::Commit commit;
 
         //commit to default
@@ -374,7 +385,8 @@ namespace armarx
             update.timeCreated = time;
 
             armem::example::ExampleData data;
-            toAron(data.memoryLink, armem::MemoryID());
+            toAron(data.memoryID, armem::MemoryID());
+            toAron(data.memoryLink.memoryID, armem::MemoryID());
             ARMARX_CHECK_NOT_NULL(data.toAron());
             update.instancesData = { data.toAron() };
         }
@@ -388,7 +400,7 @@ namespace armarx
 
             armem::example::ExampleData data;
             data.the_bool = true;
-            data.the_double = std::sin(time.toSecondsDouble());
+            data.the_double = std::sin(time.toDurationSinceEpoch().toSecondsDouble());
             data.the_float = 21.5;
             data.the_int = 42;
             data.the_long = 424242;
@@ -418,7 +430,8 @@ namespace armarx
             data.the_3x1_vector = { 24, 42, 2442 };
             data.the_4x4_matrix = 42 * Eigen::Matrix4f::Identity();
 
-            toAron(data.memoryLink, armem::MemoryID()); // ////1/1
+            toAron(data.memoryID, armem::MemoryID()); // ////1/1
+            toAron(data.memoryLink.memoryID, armem::MemoryID());
 
             simox::ColorMap cmap = simox::color::cmaps::plasma();
             {
@@ -466,10 +479,27 @@ namespace armarx
             update.instancesData = { data.toAron() };
         }
 
+        // commit to linked data
+        {
+            armem::EntityUpdate& update = commit.add();
+            update.entityID = linkedDataProviderID.withEntityName("yet_more_data");
+            update.timeCreated = time;
+
+            armem::example::LinkedData data;
+            data.yet_another_int = 42;
+            data.yet_another_string = "Hi! I'm from another core segment!";
+            data.yet_another_object.element_int = 8349;
+            data.yet_another_object.element_float = -1e3;
+            data.yet_another_object.element_string = "I'm a nested object in some linked data.";
+            ARMARX_CHECK_NOT_NULL(data.toAron());
+            update.instancesData = { data.toAron() };
+        }
+
         armem::CommitResult commitResult = memoryWriter.commit(commit);
         if (commitResult.allSuccess())
         {
-            armem::fromIce(commitResult.results.at(1).snapshotID, theAnswerSnapshotID);
+            theAnswerSnapshotID = commitResult.results.at(1).snapshotID;
+            yetMoreDataSnapshotID = commitResult.results.at(2).snapshotID;
         }
         else
         {
@@ -501,50 +531,54 @@ namespace armarx
     }
 
 
-    void ExampleMemoryClient::commitExamplesWithLinks()
+    void ExampleMemoryClient::commitExamplesWithIDs()
     {
         ARMARX_IMPORTANT << "Committing multiple entity updates with links ...";
-        const armem::Time time = armem::Time::now();
+        const armem::Time time = armem::Time::Now();
 
         armem::Commit commit;
         {
             armem::EntityUpdate& update = commit.add();
-            update.entityID = exampleDataProviderID.withEntityName("link to the_answer");
+            update.entityID = exampleDataProviderID.withEntityName("id to the_answer");
             update.timeCreated = time;
 
             armem::example::ExampleData data;
-            armem::toAron(data.memoryLink, theAnswerSnapshotID);
+            armem::toAron(data.memoryID, theAnswerSnapshotID);
+            armem::toAron(data.memoryLink.memoryID, armem::MemoryID());
 
             update.instancesData = { data.toAron() };
         }
         {
             armem::EntityUpdate& update = commit.add();
-            update.entityID = exampleDataProviderID.withEntityName("link to self");
+            update.entityID = exampleDataProviderID.withEntityName("id to self");
             update.timeCreated = time;
 
             armem::example::ExampleData data;
-            armem::toAron(data.memoryLink, update.entityID.withTimestamp(time));
+            armem::toAron(data.memoryID, update.entityID.withTimestamp(time));
+            armem::toAron(data.memoryLink.memoryID, armem::MemoryID());
 
             update.instancesData = { data.toAron() };
         }
 
         {
             armem::EntityUpdate& update = commit.add();
-            update.entityID = exampleDataProviderID.withEntityName("link to previous snapshot");
-            update.timeCreated = time - armem::Time::seconds(1);  // 1 sec in the past
+            update.entityID = exampleDataProviderID.withEntityName("id to previous snapshot");
+            update.timeCreated = time - armem::Duration::Seconds(1);  // 1 sec in the past
 
             armem::example::ExampleData data;
-            armem::toAron(data.memoryLink, armem::MemoryID());  // First entry - invalid link
+            armem::toAron(data.memoryID, armem::MemoryID());  // First entry - invalid link
+            armem::toAron(data.memoryLink.memoryID, armem::MemoryID());
 
             update.instancesData = { data.toAron() };
         }
         {
             armem::EntityUpdate& update = commit.add();
-            update.entityID = exampleDataProviderID.withEntityName("link to previous snapshot");
+            update.entityID = exampleDataProviderID.withEntityName("id to previous snapshot");
             update.timeCreated = time;
 
             armem::example::ExampleData data;
-            armem::toAron(data.memoryLink, update.entityID.withTimestamp(time - armem::Time::seconds(1)));
+            armem::toAron(data.memoryID, update.entityID.withTimestamp(time - armem::Duration::Seconds(1)));
+            armem::toAron(data.memoryLink.memoryID, armem::MemoryID());
 
             update.instancesData = { data.toAron() };
         }
@@ -584,9 +618,64 @@ namespace armarx
         }
     }
 
+
+    void ExampleMemoryClient::commitExamplesWithLinks()
+    {
+        ARMARX_IMPORTANT << "Committing an entity update with a link...";
+
+        const armem::Time time = armem::Time::Now();
+
+        armem::Commit commit;
+        {
+            armem::EntityUpdate& update = commit.add();
+            update.entityID = exampleDataProviderID.withEntityName("link to yet_more_data");
+            update.timeCreated = time;
+
+            armem::example::ExampleData data;
+            armem::toAron(data.memoryID, armem::MemoryID());
+            armem::toAron(data.memoryLink.memoryID, yetMoreDataSnapshotID);
+
+            update.instancesData = { data.toAron() };
+        }
+
+        ARMARX_CHECK_EQUAL(commit.updates.size(), 1);
+        armem::CommitResult commitResult = memoryWriter.commit(commit);
+
+        if (!commitResult.allSuccess() || commitResult.results.size() != commit.updates.size())
+        {
+            ARMARX_WARNING << commitResult.allErrorMessages();
+        }
+
+
+        // Resolve memory IDs via memory name system (works for IDs from different servers).
+        ARMARX_IMPORTANT << "Resolving multiple memory IDs via Memory Name System:";
+        {
+            std::vector<armem::MemoryID> ids;
+            for (armem::EntityUpdateResult& result : commitResult.results)
+            {
+                ids.push_back(result.snapshotID);
+            }
+            ARMARX_CHECK_EQUAL(ids.size(), commit.updates.size());
+
+            std::map<armem::MemoryID, armem::wm::EntityInstance> instances =
+                    memoryNameSystem().resolveEntityInstances(ids);
+            ARMARX_CHECK_EQUAL(instances.size(), commit.updates.size());
+
+            std::stringstream ss;
+            for (const auto& [id, instance]: instances)
+            {
+                ss << "- Snapshot " << id << " "
+                   << "\n--> Instance" << instance.id()
+                   << " (# keys in data: " << instance.data()->childrenSize() << ")"
+                   << "\n";
+            }
+            ARMARX_INFO << ss.str();
+        }
+    }
+
     void ExampleMemoryClient::commitExampleImages()
     {
-        const armem::Time time = armem::Time::now();
+        const armem::Time time = armem::Time::Now();
 
         armem::Commit commit;
         {
@@ -608,7 +697,7 @@ namespace armarx
 
     void ExampleMemoryClient::commitExamplesWithUntypedData()
     {
-        const armem::Time time = armem::Time::now();
+        const armem::Time time = armem::Time::Now();
 
         armem::Commit commit;
         {
@@ -617,7 +706,8 @@ namespace armarx
             update.timeCreated = time;
 
             armem::example::ExampleData data;
-            toAron(data.memoryLink, armem::MemoryID()); // ////1/1
+            toAron(data.memoryID, armem::MemoryID()); // ////1/1
+            toAron(data.memoryLink.memoryID, armem::MemoryID());
 
             aron::data::DictPtr aron = data.toAron();
             aron->addElement("unexpectedString", std::make_shared<aron::data::String>("unexpected value"));
diff --git a/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.h b/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.h
index 930abfea7618c4ece3f7298c97376a54b201bac6..dcbcad65cb019296032664ee1c12fc14aee1d56e 100644
--- a/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.h
+++ b/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.h
@@ -98,6 +98,7 @@ namespace armarx
         void commitExampleData();
         void queryExampleData();
 
+        void commitExamplesWithIDs();
         void commitExamplesWithLinks();
 
         void commitExampleImages();
@@ -122,9 +123,11 @@ namespace armarx
 
         armem::MemoryID exampleDataProviderID;
         armem::MemoryID theAnswerSnapshotID;
+        armem::MemoryID linkedDataProviderID;
+        armem::MemoryID yetMoreDataSnapshotID;
 
 
-        IceUtil::Time run_started;
+        armem::Time runStarted;
         unsigned int imageCounter = 0;
 
         armarx::RunningTask<ExampleMemoryClient>::pointer_type task;
diff --git a/source/RobotAPI/components/armem/client/GraspProviderExample/GraspProviderExample.cpp b/source/RobotAPI/components/armem/client/GraspProviderExample/GraspProviderExample.cpp
index 8f98b2383da3556f459ae6fa01a7f3ec190b29e2..c64b050dec343623d9d32d5d53eea8b96600335e 100644
--- a/source/RobotAPI/components/armem/client/GraspProviderExample/GraspProviderExample.cpp
+++ b/source/RobotAPI/components/armem/client/GraspProviderExample/GraspProviderExample.cpp
@@ -102,7 +102,7 @@ namespace armarx
             candidate.sourceInfo->bbox->ha3 = Vector3BasePtr(toIce(Eigen::Vector3f()));
             candidate.sourceInfo->referenceObjectPose = PoseBasePtr(toIce(Eigen::Matrix4f()));
 
-            writer.commitGraspCandidate(candidate, armem::Time::now(), "provider1");
+            writer.commitGraspCandidate(candidate, armem::Time::Now(), "provider1");
             // initialize all necessary fields of a bimanual grasp candidate and use writer to commit it to memory
             armarx::grasping::BimanualGraspCandidate bimanualCandidate = armarx::grasping::BimanualGraspCandidate();
             bimanualCandidate.groupNr = i; //non-necessary field, but used to commit different candidates
@@ -117,7 +117,7 @@ namespace armarx
             bimanualCandidate.inwardsVectorLeft = Vector3BasePtr(toIce(Eigen::Vector3f()));
             bimanualCandidate.inwardsVectorRight = Vector3BasePtr(toIce(Eigen::Vector3f()));
 
-            writer.commitBimanualGraspCandidate(bimanualCandidate, armem::Time::now(), "provider2");
+            writer.commitBimanualGraspCandidate(bimanualCandidate, armem::Time::Now(), "provider2");
 
             //test for writing Seqs, candidates from the same object appear as instances of the same snapshot
             grasping::GraspCandidateSeq candidatesToWrite;
@@ -126,7 +126,7 @@ namespace armarx
 
             candidatesToWrite.push_back(new grasping::GraspCandidate(candidate));
 
-            writer.commitGraspCandidateSeq(candidatesToWrite, armem::Time::now(), "provider1");
+            writer.commitGraspCandidateSeq(candidatesToWrite, armem::Time::Now(), "provider1");
 
             // test reader and debug by logging the group number of the candidate
 
diff --git a/source/RobotAPI/components/armem/client/VirtualRobotReaderExampleClient/VirtualRobotReaderExampleClient.cpp b/source/RobotAPI/components/armem/client/VirtualRobotReaderExampleClient/VirtualRobotReaderExampleClient.cpp
index 552f68ac7ea45c24a0041dbedaff43a06c3e2c31..639203e464ecd0e1b75b085c0de7a59b8b283435 100644
--- a/source/RobotAPI/components/armem/client/VirtualRobotReaderExampleClient/VirtualRobotReaderExampleClient.cpp
+++ b/source/RobotAPI/components/armem/client/VirtualRobotReaderExampleClient/VirtualRobotReaderExampleClient.cpp
@@ -74,13 +74,14 @@ namespace armarx::robot_state
 
     void VirtualRobotReaderExampleClient::run()
     {
+        const armem::Time now = armem::Time::Now();
 
         // initialize if needed
         if (virtualRobot == nullptr)
         {
             TIMING_START(getRobot);
 
-            virtualRobot = virtualRobotReader.getRobot(p.robotName, IceUtil::Time::now());
+            virtualRobot = virtualRobotReader.getRobot(p.robotName, now);
 
             if (virtualRobot == nullptr)
             {
@@ -93,13 +94,9 @@ namespace armarx::robot_state
 
         ARMARX_INFO << deactivateSpam(10) << "Synchronizing robot";
 
-        const IceUtil::Time now = TimeUtil::GetTime();
-
         TIMING_START(synchronizeRobot);
         virtualRobotReader.synchronizeRobot(*virtualRobot, now);
         TIMING_END_STREAM(synchronizeRobot, ARMARX_INFO);
-
-
     }
 
 }  // namespace armarx::robot_state
diff --git a/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp b/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp
index 4adee0b0fb84415490dadf5f8394716086eb3adf..7a7d65f0740024f7ef1d7b43c667c2971962429b 100644
--- a/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp
+++ b/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp
@@ -64,6 +64,7 @@ namespace armarx
     {
         // Usually, the memory server will specify a number of core segments with a specific aron type.
         workingMemory().addCoreSegment("ExampleData", armem::example::ExampleData::ToAronType());
+        workingMemory().addCoreSegment("LinkedData", armem::example::LinkedData::ToAronType());
 
         // For illustration purposes, we add more segments (without types).
         bool trim = true;
@@ -181,7 +182,7 @@ namespace armarx
                         .withProviderSegmentName(memoryID.providerSegmentName)
                         .withEntityName(memoryID.entityName);
                     update.entityID = newID;
-                    update.timeCreated = armem::Time::now();
+                    update.timeCreated = armem::Time::Now();
                     update.instancesData = { instance->data() };
 
                     armem::Commit newCommit;
diff --git a/source/RobotAPI/components/armem/server/ExampleMemory/aron/ExampleData.xml b/source/RobotAPI/components/armem/server/ExampleMemory/aron/ExampleData.xml
index be9a9788fae8045e98d211d6a2b7397d6da455eb..4efce411b680ce9a91afceff7da5523b8f67d6cc 100644
--- a/source/RobotAPI/components/armem/server/ExampleMemory/aron/ExampleData.xml
+++ b/source/RobotAPI/components/armem/server/ExampleMemory/aron/ExampleData.xml
@@ -14,6 +14,7 @@ An example data containing different native ARON types.
 
     <AronIncludes>
         <Include include="<RobotAPI/libraries/armem/aron/MemoryID.xml>" autoinclude="true" />
+        <Include include="<RobotAPI/libraries/armem/aron/MemoryLink.xml>" autoinclude="true" />
     </AronIncludes>
 
     <GenerateTypes>
@@ -29,6 +30,21 @@ An example data containing different native ARON types.
             </ObjectChild>
         </Object>
 
+        <Object name='armarx::armem::example::LinkedData'>
+
+            <ObjectChild key='yet_another_int'>
+                <Int />
+            </ObjectChild>
+            <ObjectChild key='yet_another_string'>
+                <String />
+            </ObjectChild>
+
+            <ObjectChild key='yet_another_object'>
+                <armarx::armem::example::InnerClass />
+            </ObjectChild>
+
+        </Object>
+
         <Object name='armarx::armem::example::ExampleData'>
 
             <ObjectChild key='the_int'>
@@ -43,9 +59,9 @@ An example data containing different native ARON types.
             <ObjectChild key='the_double'>
                 <Double />
             </ObjectChild>
-                <ObjectChild key='the_string'>
-            <String />
-                </ObjectChild>
+            <ObjectChild key='the_string'>
+                <String />
+            </ObjectChild>
             <ObjectChild key='the_bool'>
                 <Bool />
             </ObjectChild>
@@ -106,11 +122,16 @@ An example data containing different native ARON types.
                 </Dict>
             </ObjectChild>
 
-            <ObjectChild key="memoryLink">
+            <ObjectChild key="memoryID">
                 <armarx::armem::arondto::MemoryID />
             </ObjectChild>
 
-            </Object>
+            <ObjectChild key="memoryLink">
+                <armarx::armem::arondto::MemoryLink template="armarx::armem::example::LinkedData"/>
+            </ObjectChild>
+
+        </Object>
+
         </GenerateTypes>
 
 </AronTypeDefinition>
diff --git a/source/RobotAPI/components/armem/server/ExampleMemory/test/ExampleMemoryTest.cpp b/source/RobotAPI/components/armem/server/ExampleMemory/test/ExampleMemoryTest.cpp
index 5526876a302cd9658036a9603b753e47fd721121..362a2d2f338fe4e007a34756d006338ebd4611dc 100644
--- a/source/RobotAPI/components/armem/server/ExampleMemory/test/ExampleMemoryTest.cpp
+++ b/source/RobotAPI/components/armem/server/ExampleMemory/test/ExampleMemoryTest.cpp
@@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE(test_ExampleData_type)
 {
     armarx::aron::type::ObjectPtr type = ExampleData::ToAronType();
 
-    BOOST_CHECK_EQUAL(type->childrenSize(), 16);
+    BOOST_CHECK_EQUAL(type->childrenSize(), 20);
 
     armem::wm::Memory memory;
     armem::wm::CoreSegment& core = memory.addCoreSegment("ExampleData", type);
diff --git a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp
index 1d9c4ac147ddc2407952ed6db08c8fd4cfcc279b..15de8583b000cd27b844e6770e076e41ee5bfa9a 100644
--- a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp
+++ b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp
@@ -22,6 +22,8 @@
 
 #include "ObjectMemory.h"
 
+#include <RobotAPI/libraries/armem/core/ice_conversions_templates.h>
+
 
 namespace armarx::armem::server::obj
 {
diff --git a/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.cpp b/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.cpp
index c1bf3bc93f73ece3f5f85cf7a43a7a2d1ad270bb..5da13f82b5f74770c16f7fcbfb9c18723dd6cb80 100644
--- a/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.cpp
+++ b/source/RobotAPI/components/armem/server/RobotStateMemory/RobotStateMemory.cpp
@@ -191,7 +191,7 @@ namespace armarx::armem::server::robot_state
 
     armarx::PoseBasePtr RobotStateMemory::getGlobalRobotPose(Ice::Long timestamp_us, const std::string& robotName, const ::Ice::Current& /*unused*/)
     {
-        auto timestamp = armem::Time::microSeconds(timestamp_us);
+        armem::Time timestamp { armem::Duration::MicroSeconds(timestamp_us) };
         ARMARX_DEBUG << "Getting robot pose of robot " << robotName << " at timestamp " << timestamp << ".";
 
         auto poseMap = localizationSegment.getRobotGlobalPoses(timestamp);
@@ -201,7 +201,7 @@ namespace armarx::armem::server::robot_state
             << "Robot with name " << robotName << " does not exist at or before timestamp " << timestamp << ".\n"
             << "Available robots are: " << simox::alg::get_keys(poseMap);
 
-        return new Pose(poseMap[robotName].matrix());
+        return { new Pose(poseMap[robotName].matrix()) };
     }
 
 
diff --git a/source/RobotAPI/components/units/GraspCandidateObserver.cpp b/source/RobotAPI/components/units/GraspCandidateObserver.cpp
index d4b5ea81cab4f670ba0a073b7ae120b82295de49..41ffefe98882f69004610a233dee16614f5b4f60 100644
--- a/source/RobotAPI/components/units/GraspCandidateObserver.cpp
+++ b/source/RobotAPI/components/units/GraspCandidateObserver.cpp
@@ -126,7 +126,7 @@ void GraspCandidateObserver::reportGraspCandidates(const std::string& providerNa
 {
     std::unique_lock lock(dataMutex);
     this->candidates[providerName] = candidates;
-    graspCandidateWriter.commitGraspCandidateSeq(candidates, armarx::armem::Time::now(), providerName);
+    graspCandidateWriter.commitGraspCandidateSeq(candidates, armarx::armem::Time::Now(), providerName);
     handleProviderUpdate(providerName, candidates.size());
 }
 
diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.cpp b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.cpp
index 4658f41d72431535920580dbb6bda4e0c70c0b6e..bd02cd045bb37da2a51156a60fec1b35b61a2dbf 100644
--- a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.cpp
+++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.cpp
@@ -312,6 +312,19 @@ namespace armarx
         _tripBufWpCtrl.commitWrite();
         ARMARX_IMPORTANT << "set new waypoint\n" << wp;
     }
+    void NJointCartesianWaypointController::setWaypointAx(const Ice::FloatSeq& data, const Ice::Current&)
+    {
+        Eigen::Matrix4f wp(data.data());
+        std::lock_guard g{_tripBufWpCtrlMut};
+        auto& w = _tripBufWpCtrl.getWriteBuffer();
+        w.wpsUpdated = true;
+        w.wps.clear();
+        w.wps.emplace_back(wp);
+        _tripBufWpCtrl.commitWrite();
+        ARMARX_IMPORTANT << "set new waypoint\n" << wp;
+    }
+
+
     void NJointCartesianWaypointController::setConfigAndWaypoints(const NJointCartesianWaypointControllerRuntimeConfig& cfg,
             const std::vector<Eigen::Matrix4f>& wps,
             const Ice::Current&)
diff --git a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.h b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.h
index 4933edd9d22e5138a7ef06d09fa15aa4f908e339..22440abdc4123b86e5ec28e07bfb396b6102dfe2 100644
--- a/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.h
+++ b/source/RobotAPI/components/units/RobotUnit/NJointControllers/NJointCartesianWaypointController.h
@@ -55,6 +55,7 @@ namespace armarx
 
         void setConfig(const NJointCartesianWaypointControllerRuntimeConfig& cfg, const Ice::Current& = Ice::emptyCurrent) override;
         void setWaypoints(const std::vector<Eigen::Matrix4f>& wps, const Ice::Current& = Ice::emptyCurrent) override;
+        void setWaypointAx(const Ice::FloatSeq& data, const Ice::Current& = Ice::emptyCurrent) override;
         void setWaypoint(const Eigen::Matrix4f& wp, const Ice::Current& = Ice::emptyCurrent) override;
         void setConfigAndWaypoints(const NJointCartesianWaypointControllerRuntimeConfig& cfg, const std::vector<Eigen::Matrix4f>& wps, const Ice::Current& = Ice::emptyCurrent) override;
         void setConfigAndWaypoint(const NJointCartesianWaypointControllerRuntimeConfig& cfg, const Eigen::Matrix4f& wp, const Ice::Current& = Ice::emptyCurrent) override;
diff --git a/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidgetController.cpp b/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidgetController.cpp
index 68fbc7165c7d318cf68990f779c074d2f9e12cd4..705f0f7584a84aff9354cf2986505436491f98ff 100644
--- a/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidgetController.cpp
+++ b/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidgetController.cpp
@@ -232,7 +232,7 @@ namespace armarx
                     item->setText(col++, QString::fromStdString(ss.str()));
                 }
                 item->setText(col++, QString::number(double(pose.confidence), 'g', 2));
-                item->setText(col++, QString::fromStdString(TimeUtil::toStringDateTime(pose.timestamp)));
+                item->setText(col++, QString::fromStdString(pose.timestamp.toDateTimeString()));
 
                 {
                     std::stringstream ss;
diff --git a/source/RobotAPI/interface/armem/commit.ice b/source/RobotAPI/interface/armem/commit.ice
index 526188ecf649745cb52e1fd00212d48c602cfcee..17260a2136d2cc4c24d1ecd06f5f77ecbcb7f8c0 100644
--- a/source/RobotAPI/interface/armem/commit.ice
+++ b/source/RobotAPI/interface/armem/commit.ice
@@ -34,10 +34,10 @@ module armarx
             {
                 armem::data::MemoryID entityID;
                 aron::data::dto::AronDictSeq instancesData;
-                long timeCreatedMicroSeconds;
+                armarx::core::time::dto::DateTime timeCreated;
 
                 float confidence = 1.0;
-                long timeSentMicroSeconds = -1;
+                armarx::core::time::dto::DateTime timeSent;
             };
             sequence<EntityUpdate> EntityUpdateList;
 
@@ -46,7 +46,7 @@ module armarx
                 bool success = false;
 
                 armem::data::MemoryID snapshotID;
-                long timeArrivedMicroSeconds;
+                armarx::core::time::dto::DateTime timeArrived;
 
                 string errorMessage;
             };
diff --git a/source/RobotAPI/interface/armem/memory.ice b/source/RobotAPI/interface/armem/memory.ice
index a4cdd0cde1de4f553fd4181f6515e1fd4255ae01..617f7043f76019a2c474f588127dbcbd9c4f3991 100644
--- a/source/RobotAPI/interface/armem/memory.ice
+++ b/source/RobotAPI/interface/armem/memory.ice
@@ -1,5 +1,7 @@
 #pragma once
 
+#include <ArmarXCore/interface/core/time.ice>
+
 #include <RobotAPI/interface/aron.ice>
 
 
@@ -15,7 +17,7 @@ module armarx
                 string coreSegmentName = "";
                 string providerSegmentName = "";
                 string entityName = "";
-                long timestampMicroSeconds = -1;
+                armarx::core::time::dto::DateTime timestamp;
                 int instanceIndex = -1;
             }
 
@@ -36,9 +38,9 @@ module armarx
             /// Ice Twin of `armarx::armem::EntityInstanceMetadata`.
             class EntityInstanceMetadata
             {
-                long timeCreatedMicroSeconds;
-                long timeSentMicroSeconds;
-                long timeArrivedMicroSeconds;
+                armarx::core::time::dto::DateTime timeCreated;
+                armarx::core::time::dto::DateTime timeSent;
+                armarx::core::time::dto::DateTime timeArrived;
 
                 float confidence = 1.0;
             };
@@ -57,7 +59,7 @@ module armarx
             {
                 EntityInstanceSeq instances;
             };
-            dictionary<long, EntitySnapshot> EntityHistory;
+            dictionary<armarx::core::time::dto::DateTime, EntitySnapshot> EntityHistory;
 
 
             /// Ice Twin of `armarx::armem::Entity`.
diff --git a/source/RobotAPI/interface/armem/query.ice b/source/RobotAPI/interface/armem/query.ice
index 936294507f0b05627051fa6974309faa1db4d758..f5555e4f306bf3e73ab3e47719f89a2ddb87268d 100644
--- a/source/RobotAPI/interface/armem/query.ice
+++ b/source/RobotAPI/interface/armem/query.ice
@@ -34,13 +34,13 @@ module armarx
                     /// Get a single snapshot (default for latest).
                     class Single extends EntityQuery
                     {
-                        long timestamp = -1;  // -1 for latest
+                        armarx::core::time::dto::DateTime timestamp;  // -1 for latest
                     };
                     /// Get snapshots based on a time range (default for all).
                     class TimeRange extends EntityQuery
                     {
-                        long minTimestamp = -1;  // -1 for oldest
-                        long maxTimestamp = -1;  // -1 for latest
+                        armarx::core::time::dto::DateTime minTimestamp;  // -1 for oldest
+                        armarx::core::time::dto::DateTime maxTimestamp;  // -1 for latest
                     };
                     /**
                      * @brief Get snapshots based on an index range (default for all).
@@ -78,8 +78,8 @@ module armarx
                      */
                     class TimeApprox extends EntityQuery
                     {
-                        long timestamp = -1;
-                        long eps = -1;
+                        armarx::core::time::dto::DateTime timestamp;
+                        armarx::core::time::dto::Duration eps;
                     };
 
                     /**
@@ -90,7 +90,7 @@ module armarx
                      */
                     class BeforeOrAtTime extends EntityQuery
                     {
-                        long timestamp;
+                        armarx::core::time::dto::DateTime timestamp;
                     }
 
                     /**
@@ -104,7 +104,7 @@ module armarx
                      */
                     class BeforeTime extends EntityQuery
                     {
-                        long timestamp;
+                        armarx::core::time::dto::DateTime timestamp;
                         long maxEntries = 1;
                     }
 
diff --git a/source/RobotAPI/interface/objectpose/object_pose_types.ice b/source/RobotAPI/interface/objectpose/object_pose_types.ice
index 4b09fd18ef1c6fe771200b3338ae67073616c42b..35960cce72ba7157a2c3bfbbca61824ef6a26334 100644
--- a/source/RobotAPI/interface/objectpose/object_pose_types.ice
+++ b/source/RobotAPI/interface/objectpose/object_pose_types.ice
@@ -23,8 +23,8 @@
 
 #pragma once
 
-//fq
 #include <ArmarXCore/interface/core/BasicVectorTypes.ice>
+#include <ArmarXCore/interface/core/time.ice>
 
 #include <RobotAPI/interface/core/PoseBase.ice>
 #include <RobotAPI/interface/core/NameValueMap.ice>
@@ -101,7 +101,7 @@ module armarx
                 /// Confidence in [0, 1] (1 = full, 0 = none).
                 float confidence = 0;
                 /// Source timestamp.
-                long timestampMicroSeconds = -1;
+                armarx::core::time::dto::DateTime timestamp;
 
                 /// [Optional] Object bounding box in object's local coordinate frame.
                 Box localOOBB;
@@ -146,7 +146,7 @@ module armarx
                 /// Confidence in [0, 1] (1 = full, 0 = none).
                 float confidence = 0;
                 /// Source timestamp.
-                long timestampMicroSeconds = -1;
+                armarx::core::time::dto::DateTime timestamp;
 
                 /// Object bounding box in object's local coordinate frame. May be null.
                 Box localOOBB;
diff --git a/source/RobotAPI/interface/units/RobotUnit/NJointCartesianWaypointController.ice b/source/RobotAPI/interface/units/RobotUnit/NJointCartesianWaypointController.ice
index bf00909d6f5b95ee23fec2f982aae5d4d6ed6ec8..f02c8e8ee8720f7a45fb730f155986016cdb0331 100644
--- a/source/RobotAPI/interface/units/RobotUnit/NJointCartesianWaypointController.ice
+++ b/source/RobotAPI/interface/units/RobotUnit/NJointCartesianWaypointController.ice
@@ -56,6 +56,7 @@ module armarx
         void setConfig(NJointCartesianWaypointControllerRuntimeConfig cfg);
         void setWaypoints(Eigen::Matrix4fSeq wps);
         void setWaypoint(Eigen::Matrix4f wp);
+        void setWaypointAx(Ice::FloatSeq wp);
         void setConfigAndWaypoints(NJointCartesianWaypointControllerRuntimeConfig cfg, Eigen::Matrix4fSeq wps);
         void setConfigAndWaypoint(NJointCartesianWaypointControllerRuntimeConfig cfg, Eigen::Matrix4f wp);
         
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectPose.cpp b/source/RobotAPI/libraries/ArmarXObjects/ObjectPose.cpp
index 11e583902b8fbb0963e8f4c1b00746de01356f1b..413d4681c37d51c959573f5a2528a07d66ea4b9b 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectPose.cpp
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectPose.cpp
@@ -7,6 +7,7 @@
 #include <VirtualRobot/RobotConfig.h>
 
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+#include <ArmarXCore/core/time/ice_conversions.h>
 
 #include <RobotAPI/libraries/core/Pose.h>
 #include <RobotAPI/libraries/core/FramedPose.h>
@@ -51,7 +52,7 @@ namespace armarx::objpose
         objpose::fromIce(ice.attachment, this->attachment);
 
         confidence = ice.confidence;
-        timestamp = IceUtil::Time::microSeconds(ice.timestampMicroSeconds);
+        armarx::core::time::fromIce(ice.timestamp, timestamp);
 
         objpose::fromIce(ice.localOOBB, localOOBB);
     }
@@ -88,7 +89,7 @@ namespace armarx::objpose
         objpose::toIce(ice.attachment, this->attachment);
 
         ice.confidence = confidence;
-        ice.timestampMicroSeconds = timestamp.toMicroSeconds();
+        armarx::core::time::toIce(ice.timestamp, timestamp);
 
         objpose::toIce(ice.localOOBB, localOOBB);
     }
@@ -132,7 +133,7 @@ namespace armarx::objpose
         attachment = std::nullopt;
 
         confidence = provided.confidence;
-        timestamp = IceUtil::Time::microSeconds(provided.timestampMicroSeconds);
+        armarx::core::time::fromIce(provided.timestamp, timestamp);
 
         objpose::fromIce(provided.localOOBB, localOOBB);
     }
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectPose.h b/source/RobotAPI/libraries/ArmarXObjects/ObjectPose.h
index 66c87f22f5f369c154043e83a72146f0d5bbea54..cc8b4c6ebd1f1f112667df6c3eccc1308e5e5416 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectPose.h
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectPose.h
@@ -4,7 +4,6 @@
 #include <map>
 #include <vector>
 
-
 #include <Eigen/Core>
 
 #include <SimoxUtility/shapes/OrientedBox.h>
@@ -12,8 +11,7 @@
 #include <VirtualRobot/VirtualRobot.h>
 
 #include <ArmarXCore/core/PackagePath.h>
-
-#include <IceUtil/Time.h>
+#include <ArmarXCore/core/time/DateTime.h>
 
 #include <RobotAPI/interface/objectpose/object_pose_types.h>
 #include <RobotAPI/libraries/ArmarXObjects/forward_declarations.h>
@@ -87,7 +85,7 @@ namespace armarx::objpose
         /// Confidence in [0, 1] (1 = full, 0 = none).
         float confidence = 0;
         /// Source timestamp.
-        IceUtil::Time timestamp = IceUtil::Time::microSeconds(-1);
+        DateTime timestamp = DateTime::Invalid();
 
         /// Object bounding box in object's local coordinate frame.
         /// @see oobbRobot(), oobbGlobal()
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ProvidedObjectPose.cpp b/source/RobotAPI/libraries/ArmarXObjects/ProvidedObjectPose.cpp
index c67af0381b114b1b5e145b60a3c239b464f4ec31..c07cea85884a957218d9a9903ffcdd8c674b37bd 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ProvidedObjectPose.cpp
+++ b/source/RobotAPI/libraries/ArmarXObjects/ProvidedObjectPose.cpp
@@ -1,6 +1,7 @@
 #include "ProvidedObjectPose.h"
 
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+#include <ArmarXCore/core/time/ice_conversions.h>
 
 #include <RobotAPI/libraries/core/Pose.h>
 #include <RobotAPI/libraries/core/FramedPose.h>
@@ -34,7 +35,7 @@ namespace armarx::objpose
         objectJointValues = ice.objectJointValues;
 
         confidence = ice.confidence;
-        timestamp = IceUtil::Time::microSeconds(ice.timestampMicroSeconds);
+        armarx::core::time::fromIce(ice.timestamp, timestamp);
 
         objpose::fromIce(ice.localOOBB, localOOBB);
     }
@@ -60,7 +61,7 @@ namespace armarx::objpose
         ice.objectJointValues = objectJointValues;
 
         ice.confidence = confidence;
-        ice.timestampMicroSeconds = timestamp.toMicroSeconds();
+        armarx::core::time::toIce(ice.timestamp, timestamp);
 
         objpose::toIce(ice.localOOBB, localOOBB);
     }
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ProvidedObjectPose.h b/source/RobotAPI/libraries/ArmarXObjects/ProvidedObjectPose.h
index c323a879508a60ad1dfd6b4af58dc4c4298ec534..c8d846893dbf857f1ca8bb5dbaabae1ba0b1b14b 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ProvidedObjectPose.h
+++ b/source/RobotAPI/libraries/ArmarXObjects/ProvidedObjectPose.h
@@ -8,7 +8,7 @@
 
 #include <SimoxUtility/shapes/OrientedBox.h>
 
-#include <IceUtil/Time.h>
+#include <ArmarXCore/core/time/DateTime.h>
 
 #include <RobotAPI/interface/objectpose/object_pose_types.h>
 #include <RobotAPI/libraries/ArmarXObjects/forward_declarations.h>
@@ -57,7 +57,7 @@ namespace armarx::objpose
         /// Confidence in [0, 1] (1 = full, 0 = none).
         float confidence = 0;
         /// Source timestamp.
-        IceUtil::Time timestamp = IceUtil::Time::microSeconds(-1);
+        DateTime timestamp = DateTime::Invalid();
 
         /// Object bounding box in object's local coordinate frame.
         /// @see oobbRobot(), oobbGlobal()
diff --git a/source/RobotAPI/libraries/ArmarXObjects/aron_conversions/objpose.cpp b/source/RobotAPI/libraries/ArmarXObjects/aron_conversions/objpose.cpp
index bb9fb98e66584e8e22889d79c57900df0df1d99f..f21931adabf669f0da8804cf937fd6205c94248b 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/aron_conversions/objpose.cpp
+++ b/source/RobotAPI/libraries/ArmarXObjects/aron_conversions/objpose.cpp
@@ -104,7 +104,7 @@ void armarx::objpose::fromAron(const arondto::ObjectPose& dto, ObjectPose& bo)
 
     bo.confidence = dto.confidence;
 
-    bo.timestamp = dto.timestamp;
+    fromAron(dto.timestamp, bo.timestamp);
 
     if (dto.localOOBBValid)
     {
@@ -153,7 +153,7 @@ void armarx::objpose::toAron(arondto::ObjectPose& dto, const ObjectPose& bo)
 
     dto.confidence = bo.confidence;
 
-    dto.timestamp = bo.timestamp;
+    toAron(dto.timestamp, bo.timestamp);
 
     if (bo.localOOBB)
     {
diff --git a/source/RobotAPI/libraries/ArmarXObjects/json_conversions.cpp b/source/RobotAPI/libraries/ArmarXObjects/json_conversions.cpp
index 6080cfda786c3d6115c6647fe7decd4e5faa6b03..cf42e169e67f0f18aef427c65fd24a73160983bf 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/json_conversions.cpp
+++ b/source/RobotAPI/libraries/ArmarXObjects/json_conversions.cpp
@@ -43,7 +43,7 @@ void armarx::objpose::to_json(simox::json::json& j, const ObjectPose& op)
     j["robotPose"] = op.robotPose;
 
     j["confidence"] = op.confidence;
-    j["timestampMicroSeconds"] = op.timestamp.toMicroSeconds();
+    j["timestampMicroSeconds"] = op.timestamp.toMicroSecondsSinceEpoch();
 
     if (op.localOOBB)
     {
@@ -68,7 +68,7 @@ void armarx::objpose::from_json(const simox::json::json& j, ObjectPose& op)
     op.robotPose = j.at("robotPose");
 
     op.confidence = j.at("confidence");
-    op.timestamp = IceUtil::Time::microSeconds(j.at("timestampMicroSeconds"));
+    op.timestamp = DateTime(Duration::MicroSeconds(j.at("timestampMicroSeconds")));
 
     if (j.count("localOOBB"))
     {
diff --git a/source/RobotAPI/libraries/GraspingUtility/GraspCandidateWriter.cpp b/source/RobotAPI/libraries/GraspingUtility/GraspCandidateWriter.cpp
index 24d050e646d9bbac8ed3ab5fa30926f6b24f442a..76200b0ab1772d68cd30482e577ae870e711af10 100644
--- a/source/RobotAPI/libraries/GraspingUtility/GraspCandidateWriter.cpp
+++ b/source/RobotAPI/libraries/GraspingUtility/GraspCandidateWriter.cpp
@@ -1,13 +1,15 @@
 #include "GraspCandidateWriter.h"
+
+#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h>
+
 #include <RobotAPI/libraries/GraspingUtility/aron/GraspCandidate.aron.generated.h>
 #include <RobotAPI/libraries/GraspingUtility/aron_conversions.h>
 #include <RobotAPI/libraries/armem/core/error/mns.h>
-#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h>
+
 
 namespace armarx::armem
 {
 
-
     GraspCandidateWriter::GraspCandidateWriter(armem::client::MemoryNameSystem& memoryNameSystem)
         : memoryNameSystem(memoryNameSystem)
     {
@@ -122,7 +124,7 @@ namespace armarx::armem
         std::map<std::string, std::vector<armarx::aron::data::DictPtr>> updates = {};
         armarx::grasping::arondto::BimanualGraspCandidate aronGraspCandidate;
 
-        for (armarx::grasping::BimanualGraspCandidatePtr candidate : candidates)
+        for (const armarx::grasping::BimanualGraspCandidatePtr& candidate : candidates)
         {
             std::string objectName = "UnknownObject";
             if (candidate->sourceInfo)
@@ -161,21 +163,16 @@ namespace armarx::armem
             return false;
         }
 
-        const auto iceTimestamp = Time::microSeconds(timestamp.toMicroSeconds());
-
         const auto providerId = armem::MemoryID(result.segmentID);
         const auto entityID =
-            providerId.withEntityName(entityName).withTimestamp(iceTimestamp);
+            providerId.withEntityName(entityName).withTimestamp(timestamp);
 
         armem::EntityUpdate update;
         update.entityID = entityID;
-
-
-
         update.instancesData = instances;
-        update.timeCreated = iceTimestamp;
+        update.timeCreated = timestamp;
 
-        ARMARX_DEBUG << "Committing " << update << " at time " << iceTimestamp;
+        ARMARX_DEBUG << "Committing " << update << " at time " << timestamp;
         armem::EntityUpdateResult updateResult = memoryWriter.commit(update);
 
         ARMARX_DEBUG << updateResult;
diff --git a/source/RobotAPI/libraries/armem/CMakeLists.txt b/source/RobotAPI/libraries/armem/CMakeLists.txt
index 5feda749b6fc3eb3e1f601812b778e71b20c099b..6b105d8f67ed0ba87bfd5ae17a2fcf54fea79b70 100644
--- a/source/RobotAPI/libraries/armem/CMakeLists.txt
+++ b/source/RobotAPI/libraries/armem/CMakeLists.txt
@@ -9,6 +9,7 @@ set(LIBS
     ArmarXCore
     RemoteGui
     aron
+    aroncommon
 )
 
 set(LIB_FILES
@@ -167,6 +168,7 @@ armarx_add_library(
         "${LIBS}"
     ARON_FILES
         aron/MemoryID.xml
+        aron/MemoryLink.xml
 )
 
 
diff --git a/source/RobotAPI/libraries/armem/aron/MemoryLink.xml b/source/RobotAPI/libraries/armem/aron/MemoryLink.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3f04e393abf0c07747cdebd8288ca655f169e7c5
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/aron/MemoryLink.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<AronTypeDefinition>
+    <CodeIncludes>
+        <Include include="<RobotAPI/libraries/armem/aron/MemoryID.aron.generated.h>" />
+    </CodeIncludes>
+    <AronIncludes>
+        <Include include="<RobotAPI/libraries/armem/aron/MemoryID.xml>" />
+    </AronIncludes>
+    <GenerateTypes>
+        <Object name="armarx::armem::arondto::MemoryLink" template="T">
+            <ObjectChild key="memoryID">
+                <armarx::armem::arondto::MemoryID />
+            </ObjectChild>
+            <ObjectChild key="data">
+                <T unique_ptr="true"/>
+            </ObjectChild>
+        </Object>
+    </GenerateTypes>
+</AronTypeDefinition>
diff --git a/source/RobotAPI/libraries/armem/client/Query.cpp b/source/RobotAPI/libraries/armem/client/Query.cpp
index 52000cf3d25f118ea80cf7dfc7c5ea5830cb36f8..5829c918872623c48a2d2866d84af67b7809d919 100644
--- a/source/RobotAPI/libraries/armem/client/Query.cpp
+++ b/source/RobotAPI/libraries/armem/client/Query.cpp
@@ -1,6 +1,8 @@
 #include "Query.h"
 
 #include <RobotAPI/libraries/armem/core/wm/ice_conversions.h>
+#include <RobotAPI/libraries/armem/core/ice_conversions_templates.h>
+
 
 namespace armarx::armem::client
 {
diff --git a/source/RobotAPI/libraries/armem/client/Reader.cpp b/source/RobotAPI/libraries/armem/client/Reader.cpp
index b7a1c85dd5925353a360058cc5359a312f6e42c0..5bf6dcd0308cfad16c6401bed4c2ae940a972930 100644
--- a/source/RobotAPI/libraries/armem/client/Reader.cpp
+++ b/source/RobotAPI/libraries/armem/client/Reader.cpp
@@ -4,10 +4,14 @@
 
 #include <ArmarXCore/core/logging/Logging.h>
 
+#include <RobotAPI/libraries/armem/aron/MemoryLink.aron.generated.h>
 #include <RobotAPI/libraries/armem/core/MemoryID_operators.h>
-#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h>
+#include <RobotAPI/libraries/armem/core/aron_conversions.h>
 #include <RobotAPI/libraries/armem/core/wm/ice_conversions.h>
+#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h>
 #include <RobotAPI/libraries/armem/util/util.h>
+#include <RobotAPI/libraries/aron/common/util/object_finders.h>
+#include <RobotAPI/libraries/aron/core/data/visitor/RecursiveVisitor.h>
 
 #include "query/Builder.h"
 #include "query/query_fns.h"
@@ -81,6 +85,212 @@ namespace armarx::armem::client
     }
 
 
+    QueryResult Reader::query(const QueryInput& input,
+            armem::client::MemoryNameSystem& mns,
+            int recursionDepth) const
+    {
+        return QueryResult::fromIce(query(input.toIce(), mns, recursionDepth));
+    }
+
+
+    armem::query::data::Result Reader::query(const armem::query::data::Input& input,
+            armem::client::MemoryNameSystem& mns,
+            int recursionDepth) const
+    {
+        auto makeErrorMsg = [](auto error)
+        {
+            std::stringstream sstream;
+            sstream << "Memory query failed.\nReason: " << error.what();
+            return sstream.str();
+        };
+
+        armem::query::data::Result result;
+        ARMARX_CHECK_NOT_NULL(memoryPrx);
+        try
+        {
+            result = memoryPrx->query(input);
+            QueryResult bObj = QueryResult::fromIce(result);
+            bObj.memory.forEachInstance(
+                [&bObj, &mns, recursionDepth](armem::wm::EntityInstance& instance)
+                { resolveMemoryLinks(instance, bObj.memory, mns, recursionDepth); });
+            result = bObj.toIce();
+        }
+        catch (const Ice::ConnectionRefusedException& e)
+        {
+            result.errorMessage = makeErrorMsg(e);
+        }
+        catch (const Ice::ConnectionLostException& e)
+        {
+            result.errorMessage = makeErrorMsg(e);
+        }
+        catch (const Ice::NotRegisteredException& e)
+        {
+            result.errorMessage = makeErrorMsg(e);
+        }
+        catch (const exceptions::local::ExpressionException& e)
+        {
+            std::stringstream sstream;
+            sstream << "Encountered malformed MemoryLink: " << e.what();
+            result.errorMessage = sstream.str();
+        }
+
+        return result;
+    }
+
+
+    QueryResult Reader::query(armem::query::data::MemoryQueryPtr query, // NOLINT
+            armem::client::MemoryNameSystem& mns,
+            int recursionDepth) const
+    {
+        return this->query(armem::query::data::MemoryQuerySeq{query}, mns, recursionDepth);
+    }
+
+
+    QueryResult Reader::query(const armem::query::data::MemoryQuerySeq& queries,
+            armem::client::MemoryNameSystem& mns,
+            int recursionDepth) const
+    {
+        QueryInput input;
+        input.memoryQueries = queries;
+        return this->query(input, mns, recursionDepth);
+    }
+
+
+    QueryResult Reader::query(const QueryBuilder& queryBuilder,
+            armem::client::MemoryNameSystem& mns,
+            int recursionDepth) const
+    {
+        return this->query(queryBuilder.buildQueryInput(), mns, recursionDepth);
+    }
+
+
+    /**
+     * Get the MemoryID and data required to fill in the given MemoryLink.
+     *
+     * Returns nothing if the data could not be retrieved or its type does not
+     * match the MemoryLink's template type.
+     *
+     * @param linkData the data object of the MemoryLink
+     * @param linkType the type object of the MemoryLink
+     * @return a pair of memoryID and data to fill in a MemoryLink, or nothing if not available
+     */
+    std::optional<std::pair<MemoryID, aron::data::VariantPtr>>
+    findDataForLink(const aron::data::VariantPtr& linkData,
+                    const aron::type::VariantPtr& linkType,
+                    armem::client::MemoryNameSystem& mns)
+    {
+        static const aron::Path memoryLinkIDPath{{"memoryID"}};
+        static const aron::Path memoryLinkDataPath{{"data"}};
+        armem::arondto::MemoryID dto;
+        auto memoryIDDict =
+            aron::data::Dict::DynamicCastAndCheck(linkData->navigateAbsolute(memoryLinkIDPath));
+        dto.fromAron(memoryIDDict);
+        auto memoryID = aron::fromAron<armem::MemoryID>(dto);
+        if (!memoryID.isWellDefined() || !memoryID.hasEntityName())
+        {
+            ARMARX_INFO << "Encountered unresolvable MemoryID '" << memoryID.str()
+                        << "', ignoring.";
+            return {};
+        }
+
+        auto nextMemory = resolveID(mns, memoryID);
+        if (!nextMemory)
+        {
+            ARMARX_WARNING << "Could not retrieve data for " << memoryID.str() << ", skipping...";
+            return {};
+        }
+        auto nextDataAndType = extractDataAndType(nextMemory.value(), memoryID);
+        if (!nextDataAndType)
+        {
+            ARMARX_WARNING << "Data or type for " << memoryID.str()
+                           << " not available in memory containing that MemoryID.";
+            return {};
+        }
+        auto [nextData, nextType] = nextDataAndType.value();
+        auto linkTemplate =
+            aron::type::Object::DynamicCastAndCheck(linkType)->getTemplateInstantiations().at(0);
+        std::string nextObjectName = nextType->getObjectNameWithTemplateInstantiations();
+        if (nextType->getObjectName() != linkTemplate)
+        {
+            ARMARX_WARNING << "Linked object " << memoryID.str() << " is of the type "
+                           << nextType->getObjectName() << ", but the link requires the type "
+                           << linkTemplate;
+            return {};
+        }
+        return {{memoryID,
+                 // This is currently the only method to prefix the path to the data correctly.
+                 aron::data::Variant::FromAronDTO(
+                     nextData->toAronDTO(),
+                     linkData->getPath().withElement(memoryLinkDataPath.toString()))}};
+    }
+
+    void
+    Reader::resolveMemoryLinks(armem::wm::EntityInstance& instance,
+                               armem::wm::Memory& input,
+                               armem::client::MemoryNameSystem& mns,
+                               int recursionDepth)
+    {
+        static const aron::Path memoryLinkDataPath{{"data"}};
+        // MemoryID is used for the template instantiation as a placeholder -
+        // you could use any type here.
+        static const std::string linkType =
+            arondto::MemoryLink<arondto::MemoryID>::ToAronType()->getFullName();
+
+        std::set<armem::MemoryID> seenIDs{instance.id()};
+        std::vector<aron::Path> currentPaths{{{""}}};
+        std::vector<aron::Path> nextPaths;
+        int depth = 0;
+
+        auto dataAndType = extractDataAndType(input, instance.id());
+        if (!dataAndType)
+        {
+            ARMARX_INFO << "Instance '" << instance.id().str() << "' does not have a defined type.";
+            return;
+        }
+        auto [instanceData, instanceType] = dataAndType.value();
+        while (!currentPaths.empty() && (recursionDepth == -1 || depth < recursionDepth))
+        {
+            for (const auto& path : currentPaths)
+            {
+                aron::SubObjectFinder finder(linkType);
+                if (path.getFirstElement().empty())
+                {
+                    armarx::aron::data::visitRecursive(finder, instanceData, instanceType);
+                }
+                else
+                {
+                    armarx::aron::data::visitRecursive(finder,
+                                                       instanceData->navigateAbsolute(path),
+                                                       instanceType->navigateAbsolute(path));
+                }
+
+                for (auto& [linkPathStr, linkDataAndType] : finder.getFoundObjects()) // NOLINT
+                {
+                    auto [linkData, linkType] = linkDataAndType;
+                    auto result = findDataForLink(linkData, linkType, mns);
+                    if (result)
+                    {
+                        auto [memoryID, dataToAppend] = result.value();
+                        if (seenIDs.find(memoryID) != seenIDs.end())
+                        {
+                            continue;
+                        }
+                        seenIDs.insert(memoryID);
+
+                        aron::data::Dict::DynamicCastAndCheck(linkData)->setElement(
+                            memoryLinkDataPath.toString(), dataToAppend);
+                        nextPaths.push_back(
+                            linkData->getPath().withElement(memoryLinkDataPath.toString()));
+                    }
+                }
+            }
+            currentPaths = std::move(nextPaths);
+            nextPaths.clear();
+            ++depth;
+        }
+    }
+
+
     QueryResult Reader::queryMemoryIDs(const std::vector<MemoryID>& ids, DataMode dataMode) const
     {
         using namespace client::query_fns;
diff --git a/source/RobotAPI/libraries/armem/client/Reader.h b/source/RobotAPI/libraries/armem/client/Reader.h
index e9ee1b69afef7d2befdaaf0169b0117a13edbad5..1b957fde328f8c09b1086dc7fa2f0011cecd694b 100644
--- a/source/RobotAPI/libraries/armem/client/Reader.h
+++ b/source/RobotAPI/libraries/armem/client/Reader.h
@@ -8,6 +8,7 @@
 // RobotAPI
 #include <RobotAPI/interface/armem/server/ReadingMemoryInterface.h>
 #include <RobotAPI/interface/armem/server/StoringMemoryInterface.h>
+#include <RobotAPI/libraries/armem/client/MemoryNameSystem.h>
 #include <RobotAPI/libraries/armem/core/wm/memory_definitions.h>
 
 #include "Query.h"
@@ -41,9 +42,60 @@ namespace armarx::armem::client
 
         QueryResult query(const QueryBuilder& queryBuilder) const;
 
+        /** Perform a query with recursive memory link resolution.
+         *
+         * Resolves the links in the query result using the given MemoryNameSystem
+         * and inserts the data into the MemoryLink objects' data fields.
+         * If the inserted data also contains links, those will be resolved as well
+         * up to and including the given recursion depth. Link cycles are detected;
+         * the first repeated memory ID will not be inserted into the data.
+         * Setting the recursion depth to `-1` is equivalent to an infinite
+         * recursion depth.
+         *
+         * Standalone `MemoryID` subobjects are ignored; only MemoryIDs inside of
+         * MemoryLink subobjects are resolved. Empty or unresolvable MemoryIDs
+         * are ignored - this includes MemoryIDs whose Entity fields are not set.
+         * If the data associated with a MemoryID could not be retrieved or
+         * its type does not match the template type of the MemoryLink,
+         * it is ignored.
+         *
+         * @param input the query to perform
+         * @param mns the MemoryNameSystem to use when resolving MemoryLinks
+         * @param recursionDepth how many layers of MemoryLinks to resolve
+         */
+        QueryResult query(const QueryInput& input,
+                          armem::client::MemoryNameSystem& mns,
+                          int recursionDepth = -1) const;
+        /**
+         * @sa Reader::query(const QueryInput&, armem::client::MemoryNameSystem, int)
+         */
+        armem::query::data::Result query(const armem::query::data::Input& input,
+                                         armem::client::MemoryNameSystem& mns,
+                                         int recursionDepth = -1) const;
+
+        /**
+         * @sa Reader::query(const QueryInput&, armem::client::MemoryNameSystem, int)
+         */
+        QueryResult query(armem::query::data::MemoryQueryPtr query,
+                          armem::client::MemoryNameSystem& mns,
+                          int recursionDepth = -1) const;
+        /**
+         * @sa Reader::query(const QueryInput&, armem::client::MemoryNameSystem, int)
+         */
+        QueryResult query(const armem::query::data::MemoryQuerySeq& queries,
+                          armem::client::MemoryNameSystem& mns,
+                          int recursionDepth = -1) const;
+
+        /**
+         * @sa Reader::query(const QueryInput&, armem::client::MemoryNameSystem, int)
+         */
+        QueryResult query(const QueryBuilder& queryBuilder,
+                          armem::client::MemoryNameSystem& mns,
+                          int recursionDepth = -1) const;
+
 
         /**
-         * @brief Qeury a specific set of memory IDs.
+         * @brief Query a specific set of memory IDs.
          *
          * Each ID can refer to an entity, a snapshot or an instance. When not
          * referring to an entity instance, the latest snapshot and first
@@ -116,10 +168,16 @@ namespace armarx::armem::client
             return bool(memoryPrx);
         }
 
+    private:
+        static void resolveMemoryLinks(armem::wm::EntityInstance& instance,
+                                       armem::wm::Memory& input,
+                                       armem::client::MemoryNameSystem& mns,
+                                       int recursionDepth);
+
     public:
 
         server::ReadingMemoryInterfacePrx memoryPrx;
 
     };
 
-}
+} // namespace armarx::armem::client
diff --git a/source/RobotAPI/libraries/armem/client/Writer.cpp b/source/RobotAPI/libraries/armem/client/Writer.cpp
index 7ffeeca7a71a8ea312565b4e96cf3833300f0fcd..3c4edce62f6cbc0b2d2dc908e673fbe06afe6f53 100644
--- a/source/RobotAPI/libraries/armem/client/Writer.cpp
+++ b/source/RobotAPI/libraries/armem/client/Writer.cpp
@@ -1,6 +1,7 @@
 #include "Writer.h"
 
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+#include <ArmarXCore/core/time/ice_conversions.h>
 
 #include "../error.h"
 
@@ -111,10 +112,10 @@ namespace armarx::armem::client
          * anyway.
          */
 
-        const Time timeSent = armem::Time::now();
+        const Time timeSent = armem::Time::Now();
         for (data::EntityUpdate& update : commit.updates)
         {
-            update.timeSentMicroSeconds = timeSent.toMicroSeconds();
+            toIce(update.timeSent, timeSent);
         }
 
         data::CommitResult result;
diff --git a/source/RobotAPI/libraries/armem/client/query/selectors.cpp b/source/RobotAPI/libraries/armem/client/query/selectors.cpp
index 0ea7000b229edce38d8a797d3b542d180c2de17a..791a6190c9d344c35113fdb388c8d98f9cdf931b 100644
--- a/source/RobotAPI/libraries/armem/client/query/selectors.cpp
+++ b/source/RobotAPI/libraries/armem/client/query/selectors.cpp
@@ -1,6 +1,9 @@
 #include "selectors.h"
-#include <RobotAPI/libraries/armem/core/ice_conversions.h>
 
+#include <ArmarXCore/core/time/ice_conversions.h>
+
+#include <RobotAPI/libraries/armem/core/ice_conversions.h>
+#include <RobotAPI/libraries/armem/core/ice_conversions_templates.h>
 #include <RobotAPI/libraries/armem/core/wm/ice_conversions.h>
 
 
@@ -24,7 +27,7 @@ namespace armarx::armem::client::query
     SnapshotSelector& SnapshotSelector::latest()
     {
         auto& q = _addQuery<dq::entity::Single>();
-        q.timestamp = -1;
+        toIce(q.timestamp, Time::Invalid());
         return *this;
     }
 
diff --git a/source/RobotAPI/libraries/armem/client/util/MemoryListener.cpp b/source/RobotAPI/libraries/armem/client/util/MemoryListener.cpp
index a305de2cbcdd9aa040e6f8b14eb33a905519ec05..bc180c726f4d573fe69a3a77bfba2b0be12fe2c8 100644
--- a/source/RobotAPI/libraries/armem/client/util/MemoryListener.cpp
+++ b/source/RobotAPI/libraries/armem/client/util/MemoryListener.cpp
@@ -5,6 +5,7 @@
 #include <ArmarXCore/core/exceptions/LocalException.h>
 #include <ArmarXCore/core/logging/Logging.h>
 #include <RobotAPI/libraries/armem/core/ice_conversions.h>
+#include <RobotAPI/libraries/armem/core/ice_conversions_templates.h>
 #include <RobotAPI/libraries/armem/core/error.h>
 
 
diff --git a/source/RobotAPI/libraries/armem/core/Commit.h b/source/RobotAPI/libraries/armem/core/Commit.h
index 433703a5ac8bc3f05727cffa86be073781c4dcf1..8a1da207528940d0db22dd004faae5b15e3d07f3 100644
--- a/source/RobotAPI/libraries/armem/core/Commit.h
+++ b/source/RobotAPI/libraries/armem/core/Commit.h
@@ -36,7 +36,7 @@ namespace armarx::armem
          * @brief Time when this entity update was created (e.g. time of image recording).
          * This is the key of the entity's history.
          */
-        Time timeCreated = Time::microSeconds(-1);
+        Time timeCreated = Time::Invalid();
 
 
         // OPTIONAL
@@ -52,14 +52,14 @@ namespace armarx::armem
          *
          * Set automatically when sending the commit.
          */
-        Time timeSent = Time::microSeconds(-1);
+        Time timeSent = Time::Invalid();
 
         /**
          * @brief Time when this update arrived at the memory server.
          *
          * Set by memory server on arrival.
          */
-        Time timeArrived = Time::microSeconds(-1);
+        Time timeArrived = Time::Invalid();
 
 
         friend std::ostream& operator<<(std::ostream& os, const EntityUpdate& rhs);
@@ -74,7 +74,7 @@ namespace armarx::armem
         bool success = false;
 
         MemoryID snapshotID;
-        Time timeArrived = Time::microSeconds(-1);
+        Time timeArrived = Time::Invalid();
 
         std::string errorMessage;
 
diff --git a/source/RobotAPI/libraries/armem/core/MemoryID.cpp b/source/RobotAPI/libraries/armem/core/MemoryID.cpp
index f3b8c662ddef099b18dc09e03a81f21bd7de2bde..c2a59ff9cb7e653f74153ced3eb73d00ed7572c4 100644
--- a/source/RobotAPI/libraries/armem/core/MemoryID.cpp
+++ b/source/RobotAPI/libraries/armem/core/MemoryID.cpp
@@ -13,6 +13,7 @@
 namespace armarx::armem
 {
 
+    // This is constant, not a variable.
     const std::string MemoryID::delimiter = "/";
 
 
@@ -251,7 +252,7 @@ namespace armarx::armem
         {
             return getEntitySnapshotID();
         }
-        if (timestamp != Time::microSeconds(-1))
+        if (timestamp.isValid())
         {
             return getEntityID();
         }
@@ -350,7 +351,7 @@ namespace armarx::armem
 
     std::string MemoryID::timestampStr() const
     {
-        return hasTimestamp() ? std::to_string(timestamp.toMicroSeconds()) : "";
+        return hasTimestamp() ? std::to_string(timestamp.toMicroSecondsSinceEpoch()) : "";
     }
 
     std::string MemoryID::instanceIndexStr() const
@@ -358,9 +359,9 @@ namespace armarx::armem
         return hasInstanceIndex() ? std::to_string(instanceIndex) : "";
     }
 
-    IceUtil::Time MemoryID::timestampFromStr(const std::string& string)
+    Time MemoryID::timestampFromStr(const std::string& string)
     {
-        return Time::microSeconds(parseInteger(string, "timestamp"));
+        return Time(Duration::MicroSeconds(parseInteger(string, "timestamp")));
     }
 
     int MemoryID::instanceIndexFromStr(const std::string& string)
@@ -416,7 +417,7 @@ namespace armarx::armem
     {
         if (string.empty())
         {
-            return -1;
+            return std::numeric_limits<long>::min();
         }
         try
         {
@@ -506,7 +507,7 @@ namespace armarx::armem
             return false;
         }
 
-        if (general.timestamp.toMicroSeconds() < 0)
+        if (general.timestamp.isInvalid())
         {
             return true;
         }
diff --git a/source/RobotAPI/libraries/armem/core/MemoryID.h b/source/RobotAPI/libraries/armem/core/MemoryID.h
index d583e752258d69e8271e30be2a2d091493aa18cc..64850ddefa9d2e92cc924e33d765317a8895c067 100644
--- a/source/RobotAPI/libraries/armem/core/MemoryID.h
+++ b/source/RobotAPI/libraries/armem/core/MemoryID.h
@@ -1,5 +1,6 @@
 #pragma once
 
+#include <functional>  // for std::hash
 #include <string>
 #include <vector>
 
@@ -52,7 +53,7 @@ namespace armarx::armem
         std::string coreSegmentName = "";
         std::string providerSegmentName = "";
         std::string entityName = "";
-        Time timestamp = Time::microSeconds(-1);
+        Time timestamp = Time::Invalid();
         int instanceIndex = -1;
 
 
@@ -67,7 +68,7 @@ namespace armarx::armem
                  const std::string& coreSegmentName,
                  const std::string& providerSegmentName = "",
                  const std::string& entityName = "",
-                 Time timestamp = Time::microSeconds(-1),
+                 Time timestamp = Time::Invalid(),
                  int instanceIndex = -1);
 
 
@@ -97,27 +98,27 @@ namespace armarx::armem
 
         bool hasMemoryName() const
         {
-            return !memoryName.empty();
+            return not memoryName.empty();
         }
         bool hasCoreSegmentName() const
         {
-            return !coreSegmentName.empty();
+            return not coreSegmentName.empty();
         }
         bool hasProviderSegmentName() const
         {
-            return !providerSegmentName.empty();
+            return not providerSegmentName.empty();
         }
         bool hasEntityName() const
         {
-            return !entityName.empty();
+            return not entityName.empty();
         }
         bool hasTimestamp() const
         {
-            return timestamp.toMicroSeconds() >= 0;
+            return timestamp.isValid();
         }
         void clearTimestamp()
         {
-            timestamp = Time::microSeconds(-1);
+            timestamp = Time::Invalid();
         }
         bool hasInstanceIndex() const
         {
@@ -208,7 +209,7 @@ namespace armarx::armem
         bool operator ==(const MemoryID& other) const;
         inline bool operator !=(const MemoryID& other) const
         {
-            return !(*this == other);
+            return not (*this == other);
         }
 
         bool operator< (const MemoryID& rhs) const;
@@ -218,11 +219,11 @@ namespace armarx::armem
         }
         inline bool operator<=(const MemoryID& rhs) const
         {
-            return !operator> (rhs);
+            return not operator> (rhs);
         }
         inline bool operator>=(const MemoryID& rhs) const
         {
-            return !operator< (rhs);
+            return not operator< (rhs);
         }
 
         friend std::ostream& operator<<(std::ostream& os, const MemoryID id);
diff --git a/source/RobotAPI/libraries/armem/core/Time.cpp b/source/RobotAPI/libraries/armem/core/Time.cpp
index 25bd9a8dc09fcda3c1f86d765e1bbd74f87c6525..80933ac0bd178a17f49c50fe8c89931177d496d5 100644
--- a/source/RobotAPI/libraries/armem/core/Time.cpp
+++ b/source/RobotAPI/libraries/armem/core/Time.cpp
@@ -11,12 +11,12 @@ namespace armarx
     std::string armem::toStringMilliSeconds(const Time& time, int decimals)
     {
         std::stringstream ss;
-        ss << time.toMilliSeconds();
+        ss << time.toMicroSecondsSinceEpoch() / 1000;
         if (decimals > 0)
         {
             int div = int(std::pow(10, 3 - decimals));
             ss << "." << std::setfill('0') << std::setw(decimals)
-               << (time.toMicroSeconds() % 1000) / div;
+               << (time.toMicroSecondsSinceEpoch() % 1000) / div;
         }
         ss << " ms";
         return ss.str();
@@ -27,7 +27,7 @@ namespace armarx
     {
         static const char* mu = "\u03BC";
         std::stringstream ss;
-        ss << time.toMicroSeconds() << " " << mu << "s";
+        ss << time.toMicroSecondsSinceEpoch() << " " << mu << "s";
         return ss.str();
     }
 
@@ -40,7 +40,7 @@ namespace armarx
         {
             int div = int(std::pow(10, 6 - decimals));
             ss << "." << std::setfill('0') << std::setw(decimals)
-               << (time.toMicroSeconds() % int(1e6)) / div;
+               << (time.toMicroSecondsSinceEpoch() % int(1e6)) / div;
         }
 
         return ss.str();
@@ -49,7 +49,7 @@ namespace armarx
 
     armem::Time armem::timeFromStringMicroSeconds(const std::string& microSeconds)
     {
-        return Time::microSeconds(std::stol(microSeconds));
+        return Time(Duration::MicroSeconds(std::stol(microSeconds)), ClockType::Virtual);
     }
 
 }
diff --git a/source/RobotAPI/libraries/armem/core/Time.h b/source/RobotAPI/libraries/armem/core/Time.h
index f76f7657dda6e14a9c35bb4ad5edf58471680144..b4e100e91334abeedac42b62efbcfa79ad6b40c6 100644
--- a/source/RobotAPI/libraries/armem/core/Time.h
+++ b/source/RobotAPI/libraries/armem/core/Time.h
@@ -2,13 +2,14 @@
 
 #include <string>
 
-#include <IceUtil/Time.h>
+#include <ArmarXCore/core/time/DateTime.h>
+#include <ArmarXCore/core/time/Duration.h>
+
+#include "forward_declarations.h"
 
 
 namespace armarx::armem
 {
-    using Time = IceUtil::Time;
-    using Duration = IceUtil::Time;
 
     /**
      * @brief Returns `time` as e.g. "123456789.012 ms".
diff --git a/source/RobotAPI/libraries/armem/core/aron_conversions.cpp b/source/RobotAPI/libraries/armem/core/aron_conversions.cpp
index 4eafef35a33f746b5c8b898598ac6273cce7030e..62ff85270b07c63907d6a264eee2f73fb0d3c472 100644
--- a/source/RobotAPI/libraries/armem/core/aron_conversions.cpp
+++ b/source/RobotAPI/libraries/armem/core/aron_conversions.cpp
@@ -1,5 +1,6 @@
 #include "aron_conversions.h"
 
+#include <RobotAPI/libraries/aron/common/aron_conversions/armarx.h>
 #include <RobotAPI/libraries/armem/core/MemoryID.h>
 #include <RobotAPI/libraries/armem/aron/MemoryID.aron.generated.h>
 
@@ -10,7 +11,7 @@ void armarx::armem::fromAron(const arondto::MemoryID& dto, MemoryID& bo)
     bo.coreSegmentName = dto.coreSegmentName;
     bo.providerSegmentName = dto.providerSegmentName;
     bo.entityName = dto.entityName;
-    bo.timestamp = dto.timestamp;
+    fromAron(dto.timestamp, bo.timestamp);
     bo.instanceIndex = dto.instanceIndex;
 }
 
@@ -20,7 +21,7 @@ void armarx::armem::toAron(arondto::MemoryID& dto, const MemoryID& bo)
     dto.coreSegmentName = bo.coreSegmentName;
     dto.providerSegmentName = bo.providerSegmentName;
     dto.entityName = bo.entityName;
-    dto.timestamp = bo.timestamp;
+    toAron(dto.timestamp, bo.timestamp);
     dto.instanceIndex = bo.instanceIndex;
 }
 
diff --git a/source/RobotAPI/libraries/armem/core/aron_conversions.h b/source/RobotAPI/libraries/armem/core/aron_conversions.h
index 064aafe8d7bd4ea964aa1e020ca692d8eed45bf2..f0b1a26591333440dd41dcd5471a30c061e48f38 100644
--- a/source/RobotAPI/libraries/armem/core/aron_conversions.h
+++ b/source/RobotAPI/libraries/armem/core/aron_conversions.h
@@ -1,12 +1,16 @@
 #pragma once
 
-#include "forward_declarations.h"
-
 #include <ostream>
 
+#include "forward_declarations.h"
+
 
 namespace armarx::armem
 {
+    // Implemented in <RobotAPI/libraries/aron/common/aron_conversions/armarx.h>
+    // void fromAron(const IceUtil::Time& dto, Time& bo);
+    // void toAron(IceUtil::Time& dto, const Time& bo);
+
     void fromAron(const arondto::MemoryID& dto, MemoryID& bo);
     void toAron(arondto::MemoryID& dto, const MemoryID& bo);
 }
diff --git a/source/RobotAPI/libraries/armem/core/base/EntityBase.h b/source/RobotAPI/libraries/armem/core/base/EntityBase.h
index 9b34e11bd3d53e896f38cd2c3301c2c35dcdffd9..7395f1447d568aebfa7b1bcbf10325c0ab6728ec 100644
--- a/source/RobotAPI/libraries/armem/core/base/EntityBase.h
+++ b/source/RobotAPI/libraries/armem/core/base/EntityBase.h
@@ -311,7 +311,7 @@ namespace armarx::armem::base
          */
         const EntitySnapshotT* findLatestSnapshotBeforeOrAt(const Time& time) const
         {
-            return findLatestSnapshotBefore(time + Time::microSeconds(1));
+            return findLatestSnapshotBefore(time + Duration::MicroSeconds(1));
         }
 
         /**
@@ -339,7 +339,7 @@ namespace armarx::armem::base
          */
         const EntitySnapshotT* findFirstSnapshotAfter(const Time& time) const
         {
-            return findFirstSnapshotAfter(time - Time::microSeconds(1));
+            return findFirstSnapshotAfter(time - Duration::MicroSeconds(1));
         }
 
 
@@ -418,7 +418,7 @@ namespace armarx::armem::base
         template <class FunctionT>
         void forEachSnapshotBeforeOrAt(const Time& time, FunctionT&& func) const
         {
-            getSnapshotsBefore(time + Time::microSeconds(1), func);
+            getSnapshotsBefore(time + Duration::MicroSeconds(1), func);
         }
 
 
@@ -432,9 +432,9 @@ namespace armarx::armem::base
         void forEachSnapshotInTimeRange(const Time& min, const Time& max, FunctionT&& func) const
         {
             // Returns an iterator pointing to the first element that is not less than (i.e. greater or equal to) key.
-            auto begin = min.toMicroSeconds() > 0 ? this->_container.lower_bound(min) : this->_container.begin();
+            auto begin = min.toMicroSecondsSinceEpoch() > 0 ? this->_container.lower_bound(min) : this->_container.begin();
             // Returns an iterator pointing to the first element that is *greater than* key.
-            auto end = max.toMicroSeconds() > 0 ? this->_container.upper_bound(max) : this->_container.end();
+            auto end = max.toMicroSecondsSinceEpoch() > 0 ? this->_container.upper_bound(max) : this->_container.end();
 
             for (auto it = begin; it != end && it != this->_container.end(); ++it)
             {
diff --git a/source/RobotAPI/libraries/armem/core/base/ice_conversions.cpp b/source/RobotAPI/libraries/armem/core/base/ice_conversions.cpp
index 1e19f25a7b08671b1e3f65ea2649f056a107361a..a71881a57851833f91debb68c1f026f2b1fb7859 100644
--- a/source/RobotAPI/libraries/armem/core/base/ice_conversions.cpp
+++ b/source/RobotAPI/libraries/armem/core/base/ice_conversions.cpp
@@ -1,5 +1,7 @@
 #include "ice_conversions.h"
 
+#include <ArmarXCore/core/time/ice_conversions.h>
+
 #include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h>
 #include <RobotAPI/libraries/aron/core/type/variant/container/Object.h>
 
@@ -50,19 +52,20 @@ namespace armarx::armem::base
 }
 namespace armarx::armem
 {
+
     void base::toIce(data::EntityInstanceMetadata& ice, const EntityInstanceMetadata& metadata)
     {
         ice.confidence = metadata.confidence;
-        toIce(ice.timeArrivedMicroSeconds, metadata.timeArrived);
-        toIce(ice.timeCreatedMicroSeconds, metadata.timeCreated);
-        toIce(ice.timeSentMicroSeconds, metadata.timeSent);
+        toIce(ice.timeArrived, metadata.timeArrived);
+        toIce(ice.timeCreated, metadata.timeCreated);
+        toIce(ice.timeSent, metadata.timeSent);
     }
     void base::fromIce(const data::EntityInstanceMetadata& ice, EntityInstanceMetadata& metadata)
     {
         metadata.confidence = ice.confidence;
-        fromIce(ice.timeArrivedMicroSeconds, metadata.timeArrived);
-        fromIce(ice.timeCreatedMicroSeconds, metadata.timeCreated);
-        fromIce(ice.timeSentMicroSeconds, metadata.timeSent);
+        fromIce(ice.timeArrived, metadata.timeArrived);
+        fromIce(ice.timeCreated, metadata.timeCreated);
+        fromIce(ice.timeSent, metadata.timeSent);
     }
 
 
diff --git a/source/RobotAPI/libraries/armem/core/base/ice_conversions.h b/source/RobotAPI/libraries/armem/core/base/ice_conversions.h
index 21316623c9484f46db177d122642170822561c13..b58e820917bd8784f355793c308a8f5fe4d0efdb 100644
--- a/source/RobotAPI/libraries/armem/core/base/ice_conversions.h
+++ b/source/RobotAPI/libraries/armem/core/base/ice_conversions.h
@@ -15,6 +15,7 @@
 #include <RobotAPI/interface/armem/memory.h>
 
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+#include <ArmarXCore/core/time/ice_conversions.h>
 
 
 namespace armarx::armem::base::detail
@@ -86,7 +87,7 @@ namespace armarx::armem::base
         ice.history.clear();
         entity.forEachSnapshot([&ice](const auto & snapshot)
         {
-            armem::toIce(ice.history[armem::toIce<long>(snapshot.time())], snapshot);
+            armem::toIce(ice.history[armem::toIce<dto::Time>(snapshot.time())], snapshot);
         });
     }
     template <class ...Args>
diff --git a/source/RobotAPI/libraries/armem/core/forward_declarations.h b/source/RobotAPI/libraries/armem/core/forward_declarations.h
index 04cfbfae26533af158ad52c6c39fd49c837f1afb..283988be5244c8b9f49af8ea474faa6713439183 100644
--- a/source/RobotAPI/libraries/armem/core/forward_declarations.h
+++ b/source/RobotAPI/libraries/armem/core/forward_declarations.h
@@ -1,15 +1,17 @@
 #pragma once
 
+#include <ArmarXCore/core/time/forward_declarations.h>
 
-namespace IceUtil
+
+namespace IceInternal
 {
-    class Time;
+    template<typename T> class Handle;
 }
 
 namespace armarx::armem
 {
-    using Time = IceUtil::Time;
-    using Duration = IceUtil::Time;
+    using Time = armarx::core::time::DateTime;
+    using Duration = armarx::core::time::Duration;
 
     class MemoryID;
     class Commit;
@@ -17,6 +19,11 @@ namespace armarx::armem
     class CommitResult;
     class EntityUpdateResult;
 }
+namespace armarx::armem::dto
+{
+    using Time = armarx::core::time::dto::DateTime;
+    using Duration = armarx::core::time::dto::Duration;
+}
 
 namespace armarx::armem::arondto
 {
@@ -62,3 +69,22 @@ namespace armarx::armem::server::wm
     class Memory;
 }
 
+namespace armarx::armem::data
+{
+    struct MemoryID;
+    struct Commit;
+    struct CommitResult;
+    struct EntityUpdate;
+    struct EntityUpdateResult;
+}
+
+namespace armarx::armem::actions
+{
+    class Menu;
+}
+
+namespace armarx::armem::actions::data
+{
+    class Menu;
+    using MenuPtr = ::IceInternal::Handle<Menu>;
+}
diff --git a/source/RobotAPI/libraries/armem/core/ice_conversions.cpp b/source/RobotAPI/libraries/armem/core/ice_conversions.cpp
index 20df9176bb562ab9025c001451d6fef23793d504..1dd76ae471eab7f3041b7ea835891f53d6df3f3f 100644
--- a/source/RobotAPI/libraries/armem/core/ice_conversions.cpp
+++ b/source/RobotAPI/libraries/armem/core/ice_conversions.cpp
@@ -1,17 +1,20 @@
 #include "ice_conversions.h"
 
+#include <ArmarXCore/core/time/ice_conversions.h>
+
 #include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h>
 
+#include <RobotAPI/interface/armem/actions.h>
+#include <RobotAPI/interface/armem/commit.h>
+#include <RobotAPI/interface/armem/memory.h>
 
-void IceUtil::toIce(long& ice, const IceUtil::Time& time)
-{
-    ice = time.toMicroSeconds();
-}
+#include "ice_conversions_templates.h"
+
+#include "actions.h"
+#include "Commit.h"
+#include "MemoryID.h"
+#include "Time.h"
 
-void IceUtil::fromIce(const long& ice, IceUtil::Time& time)
-{
-    time = Time::microSeconds(ice);
-}
 
 namespace armarx
 {
@@ -22,7 +25,7 @@ namespace armarx
         ice.coreSegmentName = id.coreSegmentName;
         ice.providerSegmentName = id.providerSegmentName;
         ice.entityName = id.entityName;
-        toIce(ice.timestampMicroSeconds, id.timestamp);
+        toIce(ice.timestamp, id.timestamp);
         ice.instanceIndex = id.instanceIndex;
     }
 
@@ -32,7 +35,7 @@ namespace armarx
         id.coreSegmentName = ice.coreSegmentName;
         id.providerSegmentName = ice.providerSegmentName;
         id.entityName = ice.entityName;
-        fromIce(ice.timestampMicroSeconds, id.timestamp);
+        fromIce(ice.timestamp, id.timestamp);
         id.instanceIndex = ice.instanceIndex;
     }
 
@@ -85,10 +88,10 @@ namespace armarx
         std::transform(ice.instancesData.begin(), ice.instancesData.end(), std::back_inserter(update.instancesData),
                        aron::data::Dict::FromAronDictDTO);
 
-        update.timeCreated = Time::microSeconds(ice.timeCreatedMicroSeconds);
+        fromIce(ice.timeCreated, update.timeCreated);
 
         update.confidence = ice.confidence;
-        update.timeSent = Time::microSeconds(ice.timeSentMicroSeconds);
+        fromIce(ice.timeSent, update.timeSent);
     }
 
     void armem::toIce(data::EntityUpdate& ice, const EntityUpdate& update)
@@ -100,17 +103,17 @@ namespace armarx
         std::transform(update.instancesData.begin(), update.instancesData.end(), std::back_inserter(ice.instancesData),
                        aron::data::Dict::ToAronDictDTO);
 
-        ice.timeCreatedMicroSeconds = update.timeCreated.toMicroSeconds();
+        toIce(ice.timeCreated, update.timeCreated);
 
         ice.confidence = update.confidence;
-        ice.timeSentMicroSeconds = update.timeSent.toMicroSeconds();
+        toIce(ice.timeSent, update.timeSent);
     }
 
     void armem::fromIce(const data::EntityUpdateResult& ice, EntityUpdateResult& result)
     {
         result.success = ice.success;
         fromIce(ice.snapshotID, result.snapshotID);
-        result.timeArrived = Time::microSeconds(ice.timeArrivedMicroSeconds);
+        fromIce(ice.timeArrived, result.timeArrived);
         result.errorMessage = ice.errorMessage;
     }
 
@@ -118,7 +121,7 @@ namespace armarx
     {
         ice.success = result.success;
         toIce(ice.snapshotID, result.snapshotID);
-        ice.timeArrivedMicroSeconds = result.timeArrived.toMicroSeconds();
+        toIce(ice.timeArrived, result.timeArrived);
         ice.errorMessage = result.errorMessage;
     }
 
diff --git a/source/RobotAPI/libraries/armem/core/ice_conversions.h b/source/RobotAPI/libraries/armem/core/ice_conversions.h
index a8ef35e7938f07f14a81b8ecb731e2470b395c97..2a4daf725a32bb9ca12a5865be8207b87076871a 100644
--- a/source/RobotAPI/libraries/armem/core/ice_conversions.h
+++ b/source/RobotAPI/libraries/armem/core/ice_conversions.h
@@ -1,23 +1,6 @@
 #pragma once
 
-#include <RobotAPI/interface/armem/actions.h>
-#include <RobotAPI/interface/armem/commit.h>
-#include <RobotAPI/interface/armem/memory.h>
-
-#include "ice_conversions_templates.h"
-
-#include "actions.h"
-#include "Commit.h"
-#include "MemoryID.h"
-#include "Time.h"
-
-
-namespace IceUtil
-{
-    // Define in original namespace to allow ADL.
-    void toIce(long& ice, const Time& time);
-    void fromIce(const long& ice, Time& time);
-}
+#include "forward_declarations.h"
 
 
 namespace armarx::armem
@@ -48,5 +31,6 @@ namespace armarx::armem
 
     void fromIce(const actions::data::MenuPtr& ice, actions::Menu& menu);
     void toIce(actions::data::MenuPtr& ice, const actions::Menu& menu);
+
 }
 
diff --git a/source/RobotAPI/libraries/armem/core/json_conversions.cpp b/source/RobotAPI/libraries/armem/core/json_conversions.cpp
index e4da9d89b5e04351e5e528132406a962470364e3..2a6f2a1f6cbff1d7d348d92f9ea7b482b6c25b3b 100644
--- a/source/RobotAPI/libraries/armem/core/json_conversions.cpp
+++ b/source/RobotAPI/libraries/armem/core/json_conversions.cpp
@@ -9,7 +9,7 @@ void armarx::armem::to_json(nlohmann::json& j, const MemoryID& bo)
     j["coreSegmentName"] = bo.coreSegmentName;
     j["providerSegmentName"] = bo.providerSegmentName;
     j["entityName"] = bo.entityName;
-    j["timestamp_usec"] = bo.timestamp.toMicroSeconds();
+    j["timestamp_usec"] = bo.timestamp.toMicroSecondsSinceEpoch();
     j["timestamp_datetime"] = toDateTimeMilliSeconds(bo.timestamp);
     j["instanceIndex"] = bo.instanceIndex;
 }
@@ -20,7 +20,7 @@ void armarx::armem::from_json(const nlohmann::json& j, MemoryID& bo)
     j.at("coreSegmentName").get_to(bo.coreSegmentName);
     j.at("providerSegmentName").get_to(bo.providerSegmentName);
     j.at("entityName").get_to(bo.entityName);
-    bo.timestamp = Time::microSeconds(j.at("timestamp_usec").get<int64_t>());
+    bo.timestamp = Time(Duration::MicroSeconds(j.at("timestamp_usec").get<int64_t>()));
     // j.at("timestamp_datetime").get_to(toDateTimeMilliSeconds(bo.timestamp));
     j.at("instanceIndex").get_to(bo.instanceIndex);
 }
diff --git a/source/RobotAPI/libraries/armem/core/wm/aron_conversions.cpp b/source/RobotAPI/libraries/armem/core/wm/aron_conversions.cpp
index dacedd5e05177028fea42114a3dd02d4b609ad9a..d24ce36b544670f5e24e72177f64b839be52fc0d 100644
--- a/source/RobotAPI/libraries/armem/core/wm/aron_conversions.cpp
+++ b/source/RobotAPI/libraries/armem/core/wm/aron_conversions.cpp
@@ -23,13 +23,13 @@ void armarx::armem::from_aron(const aron::data::DictPtr& metadata, const aron::d
     e.data() = data;
 
     auto timeCreated = aron::data::Long::DynamicCastAndCheck(metadata->getElement(DATA_WRAPPER_TIME_CREATED_FIELD));
-    m.timeCreated = Time::microSeconds(timeCreated->toAronLongDTO()->value);
+    m.timeCreated = Time(Duration::MicroSeconds(timeCreated->toAronLongDTO()->value));
 
     auto timeSent = aron::data::Long::DynamicCastAndCheck(metadata->getElement(DATA_WRAPPER_TIME_SENT_FIELD));
-    m.timeSent = Time::microSeconds(timeSent->toAronLongDTO()->value);
+    m.timeSent = Time(Duration::MicroSeconds(timeSent->toAronLongDTO()->value));
 
     auto timeArrived = aron::data::Long::DynamicCastAndCheck(metadata->getElement(DATA_WRAPPER_TIME_ARRIVED_FIELD));
-    m.timeArrived = Time::microSeconds(timeArrived->toAronLongDTO()->value);
+    m.timeArrived = Time(Duration::MicroSeconds(timeArrived->toAronLongDTO()->value));
 
     auto confidence = aron::data::Double::DynamicCastAndCheck(metadata->getElement(DATA_WRAPPER_CONFIDENCE_FIELD));
     m.confidence = static_cast<float>(confidence->toAronDoubleDTO()->value);
@@ -42,20 +42,20 @@ void armarx::armem::to_aron(aron::data::DictPtr& metadata, aron::data::DictPtr&
     metadata = std::make_shared<aron::data::Dict>();
 
     auto timeWrapped = std::make_shared<aron::data::Long>();
-    timeWrapped->setValue(Time::now().toMicroSeconds());
+    timeWrapped->setValue(Time::Now().toMicroSecondsSinceEpoch());
     metadata->addElement(DATA_WRAPPER_TIME_STORED_FIELD, timeWrapped);
 
     const wm::EntityInstanceMetadata& m = e.metadata();
     auto timeCreated = std::make_shared<aron::data::Long>();
-    timeCreated->setValue(m.timeCreated.toMicroSeconds());
+    timeCreated->setValue(m.timeCreated.toMicroSecondsSinceEpoch());
     metadata->addElement(DATA_WRAPPER_TIME_CREATED_FIELD, timeCreated);
 
     auto timeSent = std::make_shared<aron::data::Long>();
-    timeSent->setValue(m.timeSent.toMicroSeconds());
+    timeSent->setValue(m.timeSent.toMicroSecondsSinceEpoch());
     metadata->addElement(DATA_WRAPPER_TIME_SENT_FIELD, timeSent);
 
     auto timeArrived = std::make_shared<aron::data::Long>();
-    timeArrived->setValue(m.timeArrived.toMicroSeconds());
+    timeArrived->setValue(m.timeArrived.toMicroSecondsSinceEpoch());
     metadata->addElement(DATA_WRAPPER_TIME_ARRIVED_FIELD, timeArrived);
 
     auto confidence = std::make_shared<aron::data::Double>();
diff --git a/source/RobotAPI/libraries/armem/core/wm/ice_conversions.cpp b/source/RobotAPI/libraries/armem/core/wm/ice_conversions.cpp
index ba6c9782e0e2663ee9395fde31956d5fdbfc2ad2..826bf6d9f2f980cd99bbd35a38a2357f585b5f79 100644
--- a/source/RobotAPI/libraries/armem/core/wm/ice_conversions.cpp
+++ b/source/RobotAPI/libraries/armem/core/wm/ice_conversions.cpp
@@ -1,5 +1,6 @@
 #include "ice_conversions.h"
 
+#include <RobotAPI/libraries/armem/core/ice_conversions.h>
 #include <RobotAPI/libraries/armem/core/base/ice_conversions.h>
 
 
diff --git a/source/RobotAPI/libraries/armem/mns/Registry.cpp b/source/RobotAPI/libraries/armem/mns/Registry.cpp
index b8b2d02c807750aad2cb36c28cd55013b2a0b496..ad3a8e54a3a292f8dfc8dd72ac72b2a7b5564041 100644
--- a/source/RobotAPI/libraries/armem/mns/Registry.cpp
+++ b/source/RobotAPI/libraries/armem/mns/Registry.cpp
@@ -53,7 +53,7 @@ namespace armarx::armem::mns
         ServerInfo& info = it->second;
         info.name = input.name;
         info.server = input.server;
-        info.timeRegistered = armem::Time::now();
+        info.timeRegistered = armem::Time::Now();
         ARMARX_DEBUG << "Registered memory '" << info.name << "'.";
 
         result.success = true;
diff --git a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp
index d5318d3f7e457065493ba38cfcdc671a29e2b9fb..a838e9e0f173de79b0a89a9d14bf103757d5b531 100644
--- a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp
+++ b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp
@@ -10,8 +10,9 @@
 
 #include <RobotAPI/libraries/aron/core/Exception.h>
 
-#include <ArmarXCore/core/logging/Logging.h>
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+#include <ArmarXCore/core/logging/Logging.h>
+#include <ArmarXCore/core/time/ice_conversions.h>
 
 
 namespace armarx::armem::server
@@ -147,7 +148,7 @@ namespace armarx::armem::server
     MemoryToIceAdapter::commit(const data::Commit& commitIce)
     {
         ARMARX_TRACE;
-        return commit(commitIce, armem::Time::now());
+        return commit(commitIce, armem::Time::Now());
     }
 
 
diff --git a/source/RobotAPI/libraries/armem/server/RemoteGuiAronDataVisitor.h b/source/RobotAPI/libraries/armem/server/RemoteGuiAronDataVisitor.h
index dfe5299f7bf37780a034b83f807496c3636728de..d77f34eb719b46c117c64a2e9ec09cd43780dad9 100644
--- a/source/RobotAPI/libraries/armem/server/RemoteGuiAronDataVisitor.h
+++ b/source/RobotAPI/libraries/armem/server/RemoteGuiAronDataVisitor.h
@@ -3,6 +3,8 @@
 #include <sstream>
 #include <stack>
 
+#include <ArmarXCore/core/logging/Logging.h>
+
 #include <ArmarXGui/libraries/RemoteGui/Client/Widgets.h>
 
 #include <RobotAPI/libraries/aron/core/data/variant/All.h>
@@ -106,6 +108,12 @@ namespace armarx::armem::server
             this->addValueLabel(key, *aron::data::NDArray::DynamicCastAndCheck(array), "ND Array");
         }
 
+        void visitUnknown(const aron::data::VariantPtr& unknown) override
+        {
+            ARMARX_IMPORTANT << "Unknown data encountered: "
+                             << (unknown ? unknown->getFullName() : "nullptr");
+        }
+
 
     private:
         template <class DataT>
diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/filter/equalityFilter/EqualityFilter.cpp b/source/RobotAPI/libraries/armem/server/ltm/base/filter/equalityFilter/EqualityFilter.cpp
index ec52015e2c9ca62a3815dc3c9f62634078e2ba59..6ca0a944c2f2bd59681128ac22f86eaa58e50b51 100644
--- a/source/RobotAPI/libraries/armem/server/ltm/base/filter/equalityFilter/EqualityFilter.cpp
+++ b/source/RobotAPI/libraries/armem/server/ltm/base/filter/equalityFilter/EqualityFilter.cpp
@@ -7,7 +7,7 @@ namespace armarx::armem::server::ltm::filter
     bool SnapshotEqualityFilter::accept(const armem::wm::EntitySnapshot& e)
     {
         auto entityID = e.id().getEntityID();
-        auto genMs = e.time().toMilliSeconds();
+        auto genMs = e.time().toMilliSecondsSinceEpoch();
 
         long lastMs = 0;
         std::vector<aron::data::DictPtr> lastData;
diff --git a/source/RobotAPI/libraries/armem/server/ltm/base/filter/frequencyFilter/FrequencyFilter.cpp b/source/RobotAPI/libraries/armem/server/ltm/base/filter/frequencyFilter/FrequencyFilter.cpp
index 5650c836523a90c48d5cfb50b9b9e6ef8b307af9..a98aab7f756e42be8d995401964170e64c83e537 100644
--- a/source/RobotAPI/libraries/armem/server/ltm/base/filter/frequencyFilter/FrequencyFilter.cpp
+++ b/source/RobotAPI/libraries/armem/server/ltm/base/filter/frequencyFilter/FrequencyFilter.cpp
@@ -6,7 +6,7 @@ namespace armarx::armem::server::ltm::filter
 {
     bool MemoryFrequencyFilter::accept(const armem::wm::Memory& e)
     {
-        auto now = armem::Time::now().toMilliSeconds();
+        auto now = armem::Time::Now().toMilliSecondsSinceEpoch();
         if (waitingTimeInMs < 0 || (now - timestampLastCommitInMs) > waitingTimeInMs)
         {
             timestampLastCommitInMs = now;
@@ -18,7 +18,7 @@ namespace armarx::armem::server::ltm::filter
     bool SnapshotFrequencyFilter::accept(const armem::wm::EntitySnapshot& e)
     {
         auto entityID = e.id().getEntityID();
-        auto genMs = e.time().toMilliSeconds();
+        auto genMs = e.time().toMilliSecondsSinceEpoch();
 
         long lastMs = 0;
         if (timestampLastCommitInMs.count(entityID) > 0)
diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.cpp
index ac1703ac910796f139b81b39aa3504e1fa21b731..b64531211cff4343271561180dd312707f1f9847 100644
--- a/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.cpp
+++ b/source/RobotAPI/libraries/armem/server/ltm/disk/Entity.cpp
@@ -81,7 +81,8 @@ namespace armarx::armem::server::ltm::disk
 
     bool Entity::forEachSnapshotInTimeRange(const Time& min, const Time& max, std::function<void(EntitySnapshot&)>&& func) const
     {
-        auto f = [&](EntitySnapshot& e) {
+        auto f = [&](EntitySnapshot& e)
+        {
             auto ts = e.id().timestamp;
             if (ts >= min && ts <= max)
             {
@@ -94,7 +95,8 @@ namespace armarx::armem::server::ltm::disk
 
     bool Entity::forEachSnapshotBeforeOrAt(const Time& time, std::function<void(EntitySnapshot&)>&& func) const
     {
-        auto f = [&](EntitySnapshot& e) {
+        auto f = [&](EntitySnapshot& e)
+        {
             auto ts = e.id().timestamp;
             if (ts <= time)
             {
@@ -107,7 +109,8 @@ namespace armarx::armem::server::ltm::disk
 
     bool Entity::forEachSnapshotBefore(const Time& time, std::function<void(EntitySnapshot&)>&& func) const
     {
-        auto f = [&](EntitySnapshot& e) {
+        auto f = [&](EntitySnapshot& e)
+        {
             auto ts = e.id().timestamp;
             if (ts < time)
             {
@@ -138,7 +141,7 @@ namespace armarx::armem::server::ltm::disk
 
     std::shared_ptr<EntitySnapshot> Entity::findLatestSnapshot() const
     {
-        Time bestMatch = Time::microSeconds(-1);
+        Time bestMatch = Time::Invalid();
         auto f = [&](EntitySnapshot& e) {
             auto ts = e.id().timestamp;
             if (ts > bestMatch)
@@ -149,7 +152,7 @@ namespace armarx::armem::server::ltm::disk
 
         forEachSnapshot(std::move(f));
 
-        if (bestMatch == Time::microSeconds(-1))
+        if (bestMatch == Time::Invalid())
         {
             return nullptr;
         }
@@ -159,7 +162,7 @@ namespace armarx::armem::server::ltm::disk
 
     std::shared_ptr<EntitySnapshot> Entity::findLatestSnapshotBefore(const Time& time) const
     {
-        Time bestMatch = Time::microSeconds(-1);
+        Time bestMatch = Time::Invalid();
         auto f = [&](EntitySnapshot& e) {
             auto ts = e.id().timestamp;
             if (ts < time && ts > bestMatch)
@@ -170,7 +173,7 @@ namespace armarx::armem::server::ltm::disk
 
         forEachSnapshot(std::move(f));
 
-        if (bestMatch == Time::microSeconds(-1))
+        if (bestMatch == Time::Invalid())
         {
             return nullptr;
         }
@@ -180,7 +183,7 @@ namespace armarx::armem::server::ltm::disk
 
     std::shared_ptr<EntitySnapshot> Entity::findLatestSnapshotBeforeOrAt(const Time& time) const
     {
-        Time bestMatch = Time::microSeconds(-1);
+        Time bestMatch = Time::Invalid();
         auto f = [&](EntitySnapshot& e) {
             auto ts = e.id().timestamp;
             if (ts <= time && ts > bestMatch)
@@ -191,7 +194,7 @@ namespace armarx::armem::server::ltm::disk
 
         forEachSnapshot(std::move(f));
 
-        if (bestMatch == Time::microSeconds(-1))
+        if (bestMatch == Time::Invalid())
         {
             return nullptr;
         }
@@ -201,8 +204,9 @@ namespace armarx::armem::server::ltm::disk
 
     std::shared_ptr<EntitySnapshot> Entity::findFirstSnapshotAfter(const Time& time) const
     {
-        Time bestMatch = Time::microSeconds(std::numeric_limits<long>::max());
-        auto f = [&](EntitySnapshot& e) {
+        Time bestMatch { Duration::MicroSeconds(std::numeric_limits<long>::max()) };
+        auto f = [&](EntitySnapshot& e)
+        {
             auto ts = e.id().timestamp;
             if (ts > time && ts < bestMatch)
             {
@@ -212,7 +216,7 @@ namespace armarx::armem::server::ltm::disk
 
         forEachSnapshot(std::move(f));
 
-        if (bestMatch == Time::microSeconds(std::numeric_limits<long>::max()))
+        if (bestMatch == Time(Duration::MicroSeconds(std::numeric_limits<long>::max())))
         {
             return nullptr;
         }
@@ -222,8 +226,9 @@ namespace armarx::armem::server::ltm::disk
 
     std::shared_ptr<EntitySnapshot> Entity::findFirstSnapshotAfterOrAt(const Time& time) const
     {
-        Time bestMatch = Time::microSeconds(std::numeric_limits<long>::max());
-        auto f = [&](EntitySnapshot& e) {
+        Time bestMatch { Duration::MicroSeconds(std::numeric_limits<long>::max()) };
+        auto f = [&](EntitySnapshot& e)
+        {
             auto ts = e.id().timestamp;
             if (ts >= time && ts < bestMatch)
             {
@@ -233,7 +238,7 @@ namespace armarx::armem::server::ltm::disk
 
         forEachSnapshot(std::move(f));
 
-        if (bestMatch == Time::microSeconds(std::numeric_limits<long>::max()))
+        if (bestMatch == Time(Duration::MicroSeconds(std::numeric_limits<long>::max())))
         {
             return nullptr;
         }
@@ -252,7 +257,8 @@ namespace armarx::armem::server::ltm::disk
 
         e.id() = id();
 
-        forEachSnapshot([&e](auto& x) {
+        forEachSnapshot([&e](auto& x)
+        {
             if (!e.hasSnapshot(x.id().timestamp)) // we only load the references if the snapshot is not existant
             {
                 armem::wm::EntitySnapshot s;
diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/EntitySnapshot.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/EntitySnapshot.cpp
index a4aece1fdc87714ffa91452d44ef573dc31b3e1d..3d43ea8a0b3540afb32863937f4d8114bc9b09cf 100644
--- a/source/RobotAPI/libraries/armem/server/ltm/disk/EntitySnapshot.cpp
+++ b/source/RobotAPI/libraries/armem/server/ltm/disk/EntitySnapshot.cpp
@@ -14,7 +14,12 @@ namespace armarx::armem::server::ltm::disk
 {
     EntitySnapshot::EntitySnapshot(const std::filesystem::path& p, const MemoryID& id, const std::shared_ptr<Processors>& filters, const DiskMemoryItem::MemoryEncodingMode mode, const unsigned long e) :
         EntitySnapshotBase(id, filters),
-        DiskMemoryItem(p, EscapeSegmentName(id.memoryName), std::filesystem::path(EscapeSegmentName(id.coreSegmentName)) / EscapeSegmentName(id.providerSegmentName) / EscapeSegmentName(id.entityName) / std::to_string(id.timestamp.toSeconds() / 3600 /* hours */) / std::to_string(id.timestamp.toSeconds()) / id.timestampStr()),
+        DiskMemoryItem(p, EscapeSegmentName(id.memoryName),
+                       std::filesystem::path(EscapeSegmentName(id.coreSegmentName))
+                       / EscapeSegmentName(id.providerSegmentName)
+                       / EscapeSegmentName(id.entityName)
+                       / std::to_string(id.timestamp.toSecondsSinceEpoch() / 3600 /* hours */)
+                       / std::to_string(id.timestamp.toSecondsSinceEpoch()) / id.timestampStr()),
         currentMode(mode),
         currentExport(e)
     {
diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.cpp b/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.cpp
index eceff8d47b41654b64e78212e125aafd7196dfa3..daea3fcfc439326545a79ad00ac53e9133afa195 100644
--- a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.cpp
+++ b/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.cpp
@@ -1,5 +1,8 @@
 #include "filesystem_util.h"
 
+#include <RobotAPI/libraries/armem/core/error/ArMemError.h>
+
+
 namespace armarx::armem::server::ltm::disk
 {
     namespace filesystem::util
diff --git a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.h b/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.h
index b229a7b7f8ac115318fb142c7a6d0f065b344d86..78a8f4b1399b8112e204fb891277ed7d52d75ba6 100644
--- a/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.h
+++ b/source/RobotAPI/libraries/armem/server/ltm/disk/detail/util/filesystem_util.h
@@ -1,11 +1,10 @@
 #pragma once
 
-// STD / STL
 #include <filesystem>
-#include <iostream>
 #include <fstream>
+#include <iostream>
+#include <vector>
 
-#include "../../../../../core/error.h"
 
 namespace armarx::armem::server::ltm::disk
 {
diff --git a/source/RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.cpp b/source/RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.cpp
index d9df528842d11fd66ba38877318785d6c4dd5263..645b8aaa33fa6669135caeb49031e11ca2d8bb6c 100644
--- a/source/RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.cpp
+++ b/source/RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.cpp
@@ -7,6 +7,6 @@ namespace armarx::armem::server::query_proc::base
 {
     void detail::checkReferenceTimestampNonNegative(const Time& timestamp)
     {
-        ARMARX_CHECK_NONNEGATIVE(timestamp.toMicroSeconds()) << "Reference timestamp must be non-negative.";
+        ARMARX_CHECK_NONNEGATIVE(timestamp.toMicroSecondsSinceEpoch()) << "Reference timestamp must be non-negative.";
     }
 }
diff --git a/source/RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.h b/source/RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.h
index 6179467a77fa12246df6dd65c6ba9a766c5ef31f..73a77eddd0d7efab69dc16f37e544049e743fc43 100644
--- a/source/RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.h
+++ b/source/RobotAPI/libraries/armem/server/query_proc/base/EntityQueryProcessorBase.h
@@ -2,9 +2,12 @@
 
 #include "BaseQueryProcessorBase.h"
 
+#include <ArmarXCore/core/time/ice_conversions.h>
+
 #include <RobotAPI/libraries/armem/core/Time.h>
 #include <RobotAPI/libraries/armem/core/error.h>
 #include <RobotAPI/libraries/armem/core/ice_conversions.h>
+#include <RobotAPI/libraries/armem/core/ice_conversions_templates.h>
 
 #include <RobotAPI/interface/armem/query.h>
 
@@ -96,7 +99,7 @@ namespace armarx::armem::server::query_proc::base
                      const armem::query::data::entity::Single& query,
                      const EntityT& entity) const
         {
-            if (query.timestamp < 0)
+            if (query.timestamp.timeSinceEpoch.microSeconds < 0)
             {
                 if (auto snapshot = entity.findLatestSnapshot())
                 {
@@ -105,7 +108,7 @@ namespace armarx::armem::server::query_proc::base
             }
             else
             {
-                const Time time = fromIce<Time>(query.timestamp);
+                const Time time = armem::fromIce<Time>(query.timestamp);
                 if (auto snapshot = entity.findSnapshot(time))
                 {
                     this->addResultSnapshot(result, *snapshot);
@@ -134,10 +137,12 @@ namespace armarx::armem::server::query_proc::base
                      const armem::query::data::entity::TimeRange& query,
                      const EntityT& entity) const
         {
-            if (query.minTimestamp <= query.maxTimestamp || query.minTimestamp < 0 || query.maxTimestamp < 0)
+            if (query.minTimestamp.timeSinceEpoch.microSeconds <= query.maxTimestamp.timeSinceEpoch.microSeconds
+                || query.minTimestamp.timeSinceEpoch.microSeconds < 0
+                || query.maxTimestamp.timeSinceEpoch.microSeconds < 0)
             {
-                Time min = fromIce<Time>(query.minTimestamp);
-                Time max = fromIce<Time>(query.maxTimestamp);
+                const Time min = fromIce<Time>(query.minTimestamp);
+                const Time max = fromIce<Time>(query.maxTimestamp);
                 process(result, min, max, entity, query);
             }
         }
@@ -224,18 +229,11 @@ namespace armarx::armem::server::query_proc::base
             const Time referenceTimestamp = fromIce<Time>(query.timestamp);
             base::detail::checkReferenceTimestampNonNegative(referenceTimestamp);
 
-            const float referenceTimestampMicroSeconds = referenceTimestamp.toMicroSeconds();
-            const float epsDuration = fromIce<Time>(query.eps).toMicroSeconds();
-
             // elements have to be in range [t_ref - eps, t_ref + eps] if eps is positive
             const auto isInRange = [&](const Time & t) -> bool
             {
-                if (epsDuration <= 0)
-                {
-                    return true;
-                }
-
-                return std::abs(t.toMicroSeconds() - referenceTimestampMicroSeconds) <= epsDuration;
+                return query.eps.microSeconds <= 0
+                       or std::abs((t - referenceTimestamp).toMicroSeconds()) <= query.eps.microSeconds;
             };
 
             // last element before or at timestamp
diff --git a/source/RobotAPI/libraries/armem/server/query_proc/wm/wm.cpp b/source/RobotAPI/libraries/armem/server/query_proc/wm/wm.cpp
index b8d25db27074f2033fd2791aa9aca787607d8da5..0a50a1c4fb7baec68c752895eb966d9f689f5778 100644
--- a/source/RobotAPI/libraries/armem/server/query_proc/wm/wm.cpp
+++ b/source/RobotAPI/libraries/armem/server/query_proc/wm/wm.cpp
@@ -1,5 +1,6 @@
 #include "wm.h"
 
+#include <ArmarXCore/core/time/ice_conversions.h>
 
 
 namespace armarx::armem::server::query_proc::wm::detail
diff --git a/source/RobotAPI/libraries/armem/server/test/ArMemLTMBenchmark.cpp b/source/RobotAPI/libraries/armem/server/test/ArMemLTMBenchmark.cpp
index 8aded460e730d913f523c44a379c069bb70c41a6..ecf13ddc3a54c6000ae7e9d6abcbfa32bec84057 100644
--- a/source/RobotAPI/libraries/armem/server/test/ArMemLTMBenchmark.cpp
+++ b/source/RobotAPI/libraries/armem/server/test/ArMemLTMBenchmark.cpp
@@ -80,7 +80,7 @@ namespace ArMemLTMBenchmark
                 std::cout << "Store instance " << i << " of memory " << memoryName << std::endl;
 
                 en.clear();
-                auto& snap = en.addSnapshot(IceUtil::Time::now());
+                auto& snap = en.addSnapshot(armem::Time::Now());
                 auto& ins = snap.addInstance();
                 auto cloned = aron::data::Dict::DynamicCastAndCheck(dict->clone());
                 ins.data() = cloned;
diff --git a/source/RobotAPI/libraries/armem/server/test/ArMemLTMTest.cpp b/source/RobotAPI/libraries/armem/server/test/ArMemLTMTest.cpp
index 85096741e92f5ede902cdd55879545476cb3facd..7999a6a5752cd1bc9432f9caec95a6f928645a20 100644
--- a/source/RobotAPI/libraries/armem/server/test/ArMemLTMTest.cpp
+++ b/source/RobotAPI/libraries/armem/server/test/ArMemLTMTest.cpp
@@ -116,7 +116,7 @@ namespace ArMemLTMTest
                 }
                 update.entityID = armem::MemoryID::fromString(memoryName + "/TestCoreSegment/TestProvider/TestEntity");
                 update.instancesData = q;
-                update.timeCreated = armem::Time::now();
+                update.timeCreated = armem::Time::Now();
                 BOOST_CHECK_NO_THROW(providerSegment.update(update));
                 BOOST_CHECK_EQUAL(providerSegment.size(), 1);
             }
diff --git a/source/RobotAPI/libraries/armem/server/test/ArMemMemoryTest.cpp b/source/RobotAPI/libraries/armem/server/test/ArMemMemoryTest.cpp
index 3ec604f35f2e586e4cc022a9248e479491b7ecad..8c3052e7d3abebf761431789865f4d0f46633cc7 100644
--- a/source/RobotAPI/libraries/armem/server/test/ArMemMemoryTest.cpp
+++ b/source/RobotAPI/libraries/armem/server/test/ArMemMemoryTest.cpp
@@ -45,7 +45,7 @@ namespace wm = armarx::armem::wm;
 BOOST_AUTO_TEST_CASE(test_time_to_string)
 {
     // 111111: seconds, 345: milliseconds, 789: microseconds
-    armem::Time time = armem::Time::microSeconds(111111345789);
+    armem::Time time { armem::Duration::MicroSeconds(111111345789) };
 
     BOOST_CHECK_EQUAL(armem::toStringMilliSeconds(time), "111111345.789 ms");
     BOOST_CHECK_EQUAL(armem::toStringMilliSeconds(time, 0), "111111345 ms");
@@ -61,7 +61,7 @@ BOOST_AUTO_TEST_CASE(test_time_to_string)
     BOOST_CHECK_EQUAL(armem::toDateTimeMilliSeconds(time, 6), "1970-01-02 07:51:51.345789");
 
     // 111111: seconds, 000: milliseconds, 789: microseconds
-    time = armem::Time::microSeconds(111111000789);
+    time = armem::Time(armem::Duration::MicroSeconds(111111000789));
     BOOST_CHECK_EQUAL(armem::toStringMilliSeconds(time), "111111000.789 ms");
     BOOST_CHECK_EQUAL(armem::toStringMicroSeconds(time), "111111000789 " "\u03BC" "s");
     BOOST_CHECK_EQUAL(armem::toDateTimeMilliSeconds(time), "1970-01-02 07:51:51.000789");
@@ -69,9 +69,8 @@ BOOST_AUTO_TEST_CASE(test_time_to_string)
     BOOST_CHECK_EQUAL(armem::toDateTimeMilliSeconds(time, 3), "1970-01-02 07:51:51.000");
     BOOST_CHECK_EQUAL(armem::toDateTimeMilliSeconds(time, 6), "1970-01-02 07:51:51.000789");
 
-
     // 111111: seconds, 345: milliseconds, 000: microseconds
-    time = armem::Time::microSeconds(111111345000);
+    time = armem::Time(armem::Duration::MicroSeconds(111111345000));
     BOOST_CHECK_EQUAL(armem::toStringMilliSeconds(time), "111111345.000 ms");
     BOOST_CHECK_EQUAL(armem::toStringMicroSeconds(time), "111111345000 " "\u03BC" "s");
     BOOST_CHECK_EQUAL(armem::toDateTimeMilliSeconds(time), "1970-01-02 07:51:51.345000");
@@ -89,7 +88,7 @@ namespace ArMemMemoryTest
     struct APITestFixture
     {
         wm::EntityInstance instance { 0 };
-        wm::EntitySnapshot snapshot { armem::Time::microSeconds(1000) };
+        wm::EntitySnapshot snapshot { armem::Time(armem::Duration::MicroSeconds(1000)) };
         wm::Entity entity { "entity" };
         wm::ProviderSegment provSeg { "provider" };
         wm::CoreSegment coreSeg { "core" };
@@ -111,7 +110,7 @@ namespace ArMemMemoryTest
         {
             BOOST_TEST_CONTEXT("Added: " << armem::print(added) << "\n Parent: " << armem::print(parent))
             {
-                const armem::Time time = armem::Time::microSeconds(1000);
+                const armem::Time time = armem::Time(armem::Duration::MicroSeconds(1000));
                 BOOST_CHECK_EQUAL(added.time(), time);
                 BOOST_CHECK_EQUAL(parent.size(), 1);
                 BOOST_CHECK(parent.hasSnapshot(time));
@@ -174,7 +173,7 @@ BOOST_AUTO_TEST_CASE(test_add_instance_move)
 
 BOOST_AUTO_TEST_CASE(test_add_snapshot_time)
 {
-    test_add_snapshot(entity.addSnapshot(armem::Time::microSeconds(1000)), entity);
+    test_add_snapshot(entity.addSnapshot(armem::Time(armem::Duration::MicroSeconds(1000))), entity);
 }
 BOOST_AUTO_TEST_CASE(test_add_snapshot_copy)
 {
@@ -386,8 +385,8 @@ BOOST_AUTO_TEST_CASE(test_key_ctors)
     wm::EntityInstance instance(10);
     BOOST_CHECK_EQUAL(instance.index(), 10);
 
-    wm::EntitySnapshot snapshot(armem::Time::milliSeconds(100));
-    BOOST_CHECK_EQUAL(snapshot.time(), armem::Time::milliSeconds(100));
+    wm::EntitySnapshot snapshot(armem::Time(armem::Duration::MilliSeconds(100)));
+    BOOST_CHECK_EQUAL(snapshot.time(), armem::Time(armem::Duration::MilliSeconds(100)));
 
     wm::Entity entity("entity");
     BOOST_CHECK_EQUAL(entity.name(), "entity");
@@ -518,8 +517,8 @@ struct CustomChecks<armem::d_ltm::Memory>
 
 struct CopyMoveCtorsOpsTestBase
 {
-    const armem::MemoryID id {"M", "C", "P", "E", armem::Time::microSeconds(123000), 1};
-    //const armem::MemoryID idMoved {"", "", "", "", armem::Time::microSeconds(123000), 1};
+    const armem::MemoryID id {"M", "C", "P", "E", armem::Time(armem::Duration::MicroSeconds(123000)), 1};
+    //const armem::MemoryID idMoved {"", "", "", "", armem::Time(armem::Duration::MicroSeconds(123000), 1};
     armem::MemoryID idMoved = id;
 
     std::string typeName;
@@ -653,7 +652,7 @@ struct CopyMoveCtorsOpsTest : public CopyMoveCtorsOpsTestBase
         }
         {
             armem::EntityUpdate update;
-            update.entityID = armem::MemoryID("M", "C", "P", "E", armem::Time::microSeconds(123000), 0);
+            update.entityID = armem::MemoryID("M", "C", "P", "E", armem::Time(armem::Duration::MicroSeconds(123000)), 0);
             update.timeCreated = update.entityID.timestamp;
             update.instancesData.emplace_back();
             in.update(update);
@@ -815,7 +814,7 @@ BOOST_AUTO_TEST_CASE(test_segment_setup)
         std::make_shared<aron::data::Dict>(),
         std::make_shared<aron::data::Dict>()
     };
-    update.timeCreated = armem::Time::milliSeconds(1000);
+    update.timeCreated = armem::Time(armem::Duration::MilliSeconds(1000));
     BOOST_CHECK_NO_THROW(providerSegment.update(update));
 
     BOOST_CHECK_EQUAL(providerSegment.size(), 1);
@@ -834,7 +833,7 @@ BOOST_AUTO_TEST_CASE(test_segment_setup)
     // Another update (on memory).
 
     update.instancesData = { std::make_shared<aron::data::Dict>() };
-    update.timeCreated = armem::Time::milliSeconds(2000);
+    update.timeCreated = armem::Time(armem::Duration::MilliSeconds(2000));
     memory.update(update);
     BOOST_CHECK_EQUAL(entity.size(), 2);
     BOOST_CHECK(entity.hasSnapshot(update.timeCreated));
@@ -843,7 +842,7 @@ BOOST_AUTO_TEST_CASE(test_segment_setup)
 
     // A third update (on entity).
     update.instancesData = { std::make_shared<aron::data::Dict>() };
-    update.timeCreated = armem::Time::milliSeconds(3000);
+    update.timeCreated = armem::Time(armem::Duration::MilliSeconds(3000));
     entity.update(update);
     BOOST_CHECK_EQUAL(entity.size(), 3);
 
@@ -859,38 +858,38 @@ BOOST_AUTO_TEST_CASE(test_history_size_in_entity)
     update.entityID.entityName = entity.name();
 
     // With unlimited history.
-    update.timeCreated = armem::Time::milliSeconds(1000);
+    update.timeCreated = armem::Time(armem::Duration::MilliSeconds(1000));
     entity.update(update);
-    update.timeCreated = armem::Time::milliSeconds(2000);
+    update.timeCreated = armem::Time(armem::Duration::MilliSeconds(2000));
     entity.update(update);
-    update.timeCreated = armem::Time::milliSeconds(3000);
+    update.timeCreated = armem::Time(armem::Duration::MilliSeconds(3000));
     entity.update(update);
     BOOST_CHECK_EQUAL(entity.size(), 3);
 
     // Now with maximum history size.
     entity.setMaxHistorySize(2);
     BOOST_CHECK_EQUAL(entity.size(), 2);
-    BOOST_CHECK(not entity.hasSnapshot(armem::Time::milliSeconds(1000)));
-    BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(2000)));
-    BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(3000)));
+    BOOST_CHECK(not entity.hasSnapshot(armem::Time(armem::Duration::MilliSeconds(1000))));
+    BOOST_CHECK(entity.hasSnapshot(armem::Time(armem::Duration::MilliSeconds(2000))));
+    BOOST_CHECK(entity.hasSnapshot(armem::Time(armem::Duration::MilliSeconds(3000))));
 
 
-    update.timeCreated = armem::Time::milliSeconds(4000);
+    update.timeCreated = armem::Time(armem::Duration::MilliSeconds(4000));
     entity.update(update);
     BOOST_CHECK_EQUAL(entity.size(), 2);
-    BOOST_CHECK(not entity.hasSnapshot(armem::Time::milliSeconds(2000)));
-    BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(3000)));
-    BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(4000)));
+    BOOST_CHECK(not entity.hasSnapshot(armem::Time(armem::Duration::MilliSeconds(2000))));
+    BOOST_CHECK(entity.hasSnapshot(armem::Time(armem::Duration::MilliSeconds(3000))));
+    BOOST_CHECK(entity.hasSnapshot(armem::Time(armem::Duration::MilliSeconds(4000))));
 
     // Disable maximum history size.
     entity.setMaxHistorySize(-1);
 
-    update.timeCreated = armem::Time::milliSeconds(5000);
+    update.timeCreated = armem::Time(armem::Duration::MilliSeconds(5000));
     entity.update(update);
     BOOST_CHECK_EQUAL(entity.size(), 3);
-    BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(3000)));
-    BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(4000)));
-    BOOST_CHECK(entity.hasSnapshot(armem::Time::milliSeconds(5000)));
+    BOOST_CHECK(entity.hasSnapshot(armem::Time(armem::Duration::MilliSeconds(3000))));
+    BOOST_CHECK(entity.hasSnapshot(armem::Time(armem::Duration::MilliSeconds(4000))));
+    BOOST_CHECK(entity.hasSnapshot(armem::Time(armem::Duration::MilliSeconds(5000))));
 }
 
 
@@ -908,15 +907,15 @@ BOOST_AUTO_TEST_CASE(test_history_size_in_provider_segment)
     {
         update.entityID.entityName = name;
 
-        update.timeCreated = armem::Time::milliSeconds(1000);
+        update.timeCreated = armem::Time(armem::Duration::MilliSeconds(1000));
         providerSegment.update(update);
-        update.timeCreated = armem::Time::milliSeconds(2000);
+        update.timeCreated = armem::Time(armem::Duration::MilliSeconds(2000));
         providerSegment.update(update);
-        update.timeCreated = armem::Time::milliSeconds(3000);
+        update.timeCreated = armem::Time(armem::Duration::MilliSeconds(3000));
         providerSegment.update(update);
     }
     update.entityID.entityName = entityNames.back();
-    update.timeCreated = armem::Time::milliSeconds(4000);
+    update.timeCreated = armem::Time(armem::Duration::MilliSeconds(4000));
     providerSegment.update(update);
 
     BOOST_CHECK_EQUAL(providerSegment.getEntity("A").size(), 3);
@@ -940,11 +939,11 @@ BOOST_AUTO_TEST_CASE(test_history_size_in_provider_segment)
     providerSegment.setMaxHistorySize(2);
 
     update.entityID.entityName = "C";
-    update.timeCreated = armem::Time::milliSeconds(1000);
+    update.timeCreated = armem::Time(armem::Duration::MilliSeconds(1000));
     providerSegment.update(update);
-    update.timeCreated = armem::Time::milliSeconds(2000);
+    update.timeCreated = armem::Time(armem::Duration::MilliSeconds(2000));
     providerSegment.update(update);
-    update.timeCreated = armem::Time::milliSeconds(3000);
+    update.timeCreated = armem::Time(armem::Duration::MilliSeconds(3000));
     providerSegment.update(update);
 
     // Check correctly inherited history size.
@@ -959,7 +958,7 @@ BOOST_AUTO_TEST_CASE(test_history_size_in_provider_segment)
     for (const std::string& name : entityNames)
     {
         update.entityID.entityName = name;
-        update.timeCreated = armem::Time::milliSeconds(5000);
+        update.timeCreated = armem::Time(armem::Duration::MilliSeconds(5000));
         providerSegment.update(update);
         BOOST_CHECK_EQUAL(providerSegment.getEntity(name).getMaxHistorySize(), -1);
         BOOST_CHECK_EQUAL(providerSegment.getEntity(name).size(), 3);
diff --git a/source/RobotAPI/libraries/armem/server/test/ArMemQueryTest.cpp b/source/RobotAPI/libraries/armem/server/test/ArMemQueryTest.cpp
index 191cfb6256257006a27bcd46bd25667e0d8b1bb8..c778cbc4fb09e2a590f7a4aa20085f19998e78f4 100644
--- a/source/RobotAPI/libraries/armem/server/test/ArMemQueryTest.cpp
+++ b/source/RobotAPI/libraries/armem/server/test/ArMemQueryTest.cpp
@@ -65,15 +65,15 @@ namespace ArMemQueryTest
             entity = armem::wm::Entity("entity");
 
             armem::wm::EntitySnapshot snapshot;
-            snapshot.time() = armem::Time::microSeconds(1000);
+            snapshot.time() = armem::Time(armem::Duration::MicroSeconds(1000));
             entity.addSnapshot(snapshot);
-            snapshot.time() = armem::Time::microSeconds(2000);
+            snapshot.time() = armem::Time(armem::Duration::MicroSeconds(2000));
             entity.addSnapshot(snapshot);
-            snapshot.time() = armem::Time::microSeconds(3000);
+            snapshot.time() = armem::Time(armem::Duration::MicroSeconds(3000));
             entity.addSnapshot(snapshot);
-            snapshot.time() = armem::Time::microSeconds(4000);
+            snapshot.time() = armem::Time(armem::Duration::MicroSeconds(4000));
             entity.addSnapshot(snapshot);
-            snapshot.time() = armem::Time::microSeconds(5000);
+            snapshot.time() = armem::Time(armem::Duration::MicroSeconds(5000));
             entity.addSnapshot(snapshot);
         }
         ~Fixture()
@@ -125,30 +125,44 @@ BOOST_AUTO_TEST_CASE(test_entity_Single_latest)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
         BOOST_CHECK_EQUAL(result.size(), 1);
-        const armem::wm::EntitySnapshot* first = result.findFirstSnapshotAfterOrAt(armem::Time::microSeconds(0));
+        const armem::wm::EntitySnapshot* first = result.findFirstSnapshotAfterOrAt(armem::Time(armem::Duration::MicroSeconds(0)));
         BOOST_REQUIRE_NE(first, nullptr);
-        BOOST_CHECK_EQUAL(first->time(), armem::Time::microSeconds(5000));
+        BOOST_CHECK_EQUAL(first->time(), armem::Time(armem::Duration::MicroSeconds(5000)));
     }
 }
 
+static armem::dto::Time
+t_usec(long usec)
+{
+    armem::dto::Time t;
+    t.timeSinceEpoch.microSeconds = usec;
+    return t;
+}
+static armem::dto::Duration
+d_usec(long usec)
+{
+    armem::dto::Duration d;
+    d.microSeconds = usec;
+    return d;
+}
 
 BOOST_AUTO_TEST_CASE(test_entity_Single_existing)
 {
-    addResults(query::entity::Single({query::QueryTarget::WM, query::QueryTarget::LTM}, 3000));
+    addResults(query::entity::Single({query::QueryTarget::WM, query::QueryTarget::LTM}, t_usec(3000)));
     BOOST_REQUIRE_GT(results.size(), 0);
 
     for (const armem::wm::Entity& result : results)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
         BOOST_REQUIRE_EQUAL(result.size(), 1);
-        BOOST_CHECK_EQUAL(result.getFirstSnapshot().time(), armem::Time::microSeconds(3000));
+        BOOST_CHECK_EQUAL(result.getFirstSnapshot().time(), armem::Time(armem::Duration::MicroSeconds(3000)));
     }
 }
 
 
 BOOST_AUTO_TEST_CASE(test_entity_Single_non_existing)
 {
-    addResults(query::entity::Single({query::QueryTarget::WM, query::QueryTarget::LTM}, 3500));
+    addResults(query::entity::Single({query::QueryTarget::WM, query::QueryTarget::LTM}, t_usec(3500)));
     BOOST_REQUIRE_GT(results.size(), 0);
 
     for (const armem::wm::Entity& result : results)
@@ -183,7 +197,8 @@ BOOST_AUTO_TEST_CASE(test_entity_All)
 
 BOOST_AUTO_TEST_CASE(test_entity_TimeRange_slice)
 {
-    addResults(query::entity::TimeRange({query::QueryTarget::WM, query::QueryTarget::LTM}, 1500, 3500));
+    addResults(query::entity::TimeRange({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                        t_usec(1500), t_usec(3500)));
     BOOST_REQUIRE_GT(results.size(), 0);
 
     for (const armem::wm::Entity& result : results)
@@ -195,7 +210,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_slice)
         std::vector<armem::Time> times = result.getTimestamps();
         std::vector<armem::Time> expected
         {
-            armem::Time::microSeconds(2000), armem::Time::microSeconds(3000)
+            armem::Time(armem::Duration::MicroSeconds(2000)), armem::Time(armem::Duration::MicroSeconds(3000))
         };
         BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end());
     }
@@ -204,7 +219,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_slice)
 
 BOOST_AUTO_TEST_CASE(test_entity_TimeRange_exact)
 {
-    addResults(query::entity::TimeRange({query::QueryTarget::WM, query::QueryTarget::LTM}, 2000, 4000));
+    addResults(query::entity::TimeRange({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                        t_usec(2000), t_usec(4000)));
     BOOST_REQUIRE_GT(results.size(), 0);
 
     for (const armem::wm::Entity& result : results)
@@ -216,7 +232,9 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_exact)
         std::vector<armem::Time> times = result.getTimestamps();
         std::vector<armem::Time> expected
         {
-            armem::Time::microSeconds(2000), armem::Time::microSeconds(3000), armem::Time::microSeconds(4000)
+            armem::Time(armem::Duration::MicroSeconds(2000)),
+            armem::Time(armem::Duration::MicroSeconds(3000)),
+            armem::Time(armem::Duration::MicroSeconds(4000))
         };
         BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end());
     }
@@ -224,14 +242,15 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_exact)
 
 BOOST_AUTO_TEST_CASE(test_entity_TimeRange_all)
 {
-    addResults(query::entity::TimeRange({query::QueryTarget::WM, query::QueryTarget::LTM}, 0, 10000));
-    addResults(query::entity::TimeRange({query::QueryTarget::WM, query::QueryTarget::LTM}, -1, -1));
+    addResults(query::entity::TimeRange({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                        t_usec(0), t_usec(10000)));
+    addResults(query::entity::TimeRange({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                        t_usec(-1), t_usec(-1)));
     BOOST_REQUIRE_GT(results.size(), 0);
 
     for (const armem::wm::Entity& result : results)
     {
         BOOST_CHECK_EQUAL(result.name(), entity.name());
-
         BOOST_CHECK_EQUAL(result.size(), entity.size());
 
         const std::vector<armem::Time> times = result.getTimestamps();
@@ -243,8 +262,10 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_all)
 
 BOOST_AUTO_TEST_CASE(test_entity_TimeRange_empty)
 {
-    addResults(query::entity::TimeRange({query::QueryTarget::WM, query::QueryTarget::LTM}, 2400, 2600));
-    addResults(query::entity::TimeRange({query::QueryTarget::WM, query::QueryTarget::LTM}, 6000, 1000));
+    addResults(query::entity::TimeRange({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                        t_usec(2400), t_usec(2600)));
+    addResults(query::entity::TimeRange({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                        t_usec(6000), t_usec(1000)));
     BOOST_REQUIRE_GT(results.size(), 0);
 
     for (const armem::wm::Entity& result : results)
@@ -258,7 +279,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_empty)
 
 BOOST_AUTO_TEST_CASE(test_entity_TimeRange_from_start)
 {
-    addResults(query::entity::TimeRange({query::QueryTarget::WM, query::QueryTarget::LTM}, -1, 2500));
+    addResults(query::entity::TimeRange({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                        t_usec(-1), t_usec(2500)));
     BOOST_REQUIRE_GT(results.size(), 0);
 
     for (const armem::wm::Entity& result : results)
@@ -270,7 +292,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_from_start)
         const std::vector<armem::Time> times = result.getTimestamps();
         std::vector<armem::Time> expected
         {
-            armem::Time::microSeconds(1000), armem::Time::microSeconds(2000)
+            armem::Time(armem::Duration::MicroSeconds(1000)),
+            armem::Time(armem::Duration::MicroSeconds(2000))
         };
         BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end());
     }
@@ -279,7 +302,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_from_start)
 
 BOOST_AUTO_TEST_CASE(test_entity_TimeRange_to_end)
 {
-    addResults(query::entity::TimeRange({query::QueryTarget::WM, query::QueryTarget::LTM}, 2500, -1));
+    addResults(query::entity::TimeRange({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                        t_usec(2500), t_usec(-1)));
     BOOST_REQUIRE_GT(results.size(), 0);
 
     for (const armem::wm::Entity& result : results)
@@ -290,7 +314,9 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_to_end)
         const std::vector<armem::Time> times = result.getTimestamps();
         std::vector<armem::Time> expected
         {
-            armem::Time::microSeconds(3000), armem::Time::microSeconds(4000), armem::Time::microSeconds(5000)
+            armem::Time(armem::Duration::MicroSeconds(3000)),
+            armem::Time(armem::Duration::MicroSeconds(4000)),
+            armem::Time(armem::Duration::MicroSeconds(5000))
         };
         BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end());
     }
@@ -302,7 +328,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeRange_to_end)
 BOOST_AUTO_TEST_CASE(test_entity_BeforeTime_1)
 {
     BOOST_REQUIRE_EQUAL(entity.size(), 5);
-    addResults(query::entity::BeforeTime({query::QueryTarget::WM, query::QueryTarget::LTM}, 3500, 1));
+    addResults(query::entity::BeforeTime({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                         t_usec(3500), 1));
     BOOST_REQUIRE_EQUAL(results.size(), 2);
 
     for (const auto& result : results)
@@ -310,14 +337,15 @@ BOOST_AUTO_TEST_CASE(test_entity_BeforeTime_1)
         const std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE_EQUAL(times.size(), 1);
 
-        BOOST_CHECK_EQUAL(times.front(), armem::Time::microSeconds(3000));
+        BOOST_CHECK_EQUAL(times.front(), armem::Time(armem::Duration::MicroSeconds(3000)));
     }
 }
 
 BOOST_AUTO_TEST_CASE(test_entity_BeforeTime_2)
 {
     BOOST_REQUIRE_EQUAL(entity.size(), 5);
-    addResults(query::entity::BeforeTime({query::QueryTarget::WM, query::QueryTarget::LTM}, 3500, 2));
+    addResults(query::entity::BeforeTime({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                         t_usec(3500), 2));
     BOOST_REQUIRE_EQUAL(results.size(), 2);
 
     for (const auto& result : results)
@@ -327,7 +355,8 @@ BOOST_AUTO_TEST_CASE(test_entity_BeforeTime_2)
 
         std::vector<armem::Time> expected
         {
-            armem::Time::microSeconds(2000), armem::Time::microSeconds(3000)
+            armem::Time(armem::Duration::MicroSeconds(2000)),
+            armem::Time(armem::Duration::MicroSeconds(3000))
         };
 
         BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end());
@@ -342,7 +371,8 @@ BOOST_AUTO_TEST_CASE(test_entity_BeforeTime_2)
 BOOST_AUTO_TEST_CASE(test_entity_BeforeOrAtTime_before)
 {
     BOOST_REQUIRE_EQUAL(entity.size(), 5);
-    addResults(query::entity::BeforeOrAtTime({query::QueryTarget::WM, query::QueryTarget::LTM}, 3500));
+    addResults(query::entity::BeforeOrAtTime({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                             t_usec(3500)));
     BOOST_REQUIRE_EQUAL(results.size(), 2);
 
     for (const auto& result : results)
@@ -350,14 +380,15 @@ BOOST_AUTO_TEST_CASE(test_entity_BeforeOrAtTime_before)
         std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE_EQUAL(times.size(), 1);
 
-        BOOST_REQUIRE_EQUAL(times.front(),  armem::Time::microSeconds(3000));
+        BOOST_REQUIRE_EQUAL(times.front(), armem::Time(armem::Duration::MicroSeconds(3000)));
     }
 }
 
 BOOST_AUTO_TEST_CASE(test_entity_BeforeOrAtTime_at)
 {
     BOOST_REQUIRE_EQUAL(entity.size(), 5);
-    addResults(query::entity::BeforeOrAtTime({query::QueryTarget::WM, query::QueryTarget::LTM}, 3000));
+    addResults(query::entity::BeforeOrAtTime({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                             t_usec(3000)));
     BOOST_REQUIRE_EQUAL(results.size(), 2);
 
     for (const auto& result : results)
@@ -365,14 +396,15 @@ BOOST_AUTO_TEST_CASE(test_entity_BeforeOrAtTime_at)
         std::vector<armem::Time> times = result.getTimestamps();
         BOOST_REQUIRE_EQUAL(times.size(), 1);
 
-        BOOST_REQUIRE_EQUAL(times.front(),  armem::Time::microSeconds(3000));
+        BOOST_REQUIRE_EQUAL(times.front(),  armem::Time(armem::Duration::MicroSeconds(3000)));
     }
 }
 
 BOOST_AUTO_TEST_CASE(test_entity_BeforeOrAtTime_lookup_past)
 {
     BOOST_REQUIRE_EQUAL(entity.size(), 5);
-    addResults(query::entity::BeforeOrAtTime({query::QueryTarget::WM, query::QueryTarget::LTM}, 1));
+    addResults(query::entity::BeforeOrAtTime({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                             t_usec(1)));
     BOOST_REQUIRE_EQUAL(results.size(), 2);
 
     for (const auto& result : results)
@@ -392,7 +424,8 @@ BOOST_AUTO_TEST_CASE(test_entity_BeforeOrAtTime_lookup_past)
 BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_no_limit)
 {
     BOOST_REQUIRE_EQUAL(entity.size(), 5);
-    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM}, 3500, -1));
+    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                         t_usec(3500), d_usec(-1)));
     BOOST_REQUIRE_EQUAL(results.size(), 2);
 
     for (const auto& result : results)
@@ -402,7 +435,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_no_limit)
 
         std::vector<armem::Time> expected
         {
-            armem::Time::microSeconds(3000), armem::Time::microSeconds(4000)
+            armem::Time(armem::Duration::MicroSeconds(3000)),
+            armem::Time(armem::Duration::MicroSeconds(4000))
         };
 
         BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end());
@@ -418,7 +452,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_no_limit)
 BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_600)
 {
     BOOST_REQUIRE_EQUAL(entity.size(), 5);
-    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM}, 3500, 600));
+    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                         t_usec(3500), d_usec(600)));
     BOOST_REQUIRE_EQUAL(results.size(), 2);
 
     for (const auto& result : results)
@@ -428,7 +463,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_600)
 
         std::vector<armem::Time> expected
         {
-            armem::Time::microSeconds(3000), armem::Time::microSeconds(4000)
+            armem::Time(armem::Duration::MicroSeconds(3000)),
+            armem::Time(armem::Duration::MicroSeconds(4000))
         };
 
         BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end());
@@ -444,7 +480,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_600)
 BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_too_small)
 {
     BOOST_REQUIRE_EQUAL(entity.size(), 5);
-    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM}, 3500, 100));
+    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                         t_usec(3500), d_usec(100)));
     BOOST_REQUIRE_EQUAL(results.size(), 2);
 
     for (const auto& result : results)
@@ -463,7 +500,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_too_small)
 BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_only_next)
 {
     BOOST_REQUIRE_EQUAL(entity.size(), 5);
-    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM}, 3700, 400));
+    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                         t_usec(3700), d_usec(400)));
     BOOST_REQUIRE_EQUAL(results.size(), 2);
 
     for (const auto& result : results)
@@ -473,7 +511,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_only_next)
 
         std::vector<armem::Time> expected
         {
-            armem::Time::microSeconds(4000)
+            armem::Time(armem::Duration::MicroSeconds(4000))
         };
 
         BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end());
@@ -488,7 +526,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_only_next)
 BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_only_previous)
 {
     BOOST_REQUIRE_EQUAL(entity.size(), 5);
-    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM}, 3300, 400));
+    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                         t_usec(3300), d_usec(400)));
     BOOST_REQUIRE_EQUAL(results.size(), 2);
 
     for (const auto& result : results)
@@ -498,7 +537,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_only_previous)
 
         std::vector<armem::Time> expected
         {
-            armem::Time::microSeconds(3000)
+            armem::Time(armem::Duration::MicroSeconds(3000))
         };
 
         BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end());
@@ -513,7 +552,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_limit_only_previous)
 BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_perfect_match)
 {
     BOOST_REQUIRE_EQUAL(entity.size(), 5);
-    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM}, 3000, -1));
+    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                         t_usec(3000), d_usec(-1)));
     BOOST_REQUIRE_EQUAL(results.size(), 2);
 
     for (const auto& result : results)
@@ -523,7 +563,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_perfect_match)
 
         std::vector<armem::Time> expected
         {
-            armem::Time::microSeconds(3000)
+            armem::Time(armem::Duration::MicroSeconds(3000))
         };
 
         BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end());
@@ -538,7 +578,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_perfect_match)
 BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_lookup_past)
 {
     BOOST_REQUIRE_EQUAL(entity.size(), 5);
-    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM}, 1, 1));
+    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                         t_usec(1), d_usec(1)));
     BOOST_REQUIRE_EQUAL(results.size(), 2);
 
     for (const auto& result : results)
@@ -556,7 +597,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_lookup_past)
 BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_lookup_future)
 {
     BOOST_REQUIRE_EQUAL(entity.size(), 5);
-    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM}, 10'000, 1));
+    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                         t_usec(10'000), d_usec(1)));
     BOOST_REQUIRE_EQUAL(results.size(), 2);
 
     for (const auto& result : results)
@@ -574,7 +616,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_lookup_future)
 BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_lookup_future_valid)
 {
     BOOST_REQUIRE_EQUAL(entity.size(), 5);
-    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM}, 10'000, -1));
+    addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                         t_usec(10'000), d_usec(-1)));
     BOOST_REQUIRE_EQUAL(results.size(), 2);
 
     for (const auto& result : results)
@@ -584,7 +627,7 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_lookup_future_valid)
 
         std::vector<armem::Time> expected
         {
-            armem::Time::microSeconds(5'000)
+            armem::Time(armem::Duration::MicroSeconds(5'000))
         };
 
         BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end());
@@ -593,7 +636,8 @@ BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_lookup_future_valid)
 
 BOOST_AUTO_TEST_CASE(test_entity_TimeApprox_lookup_invalid_timestamp)
 {
-    BOOST_REQUIRE_THROW(addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM}, -1, 1)), ::armarx::LocalException);
+    BOOST_REQUIRE_THROW(addResults(query::entity::TimeApprox({query::QueryTarget::WM, query::QueryTarget::LTM},
+                                                             t_usec(-1), d_usec(1))), ::armarx::LocalException);
 }
 
 
@@ -668,7 +712,9 @@ BOOST_AUTO_TEST_CASE(test_entity_IndexRange_slice)
         std::vector<armem::Time> times = result.getTimestamps();
         std::vector<armem::Time> expected
         {
-            armem::Time::microSeconds(2000), armem::Time::microSeconds(3000), armem::Time::microSeconds(4000)
+            armem::Time(armem::Duration::MicroSeconds(2000)),
+            armem::Time(armem::Duration::MicroSeconds(3000)),
+            armem::Time(armem::Duration::MicroSeconds(4000))
         };
         BOOST_CHECK_EQUAL_COLLECTIONS(times.begin(), times.end(), expected.begin(), expected.end());
     }
diff --git a/source/RobotAPI/libraries/armem/test/ArMemForEachTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemForEachTest.cpp
index 9c29804ebdc56444b175b3de0abd115b3a1067c0..8cb721c4b724e0c6f307a6ee6b796c01c974680a 100644
--- a/source/RobotAPI/libraries/armem/test/ArMemForEachTest.cpp
+++ b/source/RobotAPI/libraries/armem/test/ArMemForEachTest.cpp
@@ -70,7 +70,7 @@ BOOST_AUTO_TEST_CASE(test_forEach)
                 eids.insert(eid);
                 for (size_t s = 0; s <= e; ++s)
                 {
-                    const MemoryID sid = eid.withTimestamp(Time::microSeconds(int(s)));
+                    const MemoryID sid = eid.withTimestamp(Time(Duration::MicroSeconds(int(s))));
                     sids.insert(sid);
 
                     EntityUpdate update;
@@ -176,8 +176,8 @@ BOOST_AUTO_TEST_CASE(test_forEach_non_bool_func)
     // Check whether this compiles + runs without break.
 
     armem::wm::Entity entity;
-    entity.addSnapshot(armem::Time::microSeconds(500));
-    entity.addSnapshot(armem::Time::microSeconds(1500));
+    entity.addSnapshot(armem::Time(armem::Duration::MicroSeconds(500)));
+    entity.addSnapshot(armem::Time(armem::Duration::MicroSeconds(1500)));
 
     int i = 0;
     entity.forEachSnapshot([&i](const armem::wm::EntitySnapshot&) -> void
diff --git a/source/RobotAPI/libraries/armem/test/ArMemGetFindTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemGetFindTest.cpp
index 29c12884d15292706ac2be33410352fe832dbc2a..f03b02052ef9956aab079dda96677acaf5aca48d 100644
--- a/source/RobotAPI/libraries/armem/test/ArMemGetFindTest.cpp
+++ b/source/RobotAPI/libraries/armem/test/ArMemGetFindTest.cpp
@@ -58,7 +58,7 @@ namespace ArMemGetFindTest
         Fixture()
         {
             {
-                snapshot.time() = armem::Time::microSeconds(1000);
+                snapshot.time() = armem::Time(armem::Duration::MicroSeconds(1000));
                 snapshot.addInstance();
             }
             {
@@ -123,14 +123,14 @@ namespace ArMemGetFindTest
         {
             BOOST_TEST_CONTEXT("Parent: " << armem::print(parent))
             {
-                BOOST_CHECK_EQUAL(parent.hasSnapshot(entityID.withTimestamp(armem::Time::microSeconds(1000))), true);
-                BOOST_CHECK_EQUAL(parent.hasSnapshot(entityID.withTimestamp(armem::Time::microSeconds(2000))), false);
+                BOOST_CHECK_EQUAL(parent.hasSnapshot(entityID.withTimestamp(armem::Time(armem::Duration::MicroSeconds(1000)))), true);
+                BOOST_CHECK_EQUAL(parent.hasSnapshot(entityID.withTimestamp(armem::Time(armem::Duration::MicroSeconds(2000)))), false);
 
-                BOOST_CHECK_NE(parent.findSnapshot(entityID.withTimestamp(armem::Time::microSeconds(1000))), nullptr);
-                BOOST_CHECK_EQUAL(parent.findSnapshot(entityID.withTimestamp(armem::Time::microSeconds(2000))), nullptr);
+                BOOST_CHECK_NE(parent.findSnapshot(entityID.withTimestamp(armem::Time(armem::Duration::MicroSeconds(1000)))), nullptr);
+                BOOST_CHECK_EQUAL(parent.findSnapshot(entityID.withTimestamp(armem::Time(armem::Duration::MicroSeconds(2000)))), nullptr);
 
-                BOOST_CHECK_NO_THROW(parent.getSnapshot(entityID.withTimestamp(armem::Time::microSeconds(1000))));
-                BOOST_CHECK_THROW(parent.getSnapshot(entityID.withTimestamp(armem::Time::microSeconds(2000))), armem::error::MissingEntry);
+                BOOST_CHECK_NO_THROW(parent.getSnapshot(entityID.withTimestamp(armem::Time(armem::Duration::MicroSeconds(1000)))));
+                BOOST_CHECK_THROW(parent.getSnapshot(entityID.withTimestamp(armem::Time(armem::Duration::MicroSeconds(2000)))), armem::error::MissingEntry);
             }
         }
 
@@ -223,14 +223,14 @@ BOOST_AUTO_TEST_CASE(test_snapshot_get_find_instance_by_key)
 
 BOOST_AUTO_TEST_CASE(test_entity_get_find_snapshot_by_key)
 {
-    BOOST_CHECK_EQUAL(entity.hasSnapshot(armem::Time::microSeconds(1000)), true);
-    BOOST_CHECK_EQUAL(entity.hasSnapshot(armem::Time::microSeconds(2000)), false);
+    BOOST_CHECK_EQUAL(entity.hasSnapshot(armem::Time(armem::Duration::MicroSeconds(1000))), true);
+    BOOST_CHECK_EQUAL(entity.hasSnapshot(armem::Time(armem::Duration::MicroSeconds(2000))), false);
 
-    BOOST_CHECK_NE(entity.findSnapshot(armem::Time::microSeconds(1000)), nullptr);
-    BOOST_CHECK_EQUAL(entity.findSnapshot(armem::Time::microSeconds(2000)), nullptr);
+    BOOST_CHECK_NE(entity.findSnapshot(armem::Time(armem::Duration::MicroSeconds(1000))), nullptr);
+    BOOST_CHECK_EQUAL(entity.findSnapshot(armem::Time(armem::Duration::MicroSeconds(2000))), nullptr);
 
-    BOOST_CHECK_NO_THROW(entity.getSnapshot(armem::Time::microSeconds(1000)));
-    BOOST_CHECK_THROW(entity.getSnapshot(armem::Time::microSeconds(2000)), armem::error::MissingEntry);
+    BOOST_CHECK_NO_THROW(entity.getSnapshot(armem::Time(armem::Duration::MicroSeconds(1000))));
+    BOOST_CHECK_THROW(entity.getSnapshot(armem::Time(armem::Duration::MicroSeconds(2000))), armem::error::MissingEntry);
 }
 
 
diff --git a/source/RobotAPI/libraries/armem/test/ArMemIceConversionsTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemIceConversionsTest.cpp
index 9fd00a4cf944f50cbd1c0d7bd06b9b56d812c161..07ea4e3acc307aa3d7abb97c7f9bd3f450a4129e 100644
--- a/source/RobotAPI/libraries/armem/test/ArMemIceConversionsTest.cpp
+++ b/source/RobotAPI/libraries/armem/test/ArMemIceConversionsTest.cpp
@@ -26,7 +26,7 @@
 
 #include <RobotAPI/Test.h>
 #include <RobotAPI/libraries/armem/core/wm/ice_conversions.h>
-
+#include <RobotAPI/libraries/armem/core/ice_conversions_templates.h>
 
 #include <iostream>
 #include <SimoxUtility/algorithm/get_map_keys_values.h>
@@ -43,11 +43,11 @@ BOOST_AUTO_TEST_CASE(test_entity)
     std::vector<armem::Time> expectedTimestamps;
 
     armem::wm::EntitySnapshot snapshot;
-    snapshot.time() = armem::Time::milliSeconds(100);
+    snapshot.time() = armem::Time(armem::Duration::MilliSeconds(100));
     expectedTimestamps.push_back(snapshot.time());
     entity.addSnapshot(snapshot);
 
-    snapshot.time() = armem::Time::milliSeconds(300);
+    snapshot.time() = armem::Time(armem::Duration::MilliSeconds(300));
     expectedTimestamps.push_back(snapshot.time());
     entity.addSnapshot(snapshot);
 
diff --git a/source/RobotAPI/libraries/armem/test/ArMemMemoryIDTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemMemoryIDTest.cpp
index 72f09fb225aa22b50ed55a9482e7f973acbf0fd2..987cf20c980e0478056dd529d4ad877de2499ba4 100644
--- a/source/RobotAPI/libraries/armem/test/ArMemMemoryIDTest.cpp
+++ b/source/RobotAPI/libraries/armem/test/ArMemMemoryIDTest.cpp
@@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(test_MemoryID_from_to_string)
     BOOST_CHECK_EQUAL(idIn.coreSegmentName, "Core");
     BOOST_CHECK_EQUAL(idIn.providerSegmentName, "Prov");
     BOOST_CHECK_EQUAL(idIn.entityName, "entity");
-    BOOST_CHECK_EQUAL(idIn.timestamp, IceUtil::Time::microSeconds(2810381));
+    BOOST_CHECK_EQUAL(idIn.timestamp, armem::Time(armem::Duration::MicroSeconds(2810381)));
     BOOST_CHECK_EQUAL(idIn.instanceIndex, 2);
 
 
@@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(test_MemoryID_from_to_string)
     BOOST_CHECK_EQUAL(idIn.coreSegmentName, "AtTheEnd/");
     BOOST_CHECK_EQUAL(idIn.providerSegmentName, "/AtTheStart");
     BOOST_CHECK_EQUAL(idIn.entityName, "YCB/sugar/-1");
-    BOOST_CHECK_EQUAL(idIn.timestamp, IceUtil::Time::microSeconds(-1));
+    BOOST_CHECK_EQUAL(idIn.timestamp, armem::Time::Invalid());
     BOOST_CHECK_EQUAL(idIn.instanceIndex, 2);
 
     BOOST_TEST_CONTEXT(VAROUT(idIn.str()))
@@ -134,7 +134,6 @@ BOOST_AUTO_TEST_CASE(test_MemoryID_from_to_string)
         armem::MemoryID idOut(idIn.str());
         BOOST_CHECK_EQUAL(idOut, idIn);
     }
-
 }
 
 
diff --git a/source/RobotAPI/libraries/armem/test/ArMemQueryBuilderTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemQueryBuilderTest.cpp
index 78d3077c082e41f32bf6dfd398e9e7d474e19dc3..535ce2b80b6b9b5ac7c95fcf3f9847ab943d1729 100644
--- a/source/RobotAPI/libraries/armem/test/ArMemQueryBuilderTest.cpp
+++ b/source/RobotAPI/libraries/armem/test/ArMemQueryBuilderTest.cpp
@@ -25,10 +25,12 @@
 #define ARMARX_BOOST_TEST
 
 #include <RobotAPI/Test.h>
+
+#include <ArmarXCore/core/time/ice_conversions.h>
+
+#include <RobotAPI/libraries/armem/core/ice_conversions_templates.h>
 #include <RobotAPI/libraries/armem/client/query/Builder.h>
 #include <RobotAPI/libraries/armem/client/query/query_fns.h>
-#include <RobotAPI/libraries/armem/core/wm/ice_conversions.h>
-
 
 #include <iostream>
 
@@ -97,9 +99,10 @@ BOOST_AUTO_TEST_CASE(test_mixed)
     .entities(withName(entityNames.at(0)),
               withName(entityNames.at(1)))
     .snapshots(latest(),
-               atTime(armem::Time::milliSeconds(3000)),
+               atTime(armem::Time(armem::Duration::MilliSeconds(3000))),
                indexRange(5, -10),
-               timeRange(armem::Time::milliSeconds(1000), armem::Time::milliSeconds(2000)))
+               timeRange(armem::Time(armem::Duration::MilliSeconds(1000)),
+                         armem::Time(armem::Duration::MilliSeconds(2000))))
     ;
 
 
@@ -138,13 +141,13 @@ BOOST_AUTO_TEST_CASE(test_mixed)
         {
             auto latest = query::entity::SinglePtr::dynamicCast(*it);
             BOOST_REQUIRE(latest);
-            BOOST_CHECK_EQUAL(latest->timestamp, -1);
+            BOOST_CHECK_EQUAL(latest->timestamp.timeSinceEpoch.microSeconds, armem::Time::Invalid().toMicroSecondsSinceEpoch());
             ++it;
         }
         {
             auto atTime = query::entity::SinglePtr::dynamicCast(*it);
             BOOST_REQUIRE(atTime);
-            BOOST_CHECK_EQUAL(atTime->timestamp, armem::toIce<long>(armem::Time::milliSeconds(3000)));
+            BOOST_CHECK_EQUAL(atTime->timestamp, armem::toIce<armem::dto::Time>(armem::Time(armem::Duration::MilliSeconds(3000))));
             ++it;
         }
         {
@@ -157,12 +160,11 @@ BOOST_AUTO_TEST_CASE(test_mixed)
         {
             auto timeRange = query::entity::TimeRangePtr::dynamicCast(*it);
             BOOST_REQUIRE(timeRange);
-            BOOST_CHECK_EQUAL(timeRange->minTimestamp, armem::toIce<long>(armem::Time::milliSeconds(1000)));
-            BOOST_CHECK_EQUAL(timeRange->maxTimestamp, armem::toIce<long>(armem::Time::milliSeconds(2000)));
+            BOOST_CHECK_EQUAL(timeRange->minTimestamp, armem::toIce<armem::dto::Time>(armem::Time(armem::Duration::MilliSeconds(1000))));
+            BOOST_CHECK_EQUAL(timeRange->maxTimestamp, armem::toIce<armem::dto::Time>(armem::Time(armem::Duration::MilliSeconds(2000))));
             ++it;
         }
     }
-
 }
 
 
@@ -187,6 +189,7 @@ BOOST_AUTO_TEST_CASE(test_branched_hierarchy)
     .snapshots().latest();
 
 
+    BOOST_TEST_MESSAGE(std::numeric_limits<long>::min());
     armem::client::QueryInput input = qb.buildQueryInput();
     const query::ProviderSegmentQuerySeq& provQueries = input.memoryQueries.front()->coreSegmentQueries.front()->providerSegmentQueries;
 
@@ -211,7 +214,7 @@ BOOST_AUTO_TEST_CASE(test_branched_hierarchy)
         BOOST_CHECK_EQUAL(regex->entityQueries.size(), 1);
         auto snapshotLatest = query::entity::SinglePtr::dynamicCast(regex->entityQueries.at(0));
         BOOST_CHECK(snapshotLatest);
-        BOOST_CHECK_EQUAL(snapshotLatest->timestamp, -1);
+        BOOST_CHECK_EQUAL(snapshotLatest->timestamp.timeSinceEpoch.microSeconds, armem::Time::Invalid().toMicroSecondsSinceEpoch());
 
         ++it;
     }
diff --git a/source/RobotAPI/libraries/armem/util/util.cpp b/source/RobotAPI/libraries/armem/util/util.cpp
index 34f0e2f56d9d47ea7db8b54e198e6faa9d0b25d9..fcaab64e05b6eb35e9c516a9637f77a97b210952 100644
--- a/source/RobotAPI/libraries/armem/util/util.cpp
+++ b/source/RobotAPI/libraries/armem/util/util.cpp
@@ -1,3 +1,68 @@
 #include "util.h"
 
-// intentionally left blank
\ No newline at end of file
+#include <RobotAPI/libraries/armem/client.h>
+#include <RobotAPI/libraries/armem/core/error/mns.h>
+
+namespace armarx::armem
+{
+
+    std::optional<armarx::armem::wm::Memory>
+    resolveID(armarx::armem::client::MemoryNameSystem& mns, const armarx::armem::MemoryID& memoryID)
+    {
+        armarx::armem::client::Reader reader;
+        try
+        {
+            reader = mns.getReader(memoryID);
+        }
+        catch (const armarx::armem::error::CouldNotResolveMemoryServer& e)
+        {
+            ARMARX_WARNING << armarx::armem::error::CouldNotResolveMemoryServer::makeMsg(memoryID);
+            return {};
+        }
+
+        const armarx::armem::ClientQueryResult result = reader.queryMemoryIDs({memoryID});
+        if (result.success)
+        {
+            return result.memory;
+        }
+        ARMARX_WARNING << "Could not query memory for ID " << memoryID << ", "
+                       << result.errorMessage;
+        return {};
+    }
+
+
+    std::optional<std::pair<armarx::aron::data::DictPtr, armarx::aron::type::ObjectPtr>>
+    extractDataAndType(const armarx::armem::wm::Memory& memory,
+                       const armarx::armem::MemoryID& memoryID)
+    {
+        const auto* instance = memory.findLatestInstance(memoryID);
+        if (instance == nullptr)
+        {
+            return {};
+        }
+
+        armarx::aron::data::DictPtr aronData = instance->data();
+        armarx::aron::type::ObjectPtr aronType;
+        const auto* providerSegment = memory.findProviderSegment(memoryID);
+        if (providerSegment == nullptr)
+        {
+            return {};
+        }
+
+        if (!providerSegment->hasAronType())
+        {
+            const auto* coreSegment = memory.findCoreSegment(memoryID);
+            if (coreSegment == nullptr || !coreSegment->hasAronType())
+            {
+                return {};
+            }
+            aronType = coreSegment->aronType();
+        }
+        else
+        {
+            aronType = providerSegment->aronType();
+        }
+
+        return {{aronData, aronType}};
+    }
+} // namespace armarx::armem
diff --git a/source/RobotAPI/libraries/armem/util/util.h b/source/RobotAPI/libraries/armem/util/util.h
index a337bfafb784725dbfdd7cef9e158361a8911c97..7ffdfbfdc4f874ce264d9a61e2ffb030291827d9 100644
--- a/source/RobotAPI/libraries/armem/util/util.h
+++ b/source/RobotAPI/libraries/armem/util/util.h
@@ -26,6 +26,7 @@
 
 #include <ArmarXCore/core/logging/Logging.h>
 
+#include <RobotAPI/libraries/armem/client/MemoryNameSystem.h>
 #include <RobotAPI/libraries/armem/core/wm/memory_definitions.h>
 #include <RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/AronGeneratedClass.h>
 
@@ -165,4 +166,37 @@ namespace armarx::armem
         return outV;
     }
 
+    /**
+     * @brief resolve a single MemoryID with the given MemoryNameSystem.
+     *
+     * Returns a Memory containing only the desired segment / entity if it was
+     * successfully queried. If the query was unsuccessful (the MNS could not
+     * resolve the memory server, the MemoryID does not exist, etc.),
+     * nothing is returned.
+     *
+     * @param mns the MemoryNameSystem to use for the query
+     * @param memoryID the MemoryID to query for
+     * @return memory containing the object referenced by the MemoryID if available
+     */
+    std::optional<armarx::armem::wm::Memory>
+    resolveID(armarx::armem::client::MemoryNameSystem& mns,
+              const armarx::armem::MemoryID& memoryID);
+
+
+    /**
+     * @brief get the data and type of the given MemoryID in the given Memory.
+     *
+     * Returns the data and the type of the latest instance corresponding to
+     * the given MemoryID (whatever `memory.findLatestInstance(memoryID)` returns).
+     * If no such instance exists in the memory or no type for the instance is available,
+     * nothing is returned.
+     *
+     * @param memory the Memory to extract the data and type from
+     * @param memoryID the MemoryID of the instance to extract
+     * @return pair of data and type for the instance if available
+     */
+    std::optional<std::pair<armarx::aron::data::DictPtr, armarx::aron::type::ObjectPtr>>
+    extractDataAndType(const armarx::armem::wm::Memory& memory,
+                       const armarx::armem::MemoryID& memoryID);
+
 } // namespace armarx::armem
diff --git a/source/RobotAPI/libraries/armem_grasping/server/KnownGraspProviderSegment.cpp b/source/RobotAPI/libraries/armem_grasping/server/KnownGraspProviderSegment.cpp
index e66a190bdf75e652c6505d91f7aae4fe9ae9649a..f1ad93a2c87396e2f178d2ed522d39dcd7de95b9 100644
--- a/source/RobotAPI/libraries/armem_grasping/server/KnownGraspProviderSegment.cpp
+++ b/source/RobotAPI/libraries/armem_grasping/server/KnownGraspProviderSegment.cpp
@@ -110,7 +110,7 @@ namespace armarx::armem::grasping::segment
     {
         // load data from prior knowledge
         ObjectFinder objectFinder;
-        const auto now = armem::Time::now();
+        const auto now = armem::Time::Now();
 
         const bool checkPaths = false;
         std::vector<ObjectInfo> infos = objectFinder.findAllObjects(checkPaths);
diff --git a/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp b/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp
index f16545280290edb77d0d41dc61a6d3cb916fe9a0..0d89cd82cce205a1032dfe9d895bb4845f7bdc53 100644
--- a/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp
+++ b/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp
@@ -234,7 +234,7 @@ namespace armarx::armem::gui
     void MemoryViewer::commit()
     {
         TIMING_START(Commit);
-        auto now = armem::Time::now();
+        auto now = armem::Time::Now();
 
         const std::string memoryIDStr = memoryGroup->commitWidget()->getMemoryID();
         const std::string aronJSONStr = memoryGroup->commitWidget()->getAronJSON();
@@ -357,24 +357,41 @@ namespace armarx::armem::gui
 
 
     void
-    MemoryViewer::startDueQueries(std::map<std::string, Ice::AsyncResultPtr>& queries,
-                                  const std::map<std::string, armem::client::Reader>& readers)
+    MemoryViewer::startDueQueries(
+        std::map<std::string, std::future<armem::query::data::Result>>& queries,
+        const std::map<std::string, armem::client::Reader>& readers)
     {
         armem::client::QueryInput input = memoryGroup->queryWidget()->queryInput();
+        int recursionDepth = memoryGroup->queryWidget()->queryLinkRecursionDepth();
 
-        for (auto& [name, reader] : readers)
+        // Can't use a structured binding here because you can't capture those in a lambda
+        // according to the C++ standard.
+        for (const auto& pair : readers)
         {
+            const auto& name = pair.first;
+            const auto& reader = pair.second;
             if (queries.count(name) == 0)
             {
-                queries[name] = reader.memoryPrx->begin_query(input.toIce());
+                // You could pass the query function itself to async here,
+                // but that caused severe template headaches when I tried it.
+                queries[name] =
+                    std::async(std::launch::async,
+                               [&reader, input, recursionDepth, this]()
+                               {
+                                   // Can't resolve MemoryLinks without data
+                                   return recursionDepth == 0 || input.dataMode == DataMode::NoData
+                                              ? reader.query(input.toIce())
+                                              : reader.query(input.toIce(), mns, recursionDepth);
+                               });
             }
         }
     }
 
 
     std::map<std::string, client::QueryResult>
-    MemoryViewer::collectQueryResults(std::map<std::string, Ice::AsyncResultPtr>& queries,
-                                      const std::map<std::string, client::Reader>& readers)
+    MemoryViewer::collectQueryResults(
+        std::map<std::string, std::future<armem::query::data::Result>>& queries,
+        const std::map<std::string, client::Reader>& readers)
     {
         TIMING_START(tCollectQueryResults)
 
@@ -382,16 +399,15 @@ namespace armarx::armem::gui
         for (auto it = queries.begin(); it != queries.end();)
         {
             const std::string& name = it->first;
-            Ice::AsyncResultPtr& queryPromise = it->second;
+            std::future<armem::query::data::Result>* queryPromise = &it->second;
 
-            if (queryPromise->isCompleted())
+            if (queryPromise->wait_for(std::chrono::seconds(0)) == std::future_status::ready)
             {
                 if (auto jt = memoryReaders.find(name); jt != readers.end())
                 {
                     try
                     {
-                        results[name] = client::QueryResult::fromIce(
-                            jt->second.memoryPrx->end_query(queryPromise));
+                        results[name] = client::QueryResult::fromIce(queryPromise->get());
                     }
                     catch (const Ice::ConnectionRefusedException&)
                     {
@@ -401,7 +417,7 @@ namespace armarx::armem::gui
                 // else: Server is gone (MNS knew about it) => Skip result.
 
                 // Promise is completed => Clean up in any case.
-                it = runningQueries.erase(it);
+                it = queries.erase(it);
             }
             else
             {
diff --git a/source/RobotAPI/libraries/armem_gui/MemoryViewer.h b/source/RobotAPI/libraries/armem_gui/MemoryViewer.h
index 51cda4cb797911c3afcd1afaf43657b145b9a140..9b0d2a8fff364cd2f702c11a1769243b435ac0ce 100644
--- a/source/RobotAPI/libraries/armem_gui/MemoryViewer.h
+++ b/source/RobotAPI/libraries/armem_gui/MemoryViewer.h
@@ -1,5 +1,6 @@
 #pragma once
 
+#include <future>
 #include <string>
 
 #include <QObject>
@@ -120,12 +121,12 @@ namespace armarx::armem::gui
 
         /// Start a query for each entry in `memoryReaders` which is not in `runningQueries`.
         void startDueQueries(
-            std::map<std::string, Ice::AsyncResultPtr>& queries,
+            std::map<std::string, std::future<armem::query::data::Result>>& queries,
             const std::map<std::string, armem::client::Reader>& readers);
 
         std::map<std::string, client::QueryResult>
         collectQueryResults(
-            std::map<std::string, Ice::AsyncResultPtr>& queries,
+            std::map<std::string, std::future<armem::query::data::Result>>& queries,
             const std::map<std::string, armem::client::Reader>& readers);
 
         void applyQueryResults(
@@ -142,7 +143,7 @@ namespace armarx::armem::gui
         std::map<std::string, armem::client::Writer> memoryWriters;
         std::map<std::string, armem::wm::Memory> memoryData;
 
-        std::map<std::string, Ice::AsyncResultPtr> runningQueries;
+        std::map<std::string, std::future<armem::query::data::Result>> runningQueries;
         /// Periodically triggers query result collection.
         QTimer* processQueryResultTimer;
 
diff --git a/source/RobotAPI/libraries/armem_gui/instance/MemoryIDTreeWidgetItem.cpp b/source/RobotAPI/libraries/armem_gui/instance/MemoryIDTreeWidgetItem.cpp
index ebb4473bb1941a713526d646b37744f5a3314c1c..5cde16500c5e1dbd05f9f376ccf84f3bd2504f39 100644
--- a/source/RobotAPI/libraries/armem_gui/instance/MemoryIDTreeWidgetItem.cpp
+++ b/source/RobotAPI/libraries/armem_gui/instance/MemoryIDTreeWidgetItem.cpp
@@ -36,7 +36,7 @@ namespace armarx::armem::gui::instance
             static const char* mu = "\u03BC";
             std::stringstream ss;
             ss << toDateTimeMilliSeconds(id.timestamp)
-               << " (" << id.timestamp.toMicroSeconds() << " " << mu << "s)";
+               << " (" << id.timestamp.toMicroSecondsSinceEpoch() << " " << mu << "s)";
             child(4)->setText(valueColumn, QString::fromStdString(ss.str()));
         }
     }
diff --git a/source/RobotAPI/libraries/armem_gui/instance/display_visitors/TypedDataDisplayVisitor.cpp b/source/RobotAPI/libraries/armem_gui/instance/display_visitors/TypedDataDisplayVisitor.cpp
index 6a132629b65031c1b27225528872bcb4c20cd611..eed9bb9ef66902f3ed15a5ad238bdc24c01b2595 100644
--- a/source/RobotAPI/libraries/armem_gui/instance/display_visitors/TypedDataDisplayVisitor.cpp
+++ b/source/RobotAPI/libraries/armem_gui/instance/display_visitors/TypedDataDisplayVisitor.cpp
@@ -87,7 +87,7 @@ namespace armarx::aron
     void TypedDataDisplayVisitor::visitTime(const data::VariantPtr& data, const type::VariantPtr& type)
     {
         auto l = data::Long::DynamicCastAndCheck(data);
-        armem::Time time = armem::Time::microSeconds(l->getValue());
+        armem::Time time { armem::Duration::MicroSeconds(l->getValue()) };
         value << armem::toDateTimeMilliSeconds(time);
     }
 
diff --git a/source/RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilder.cpp b/source/RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilder.cpp
index 5ed578979d2516f3c089685c1bf5bc44843ad157..27cb691cf870d1663305cb25a60f2541dc29e7c6 100644
--- a/source/RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilder.cpp
+++ b/source/RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilder.cpp
@@ -18,7 +18,7 @@ namespace armarx::armem::gui::instance
         builder.setUpdateItemFn([this, &data](const std::string & key, QTreeWidgetItem * item)
         {
             auto child = data->getElement(key);
-            this->update(item, key, child);
+            this->update(item, key, child, data->getPath());
             return true;
         });
 
@@ -27,20 +27,24 @@ namespace armarx::armem::gui::instance
 
     void DataTreeBuilder::updateTree(QTreeWidgetItem* parent, const aron::data::ListPtr& data)
     {
-        auto children = data->getChildren();
 
         ListBuilder builder = getListBuilder();
-        builder.setUpdateItemFn([this, &children](size_t key, QTreeWidgetItem * item)
+        builder.setUpdateItemFn([this, &data](size_t key, QTreeWidgetItem * item)
         {
-            this->update(item, std::to_string(key), children.at(key));
+            auto child = data->getElement(key);
+            this->update(item, std::to_string(key), child, data->getPath());
             return true;
         });
 
-        builder.updateTreeWithContainer(parent, getIndex(children.size()));
+        builder.updateTreeWithContainer(parent, getIndex(data->childrenSize()));
     }
 
 
-    void DataTreeBuilder::update(QTreeWidgetItem* item, const std::string& key, const aron::data::VariantPtr& data)
+    void
+    DataTreeBuilder::update(QTreeWidgetItem* item,
+                            const std::string& key,
+                            const aron::data::VariantPtr& data,
+                            const aron::Path& parentPath)
     {
         if (data)
         {
@@ -59,8 +63,9 @@ namespace armarx::armem::gui::instance
         {
             // Optional data?
             this->setRowTexts(item, key, "(none)");
+            auto empty = std::make_shared<aron::data::Dict>(parentPath.withElement(key));
+            updateTree(item, empty);
         }
-    }
-
 
+    }
 }
diff --git a/source/RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilder.h b/source/RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilder.h
index 4ae61c3036195e08055582d5e7251857a30ca650..80773c86aa7074b88b962fa2ae44c7b4f54e65f1 100644
--- a/source/RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilder.h
+++ b/source/RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilder.h
@@ -22,9 +22,9 @@ namespace armarx::armem::gui::instance
 
 
     protected:
-
-        void update(QTreeWidgetItem* item, const std::string& key, const aron::data::VariantPtr& data);
-
+        void update(QTreeWidgetItem* item,
+                    const std::string& key,
+                    const aron::data::VariantPtr& data,
+                    const aron::Path& parentPath);
     };
-
 }
diff --git a/source/RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.cpp b/source/RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.cpp
index de85c11c08080c88c5f5d72f5b00900547a66fbc..70edd5a5149617618e8ab023a8ccb48f4a629dee 100644
--- a/source/RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.cpp
+++ b/source/RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.cpp
@@ -213,31 +213,31 @@ namespace armarx::armem::gui::instance
             }
         }
 
-        if (data)
+        // We pass empty containers if data is null so that subitems of the data are deleted.
+        auto emptyDict = aron::data::Dict(type->getPath());
+        auto emptyList = aron::data::List(type->getPath());
+        if (const auto d = aron::data::Dict::DynamicCast(data); const auto t = type::Object::DynamicCast(type))
         {
-            if (const auto d = aron::data::Dict::DynamicCast(data); const auto t = type::Object::DynamicCast(type))
-            {
-                _updateTree(item, *t, *d);
-            }
-            else if (const auto d = aron::data::Dict::DynamicCast(data); const auto t = type::Dict::DynamicCast(type))
-            {
-                _updateTree(item, *t, *d);
-            }
-            else if (const auto d = aron::data::List::DynamicCast(data); const auto t = type::List::DynamicCast(type))
-            {
-                _updateTree(item, *t, *d);
-            }
-            else if (const auto d = aron::data::List::DynamicCast(data); const auto t = type::Pair::DynamicCast(type))
-            {
-                _updateTree(item, *t, *d);
-            }
-            else if (const auto d = aron::data::List::DynamicCast(data); const auto t = type::Tuple::DynamicCast(type))
-            {
-                _updateTree(item, *t, *d);
-            }
-            // else???
-            // phesch: else we stop here, since there's no container to recurse into.
+            _updateTree(item, *t, d ? *d : emptyDict);
+        }
+        else if (const auto d = aron::data::Dict::DynamicCast(data); const auto t = type::Dict::DynamicCast(type))
+        {
+            _updateTree(item, *t, d ? *d : emptyDict);
+        }
+        else if (const auto d = aron::data::List::DynamicCast(data); const auto t = type::List::DynamicCast(type))
+        {
+            _updateTree(item, *t, d ? *d : emptyList);
+        }
+        else if (const auto d = aron::data::List::DynamicCast(data); const auto t = type::Pair::DynamicCast(type))
+        {
+            _updateTree(item, *t, d ? *d : emptyList);
+        }
+        else if (const auto d = aron::data::List::DynamicCast(data); const auto t = type::Tuple::DynamicCast(type))
+        {
+            _updateTree(item, *t, d ? *d : emptyList);
         }
+        // else???
+        // phesch: else we stop here, since there's no container to recurse into.
     }
 
     
diff --git a/source/RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedDataVisitor.cpp b/source/RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedDataVisitor.cpp
index 3a3a3b4d6f007a92a009df9d59ddd5ad65d9c070..bc8c27104f78f11547ecc72c6dbc93cded31893b 100644
--- a/source/RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedDataVisitor.cpp
+++ b/source/RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedDataVisitor.cpp
@@ -24,7 +24,7 @@ namespace armarx::armem::gui::instance
     void TreeTypedDataVisitor::streamValueText(const aron::data::Long& data, const aron::type::Time& type, std::stringstream& ss) const
     {
         (void) type;
-        armem::Time time = armem::Time::microSeconds(data.getValue());
+        armem::Time time { armem::Duration::MicroSeconds(data.getValue()) };
         armem::toDateTimeMilliSeconds(time);
         ss << armem::toDateTimeMilliSeconds(time);
     }
diff --git a/source/RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedJSONConverter.cpp b/source/RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedJSONConverter.cpp
index f80717342b3bc98dc1ebf9b7a72a4b274ede768a..950f034f8596fe7f3f6034ee675f3f45ffc5f08c 100644
--- a/source/RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedJSONConverter.cpp
+++ b/source/RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedJSONConverter.cpp
@@ -275,7 +275,7 @@ namespace armarx::armem::gui::instance
     {
         const std::string key = elementData->getPath().getLastElement();
         int64_t l = *aron::data::Long::DynamicCastAndCheck(elementData);
-        armem::Time time = armem::Time::microSeconds(l);
+        armem::Time time { armem::Duration::MicroSeconds(l) };
         insertIntoJSON(key, l);
         if (!jsonStack.top().second.is_array())
         {
diff --git a/source/RobotAPI/libraries/armem_gui/memory/TreeWidget.cpp b/source/RobotAPI/libraries/armem_gui/memory/TreeWidget.cpp
index 858c932bdba6825696a99de538bbdf02284c159c..f5ec0c9139e8db63acdb2ad006b15ec4ab1e32cb 100644
--- a/source/RobotAPI/libraries/armem_gui/memory/TreeWidget.cpp
+++ b/source/RobotAPI/libraries/armem_gui/memory/TreeWidget.cpp
@@ -116,12 +116,12 @@ namespace armarx::armem::gui::memory
         snapshotBuilder.setMakeItemFn([this](const wm::EntitySnapshot & snapshot)
         {
             QTreeWidgetItem* item = makeItem(toDateTimeMilliSeconds(snapshot.time()), snapshot);
-            item->setData(int(Columns::KEY), Qt::ItemDataRole::UserRole, QVariant(static_cast<qlonglong>(snapshot.time().toMicroSeconds())));
+            item->setData(int(Columns::KEY), Qt::ItemDataRole::UserRole, QVariant(static_cast<qlonglong>(snapshot.time().toMicroSecondsSinceEpoch())));
             return item;
         });
         snapshotBuilder.setCompareFn([](const wm::EntitySnapshot & snapshot, QTreeWidgetItem * item)
         {
-            return armarx::detail::compare(static_cast<qlonglong>(snapshot.time().toMicroSeconds()),
+            return armarx::detail::compare(static_cast<qlonglong>(snapshot.time().toMicroSecondsSinceEpoch()),
                                            item->data(int(Columns::KEY), Qt::ItemDataRole::UserRole).toLongLong());
         });
         snapshotBuilder.setUpdateItemFn([this](const wm::EntitySnapshot & snapshot, QTreeWidgetItem * snapshotItem)
diff --git a/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.cpp b/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.cpp
index 2bdef0d95aa45845d27170508f83aed51a3e7829..82a8cca0b365cbdb367d28cff620864c72c570f6 100644
--- a/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.cpp
+++ b/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.cpp
@@ -1,12 +1,14 @@
 #include "QueryWidget.h"
 
-#include <QWidget>
-#include <QTabWidget>
-#include <QPushButton>
 #include <QCheckBox>
+#include <QGroupBox>
 #include <QHBoxLayout>
+#include <QLabel>
+#include <QPushButton>
+#include <QSpinBox>
+#include <QTabWidget>
 #include <QVBoxLayout>
-#include <QGroupBox>
+#include <QWidget>
 
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
 
@@ -23,14 +25,20 @@ namespace armarx::armem::gui
         _dataCheckBox = new QCheckBox("Get Data");
         _dataCheckBox->setChecked(true);
 
-        _storeInLTMButton = new QPushButton("Store query result in LTM");
+        _recursionDepthSpinner = new QSpinBox();
+        _recursionDepthSpinner->setMinimum(-1);
+        _recursionDepthSpinner->setValue(0);
+        _recursionDepthSpinner->setEnabled(_dataCheckBox->isChecked());
 
-        //_tabWidget = new QTabWidget();
+        _recursionDepthLabel = new QLabel("Link resolution depth");
+
+        _storeInLTMButton = new QPushButton("Store query result in LTM");
 
         _snapshotSelectorWidget = new SnapshotSelectorWidget();
-        //_tabWidget->addTab(_snapshotSelectorWidget, QString("Snapshots"));
 
         hlayout1->addWidget(_dataCheckBox);
+        hlayout1->addWidget(_recursionDepthSpinner);
+        hlayout1->addWidget(_recursionDepthLabel);
         hlayout1->addWidget(_storeInLTMButton);
 
         hlayout2->addWidget(_snapshotSelectorWidget);
@@ -44,6 +52,10 @@ namespace armarx::armem::gui
         // Public connections.
         connect(_storeInLTMButton, &QPushButton::pressed, this, &This::storeInLTM);
 
+        // Private connections.
+        connect(
+            _dataCheckBox, &QCheckBox::stateChanged, this, &This::setRecursionDepthSpinnerEnabled);
+
         setLayout(vlayout);
     }
 
@@ -55,6 +67,11 @@ namespace armarx::armem::gui
                : armem::DataMode::NoData;
     }
 
+    int QueryWidget::queryLinkRecursionDepth() const
+    {
+        return _recursionDepthSpinner->value();
+    }
+
     armem::client::QueryInput QueryWidget::queryInput()
     {
         armem::client::query::Builder qb(dataMode());
@@ -67,4 +84,18 @@ namespace armarx::armem::gui
         return qb.buildQueryInput();
     }
 
+    void
+    QueryWidget::setRecursionDepthSpinnerEnabled(int state)
+    {
+        switch (state)
+        {
+            case Qt::Checked:
+                _recursionDepthSpinner->setEnabled(true);
+                break;
+            case Qt::Unchecked:
+            default:
+                _recursionDepthSpinner->setEnabled(false);
+                break;
+        }
+    }
 }
diff --git a/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.h b/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.h
index 2bc7f223d5db52435b7571970bb4cd398aaeec49..3b950acf05899e1e187273d1a2d7da57def4de1e 100644
--- a/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.h
+++ b/source/RobotAPI/libraries/armem_gui/query_widgets/QueryWidget.h
@@ -23,6 +23,8 @@ namespace armarx::armem::gui
 
         armem::DataMode dataMode() const;
 
+        int queryLinkRecursionDepth() const;
+
         armem::client::QueryInput queryInput();
 
 
@@ -36,6 +38,7 @@ namespace armarx::armem::gui
 
 
     private slots:
+        void setRecursionDepthSpinnerEnabled(int state);
 
     signals:
 
@@ -44,10 +47,10 @@ namespace armarx::armem::gui
     private:
 
         QCheckBox* _dataCheckBox;
+        QLabel* _recursionDepthLabel;
+        QSpinBox* _recursionDepthSpinner;
         QPushButton* _storeInLTMButton;
 
-        QTabWidget* _tabWidget;
-
         SnapshotSelectorWidget* _snapshotSelectorWidget;
 
     };
diff --git a/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotForm.cpp b/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotForm.cpp
index 1d6c0cff39fd69da5e7f29844c64fabc1843f9a4..e6ed6aaaf3d6860c2960dbb83215b5791b8b53de 100644
--- a/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotForm.cpp
+++ b/source/RobotAPI/libraries/armem_gui/query_widgets/SnapshotForm.cpp
@@ -99,9 +99,9 @@ namespace armarx::armem::gui
     void SnapshotFormSingle::fillEntitySelector(client::query::SnapshotSelector& selector)
     {
         const Time time = latest->isChecked()
-                          ? Time::microSeconds(-1)
-                          : (Time::seconds(dateTime->dateTime().toSecsSinceEpoch()))
-                          + Time::microSeconds(microseconds->value());
+                          ? Time::Invalid()
+                          : (Time(Duration::Seconds(dateTime->dateTime().toSecsSinceEpoch()))
+                             + Duration::MicroSeconds(microseconds->value()));
         selector.atTime(time);
     }
 
@@ -152,17 +152,17 @@ namespace armarx::armem::gui
 
     void SnapshotFormTimeRange::fillEntitySelector(client::query::SnapshotSelector& selector)
     {
-        Time defaults = Time::microSeconds(-1);
+        Time defaults = Time::Invalid();
         Time min = defaults, max = defaults;
 
         if (!fromBegin->isChecked())
         {
-            min = Time::milliSeconds(fromDateTime->dateTime().toMSecsSinceEpoch());
+            min = Time(Duration::MilliSeconds(fromDateTime->dateTime().toMSecsSinceEpoch()));
         }
         if (!toEnd->isChecked())
         {
-            max = Time::milliSeconds(toDateTime->dateTime().toMSecsSinceEpoch())
-                  + Time::microSeconds(int(1e6) - 1);
+            max = Time(Duration::MilliSeconds(toDateTime->dateTime().toMSecsSinceEpoch()))
+                  + Duration::MicroSeconds(int(1e6) - 1);
         }
 
         selector.timeRange(min, max);
diff --git a/source/RobotAPI/libraries/armem_motions/server/MotionSegment.cpp b/source/RobotAPI/libraries/armem_motions/server/MotionSegment.cpp
index 7b83360d50562977bf629a9ca4116f1c91089219..195cc6ebcecdc851b3c259d02172cfd43d6f7d7c 100644
--- a/source/RobotAPI/libraries/armem_motions/server/MotionSegment.cpp
+++ b/source/RobotAPI/libraries/armem_motions/server/MotionSegment.cpp
@@ -5,6 +5,7 @@
 #include "mdb_conversions.h"
 
 #include <RobotAPI/libraries/PriorKnowledge/motions/MotionFinder.h>
+#include <RobotAPI/libraries/aron/common/aron_conversions.h>
 #include <RobotAPI/libraries/armem/core/wm/memory_definitions.h>
 #include <RobotAPI/libraries/armem/server/wm/memory_definitions.h>
 
@@ -70,14 +71,14 @@ namespace armarx::armem::server::motions::mdb::segment
                             ss << "\n" << attachedFile.fileName << " (" << key << ")";
                         }
                     }
-                    ARMARX_INFO << ss.str();
+                    ARMARX_INFO << ss.str();  // ToDo @Fabian PK: Remove
                     auto& entity = this->segmentPtr->addEntity(std::to_string(op->id));
-                    auto& snapshot = entity.addSnapshot(op->createdDate);
+                    auto& snapshot = entity.addSnapshot(aron::fromAron<armem::Time>(op->createdDate));
 
                     armem::wm::EntityInstance& instance = snapshot.addInstance();
-                    instance.metadata().timeCreated = op->createdDate;
-                    instance.metadata().timeSent = IceUtil::Time::now();
-                    instance.metadata().timeArrived = IceUtil::Time::now();
+                    instance.metadata().timeCreated = aron::fromAron<armem::Time>(op->createdDate);
+                    instance.metadata().timeSent = Time::Now();
+                    instance.metadata().timeArrived = Time::Now();
                     instance.metadata().confidence = 1.0;
                     instance.data() = op->toAron();
                 }
@@ -86,7 +87,6 @@ namespace armarx::armem::server::motions::mdb::segment
                     ARMARX_WARNING << "Found an invalid path to a motion file: " << pathToInfoJson;
                 }
             }
-            IceUtil::Time::now();
 
             loadedMotions += allMotions.size();
         }
diff --git a/source/RobotAPI/libraries/armem_mps/server/MotionPrimitives/Segment.cpp b/source/RobotAPI/libraries/armem_mps/server/MotionPrimitives/Segment.cpp
index 579e921ca55cb32ebb8031202572ee0b0238390f..a45cd788ff673d0e5a9c78e5a92940d0d2daf3c9 100644
--- a/source/RobotAPI/libraries/armem_mps/server/MotionPrimitives/Segment.cpp
+++ b/source/RobotAPI/libraries/armem_mps/server/MotionPrimitives/Segment.cpp
@@ -56,21 +56,22 @@ namespace armarx::armem::server::motions::mps::segment
             auto allMotions = motionFinder.findAll("trajectories");
             for (const auto& motionFinderInfo : allMotions)
             {
-              auto pathToInfoJson = motionFinderInfo.getFullPath() / motionFinderInfo.getID();// / (motionFinderInfo.getID() + ".csv"); // todo: needs to be adapted, account for task and joint space
-              for(const auto & entry: std::filesystem::directory_iterator(pathToInfoJson)){
-                  if(std::string(entry.path().filename()).rfind("taskspace", 0) == 0){
+                auto pathToInfoJson = motionFinderInfo.getFullPath() / motionFinderInfo.getID();// / (motionFinderInfo.getID() + ".csv"); // todo: needs to be adapted, account for task and joint space
+                for (const auto & entry: std::filesystem::directory_iterator(pathToInfoJson))
+                {
+                    if (std::string(entry.path().filename()).rfind("taskspace", 0) == 0)
+                    {
                       //ARMARX_IMPORTANT << entry.path().filename();
                       loadSingleMotionFinder(entry.path(), motionFinderInfo.getID(), true);
                       loadedMotions += allMotions.size();
-                  }
-                  /*else if(std::string(entry.path().filename()).rfind("joint-trajectory", 0) == 0){
+                    }
+                    /*else if (std::string(entry.path().filename()).rfind("joint-trajectory", 0) == 0)
+                    {
                       loadSingleMotionFinder(entry.path(), motionFinderInfo.getID(), false);
                       loadedMotions += allMotions.size();
-                  }*/
-              }
-
+                    }*/
+                }
             }
-            IceUtil::Time::now();
 
             loadedMotions += allMotions.size();
         }
@@ -81,46 +82,49 @@ namespace armarx::armem::server::motions::mps::segment
     void MPSegment::loadSingleMotionFinder(const std::string &pathToInfoJson, const std::string &entityName, bool taskspace)
     {
         if (auto op = util::createFromFile(pathToInfoJson, taskspace); op.has_value())
-          {
-               std::stringstream ss;
-              ss << "Found valid instance at: " << pathToInfoJson << ". The motionID is: ";
-
-              armem::wm::EntityInstance instance;
-              instance.metadata().timeCreated = IceUtil::Time::now();//op->createdDate;
-              instance.metadata().timeSent = IceUtil::Time::now();
-              instance.metadata().timeArrived = IceUtil::Time::now();
-              instance.metadata().confidence = 1.0;
-
-              if(taskspace){
-                  std::filesystem::path path(pathToInfoJson);
-                  for(const auto & entry: std::filesystem::directory_iterator(path.parent_path())){
-                      std::string newname = "joint-trajectory" + std::string(path.filename()).erase(0, 20);
-                      if(std::string(entry.path().filename()).rfind(newname, 0) == 0){
-                          if (auto op2 = util::createFromFile(entry.path(), false); op.has_value()) // here now mps::createFromFile(pathToInfoJson)
-                          {
-                              op->jointSpace = op2->jointSpace;
-                              instance.data() = op->toAron();
-                              if(this->segmentPtr->hasEntity(entityName)){
-                                   auto& entity = this->segmentPtr->getEntity(entityName);
-                                   auto& snapshot = entity.addSnapshot(IceUtil::Time::now());
-                                   snapshot.addInstance(instance);
-                                }else{
-                                   auto& entity = this->segmentPtr->addEntity(entityName);
-                                   auto& snapshot = entity.addSnapshot(IceUtil::Time::now());
-                                   snapshot.addInstance(instance);
-                                }
-                              ARMARX_IMPORTANT << "Full content trajectory: " << op->name;
-                          }
-                      }
-                  }
-              }
-
-
-
-          }
-          else
-          {
-              ARMARX_WARNING << "Found an invalid path to a motion file: " << pathToInfoJson;
-          }
+        {
+            std::stringstream ss;
+            ss << "Found valid instance at: " << pathToInfoJson << ". The motionID is: ";
+
+            armem::wm::EntityInstance instance;
+            instance.metadata().timeCreated = armem::Time::Now();  //op->createdDate;
+            instance.metadata().timeSent = armem::Time::Now();
+            instance.metadata().timeArrived = armem::Time::Now();
+            instance.metadata().confidence = 1.0;
+
+            if(taskspace)
+            {
+                std::filesystem::path path(pathToInfoJson);
+                for (const auto & entry: std::filesystem::directory_iterator(path.parent_path()))
+                {
+                    std::string newname = "joint-trajectory" + std::string(path.filename()).erase(0, 20);
+                    if (std::string(entry.path().filename()).rfind(newname, 0) == 0)
+                    {
+                        if (auto op2 = util::createFromFile(entry.path(), false); op.has_value()) // here now mps::createFromFile(pathToInfoJson)
+                        {
+                            op->jointSpace = op2->jointSpace;
+                            instance.data() = op->toAron();
+                            if (this->segmentPtr->hasEntity(entityName))
+                            {
+                                auto& entity = this->segmentPtr->getEntity(entityName);
+                                auto& snapshot = entity.addSnapshot(armem::Time::Now());
+                                snapshot.addInstance(instance);
+                            }
+                            else
+                            {
+                                auto& entity = this->segmentPtr->addEntity(entityName);
+                                auto& snapshot = entity.addSnapshot(armem::Time::Now());
+                                snapshot.addInstance(instance);
+                            }
+                            ARMARX_IMPORTANT << "Full content trajectory: " << op->name;
+                        }
+                    }
+                }
+            }
+        }
+        else
+        {
+          ARMARX_WARNING << "Found an invalid path to a motion file: " << pathToInfoJson;
+        }
     }
 }
diff --git a/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.cpp b/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.cpp
index f26a62736999d28a55001dbaee56d515c6cdd16c..c16ff257603b9fded0a5ea72737b92b40667fdb6 100644
--- a/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.cpp
+++ b/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.cpp
@@ -24,10 +24,11 @@
 namespace armarx::armem::articulated_object
 {
 
-    VirtualRobot::RobotPtr ArticulatedObjectReader::getArticulatedObject(const std::string& name,
+    VirtualRobot::RobotPtr ArticulatedObjectReader::getArticulatedObject(
+            const std::string& name,
             const armem::Time& timestamp)
     {
-        const auto descriptions = queryDescriptions(IceUtil::Time::now());
+        const auto descriptions = queryDescriptions(armem::Time::Now());
 
         ARMARX_INFO << "Found " << descriptions.size() << " articulated object descriptions";
 
@@ -45,9 +46,9 @@ namespace armarx::armem::articulated_object
 
         ARMARX_DEBUG << "Object " << name << " available";
 
-        auto obj =
-            VirtualRobot::RobotIO::loadRobot(ArmarXDataPath::resolvePath(it->xml.serialize().path),
-                                             VirtualRobot::RobotIO::eStructure);
+        auto obj = VirtualRobot::RobotIO::loadRobot(
+                    ArmarXDataPath::resolvePath(it->xml.serialize().path),
+                    VirtualRobot::RobotIO::eStructure);
 
         if (not obj)
         {
diff --git a/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.h b/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.h
index 5d918ddf474bfb110afaede2c4ce765ae446e931..65e8f2fba2ba962429e040e1d0e1eefc514e2355 100644
--- a/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.h
+++ b/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectReader.h
@@ -10,7 +10,8 @@ namespace armarx::armem::articulated_object
     public:
         using Reader::Reader;
 
-        VirtualRobot::RobotPtr getArticulatedObject(const std::string& name,
+        VirtualRobot::RobotPtr getArticulatedObject(
+                const std::string& name,
                 const armem::Time& timestamp);
     };
 } // namespace armarx::armem::articulated_object
diff --git a/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectWriter.cpp b/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectWriter.cpp
index 8caad31be27b227a8df1eb482f568ccf023b0f33..6cbb3ecdcfee0334df79a9d6728080c5bce55f5f 100644
--- a/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectWriter.cpp
+++ b/source/RobotAPI/libraries/armem_objects/client/articulated_object/ArticulatedObjectWriter.cpp
@@ -12,7 +12,8 @@
 
 namespace armarx::armem::articulated_object
 {
-    armem::articulated_object::ArticulatedObject convert(const VirtualRobot::Robot& obj,
+    armem::articulated_object::ArticulatedObject convert(
+            const VirtualRobot::Robot& obj,
             const armem::Time& timestamp)
     {
         ARMARX_DEBUG << "Filename is " << obj.getFilename();
@@ -37,14 +38,15 @@ namespace armarx::armem::articulated_object
     }
 
     bool
-    ArticulatedObjectWriter::storeArticulatedObject(const VirtualRobot::RobotPtr& articulatedObject,
+    ArticulatedObjectWriter::storeArticulatedObject(
+            const VirtualRobot::RobotPtr& articulatedObject,
             const armem::Time& timestamp)
     {
 
         ARMARX_CHECK_NOT_NULL(articulatedObject);
 
         armarx::armem::articulated_object::ArticulatedObject armemArticulatedObject =
-            convert(*articulatedObject, IceUtil::Time::now());
+            convert(*articulatedObject, Time::Now());
 
         return store(armemArticulatedObject);
     }
diff --git a/source/RobotAPI/libraries/armem_objects/client/articulated_object/Writer.cpp b/source/RobotAPI/libraries/armem_objects/client/articulated_object/Writer.cpp
index 05506152012d6527110801adb5bfe5b015a42d1b..fbce08b6323e1a1235bd000aadbd4e73ff6cbf8c 100644
--- a/source/RobotAPI/libraries/armem_objects/client/articulated_object/Writer.cpp
+++ b/source/RobotAPI/libraries/armem_objects/client/articulated_object/Writer.cpp
@@ -97,7 +97,7 @@ namespace armarx::armem::articulated_object
 
     void Writer::updateKnownObjects()
     {
-        knownObjects = queryDescriptions(IceUtil::Time::now());
+        knownObjects = queryDescriptions(Time::Now());
 
         ARMARX_INFO << "Known articulated objects " << simox::alg::get_keys(knownObjects);
     }
diff --git a/source/RobotAPI/libraries/armem_objects/client/instance/ObjectWriter.cpp b/source/RobotAPI/libraries/armem_objects/client/instance/ObjectWriter.cpp
index ad9c8c83f2ca8889292c8a2023a74fd54528e04a..84b1e4613b8b4bbe8a72938949d503276500e407 100644
--- a/source/RobotAPI/libraries/armem_objects/client/instance/ObjectWriter.cpp
+++ b/source/RobotAPI/libraries/armem_objects/client/instance/ObjectWriter.cpp
@@ -65,7 +65,7 @@ namespace armarx::armem::obj::instance
         e.entityID.providerSegmentName = provider;
         e.entityID.entityName = inst.pose.objectID.dataset + "/" + inst.pose.objectID.className + "/" + inst.pose.objectID.instanceName;
         e.timeCreated = t;
-        e.timeSent = IceUtil::Time::now();
+        e.timeSent = armem::Time::Now();
         e.instancesData = { inst.toAron() };
 
         auto res = memoryWriter.commit(c);
diff --git a/source/RobotAPI/libraries/armem_objects/server/class/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/class/Segment.cpp
index a0e9bce51558d7fb39caf50a331919dc16034793..3250a1cca34d47df08e4d9218c0bfeda729163b0 100644
--- a/source/RobotAPI/libraries/armem_objects/server/class/Segment.cpp
+++ b/source/RobotAPI/libraries/armem_objects/server/class/Segment.cpp
@@ -79,7 +79,7 @@ namespace armarx::armem::server::obj::clazz
 
     void Segment::loadByObjectFinder()
     {
-        const Time now = TimeUtil::GetTime();
+        const Time now = Time::Now();
 
         const bool checkPaths = false;
         std::vector<ObjectInfo> infos = objectFinder.findAllObjects(checkPaths);
diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Decay.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/Decay.cpp
index df3728fb3bbc6149fb329e60a3a94083caa6a441..ac072e19693c213989cd5f6fc8acfb3de1cc8380 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/Decay.cpp
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/Decay.cpp
@@ -3,6 +3,7 @@
 #include <SimoxUtility/math/scale_value.h>
 
 #include <ArmarXCore/core/time/TimeUtil.h>
+#include <ArmarXCore/core/time/DateTime.h>
 
 
 namespace armarx::armem::server::obj::instance
@@ -24,7 +25,7 @@ namespace armarx::armem::server::obj::instance
                        "Remove objects whose confidence is lower than this value.");
     }
 
-    void Decay::updateConfidence(objpose::ObjectPose& pose, IceUtil::Time now) const
+    void Decay::updateConfidence(objpose::ObjectPose& pose, const DateTime& now) const
     {
         if (pose.attachment or pose.isStatic)
         {
@@ -36,7 +37,7 @@ namespace armarx::armem::server::obj::instance
         }
     }
 
-    void Decay::updateConfidences(objpose::ObjectPoseSeq& objectPoses, IceUtil::Time now) const
+    void Decay::updateConfidences(objpose::ObjectPoseSeq& objectPoses, const DateTime& now) const
     {
         for (objpose::ObjectPose& pose : objectPoses)
         {
@@ -44,7 +45,7 @@ namespace armarx::armem::server::obj::instance
         }
     }
 
-    float Decay::calculateConfidence(IceUtil::Time localization, IceUtil::Time now) const
+    float Decay::calculateConfidence(const DateTime& localization, const DateTime& now) const
     {
         const float duration = static_cast<float>((now - localization).toSecondsDouble());
         if (duration < delaySeconds)
diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Decay.h b/source/RobotAPI/libraries/armem_objects/server/instance/Decay.h
index a44652d5528bceefed921dec184fe8b87fd19bfe..4adf757da588b0c0525a526e70ccd707f95de9a2 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/Decay.h
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/Decay.h
@@ -1,9 +1,8 @@
 #pragma once
 
-#include <IceUtil/Time.h>
-
 #include <ArmarXCore/core/logging/Logging.h>
 #include <ArmarXCore/core/services/tasks/TaskUtil.h>
+#include <ArmarXCore/core/time/forward_declarations.h>
 
 #include <ArmarXGui/libraries/RemoteGui/Client/Widgets.h>
 
@@ -23,12 +22,12 @@ namespace armarx::armem::server::obj::instance
 
         void defineProperties(armarx::PropertyDefinitionsPtr defs, const std::string& prefix = "decay.");
 
-        void updateConfidence(objpose::ObjectPose& pose, IceUtil::Time now) const;
-        void updateConfidences(objpose::ObjectPoseSeq& objectPoses, IceUtil::Time now) const;
+        void updateConfidence(objpose::ObjectPose& pose, const DateTime& now) const;
+        void updateConfidences(objpose::ObjectPoseSeq& objectPoses, const DateTime& now) const;
 
     private:
 
-        float calculateConfidence(IceUtil::Time localization, IceUtil::Time now) const;
+        float calculateConfidence(const DateTime& localization, const DateTime& now) const;
 
 
     public:
diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/RobotHeadMovement.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/RobotHeadMovement.cpp
index 973cf5a551228705b918560ad48648db5795ab1f..d1a6c91672c595f2ceba9fa5840f30347d586fff 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/RobotHeadMovement.cpp
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/RobotHeadMovement.cpp
@@ -74,27 +74,27 @@ namespace armarx::armem::server::obj::instance
 
     void RobotHeadMovement::movementStarts(long discardIntervalMs)
     {
-        return movementStarts(IceUtil::Time::milliSeconds(discardIntervalMs));
+        return movementStarts(Duration::MilliSeconds(discardIntervalMs));
     }
-    void RobotHeadMovement::movementStarts(IceUtil::Time discardInterval)
+    void RobotHeadMovement::movementStarts(const Duration& discardInterval)
     {
-        discardUpdatesUntil = TimeUtil::GetTime() + discardInterval;
+        discardUpdatesUntil = DateTime::Now() + discardInterval;
     }
     void RobotHeadMovement::movementStops(long discardIntervalMs)
     {
-        return movementStops(IceUtil::Time::milliSeconds(discardIntervalMs));
+        return movementStops(Duration::MilliSeconds(discardIntervalMs));
     }
-    void RobotHeadMovement::movementStops(IceUtil::Time discardInterval)
+    void RobotHeadMovement::movementStops(const Duration& discardInterval)
     {
         if (discardInterval.toMilliSeconds() < 0)
         {
             //  Stop discarding.
-            discardUpdatesUntil = IceUtil::Time::milliSeconds(-1);
+            discardUpdatesUntil = DateTime::Invalid();
         }
         else
         {
             // Basically the same as starting.
-            discardUpdatesUntil = TimeUtil::GetTime() + discardInterval;
+            discardUpdatesUntil = DateTime::Now() + discardInterval;
         }
     }
 
@@ -115,7 +115,7 @@ namespace armarx::armem::server::obj::instance
                 ARMARX_UNEXPECTED_ENUM_VALUE(objpose::HeadMovementAction, input.action);
                 break;
         }
-        output.discardUpdatesUntilMilliSeconds = this->discardUpdatesUntil.toMilliSeconds();
+        output.discardUpdatesUntilMilliSeconds = this->discardUpdatesUntil.toMilliSecondsSinceEpoch();
         return output;
     }
 
@@ -131,7 +131,7 @@ namespace armarx::armem::server::obj::instance
                 // ARMARX_IMPORTANT << "Ignoring pose update because robot head is moving! until " << discardUpdatesUntil;
                 discard.all = true;
             }
-            else if (TimeUtil::GetTime() < discardUpdatesUntil)
+            else if (DateTime::Now() < discardUpdatesUntil)
             {
                 discard.all = true;
                 // ARMARX_IMPORTANT << "Ignoring pose update because robot head has moved until: " << discardUpdatesUntil;
diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/RobotHeadMovement.h b/source/RobotAPI/libraries/armem_objects/server/instance/RobotHeadMovement.h
index b6b0acb6da46d593f2da2677e9e7258ce6d7e0c2..b4da82e8239494f191cad7a1da79c39585f4b13d 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/RobotHeadMovement.h
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/RobotHeadMovement.h
@@ -4,10 +4,9 @@
 #include <vector>
 #include <optional>
 
-#include <IceUtil/Time.h>
-
 #include <ArmarXCore/interface/observers/ObserverInterface.h>
 #include <ArmarXCore/core/logging/Logging.h>
+#include <ArmarXCore/core/time/DateTime.h>
 #include <ArmarXCore/observers/variant/DatafieldRef.h>
 
 #include <ArmarXGui/libraries/RemoteGui/Client/Widgets.h>
@@ -34,16 +33,16 @@ namespace armarx::armem::server::obj::instance
         bool isMoving() const;
 
         void movementStarts(long discardIntervalMs);
-        void movementStarts(IceUtil::Time discardInterval);
+        void movementStarts(const Duration& discardInterval);
         void movementStops(long discardIntervalMs);
-        void movementStops(IceUtil::Time discardInterval);
+        void movementStops(const Duration& discardInterval);
 
         objpose::SignalHeadMovementOutput signalHeadMovement(const objpose::SignalHeadMovementInput& input);
 
 
         struct Discard
         {
-            std::optional<IceUtil::Time> updatesUntil;
+            std::optional<DateTime> updatesUntil;
             bool all = false;
         };
         Discard getDiscard();
@@ -60,7 +59,7 @@ namespace armarx::armem::server::obj::instance
 
         KinematicUnitObserverInterfacePrx kinematicUnitObserver;
         std::vector<DatafieldRefPtr> jointVelocitiesDatafields;
-        IceUtil::Time discardUpdatesUntil = IceUtil::Time::seconds(-1);
+        DateTime discardUpdatesUntil = DateTime::Invalid();
 
         DebugObserverInterfacePrx debugObserver;
 
diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
index 351d0f5ac4ef71a4e2af10a460bb796e227370f5..60fd8f1b5dd3767083ef4c41c8a52ea2188e6dde 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
@@ -9,6 +9,7 @@
 
 #include <RobotAPI/libraries/armem/core/aron_conversions.h>
 #include <RobotAPI/libraries/armem/core/error.h>
+#include <RobotAPI/libraries/armem/core/ice_conversions_templates.h>
 #include <RobotAPI/libraries/armem/client/Writer.h>
 #include <RobotAPI/libraries/armem/client/query/Builder.h>
 #include <RobotAPI/libraries/armem/client/query/query_fns.h>
@@ -29,21 +30,19 @@
 
 #include <ArmarXCore/core/logging/Logging.h>
 #include <ArmarXCore/core/system/cmake/CMakePackageFinder.h>
-#include <ArmarXCore/core/time/TimeUtil.h>
+#include <ArmarXCore/core/time/DateTime.h>
+#include <ArmarXCore/core/time/ice_conversions.h>
 
 #include <SimoxUtility/algorithm/get_map_keys_values.h>
 #include <SimoxUtility/algorithm/string.h>
 #include <SimoxUtility/json.h>
 #include <SimoxUtility/math/pose/pose.h>
 
-
 #include <Eigen/Geometry>
-#include <IceUtil/Time.h>
 
 #include <sstream>
 
 
-
 namespace armarx::armem::server::obj::instance
 {
 
@@ -148,7 +147,7 @@ namespace armarx::armem::server::obj::instance
         stats.numUpdated = 0;
         for (const objpose::data::ProvidedObjectPose& provided : providedPoses)
         {
-            const Time timestamp = Time::microSeconds(provided.timestampMicroSeconds);
+            const Time timestamp = armem::fromIce<Time>(provided.timestamp);
 
             // Check whether we have an old snapshot for this object.
             std::optional<objpose::ObjectPose> previousPose;
@@ -230,7 +229,7 @@ namespace armarx::armem::server::obj::instance
 
     void Segment::commitObjectPoses(const ObjectPoseSeq& objectPoses, const std::string& providerName)
     {
-        Time now = TimeUtil::GetTime();
+        Time now = Time::Now();
 
         ARMARX_CHECK_NOT_NULL(segmentPtr);
         const MemoryID coreSegmentID = segmentPtr->id();
@@ -269,7 +268,7 @@ namespace armarx::armem::server::obj::instance
 
 
     objpose::ObjectPoseMap
-    Segment::getObjectPoses(IceUtil::Time now)
+    Segment::getObjectPoses(const DateTime& now)
     {
         ObjectPoseMap objectPoses = getLatestObjectPoses();
         updateObjectPoses(objectPoses, now);
@@ -281,7 +280,7 @@ namespace armarx::armem::server::obj::instance
     objpose::ObjectPoseMap
     Segment::getObjectPosesByProvider(
         const std::string& providerName,
-        IceUtil::Time now)
+        const DateTime& now)
     {
         ARMARX_CHECK_NOT_NULL(segmentPtr);
         ObjectPoseMap objectPoses = getLatestObjectPoses(segmentPtr->getProviderSegment(providerName));
@@ -325,7 +324,7 @@ namespace armarx::armem::server::obj::instance
     }
 
 
-    void Segment::updateObjectPoses(ObjectPoseMap& objectPoses, IceUtil::Time now)
+    void Segment::updateObjectPoses(ObjectPoseMap& objectPoses, const DateTime& now)
     {
         bool agentSynchronized = false;
 
@@ -338,7 +337,7 @@ namespace armarx::armem::server::obj::instance
 
     void Segment::updateObjectPoses(
         ObjectPoseMap& objectPoses,
-        IceUtil::Time now,
+        const DateTime& now,
         VirtualRobot::RobotPtr agent,
         bool& agentSynchronized) const
     {
@@ -351,7 +350,7 @@ namespace armarx::armem::server::obj::instance
 
     void Segment::updateObjectPose(
         ObjectPose& objectPose,
-        IceUtil::Time now,
+        const DateTime& now,
         VirtualRobot::RobotPtr agent,
         bool& agentSynchronized) const
     {
@@ -493,7 +492,7 @@ namespace armarx::armem::server::obj::instance
     ::armarx::armem::articulated_object::ArticulatedObjects
     Segment::getArticulatedObjects()
     {
-        objpose::ObjectPoseMap objectPoses = getObjectPoses(IceUtil::Time::now());
+        objpose::ObjectPoseMap objectPoses = getObjectPoses(Time::Now());
 
         ARMARX_INFO << "Found " << objectPoses.size() << " object poses";
 
@@ -507,7 +506,6 @@ namespace armarx::armem::server::obj::instance
             articulatedObject.instance = objectPose.objectID.instanceName();
             articulatedObject.timestamp = objectPose.timestamp;
 
-
             ARMARX_INFO << "Object id is " << objectId.str();
             ARMARX_INFO << "Object id for objectPose is " << objectPose.objectID.str();
 
@@ -537,8 +535,6 @@ namespace armarx::armem::server::obj::instance
                 continue;
             }
 
-
-
             if (not articulatedObject.config.jointMap.empty())
             {
                 objects.push_back(articulatedObject);
@@ -578,7 +574,7 @@ namespace armarx::armem::server::obj::instance
     objpose::AttachObjectToRobotNodeOutput
     Segment::attachObjectToRobotNode(const objpose::AttachObjectToRobotNodeInput& input)
     {
-        const armem::Time now = armem::Time::now();
+        const armem::Time now = armem::Time::Now();
 
         objpose::AttachObjectToRobotNodeOutput output;
         output.success = false;  // We are not successful until proven otherwise.
@@ -670,7 +666,7 @@ namespace armarx::armem::server::obj::instance
     Segment::detachObjectFromRobotNode(
         const objpose::DetachObjectFromRobotNodeInput& input)
     {
-        const armem::Time now = armem::Time::now();
+        const armem::Time now = armem::Time::Now();
 
         ObjectID objectID = armarx::fromIce(input.objectID);
         std::string providerName = input.providerName;
@@ -720,7 +716,7 @@ namespace armarx::armem::server::obj::instance
     {
         ARMARX_CHECK_NOT_NULL(segmentPtr);
 
-        const armem::Time now = armem::Time::now();
+        const armem::Time now = armem::Time::Now();
 
         objpose::DetachAllObjectsFromRobotNodesOutput output;
         output.numDetached = 0;
@@ -867,7 +863,7 @@ namespace armarx::armem::server::obj::instance
         std::string filename = _filename;
 
         filename = simox::alg::replace_all(filename, timestampPlaceholder,
-                                           Time::now().toString("%Y-%m-%d_%H-%M-%S"));
+                                           Time::Now().toString("%Y-%m-%d_%H-%M-%S"));
         if (not simox::alg::ends_with(filename, ".json"))
         {
             filename += ".json";
@@ -925,7 +921,7 @@ namespace armarx::armem::server::obj::instance
 
     void Segment::commitSceneSnapshot(const armarx::objects::Scene& scene, const std::string& sceneName)
     {
-        const Time now = TimeUtil::GetTime();
+        const Time now = Time::Now();
         std::map<ObjectID, int> idCounters;
 
         objpose::ObjectPoseSeq objectPoses;
diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h
index 24f80704f8580c386bfaf346502cccd9fa86c1c6..da97aac841559b845fb308e93ac572739efb7c3c 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h
@@ -16,6 +16,7 @@
 #include <RobotAPI/libraries/ArmarXObjects/ObjectID.h>
 #include <RobotAPI/libraries/ArmarXObjects/ObjectPose.h>
 #include <RobotAPI/libraries/ArmarXObjects/ObjectFinder.h>
+#include <RobotAPI/libraries/ArmarXObjects/forward_declarations.h>
 
 #include <RobotAPI/libraries/armem/server/wm/memory_definitions.h>
 #include <RobotAPI/libraries/armem/server/segment/SpecializedSegment.h>
@@ -24,10 +25,6 @@
 #include "Decay.h"
 
 
-namespace armarx::objects
-{
-    struct Scene;
-}
 namespace armarx::armem::arondto
 {
     class ObjectInstance;
@@ -68,8 +65,8 @@ namespace armarx::armem::server::obj::instance
         void commitObjectPoses(const ObjectPoseSeq& objectPoses, const std::string& providerName = "");
 
 
-        objpose::ObjectPoseMap getObjectPoses(IceUtil::Time now);
-        objpose::ObjectPoseMap getObjectPosesByProvider(const std::string& providerName, IceUtil::Time now);
+        objpose::ObjectPoseMap getObjectPoses(const DateTime& now);
+        objpose::ObjectPoseMap getObjectPosesByProvider(const std::string& providerName, const DateTime& now);
 
         wm::Entity* findObjectEntity(const ObjectID& objectID, const std::string& providerName = "");
         std::optional<simox::OrientedBoxf> getObjectOOBB(const ObjectID& id);
@@ -115,16 +112,16 @@ namespace armarx::armem::server::obj::instance
 
         void updateObjectPoses(
             ObjectPoseMap& objectPoses,
-            IceUtil::Time now);
+            const DateTime& now);
         void updateObjectPoses(
             ObjectPoseMap& objectPoses,
-            IceUtil::Time now,
+            const DateTime& now,
             VirtualRobot::RobotPtr agent,
             bool& agentSynchronized
         ) const;
         void updateObjectPose(
             ObjectPose& objectPose,
-            IceUtil::Time now,
+            const DateTime& now,
             VirtualRobot::RobotPtr agent,
             bool& agentSynchronized
         ) const;
diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp
index ef00638e9ed76d0bbe05de3ab6af98f3687fe9d7..b7f7a63085b31cb3672ad6c0307fc5afe2096c4e 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp
@@ -218,7 +218,7 @@ namespace armarx::armem::server::obj::instance
     {
         TIMING_START(tGetObjectPoses);
 
-        const IceUtil::Time now = TimeUtil::GetTime();
+        const Time now = Time::Now();
         const objpose::ObjectPoseSeq objectPoses = segment.doLocked([this, &now]()
         {
             return simox::alg::get_values(segment.getObjectPoses(now));
@@ -242,7 +242,7 @@ namespace armarx::armem::server::obj::instance
     {
         TIMING_START(GetObjectPoses);
 
-        const IceUtil::Time now = TimeUtil::GetTime();
+        const Time now = Time::Now();
         const objpose::ObjectPoseSeq objectPoses = segment.doLocked([this, &now, &providerName]()
         {
             return simox::alg::get_values(segment.getObjectPosesByProvider(providerName, now));
@@ -451,7 +451,7 @@ namespace armarx::armem::server::obj::instance
 
                     segment.doLocked([this, &objectPoses, &objectFinder]()
                     {
-                        const IceUtil::Time now = TimeUtil::GetTime();
+                        const Time now = Time::Now();
 
                         // Also include decayed objects in result
                         // Store original setting.
diff --git a/source/RobotAPI/libraries/armem_robot/aron_conversions.cpp b/source/RobotAPI/libraries/armem_robot/aron_conversions.cpp
index 0ab9ff1a46f9e756471ccf8d257e966dcfb7f2ef..5db2b55603580aa42450938630483d2e8c4270f5 100644
--- a/source/RobotAPI/libraries/armem_robot/aron_conversions.cpp
+++ b/source/RobotAPI/libraries/armem_robot/aron_conversions.cpp
@@ -53,14 +53,14 @@ namespace armarx::armem::robot
 
     void fromAron(const arondto::RobotState& dto, RobotState& bo)
     {
-        bo.timestamp = dto.timestamp;
+        fromAron(dto.timestamp, bo.timestamp);
         bo.globalPose.matrix() = dto.globalPose;
         bo.jointMap            = dto.jointMap;
     }
 
     void toAron(arondto::RobotState& dto, const RobotState& bo)
     {
-        dto.timestamp = bo.timestamp;
+        toAron(dto.timestamp, bo.timestamp);
         dto.globalPose = bo.globalPose.matrix();
         dto.jointMap   = bo.jointMap;
     }
@@ -97,14 +97,14 @@ namespace armarx::armem
 
     void robot::fromAron(const objpose::arondto::ObjectPose& dto, RobotState& bo)
     {
-        bo.timestamp = dto.timestamp;
+        fromAron(dto.timestamp, bo.timestamp);
         bo.globalPose = dto.objectPoseGlobal;
         bo.jointMap = dto.objectJointValues;
     }
 
     void robot::toAron(objpose::arondto::ObjectPose& dto, const RobotState& bo)
     {
-        dto.timestamp = bo.timestamp;
+        toAron(dto.timestamp, bo.timestamp);
         dto.objectPoseGlobal = bo.globalPose.matrix();
         dto.objectJointValues = bo.jointMap;
     }
diff --git a/source/RobotAPI/libraries/armem_robot/types.cpp b/source/RobotAPI/libraries/armem_robot/types.cpp
index 01847402c1e1bdde24956203620c13e15328e913..6f09eee1acef62472a1e8cc0027f49c9db6efe46 100644
--- a/source/RobotAPI/libraries/armem_robot/types.cpp
+++ b/source/RobotAPI/libraries/armem_robot/types.cpp
@@ -1,11 +1,24 @@
 #include "types.h"
 
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+
+
 namespace armarx::armem::robot
 {
-  std::ostream& operator<<(std::ostream &os, const RobotDescription &rhs) 
-  {
-     os << "RobotDescription { name: '" << rhs.name << "', xml: '" << rhs.xml << "' }";
-     return os;
-  }
+
+    std::ostream& operator<<(std::ostream &os, const RobotDescription &rhs)
+    {
+        os << "RobotDescription { name: '" << rhs.name << "', xml: '" << rhs.xml << "' }";
+        return os;
+    }
+
+
+    std::string Robot::name() const
+    {
+        ARMARX_CHECK_NOT_EMPTY(description.name) << "The robot name must be set!";
+        ARMARX_CHECK_NOT_EMPTY(instance) << "The robot instance name must be provided!";
+
+        return description.name + "/" + instance;
+    }
   
 }
diff --git a/source/RobotAPI/libraries/armem_robot/types.h b/source/RobotAPI/libraries/armem_robot/types.h
index 10ca7475f0d119aeb8f40e2f0d674bb3a6450691..345564d4b859af306acecdc82d00096c4a559351 100644
--- a/source/RobotAPI/libraries/armem_robot/types.h
+++ b/source/RobotAPI/libraries/armem_robot/types.h
@@ -1,23 +1,22 @@
 #pragma once
 
+#include <filesystem>
 #include <map>
 #include <vector>
-#include <filesystem>
 
 #include <Eigen/Geometry>
 
-#include <IceUtil/Time.h>
+#include <ArmarXCore/core/PackagePath.h>
+#include <ArmarXCore/core/time/DateTime.h>
 
-#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
 #include <RobotAPI/libraries/ArmarXObjects/ObjectID.h>
-#include <ArmarXCore/core/PackagePath.h>
 
 
 namespace armarx::armem::robot
 {
     struct RobotDescription
     {
-        // IceUtil::Time timestamp;
+        // DateTime timestamp;
 
         std::string name;
         PackagePath xml{"", std::filesystem::path("")};
@@ -46,7 +45,7 @@ namespace armarx::armem::robot
         using JointMap = std::map<std::string, float>;
         using Pose = Eigen::Affine3f;
 
-        IceUtil::Time timestamp;
+        DateTime timestamp;
 
         Pose globalPose;
         JointMap jointMap;
@@ -60,15 +59,9 @@ namespace armarx::armem::robot
 
         RobotState config;
 
-        IceUtil::Time timestamp;
-
-        std::string name() const 
-        {
-            ARMARX_CHECK_NOT_EMPTY(description.name) << "The robot name must be set!";
-            ARMARX_CHECK_NOT_EMPTY(instance) << "The robot instance name must be provided!";
+        DateTime timestamp;
 
-            return description.name + "/" + instance;
-        }
+        std::string name() const;
     };
 
     using Robots = std::vector<Robot>;
diff --git a/source/RobotAPI/libraries/armem_robot_state/aron_conversions.cpp b/source/RobotAPI/libraries/armem_robot_state/aron_conversions.cpp
index 03a578fab3b9250f724efcd646c24400d8a898d2..30f3a489cc9b7b2e8bc8f6e80c76d7bbccf15142 100644
--- a/source/RobotAPI/libraries/armem_robot_state/aron_conversions.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/aron_conversions.cpp
@@ -2,15 +2,15 @@
 
 #include <string>
 
-#include <IceUtil/Time.h>
-
 #include <ArmarXCore/core/logging/Logging.h>
+
 #include <RobotAPI/libraries/armem_robot_state/aron/JointState.aron.generated.h>
 #include <RobotAPI/libraries/armem_robot_state/aron/Proprioception.aron.generated.h>
 #include <RobotAPI/libraries/armem_robot_state/aron/Transform.aron.generated.h>
 #include <RobotAPI/libraries/armem_robot_state/types.h>
 #include <RobotAPI/libraries/aron/common/aron_conversions.h>
 
+
 namespace armarx::armem
 {
 
@@ -38,7 +38,7 @@ namespace armarx::armem
         aron::toAron(dto.parentFrame, bo.parentFrame);
         aron::toAron(dto.frame, bo.frame);
         aron::toAron(dto.agent, bo.agent);
-        dto.timestamp = bo.timestamp;
+        toAron(dto.timestamp, bo.timestamp);
     }
 
     void
@@ -47,7 +47,7 @@ namespace armarx::armem
         aron::fromAron(dto.parentFrame, bo.parentFrame);
         aron::fromAron(dto.frame, bo.frame);
         aron::fromAron(dto.agent, bo.agent);
-        bo.timestamp = dto.timestamp;
+        fromAron(dto.timestamp, bo.timestamp);
     }
 
     /* JointState */
diff --git a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp
index b3dee3440967cf79ae9feee73403116345a23cbf..7a4305c6fe26ea6bf54aab17e9e87843688aa0a1 100644
--- a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.cpp
@@ -9,6 +9,7 @@
 #include <ArmarXCore/core/exceptions/LocalException.h>
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
 #include <ArmarXCore/core/logging/Logging.h>
+#include <ArmarXCore/core/time/Clock.h>
 
 #include <RobotAPI/libraries/armem/client/query/Builder.h>
 #include <RobotAPI/libraries/armem/core/Time.h>
@@ -94,13 +95,13 @@ namespace armarx::armem::robot_state
     }
 
     void
-    RobotReader::setSyncTimeout(const armem::Time& duration)
+    RobotReader::setSyncTimeout(const armem::Duration& duration)
     {
         syncTimeout = duration;
     }
 
     void
-    RobotReader::setSleepAfterSyncFailure(const armem::Time& duration)
+    RobotReader::setSleepAfterSyncFailure(const armem::Duration& duration)
     {
         ARMARX_CHECK_NONNEGATIVE(duration.toMicroSeconds());
         sleepAfterFailure = duration;
@@ -109,7 +110,7 @@ namespace armarx::armem::robot_state
     bool
     RobotReader::synchronize(robot::Robot& obj, const armem::Time& timestamp)
     {
-        const auto tsStartFunctionInvokation = armem::Time::now();
+        const auto tsStartFunctionInvokation = armem::Time::Now();
 
         while (true)
         {
@@ -120,7 +121,7 @@ namespace armarx::armem::robot_state
                 ARMARX_VERBOSE << "Could not synchronize object " << obj.description.name;
 
                 // if the syncTime is non-positive there will be no retry
-                const auto elapsedTime = armem::Time::now() - tsStartFunctionInvokation;
+                const auto elapsedTime = armem::Time::Now() - tsStartFunctionInvokation;
                 if (elapsedTime > syncTimeout)
                 {
                     ARMARX_WARNING << "Could not synchronize object " << obj.description.name;
@@ -128,8 +129,7 @@ namespace armarx::armem::robot_state
                 }
 
                 ARMARX_INFO << "Retrying to query robot state after failure";
-                std::this_thread::sleep_for(
-                    std::chrono::microseconds(sleepAfterFailure.toMicroSeconds()));
+                Clock::WaitFor(sleepAfterFailure);
             }
 
             obj.config = std::move(*state);
diff --git a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.h b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.h
index 46b0924fc2cb06ebee34ff8b61174746939dd7dc..6682fcd79130501530d54f770d342d02676fd069 100644
--- a/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.h
+++ b/source/RobotAPI/libraries/armem_robot_state/client/common/RobotReader.h
@@ -24,7 +24,7 @@
 #include <mutex>
 #include <optional>
 
-#include "RobotAPI/libraries/armem/core/Time.h"
+#include <RobotAPI/libraries/armem/core/Time.h>
 #include <RobotAPI/libraries/armem/client/MemoryNameSystem.h>
 #include <RobotAPI/libraries/armem/client/Reader.h>
 #include <RobotAPI/libraries/armem_robot/client/interfaces.h>
@@ -81,8 +81,8 @@ namespace armarx::armem::robot_state
         queryPlatformState(const robot::RobotDescription& description,
                            const armem::Time& timestamp) const;
 
-        void setSyncTimeout(const armem::Time& duration);
-        void setSleepAfterSyncFailure(const armem::Time& duration);
+        void setSyncTimeout(const armem::Duration& duration);
+        void setSleepAfterSyncFailure(const armem::Duration& duration);
 
         enum class Hand
         {
@@ -101,8 +101,8 @@ namespace armarx::armem::robot_state
 
     protected:
         // by default, no timeout mechanism
-        armem::Time syncTimeout = armem::Time::microSeconds(0);
-        armem::Time sleepAfterFailure = armem::Time::microSeconds(0);
+        armem::Duration syncTimeout  = armem::Duration::MicroSeconds(0);
+        armem::Duration sleepAfterFailure = armem::Duration::MicroSeconds(0);
 
     private:
         std::optional<robot::RobotState> getRobotState(const armarx::armem::wm::Memory& memory,
diff --git a/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.cpp b/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.cpp
index 5ef7564f8a0e374060114d0391bfaeebf1df6198..6eeb7e2e9503dd6cf0f876bc4676dc50effc3b50 100644
--- a/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/client/common/VirtualRobotReader.cpp
@@ -11,6 +11,7 @@
 #include <ArmarXCore/core/logging/Logging.h>
 #include <ArmarXCore/core/system/ArmarXDataPath.h>
 #include <ArmarXCore/core/system/cmake/CMakePackageFinder.h>
+#include <ArmarXCore/core/time/Clock.h>
 
 
 namespace armarx::armem::robot_state
@@ -100,8 +101,7 @@ namespace armarx::armem::robot_state
             }
 
             ARMARX_INFO << "Retrying to query robot after failure";
-            std::this_thread::sleep_for(
-                std::chrono::microseconds(sleepAfterFailure.toMicroSeconds()));
+            Clock::WaitFor(sleepAfterFailure);
         }
 
         ARMARX_WARNING << "Failed to get synchronized robot `" << name << "`";
diff --git a/source/RobotAPI/libraries/armem_robot_state/client/localization/TransformWriter.cpp b/source/RobotAPI/libraries/armem_robot_state/client/localization/TransformWriter.cpp
index ba34586a1e77390efbecd18abba1e726db6f7467..932f55b0a6ea2ff74762a62ffa74f88d0ff18422 100644
--- a/source/RobotAPI/libraries/armem_robot_state/client/localization/TransformWriter.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/client/localization/TransformWriter.cpp
@@ -94,7 +94,7 @@ namespace armarx::armem::client::robot_state::localization
         // const auto& timestamp = transform.header.timestamp;
         const MemoryID entityID = providerId.withEntityName(
                                       transform.header.parentFrame + "," + transform.header.frame);
-        const Time timestamp = Time::now(); // FIXME remove
+        const Time timestamp = Time::Now();  // FIXME remove
 
         armem::EntityUpdate update;
         update.entityID = entityID;
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/common/Visu.cpp b/source/RobotAPI/libraries/armem_robot_state/server/common/Visu.cpp
index 67d537d19cf74af3da62dc72ae217f996977433f..e68119affae5664f232dba25c679a8cce9fbdd10 100644
--- a/source/RobotAPI/libraries/armem_robot_state/server/common/Visu.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/server/common/Visu.cpp
@@ -123,7 +123,7 @@ namespace armarx::armem::server::robot_state
         {
             if (p.enabled)
             {
-                const Time timestamp = Time::now();
+                const Time timestamp = Time::Now();
                 ARMARX_DEBUG << "Visu task at " << armem::toStringMilliSeconds(timestamp);
 
                 try
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/description/Segment.cpp b/source/RobotAPI/libraries/armem_robot_state/server/description/Segment.cpp
index 185356425ca3d657014f2b0e0b2e56631e443f4f..f6cba1d8c22086497f7eb537c6a3e16fa2e2faf4 100644
--- a/source/RobotAPI/libraries/armem_robot_state/server/description/Segment.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/server/description/Segment.cpp
@@ -44,7 +44,7 @@ namespace armarx::armem::server::robot_state::description
 
     void Segment::commitRobotDescription(const robot::RobotDescription& robotDescription)
     {
-        const Time now = TimeUtil::GetTime();
+        const Time now = Time::Now();
 
         const MemoryID providerID = segmentPtr->id().withProviderSegmentName(robotDescription.name);
         segmentPtr->addProviderSegment(providerID.providerSegmentName, arondto::RobotDescription::ToAronType());
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.cpp
index 12638d84e18a8a3439b560fb9e2287c3fe233c79..f50c4e5619d70b7910d6d3ef544c2ca4f9d7fdc9 100644
--- a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/RobotUnitReader.cpp
@@ -89,7 +89,7 @@ namespace armarx::armem::server::robot_state::proprioception
 
         RobotUnitData result;
         result.proprioception = converter->convert(data.value(), description);
-        result.timestamp = Time::microSeconds(data->timestampUSec);
+        result.timestamp = Time(Duration::MicroSeconds(data->timestampUSec));
 
         auto stop = std::chrono::high_resolution_clock::now();
         auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
diff --git a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.cpp b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.cpp
index 9bf3f1e8129fe0d2f2194d1f9e223077678e93f0..ca9e43ed9d4a7022dd4c6a4eecba530e81bf7b21 100644
--- a/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.cpp
+++ b/source/RobotAPI/libraries/armem_robot_state/server/proprioception/Segment.cpp
@@ -78,7 +78,7 @@ namespace armarx::armem::server::robot_state::proprioception
         RobotJointPositionMap jointMap;
         int i = 0;
 
-        Duration tFindData = Duration::milliSeconds(0), tReadJointPositions = Duration::milliSeconds(0);
+        Duration tFindData = Duration::MilliSeconds(0), tReadJointPositions = Duration::MilliSeconds(0);
         TIMING_START(tProcessEntities)
         segmentPtr->forEachEntity([&](const wm::Entity & entity)
         {
@@ -97,8 +97,8 @@ namespace armarx::armem::server::robot_state::proprioception
                     data = snapshot->findInstanceData();
                 }
 
-                TIMING_END_COMMENT_STREAM(_tFindData, "tFindData " + std::to_string(i), ARMARX_DEBUG)
-                tFindData += _tFindData;
+                TIMING_END_COMMENT_STREAM(_tFindData, "tFindData " + std::to_string(i), ARMARX_DEBUG);
+                tFindData += Duration::MicroSeconds(_tFindData.toMicroSeconds());
             }
             if (data)
             {
@@ -107,7 +107,7 @@ namespace armarx::armem::server::robot_state::proprioception
                 jointMap.emplace(entity.id().providerSegmentName, readJointPositions(*data));
 
                 TIMING_END_COMMENT_STREAM(_tReadJointPositions, "tReadJointPositions " + std::to_string(i), ARMARX_DEBUG)
-                tReadJointPositions += _tReadJointPositions;
+                tReadJointPositions += Duration::MicroSeconds(_tReadJointPositions.toMicroSeconds());
             }
             ++i;
         });
diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.cpp b/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.cpp
index 7a4b75514d9dde08b6fbd098f77547d626cb1b82..745968174eff5fbd83b4d2147fa24a7931515797 100644
--- a/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.cpp
+++ b/source/RobotAPI/libraries/armem_skills/server/segment/ExecutableSkillLibrarySegment.cpp
@@ -49,7 +49,7 @@ namespace armarx::skills::segment
             armem::Commit commit;
             auto& entityUpdate = commit.add();
             entityUpdate.confidence = 1.0;
-            entityUpdate.timeCreated = armem::Time::now();
+            entityUpdate.timeCreated = armem::Time::Now();
             entityUpdate.instancesData = {skillDescription.toAron()};
             entityUpdate.entityID = provId.withEntityName(skillDescription.skillName);
 
diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp
index 47270f33b3c20872b2d7a1d5c35058a3b618acd6..af8af24c230d36a91a52e9b15528a6fa9eff7f3a 100644
--- a/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp
+++ b/source/RobotAPI/libraries/armem_skills/server/segment/SkillEventSegment.cpp
@@ -54,7 +54,7 @@ namespace armarx::skills::segment
         armem::Commit comm;
         auto& entityUpdate = comm.add();
         entityUpdate.confidence = 1.0;
-        entityUpdate.timeCreated = armem::Time::now();
+        entityUpdate.timeCreated = armem::Time::Now();
         entityUpdate.instancesData = { aron };
         entityUpdate.entityID = commitId;
 
diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/SkillExecutionRequestSegment.cpp b/source/RobotAPI/libraries/armem_skills/server/segment/SkillExecutionRequestSegment.cpp
index 39b2ace4b719802477139cd917fff15a627e18e5..9c43b717aca7503962c1eb096202eee2e767bd00 100644
--- a/source/RobotAPI/libraries/armem_skills/server/segment/SkillExecutionRequestSegment.cpp
+++ b/source/RobotAPI/libraries/armem_skills/server/segment/SkillExecutionRequestSegment.cpp
@@ -65,7 +65,7 @@ namespace armarx::skills::segment
         entityUpdate.entityID = skillExecutionMemID;
         entityUpdate.instancesData = { aron };
         entityUpdate.confidence = 1.0;
-        entityUpdate.timeCreated = armem::Time::now();
+        entityUpdate.timeCreated = armem::Time::Now();
 
         iceMemory.commit(comm);
     }
diff --git a/source/RobotAPI/libraries/armem_skills/server/segment/StatechartListenerSegment.cpp b/source/RobotAPI/libraries/armem_skills/server/segment/StatechartListenerSegment.cpp
index cee0e3a18293dfa15534ece89c8d40f6afdca8cd..46629f7cd066751e6286cb38cb081f5442b6b869 100644
--- a/source/RobotAPI/libraries/armem_skills/server/segment/StatechartListenerSegment.cpp
+++ b/source/RobotAPI/libraries/armem_skills/server/segment/StatechartListenerSegment.cpp
@@ -26,7 +26,7 @@ namespace armarx::skills::segment
     void StatechartListenerProviderSegment::reportStatechartTransitionWithParameters(const ProfilerStatechartTransitionWithParameters& t)
     {
         const std::string& entityName = getStatechartName(t.targetStateIdentifier);
-        IceUtil::Time transitionTime = IceUtil::Time::microSeconds(t.timestamp);
+        armem::Time transitionTime = armem::Time(armem::Duration::MicroSeconds(t.timestamp));
 
         armem::EntityUpdate update;
         update.entityID = segmentPtr->id().withEntityName(entityName);
diff --git a/source/RobotAPI/libraries/armem_system_state/server/CPUSegment.cpp b/source/RobotAPI/libraries/armem_system_state/server/CPUSegment.cpp
index 426ab0822c7542b00f38a15cc27d36edf5da6265..fa392c615789ffac9e8ae2b9fd70eda0052e6d27 100644
--- a/source/RobotAPI/libraries/armem_system_state/server/CPUSegment.cpp
+++ b/source/RobotAPI/libraries/armem_system_state/server/CPUSegment.cpp
@@ -63,7 +63,7 @@ namespace armarx::armem::server::systemstate::segment
         EntityUpdate update;
         update.entityID = providerId.withEntityName("CurrentCpuLoad");
         update.confidence = 1.0;
-        update.timeCreated = armem::Time::now();
+        update.timeCreated = armem::Time::Now();
         update.instancesData = { data };
 
         segmentPtr->update(update);
diff --git a/source/RobotAPI/libraries/armem_system_state/server/RAMSegment.cpp b/source/RobotAPI/libraries/armem_system_state/server/RAMSegment.cpp
index a99e1c0b1b407e000ffdd4dee8ec988a1769b5e1..f02b8f4fa263687d52336012322ca640ecd84f1d 100644
--- a/source/RobotAPI/libraries/armem_system_state/server/RAMSegment.cpp
+++ b/source/RobotAPI/libraries/armem_system_state/server/RAMSegment.cpp
@@ -54,7 +54,7 @@ namespace armarx::armem::server::systemstate::segment
         EntityUpdate update;
         update.entityID = providerId.withEntityName("CurrentMemoryLoad");
         update.confidence = 1.0;
-        update.timeCreated = armem::Time::now();
+        update.timeCreated = armem::Time::Now();
         update.instancesData = { data };
 
         segmentPtr->update(update);
diff --git a/source/RobotAPI/libraries/armem_vision/aron_conversions.cpp b/source/RobotAPI/libraries/armem_vision/aron_conversions.cpp
index b4caa2632769a098c970b7ec378bceb49e54f051..4819a27abc53f7b10696da6d452bb2d133a82fd4 100644
--- a/source/RobotAPI/libraries/armem_vision/aron_conversions.cpp
+++ b/source/RobotAPI/libraries/armem_vision/aron_conversions.cpp
@@ -6,12 +6,14 @@
 
 #include <RobotAPI/interface/units/LaserScannerUnit.h>
 #include <RobotAPI/libraries/armem_vision/aron/LaserScan.aron.generated.h>
+#include <RobotAPI/libraries/armem/core/aron_conversions.h>
 #include <RobotAPI/libraries/aron/common/aron_conversions.h>
 #include <RobotAPI/libraries/aron/converter/common/Converter.h>
 #include <RobotAPI/libraries/aron/core/data/variant/complex/NDArray.h>
 
 #include "types.h"
 
+
 namespace armarx::armem
 {
 
@@ -20,7 +22,7 @@ namespace armarx::armem
     {
         return {.agent     = aronSensorHeader.agent,
                 .frame     = aronSensorHeader.frame,
-                .timestamp = aronSensorHeader.timestamp};
+                .timestamp = aron::fromAron<Time>(aronSensorHeader.timestamp)};
     }
 
     void fromAron(const arondto::LaserScanStamped& aronLaserScan,
@@ -40,7 +42,7 @@ namespace armarx::armem
 
         // laserScan = fromAron(aronLaserScan.data);
 
-        timestamp = header.timestamp.toMicroSeconds();
+        timestamp = header.timestamp.toMicroSecondsSinceEpoch();
         frame     = header.frame;
         agentName = header.agent;
     }
@@ -54,7 +56,7 @@ namespace armarx::armem
 
     int64_t toAron(const armem::Time& timestamp)
     {
-        return timestamp.toMicroSeconds();
+        return timestamp.toMicroSecondsSinceEpoch();
     }
 
     arondto::SensorHeader toAron(const SensorHeader& sensorHeader)
@@ -63,7 +65,7 @@ namespace armarx::armem
 
         aronSensorHeader.agent     = sensorHeader.agent;
         aronSensorHeader.frame     = sensorHeader.frame;
-        aronSensorHeader.timestamp = sensorHeader.timestamp;
+        toAron(aronSensorHeader.timestamp, sensorHeader.timestamp);
 
         return aronSensorHeader;
     }
diff --git a/source/RobotAPI/libraries/armem_vision/client/laser_scans/Writer.cpp b/source/RobotAPI/libraries/armem_vision/client/laser_scans/Writer.cpp
index 861e02c4c9fcabbc40caebba3451b69e81e5016c..0cfe7fb95f4abdf1d5065a6d0f245e516644bc8f 100644
--- a/source/RobotAPI/libraries/armem_vision/client/laser_scans/Writer.cpp
+++ b/source/RobotAPI/libraries/armem_vision/client/laser_scans/Writer.cpp
@@ -65,7 +65,7 @@ namespace armarx::armem::vision::laser_scans::client
             return false;
         }
 
-        const auto iceTimestamp = Time::microSeconds(timestamp);
+        const auto iceTimestamp = Time(Duration::MicroSeconds(timestamp));
 
         const auto providerId = armem::MemoryID(result.segmentID);
         const auto entityID =
diff --git a/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Writer.cpp b/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Writer.cpp
index 3275d888db9c8841e1dd7a8baf45582d27ab03ed..e781a2582e511b59f3ebefe9cde4a35d425da60a 100644
--- a/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Writer.cpp
+++ b/source/RobotAPI/libraries/armem_vision/client/occupancy_grid/Writer.cpp
@@ -25,7 +25,7 @@ namespace armarx::armem::vision::occupancy_grid::client
             return false;
         }
 
-        const auto iceTimestamp = Time::microSeconds(timestamp);
+        const auto iceTimestamp = Time(Duration::MicroSeconds(timestamp));
 
         const auto providerId = armem::MemoryID(result.segmentID);
         const auto entityID   = providerId.withEntityName(frame).withTimestamp(iceTimestamp);
diff --git a/source/RobotAPI/libraries/aron/common/CMakeLists.txt b/source/RobotAPI/libraries/aron/common/CMakeLists.txt
index 463f59dd1454c0f23fde9b304b5de1b29ae4345b..98cfb29ec529238b6e76c50c51e6563cb4fb4dcb 100644
--- a/source/RobotAPI/libraries/aron/common/CMakeLists.txt
+++ b/source/RobotAPI/libraries/aron/common/CMakeLists.txt
@@ -18,6 +18,7 @@ armarx_add_library(
         aron_conversions/simox.h
         aron_conversions/stl.h
         aron_conversions/eigen.h
+        util/object_finders.h
 
     SOURCES
         aron_conversions/core.cpp
@@ -25,6 +26,7 @@ armarx_add_library(
         aron_conversions/simox.cpp
         aron_conversions/stl.cpp
         aron_conversions/eigen.cpp
+        util/object_finders.cpp
 )
 
 
diff --git a/source/RobotAPI/libraries/aron/common/aron_conversions/armarx.cpp b/source/RobotAPI/libraries/aron/common/aron_conversions/armarx.cpp
index 13535b2449250b9c3991accdee2d9289d16fbfaf..beb2f7a552e27e239c9f3b4514cfa4170bd6828a 100644
--- a/source/RobotAPI/libraries/aron/common/aron_conversions/armarx.cpp
+++ b/source/RobotAPI/libraries/aron/common/aron_conversions/armarx.cpp
@@ -1,116 +1,128 @@
 #include "armarx.h"
 
+#include <IceUtil/Time.h>
+
+#include <ArmarXCore/core/time/ice_conversions.h>
 
 #include <RobotAPI/libraries/aron/common/aron_conversions/core.h>
 #include <RobotAPI/libraries/aron/common/aron_conversions/stl.h>
 
-namespace armarx
+
+void IceUtil::fromAron(const long& dto, IceUtil::Time& bo)
 {
+    bo = IceUtil::Time::microSeconds(dto);
+}
 
-    /* PackagePath */
+void IceUtil::toAron(long& dto, const IceUtil::Time& bo)
+{
+    dto = bo.toMicroSeconds();
+}
 
-    void fromAron(const arondto::PackagePath& dto, PackagePath& bo)
-    {
-        bo = {dto.package, dto.path};
-    }
 
-    void toAron(arondto::PackagePath& dto, const PackagePath& bo)
-    {
-        const data::PackagePath icedto = bo.serialize();
-        dto.package                    = icedto.package;
-        dto.path                       = icedto.path;
-    }
+void IceUtil::fromAron(const IceUtil::Time& dto, armarx::DateTime& bo)
+{
+    fromIce(dto, bo);
+}
 
-    void fromAron(const long& dto, IceUtil::Time& bo)
-    {
-        bo = IceUtil::Time::microSeconds(dto);
-    }
+void IceUtil::toAron(IceUtil::Time& dto, const armarx::DateTime& bo)
+{
+    toIce(dto, bo);
+}
 
-    void toAron(long& dto, const IceUtil::Time& bo)
-    {
-        dto = bo.toMicroSeconds();
-    }
 
-    void fromAron(const arondto::ClockType& dto, ClockType& bo)
-    {
-        switch (dto.value)
-        {
-            case arondto::ClockType::Realtime:
-                bo = ClockType::Realtime;
-                break;
-            case arondto::ClockType::Monotonic:
-                bo = ClockType::Monotonic;
-                break;
-            case arondto::ClockType::Virtual:
-                bo = ClockType::Virtual;
-                break;
-            case arondto::ClockType::Unknown:
-                bo = ClockType::Unknown;
-                break;
-        }
-    }
+/* PackagePath */
 
-    void toAron(arondto::ClockType& dto, const ClockType& bo)
-    {
-        switch (bo)
-        {
-            case ClockType::Realtime:
-                dto = arondto::ClockType::Realtime;
-                break;
-            case ClockType::Monotonic:
-                dto = arondto::ClockType::Monotonic;
-                break;
-            case ClockType::Virtual:
-                dto = arondto::ClockType::Virtual;
-                break;
-            case ClockType::Unknown:
-                dto = arondto::ClockType::Unknown;
-                break;
-        }
-    }
+void armarx::fromAron(const arondto::PackagePath& dto, PackagePath& bo)
+{
+    bo = {dto.package, dto.path};
+}
 
-    void fromAron(const arondto::Duration& dto, Duration& bo)
-    {
-        bo = Duration::MicroSeconds(dto.microSeconds);
-    }
+void armarx::toAron(arondto::PackagePath& dto, const PackagePath& bo)
+{
+    const data::PackagePath icedto = bo.serialize();
+    dto.package                    = icedto.package;
+    dto.path                       = icedto.path;
+}
 
-    void toAron(arondto::Duration& dto, const Duration& bo)
-    {
-        dto.microSeconds = bo.toMicroSeconds();
-    }
 
-    void fromAron(const arondto::Frequency& dto, Frequency& bo)
+void armarx::fromAron(const arondto::ClockType& dto, ClockType& bo)
+{
+    switch (dto.value)
     {
-        Duration cycleDuration;
-        fromAron(dto.cycleDuration, cycleDuration);
-        bo = Frequency(cycleDuration);
+        case arondto::ClockType::Realtime:
+            bo = ClockType::Realtime;
+            break;
+        case arondto::ClockType::Monotonic:
+            bo = ClockType::Monotonic;
+            break;
+        case arondto::ClockType::Virtual:
+            bo = ClockType::Virtual;
+            break;
+        case arondto::ClockType::Unknown:
+            bo = ClockType::Unknown;
+            break;
     }
+}
 
-    void toAron(arondto::Frequency& dto, const Frequency& bo)
+void armarx::toAron(arondto::ClockType& dto, const ClockType& bo)
+{
+    switch (bo)
     {
-        arondto::Duration cycleDuration;
-        toAron(cycleDuration, bo.toCycleDuration());
-        dto.cycleDuration = cycleDuration;
+        case ClockType::Realtime:
+            dto = arondto::ClockType::Realtime;
+            break;
+        case ClockType::Monotonic:
+            dto = arondto::ClockType::Monotonic;
+            break;
+        case ClockType::Virtual:
+            dto = arondto::ClockType::Virtual;
+            break;
+        case ClockType::Unknown:
+            dto = arondto::ClockType::Unknown;
+            break;
     }
+}
 
-    void fromAron(const arondto::DateTime& dto, DateTime& bo)
-    {
-        Duration timeSinceEpoch;
-        fromAron(dto.timeSinceEpoch, timeSinceEpoch);
-        ClockType clockType;
-        fromAron(dto.clockType, clockType);
-        bo = DateTime(timeSinceEpoch, clockType, dto.hostname);
-    }
+void armarx::fromAron(const arondto::Duration& dto, Duration& bo)
+{
+    bo = Duration::MicroSeconds(dto.microSeconds);
+}
 
-    void toAron(arondto::DateTime& dto, const DateTime& bo)
-    {
-        arondto::Duration timeSinceEpoch;
-        toAron(timeSinceEpoch, bo.toDurationSinceEpoch());
-        dto.timeSinceEpoch = timeSinceEpoch;
-        arondto::ClockType clockType;
-        toAron(clockType, bo.clockType());
-        dto.clockType = clockType;
-        dto.hostname = bo.hostname();
-    }
+void armarx::toAron(arondto::Duration& dto, const Duration& bo)
+{
+    dto.microSeconds = bo.toMicroSeconds();
+}
+
+void armarx::fromAron(const arondto::Frequency& dto, Frequency& bo)
+{
+    Duration cycleDuration;
+    fromAron(dto.cycleDuration, cycleDuration);
+    bo = Frequency(cycleDuration);
+}
 
-} // namespace armarx
+void armarx::toAron(arondto::Frequency& dto, const Frequency& bo)
+{
+    arondto::Duration cycleDuration;
+    toAron(cycleDuration, bo.toCycleDuration());
+    dto.cycleDuration = cycleDuration;
+}
+
+void armarx::fromAron(const arondto::DateTime& dto, DateTime& bo)
+{
+    Duration timeSinceEpoch;
+    fromAron(dto.timeSinceEpoch, timeSinceEpoch);
+    ClockType clockType;
+    fromAron(dto.clockType, clockType);
+    bo = DateTime(timeSinceEpoch, clockType, dto.hostname);
+}
+
+void armarx::toAron(arondto::DateTime& dto, const DateTime& bo)
+{
+    arondto::Duration timeSinceEpoch;
+    toAron(timeSinceEpoch, bo.toDurationSinceEpoch());
+    dto.timeSinceEpoch = timeSinceEpoch;
+    arondto::ClockType clockType;
+    toAron(clockType, bo.clockType());
+    dto.clockType = clockType;
+    dto.hostname = bo.hostname();
+}
diff --git a/source/RobotAPI/libraries/aron/common/aron_conversions/armarx.h b/source/RobotAPI/libraries/aron/common/aron_conversions/armarx.h
index 3f66752a865a0cfe2a0cb7e790e232f087751e2b..807605ec099b5e41110992d28c23bcecb0b92be0 100644
--- a/source/RobotAPI/libraries/aron/common/aron_conversions/armarx.h
+++ b/source/RobotAPI/libraries/aron/common/aron_conversions/armarx.h
@@ -3,21 +3,27 @@
 #include <ArmarXCore/core/PackagePath.h>
 #include <ArmarXCore/core/time_minimal.h>
 
-#include <IceUtil/Time.h>
-
 #include <RobotAPI/libraries/aron/common/aron/PackagePath.aron.generated.h>
 #include <RobotAPI/libraries/aron/common/aron/time.aron.generated.h>
 #include <RobotAPI/libraries/aron/common/aron/framed.aron.generated.h>
 
+
+namespace IceUtil
+{
+    class Time;
+
+    void fromAron(const long& dto, IceUtil::Time& bo);
+    void toAron(long& dto, const IceUtil::Time& bo);
+
+    void fromAron(const IceUtil::Time& dto, armarx::DateTime& bo);
+    void toAron(IceUtil::Time& dto, const armarx::DateTime& bo);
+}
 namespace armarx
 {
 
     void fromAron(const arondto::PackagePath& dto, PackagePath& bo);
     void toAron(arondto::PackagePath& dto, const PackagePath& bo);
 
-    void fromAron(const long& dto, IceUtil::Time& bo);
-    void toAron(long& dto, const IceUtil::Time& bo);
-
     void fromAron(const arondto::ClockType& dto, ClockType& bo);
     void toAron(arondto::ClockType& dto, const ClockType& bo);
 
diff --git a/source/RobotAPI/libraries/aron/common/util/object_finders.cpp b/source/RobotAPI/libraries/aron/common/util/object_finders.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e6bba147d3f274652f3e173667013383d5d56697
--- /dev/null
+++ b/source/RobotAPI/libraries/aron/common/util/object_finders.cpp
@@ -0,0 +1,60 @@
+/**
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX 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 <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::libraries::aron
+ * @author     Philip Scherer ( ulila@student.kit.edu )
+ * @date       2021
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#include "object_finders.h"
+
+namespace armarx::aron
+{
+    SubObjectFinder::SubObjectFinder(const std::string& typeNamePrefix) :
+        typeNamePrefix(typeNamePrefix)
+    {
+    }
+
+    const std::map<std::string, std::pair<aron::data::VariantPtr, aron::type::VariantPtr>>&
+    SubObjectFinder::getFoundObjects()
+    {
+        return foundSubObjects;
+    }
+
+    void
+    SubObjectFinder::visitObjectOnEnter(DataInput& elementData, TypeInput& elementType)
+    {
+        if (elementType && simox::alg::starts_with(elementType->getFullName(), typeNamePrefix))
+        {
+            foundSubObjects.emplace(elementData->getPath().toString(),
+                                    std::make_pair(elementData, elementType));
+        }
+    }
+
+    void
+    SubObjectFinder::visitUnknown(DataInput& elementData, TypeInput& elementType)
+    {
+        // Ignore (the base class throws an exception here)
+    }
+
+    SubObjectFinder::MapElements
+    SubObjectFinder::getObjectElements(DataInput& elementData, TypeInput& elementType)
+    {
+        return RecursiveConstTypedVariantVisitor::GetObjectElementsWithNullType(elementData,
+                                                                                elementType);
+    }
+} // namespace armarx::aron
diff --git a/source/RobotAPI/libraries/aron/common/util/object_finders.h b/source/RobotAPI/libraries/aron/common/util/object_finders.h
new file mode 100644
index 0000000000000000000000000000000000000000..ff67043de5cea4e608dd3f9d488130d80255005d
--- /dev/null
+++ b/source/RobotAPI/libraries/aron/common/util/object_finders.h
@@ -0,0 +1,132 @@
+/**
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX 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 <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::libraries::aron
+ * @author     Philip Scherer ( ulila@student.kit.edu )
+ * @date       2021
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <map>
+#include <vector>
+
+#include <SimoxUtility/algorithm/string.h>
+
+#include <RobotAPI/libraries/aron/common/aron_conversions/core.h>
+#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h>
+#include <RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.h>
+
+namespace armarx::aron
+{
+    /**
+     * Finds aron objects with a given type name prefix in aron variants.
+     *
+     * Construct it with the prefix you want to search for,
+     * then use `visitRecursive` to run the finder over the variant to search.
+     * Get a map of paths to data and type of the found objects using `getFoundObjects`.
+     */
+    class SubObjectFinder : public armarx::aron::data::RecursiveConstTypedVariantVisitor
+    {
+    public:
+        SubObjectFinder(const std::string& typeNamePrefix);
+
+        ~SubObjectFinder() override = default;
+
+        /**
+         * Get the objects that have been found.
+         *
+         * The keys are strings instead of `aron::Path`s because those don't support comparisons.
+         *
+         * @return map of paths to pair of data and type variants
+         */
+        const std::map<std::string, std::pair<aron::data::VariantPtr, aron::type::VariantPtr>>&
+        getFoundObjects();
+
+        void visitObjectOnEnter(DataInput& elementData, TypeInput& elementType) override;
+
+        void visitUnknown(DataInput& elementData, TypeInput& elementType) override;
+
+        MapElements getObjectElements(DataInput& elementData, TypeInput& elementType) override;
+
+    private:
+        std::string typeNamePrefix;
+        std::map<std::string, std::pair<aron::data::VariantPtr, aron::type::VariantPtr>>
+            foundSubObjects;
+    };
+
+    /**
+     * Finds aron objects with a given type name prefix in aron variants and returns them as BOs.
+     *
+     * Construct it with the prefix you want to search for,
+     * then use `visitRecursive` to run the finder over the variant to search.
+     * Get a map of paths to your BOs using `getFoundObjects`.
+     *
+     * \tparam DTOType the _generated_ aron type of your data.
+     * \tparam BOType the type of your final BO.
+     */
+    template <typename DTOType, typename BOType>
+    class BOSubObjectFinder : public armarx::aron::data::RecursiveConstTypedVariantVisitor
+    {
+    public:
+        BOSubObjectFinder() = default;
+        ~BOSubObjectFinder() override = default;
+
+        /**
+         * Get the objects that have been found.
+         *
+         * The keys are strings instead of `aron::Path`s because those don't support comparisons.
+         *
+         * @return map of paths to BOs.
+         */
+        const std::map<std::string, BOType>&
+        getFoundObjects()
+        {
+            return foundSubObjects;
+        }
+
+        void
+        visitObjectOnEnter(DataInput& elementData, TypeInput& elementType) override
+        {
+            if (elementType->getFullName() == DTOType::ToAronType()->getFullName())
+            {
+                auto dict = armarx::aron::data::Dict::DynamicCastAndCheck(elementData);
+                DTOType dto;
+                dto.fromAron(dict);
+                BOType boObj = armarx::aron::fromAron<BOType, DTOType>(dto);
+                foundSubObjects.emplace(elementData->getPath().toString(), boObj);
+            }
+        }
+
+        void
+        visitUnknown(DataInput& elementData, TypeInput& elementType) override
+        {
+            // Ignore (the base class throws an exception here)
+        }
+
+        MapElements
+        getObjectElements(DataInput& elementData, TypeInput& elementType) override
+        {
+            return RecursiveConstTypedVariantVisitor::GetObjectElementsWithNullType(elementData,
+                                                                                    elementType);
+        }
+
+    private:
+        std::map<std::string, BOType> foundSubObjects;
+    };
+
+} // namespace armarx::aron
diff --git a/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/Generator.cpp b/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/Generator.cpp
index 8e437dd62935c3de5fadf1c93daf10d89270c813..4c0969f0de800c66a6a766fa4a4a80ebf21f6c64 100644
--- a/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/Generator.cpp
+++ b/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/Generator.cpp
@@ -211,7 +211,7 @@ namespace armarx::aron::codegenerator::cpp
 
         CppMethodPtr m = CppMethodPtr(new CppMethod("template<class WriterT>\nstatic typename WriterT::ReturnType writeType(WriterT& " + ARON_WRITER_ACCESSOR + ", std::vector<std::string> " + ARON_TEMPLATE_INSTANTIATIONS_ACCESSOR + " = {}, armarx::aron::type::Maybe "+ ARON_MAYBE_TYPE_ACCESSOR +" = armarx::aron::type::Maybe::eNone, const armarx::aron::Path& "+ARON_PATH_ACCESSOR+" = armarx::aron::Path())", doc.str()));
         CppBlockPtr b = std::make_shared<CppBlock>();
-        b->addLine("using T [[maybe_unused]] = typename WriterT::ReturnType;");
+        b->addLine("using _Aron_T [[maybe_unused]] = typename WriterT::ReturnType;");
 
         std::string dummy;
         b->appendBlock(this->getWriteTypeBlock("", "", Path(), dummy));
@@ -228,7 +228,7 @@ namespace armarx::aron::codegenerator::cpp
 
         CppMethodPtr m = CppMethodPtr(new CppMethod("template<class WriterT>\ntypename WriterT::ReturnType write(WriterT& " + ARON_WRITER_ACCESSOR + ", const armarx::aron::Path& "+ARON_PATH_ACCESSOR+" = armarx::aron::Path()) const", doc.str()));
         CppBlockPtr b = std::make_shared<CppBlock>();
-        b->addLine("using T [[maybe_unused]] = typename WriterT::ReturnType;");
+        b->addLine("using _Aron_T [[maybe_unused]] = typename WriterT::ReturnType;");
 
         std::string dummy;
         b->appendBlock(this->getWriteBlock("", Path(), dummy));
@@ -245,8 +245,8 @@ namespace armarx::aron::codegenerator::cpp
 
         CppMethodPtr m = CppMethodPtr(new CppMethod("template<class ReaderT>\nvoid read(ReaderT& " + ARON_READER_ACCESSOR + ", typename ReaderT::InputType& input)", doc.str()));
         CppBlockPtr b = std::make_shared<CppBlock>();
-        b->addLine("using T [[maybe_unused]] = typename ReaderT::InputType;");
-        b->addLine("using TNonConst [[maybe_unused]] = typename ReaderT::InputTypeNonConst;");
+        b->addLine("using _Aron_T [[maybe_unused]] = typename ReaderT::InputType;");
+        b->addLine("using _Aron_TNonConst [[maybe_unused]] = typename ReaderT::InputTypeNonConst;");
 
         b->addLine("this->resetSoft();");
         b->addLine("if (" + ARON_READER_ACCESSOR + ".readNull(input))");
diff --git a/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/container/Dict.cpp b/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/container/Dict.cpp
index 16d73e0611df481b0139d895ab10529c2577387e..5d50b76c48b3aaf664722d97152e6390b8145b0e 100644
--- a/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/container/Dict.cpp
+++ b/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/container/Dict.cpp
@@ -72,7 +72,7 @@ namespace armarx::aron::codegenerator::cpp::generator
         variantAccessor = ARON_VARIANT_RETURN_ACCESSOR+ "_" + escaped_accessor;
 
         const std::string elementsAccessor = variantAccessor + "_dictElements";
-        block_if_data->addLine("std::map<std::string, T> " + elementsAccessor + ";");
+        block_if_data->addLine("std::map<std::string, _Aron_T> " + elementsAccessor + ";");
 
         std::string accessor_iterator_key = ARON_VARIABLE_PREFIX + "_" + escaped_accessor + "_key";
         std::string accessor_iterator_val = ARON_VARIABLE_PREFIX + "_" + escaped_accessor + "_value";
@@ -107,7 +107,7 @@ namespace armarx::aron::codegenerator::cpp::generator
         std::string accessor_iterator_value = ARON_VARIABLE_PREFIX + "_" + escaped_accessor + "_dictValue";
         std::string accessor_iterator_key = ARON_VARIABLE_PREFIX + "_" + escaped_accessor + "_dictKey";
 
-        block_if_data->addLine("std::map<std::string, TNonConst> " + elements_accessor + ";");
+        block_if_data->addLine("std::map<std::string, _Aron_TNonConst> " + elements_accessor + ";");
         block_if_data->addLine("" + ARON_READER_ACCESSOR + ".readDict(" + variantAccessor + ", " + elements_accessor + ");");
         block_if_data->addLine("for (const auto& [" + accessor_iterator_key + ", " + accessor_iterator_value + "] : " + elements_accessor + ")");
         {
diff --git a/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/container/List.cpp b/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/container/List.cpp
index a69f1767565aa2ea8f242c27a4fd03b4450567c3..76094035446a7f90a3d39afe85a8d1bd16ae3e23 100644
--- a/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/container/List.cpp
+++ b/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/container/List.cpp
@@ -71,7 +71,7 @@ namespace armarx::aron::codegenerator::cpp::generator
         variantAccessor = ARON_VARIANT_RETURN_ACCESSOR+ "_" + escaped_accessor;
 
         const std::string elementsAccessor = variantAccessor + "_listElements";
-        block_if_data->addLine("std::vector<T> " + elementsAccessor + ";");
+        block_if_data->addLine("std::vector<_Aron_T> " + elementsAccessor + ";");
 
         std::string accessor_iterator = ARON_VARIABLE_PREFIX + "_" + escaped_accessor + "_it";
 
@@ -102,7 +102,7 @@ namespace armarx::aron::codegenerator::cpp::generator
         std::string elements_accessor = ARON_VARIABLE_PREFIX + "_" + escaped_accessor + "_listElements";
         std::string accessor_iterator_value = ARON_VARIABLE_PREFIX + "_" + escaped_accessor + "_listValue";
 
-        block_if_data->addLine("std::vector<TNonConst> " + elements_accessor + ";");
+        block_if_data->addLine("std::vector<_Aron_TNonConst> " + elements_accessor + ";");
         block_if_data->addLine("" + ARON_READER_ACCESSOR + ".readList(" + variantAccessor + ", " + elements_accessor + ");");
         block_if_data->addLine("for (const auto& " + accessor_iterator_value + " : " + elements_accessor + ")");
         {
diff --git a/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/container/Pair.cpp b/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/container/Pair.cpp
index 4f7cde8f0582a191037c5cd49532f785221394e9..d4edd5476373c0c49029c39ccc7537259116192f 100644
--- a/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/container/Pair.cpp
+++ b/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/container/Pair.cpp
@@ -114,7 +114,7 @@ namespace armarx::aron::codegenerator::cpp::generator
         std::string escaped_accessor = EscapeAccessor(cppAccessor);
         std::string elements_accessor = ARON_VARIABLE_PREFIX + "_" + escaped_accessor + "_pairElements";
 
-        block_if_data->addLine("std::vector<TNonConst> " + elements_accessor + ";");
+        block_if_data->addLine("std::vector<_Aron_TNonConst> " + elements_accessor + ";");
         block_if_data->addLine("" + ARON_READER_ACCESSOR + ".readList("+elements_accessor+"); // of " + cppAccessor);
 
         auto child_s1 = FromAronType(*type.getFirstAcceptedType());
diff --git a/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/container/Tuple.cpp b/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/container/Tuple.cpp
index 5f2c241cb9024f721f867a54c1bad9a30db96759..84db8b60aab51848000f36d38cc85c8ad6889151 100644
--- a/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/container/Tuple.cpp
+++ b/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/container/Tuple.cpp
@@ -60,7 +60,7 @@ namespace armarx::aron::codegenerator::cpp::generator
         variantAccessor = ARON_VARIANT_RETURN_ACCESSOR+ "_" + escaped_accessor;
 
         const std::string acceptedTypesAccessor = variantAccessor + "_tupleAcceptedTypes";
-        block_if_data->addLine("std::vector<T> " + acceptedTypesAccessor + ";");
+        block_if_data->addLine("std::vector<_Aron_T> " + acceptedTypesAccessor + ";");
 
         unsigned int i = 0;
         for (const auto& type : type.getAcceptedTypes())
@@ -87,7 +87,7 @@ namespace armarx::aron::codegenerator::cpp::generator
         variantAccessor = ARON_VARIANT_RETURN_ACCESSOR+ "_" + escaped_accessor;
 
         const std::string elementsAccessor = variantAccessor + "_tupleElements";
-        block_if_data->addLine("std::vector<T> " + elementsAccessor + ";");
+        block_if_data->addLine("std::vector<_Aron_T> " + elementsAccessor + ";");
 
         unsigned int i = 0;
         for (const auto& type : type.getAcceptedTypes())
@@ -114,7 +114,7 @@ namespace armarx::aron::codegenerator::cpp::generator
         std::string resolved_accessor = resolveMaybeAccessor(cppAccessor);
         std::string elements_accessor = ARON_VARIABLE_PREFIX + "_" + escaped_accessor + "_tupleElements";
 
-        block_if_data->addLine("std::vector<TNonConst> " + elements_accessor + ";");
+        block_if_data->addLine("std::vector<_Aron_TNonConst> " + elements_accessor + ";");
         block_if_data->addLine("" + ARON_READER_ACCESSOR + ".readList("+elements_accessor+"); // of " + cppAccessor);
 
         unsigned int i = 0;
diff --git a/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/toplevel/ObjectClass.cpp b/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/toplevel/ObjectClass.cpp
index 70df7d108e582d0badc09abd7922296fba769dd5..cf15c169b4afec4e5fd833e40bb16b6e74672dc8 100644
--- a/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/toplevel/ObjectClass.cpp
+++ b/source/RobotAPI/libraries/aron/core/codegenerator/codewriter/cpp/generator/toplevel/ObjectClass.cpp
@@ -97,7 +97,7 @@ namespace armarx::aron::codegenerator::cpp::generator
         static const std::string OBJECT_EXTENDS_ACCESSOR = ARON_VARIABLE_PREFIX + "_objectExtends";
 
         CppBlockPtr b = std::make_shared<CppBlock>();
-        b->addLine("std::map<std::string, T> " + OBJECT_MEMBERS_ACCESSOR + ";");
+        b->addLine("std::map<std::string, _Aron_T> " + OBJECT_MEMBERS_ACCESSOR + ";");
 
         if (type.getExtends() != nullptr)
         {
@@ -152,9 +152,9 @@ namespace armarx::aron::codegenerator::cpp::generator
 
         CppBlockPtr block_if_data = std::make_shared<CppBlock>();
 
-        block_if_data->addLine("std::map<std::string, T> " + OBJECT_MEMBERS_ACCESSOR + ";");
+        block_if_data->addLine("std::map<std::string, _Aron_T> " + OBJECT_MEMBERS_ACCESSOR + ";");
 
-        block_if_data->addLine("std::optional<T> " + OBJECT_EXTENDS_ACCESSOR + ";");
+        block_if_data->addLine("std::optional<_Aron_T> " + OBJECT_EXTENDS_ACCESSOR + ";");
         if (type.getExtends() != nullptr)
         {
             const auto extends_s = FromAronType(*type.getExtends());
@@ -187,7 +187,7 @@ namespace armarx::aron::codegenerator::cpp::generator
         static const std::string OBJECT_EXTENDS_ACCESSOR = ARON_VARIABLE_PREFIX + "_objectExtends";
 
         CppBlockPtr block_if_data = std::make_shared<CppBlock>();
-        block_if_data->addLine("std::map<std::string, TNonConst> " + OBJECT_MEMBERS_ACCESSOR + ";");
+        block_if_data->addLine("std::map<std::string, _Aron_TNonConst> " + OBJECT_MEMBERS_ACCESSOR + ";");
 
         if (type.getExtends() != nullptr)
         {
diff --git a/source/RobotAPI/libraries/aron/core/data/rw/writer/variant/VariantWriter.h b/source/RobotAPI/libraries/aron/core/data/rw/writer/variant/VariantWriter.h
index 4ff55335a50edba6543b171a6bdc323dc50823e6..0be0b34898308d217d221659d3524d77b2cf8f5c 100644
--- a/source/RobotAPI/libraries/aron/core/data/rw/writer/variant/VariantWriter.h
+++ b/source/RobotAPI/libraries/aron/core/data/rw/writer/variant/VariantWriter.h
@@ -51,5 +51,7 @@ namespace armarx::aron::data::writer
         data::VariantPtr writeDouble(const double i, const Path& p = Path()) override;
         data::VariantPtr writeString(const std::string& i, const Path& p = Path()) override;
         data::VariantPtr writeBool(const bool i, const Path& p = Path()) override;
+
+        using WriterInterface<data::VariantPtr>::writeDict;
     };
 }
diff --git a/source/RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.cpp b/source/RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.cpp
index a91f1ac118ba3525ee8a1030915711fb28448c5f..0f6f90a193a9391f943fca4466c294f6ac9d69e9 100644
--- a/source/RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.cpp
+++ b/source/RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.cpp
@@ -536,6 +536,31 @@ namespace armarx::aron::data
         return ret;
     }
 
+    RecursiveConstTypedVariantVisitor::MapElements
+    RecursiveConstTypedVariantVisitor::GetObjectElementsWithNullType(DataInput& o, TypeInput& t)
+    {
+        std::map<std::string, std::pair<aron::data::VariantPtr, aron::type::VariantPtr>> ret;
+        auto data = aron::data::Dict::DynamicCastAndCheck(o);
+        auto type = aron::type::Object::DynamicCastAndCheck(t);
+
+        if (data)
+        {
+            for (const auto& [key, e] : data->getElements())
+            {
+                if (type && type->hasMemberType(key))
+                {
+                    auto memberType = type->getMemberType(key);
+                    ret.insert({key, {e, memberType}});
+                }
+                else
+                {
+                    ret.insert({key, {e, nullptr}});
+                }
+            }
+        }
+        return ret;
+    }
+
     RecursiveConstTypedVariantVisitor::MapElements
     RecursiveConstTypedVariantVisitor::GetDictElements(DataInput& o, TypeInput& t)
     {
diff --git a/source/RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.h b/source/RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.h
index 8a8cc2a906bfc2e3e37734670468ff8207d308f7..389db80a53d43bdb0514f39cbd5276b8f71291bb 100644
--- a/source/RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.h
+++ b/source/RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.h
@@ -201,6 +201,12 @@ namespace armarx::aron::data
     {
         type::Descriptor getDescriptor(DataInput& o, TypeInput& n) override;
         static MapElements GetObjectElements(DataInput& o, TypeInput& t);
+        /* This override exists for visitors that need to handle untyped members in the hierarchy.
+         * Using it instead of `GetObjectElements` will allow your visitor to visit objects with
+         * a nullptr as their type. However, you will have to handle nullptr types in your
+         * visitor's methods.
+         */
+        static MapElements GetObjectElementsWithNullType(DataInput& o, TypeInput& t);
         static MapElements GetDictElements(DataInput& o, TypeInput& t);
         static ListElements GetListElements(DataInput& o, TypeInput& t);
         static PairElements GetPairElements(DataInput& o, TypeInput& t);