Upgraded the rest of Time.

Change-Id: I0ee083837e51d8f74a798b7ba14a3b6bb3859f35
diff --git a/aos/common/actions/action_test.cc b/aos/common/actions/action_test.cc
index 21da2c7..1538d03 100644
--- a/aos/common/actions/action_test.cc
+++ b/aos/common/actions/action_test.cc
@@ -2,6 +2,7 @@
 
 #include <memory>
 #include <thread>
+#include <chrono>
 
 #include "gtest/gtest.h"
 
@@ -13,13 +14,14 @@
 #include "aos/common/event.h"
 #include "aos/testing/test_shm.h"
 
-using ::aos::time::Time;
-
 namespace aos {
 namespace common {
 namespace actions {
 namespace testing {
 
+
+namespace chrono = ::std::chrono;
+
 class TestActorIndex
     : public aos::common::actions::ActorBase<actions::TestActionQueueGroup> {
  public:
@@ -135,7 +137,7 @@
 
   ASSERT_FALSE(actions::test_action.status.FetchLatest());
   ::std::thread init_thread([&nop_act]() { nop_act.Initialize(); });
-  ::aos::time::SleepFor(::aos::time::Time::InSeconds(0.1));
+  ::std::this_thread::sleep_for(chrono::milliseconds(100));
   ASSERT_TRUE(actions::test_action.goal.MakeWithBuilder().run(1).Send());
   init_thread.join();
   ASSERT_TRUE(actions::test_action.status.FetchLatest());
diff --git a/aos/common/actions/actor.h b/aos/common/actions/actor.h
index 5d0c70d..d2d05fc 100644
--- a/aos/common/actions/actor.h
+++ b/aos/common/actions/actor.h
@@ -4,12 +4,13 @@
 #include <stdio.h>
 #include <inttypes.h>
 
+#include <chrono>
 #include <functional>
 
+#include "aos/common/controls/control_loop.h"
 #include "aos/common/logging/logging.h"
 #include "aos/common/logging/queue_logging.h"
 #include "aos/common/time.h"
-#include "aos/common/controls/control_loop.h"
 #include "aos/common/util/phased_loop.h"
 
 namespace aos {
@@ -65,13 +66,14 @@
   // Returns false if the action was canceled or failed, and true if the wait
   // succeeded.
   bool WaitOrCancel(monotonic_clock::duration duration) {
-    return !WaitUntil([]() {
-      ::aos::time::PhasedLoopXMS(
-          ::std::chrono::duration_cast<::std::chrono::milliseconds>(
-              ::aos::controls::kLoopFrequency).count(),
-          2500);
-      return false;
-    }, ::aos::monotonic_clock::now() + duration);
+    ::aos::time::PhasedLoop phased_loop(::aos::controls::kLoopFrequency,
+                                        ::std::chrono::milliseconds(5) / 2);
+    return !WaitUntil(
+        [&phased_loop]() {
+          phased_loop.SleepUntilNext();
+          return false;
+        },
+        ::aos::monotonic_clock::now() + duration);
   }
 
   // Returns true if the action should be canceled.
diff --git a/aos/common/condition_test.cc b/aos/common/condition_test.cc
index 0e7bfe4..f8e4e65 100644
--- a/aos/common/condition_test.cc
+++ b/aos/common/condition_test.cc
@@ -5,6 +5,7 @@
 #include <sys/wait.h>
 
 #include <atomic>
+#include <chrono>
 #include <thread>
 
 #include "gtest/gtest.h"
@@ -21,18 +22,16 @@
 #include "aos/common/util/thread.h"
 #include "aos/testing/prevent_exit.h"
 
-using ::aos::time::Time;
-
 namespace aos {
 namespace testing {
 
+namespace chrono = ::std::chrono;
+
 class ConditionTestCommon : public ::testing::Test {
  public:
   ConditionTestCommon() {}
 
-  void Settle() {
-    time::SleepFor(::Time::InSeconds(0.008));
-  }
+  void Settle() { ::std::this_thread::sleep_for(chrono::milliseconds(8)); }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ConditionTestCommon);
@@ -132,16 +131,22 @@
   };
 
   // This amount gets added to any passed in delay to make the test repeatable.
-  static constexpr ::Time kMinimumDelay = ::Time::InSeconds(0.15);
-  static constexpr ::Time kDefaultTimeout = ::Time::InSeconds(0.15);
+  static constexpr chrono::milliseconds kMinimumDelay =
+      chrono::milliseconds(150);
+  static constexpr chrono::milliseconds kDefaultTimeout =
+      chrono::milliseconds(150);
 
   // delay is how long to wait before doing action to condition.
   // timeout is how long to wait after delay before deciding that it's hung.
-  ConditionTestProcess(const ::Time &delay, Action action, Condition *condition,
-                       const ::Time &timeout = kDefaultTimeout)
-    : delay_(kMinimumDelay + delay), action_(action), condition_(condition),
-      timeout_(delay_ + timeout), child_(-1),
-      shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
+  ConditionTestProcess(chrono::milliseconds delay, Action action,
+                       Condition *condition,
+                       chrono::milliseconds timeout = kDefaultTimeout)
+      : delay_(kMinimumDelay + delay),
+        action_(action),
+        condition_(condition),
+        timeout_(delay_ + timeout),
+        child_(-1),
+        shared_(static_cast<Shared *>(shm_malloc(sizeof(Shared)))) {
     new (shared_) Shared();
   }
   ~ConditionTestProcess() {
@@ -179,15 +184,17 @@
       return ::testing::AssertionFailure() << "already returned";
     }
     if (shared_->delayed) {
-      if (shared_->start_time > ::Time::Now() + timeout_) {
+      if (shared_->start_time > monotonic_clock::now() + timeout_) {
         Kill();
         return ::testing::AssertionSuccess() << "already been too long";
       }
     } else {
       CHECK_EQ(0, futex_wait(&shared_->done_delaying));
     }
-    time::SleepFor(::Time::InSeconds(0.01));
-    if (!shared_->finished) time::SleepUntil(shared_->start_time + timeout_);
+    ::std::this_thread::sleep_for(chrono::milliseconds(10));
+    if (!shared_->finished) {
+      ::std::this_thread::sleep_until(shared_->start_time + timeout_);
+    }
     if (shared_->finished) {
       Join();
       return ::testing::AssertionFailure() << "completed within timeout";
@@ -204,14 +211,17 @@
  private:
   struct Shared {
     Shared()
-      : started(false), delayed(false), done_delaying(0), start_time(0, 0),
-        finished(false), ready(0) {
-    }
+        : started(false),
+          delayed(false),
+          done_delaying(0),
+          start_time(monotonic_clock::epoch()),
+          finished(false),
+          ready(0) {}
 
     volatile bool started;
     volatile bool delayed;
     aos_futex done_delaying;
-    ::Time start_time;
+    monotonic_clock::time_point start_time;
     volatile bool finished;
     aos_futex ready;
   };
@@ -223,8 +233,8 @@
       ASSERT_EQ(1, futex_set(&shared_->ready));
       ASSERT_FALSE(condition_->m()->Lock());
     }
-    time::SleepFor(delay_);
-    shared_->start_time = ::Time::Now();
+    ::std::this_thread::sleep_for(delay_);
+    shared_->start_time = monotonic_clock::now();
     shared_->delayed = true;
     ASSERT_NE(-1, futex_set(&shared_->done_delaying));
     if (action_ != Action::kWaitLockStart) {
@@ -253,10 +263,10 @@
     Join();
   }
 
-  const ::Time delay_;
+  const chrono::milliseconds delay_;
   const Action action_;
   Condition *const condition_;
-  const ::Time timeout_;
+  const chrono::milliseconds timeout_;
 
   pid_t child_;
 
@@ -264,13 +274,13 @@
 
   DISALLOW_COPY_AND_ASSIGN(ConditionTestProcess);
 };
-constexpr ::Time ConditionTestProcess::kMinimumDelay;
-constexpr ::Time ConditionTestProcess::kDefaultTimeout;
+constexpr chrono::milliseconds ConditionTestProcess::kMinimumDelay;
+constexpr chrono::milliseconds ConditionTestProcess::kDefaultTimeout;
 
 // Makes sure that the testing framework and everything work for a really simple
 // Wait() and then Signal().
 TEST_F(ConditionTest, Basic) {
-  ConditionTestProcess child(::Time(0, 0),
+  ConditionTestProcess child(chrono::milliseconds(0),
                              ConditionTestProcess::Action::kWait,
                              &shared_->condition);
   child.Start();
@@ -282,7 +292,7 @@
 
 // Makes sure that the worker child locks before it tries to Wait() etc.
 TEST_F(ConditionTest, Locking) {
-  ConditionTestProcess child(::Time(0, 0),
+  ConditionTestProcess child(chrono::milliseconds(0),
                              ConditionTestProcess::Action::kWait,
                              &shared_->condition);
   ASSERT_FALSE(shared_->mutex.Lock());
@@ -299,7 +309,7 @@
 // Tests that the work child only catches a Signal() after the mutex gets
 // unlocked.
 TEST_F(ConditionTest, LockFirst) {
-  ConditionTestProcess child(::Time(0, 0),
+  ConditionTestProcess child(chrono::milliseconds(0),
                              ConditionTestProcess::Action::kWait,
                              &shared_->condition);
   ASSERT_FALSE(shared_->mutex.Lock());
@@ -317,7 +327,7 @@
 
 // Tests that the mutex gets relocked after Wait() returns.
 TEST_F(ConditionTest, Relocking) {
-  ConditionTestProcess child(::Time(0, 0),
+  ConditionTestProcess child(chrono::milliseconds(0),
                              ConditionTestProcess::Action::kWaitNoUnlock,
                              &shared_->condition);
   child.Start();
@@ -330,13 +340,13 @@
 
 // Tests that Signal() stops exactly 1 Wait()er.
 TEST_F(ConditionTest, SignalOne) {
-  ConditionTestProcess child1(::Time(0, 0),
+  ConditionTestProcess child1(chrono::milliseconds(0),
                               ConditionTestProcess::Action::kWait,
                               &shared_->condition);
-  ConditionTestProcess child2(::Time(0, 0),
+  ConditionTestProcess child2(chrono::milliseconds(0),
                               ConditionTestProcess::Action::kWait,
                               &shared_->condition);
-  ConditionTestProcess child3(::Time(0, 0),
+  ConditionTestProcess child3(chrono::milliseconds(0),
                               ConditionTestProcess::Action::kWait,
                               &shared_->condition);
   auto number_finished = [&]() { return (child1.IsFinished() ? 1 : 0) +
@@ -362,13 +372,13 @@
 
 // Tests that Brodcast() wakes multiple Wait()ers.
 TEST_F(ConditionTest, Broadcast) {
-  ConditionTestProcess child1(::Time(0, 0),
+  ConditionTestProcess child1(chrono::milliseconds(0),
                               ConditionTestProcess::Action::kWait,
                               &shared_->condition);
-  ConditionTestProcess child2(::Time(0, 0),
+  ConditionTestProcess child2(chrono::milliseconds(0),
                               ConditionTestProcess::Action::kWait,
                               &shared_->condition);
-  ConditionTestProcess child3(::Time(0, 0),
+  ConditionTestProcess child3(chrono::milliseconds(0),
                               ConditionTestProcess::Action::kWait,
                               &shared_->condition);
   child1.Start();
diff --git a/aos/common/controls/control_loop-tmpl.h b/aos/common/controls/control_loop-tmpl.h
index 81b5d20..474c5ce 100644
--- a/aos/common/controls/control_loop-tmpl.h
+++ b/aos/common/controls/control_loop-tmpl.h
@@ -63,8 +63,7 @@
       // If the driver's station reports being disabled, we're probably not
       // actually going to send motor values regardless of what the FPGA
       // reports.
-      last_pwm_sent_ = monotonic_clock::time_point(
-          ::std::chrono::nanoseconds(::aos::robot_state->sent_time.ToNSec()));
+      last_pwm_sent_ = ::aos::robot_state->sent_time;
     }
   }
 
diff --git a/aos/common/event.cc b/aos/common/event.cc
index af9c9c5..ffb62b4 100644
--- a/aos/common/event.cc
+++ b/aos/common/event.cc
@@ -1,5 +1,7 @@
 #include "aos/common/event.h"
 
+#include <chrono>
+
 #include "aos/common/type_traits.h"
 #include "aos/common/logging/logging.h"
 
@@ -20,8 +22,14 @@
   }
 }
 
-bool Event::WaitTimeout(const ::aos::time::Time &timeout) {
-  const auto timeout_timespec = timeout.ToTimespec();
+bool Event::WaitTimeout(monotonic_clock::duration timeout) {
+  ::std::chrono::seconds sec =
+      ::std::chrono::duration_cast<::std::chrono::seconds>(timeout);
+  ::std::chrono::nanoseconds nsec =
+      ::std::chrono::duration_cast<::std::chrono::nanoseconds>(timeout - sec);
+  struct timespec timeout_timespec;
+  timeout_timespec.tv_sec = sec.count();
+  timeout_timespec.tv_nsec = nsec.count();
   while (true) {
     if (__atomic_load_n(&impl_, __ATOMIC_SEQ_CST) != 0) {
       return true;
diff --git a/aos/common/event.h b/aos/common/event.h
index b3ee87b..559aad5 100644
--- a/aos/common/event.h
+++ b/aos/common/event.h
@@ -42,7 +42,7 @@
   // Waits for the event to be set or until timeout has elapsed. Returns
   // immediately if it is already set.
   // Returns true if the event was Set or false if the timeout expired.
-  bool WaitTimeout(const ::aos::time::Time &timeout);
+  bool WaitTimeout(monotonic_clock::duration timeout);
 
   // Wakes up all Wait()ers and sets the event (atomically).
   void Set();
diff --git a/aos/common/event_test.cc b/aos/common/event_test.cc
index 91af403..764dd49 100644
--- a/aos/common/event_test.cc
+++ b/aos/common/event_test.cc
@@ -1,15 +1,19 @@
 #include "aos/common/event.h"
 
+#include <chrono>
 #include <thread>
 
 #include "gtest/gtest.h"
 
-#include "aos/testing/test_logging.h"
 #include "aos/common/time.h"
+#include "aos/testing/test_logging.h"
 
 namespace aos {
 namespace testing {
 
+namespace chrono = ::std::chrono;
+namespace this_thread = ::std::this_thread;
+
 class EventTest : public ::testing::Test {
  public:
   Event test_event_;
@@ -50,38 +54,38 @@
 
 // Tests that an event blocks correctly.
 TEST_F(EventTest, Blocks) {
-  time::Time start_time, finish_time;
+  monotonic_clock::time_point start_time, finish_time;
   // Without this, it sometimes manages to fail under tsan.
   Event started;
   ::std::thread thread([this, &start_time, &finish_time, &started]() {
-    start_time = time::Time::Now();
+    start_time = monotonic_clock::now();
     started.Set();
     test_event_.Wait();
-    finish_time = time::Time::Now();
+    finish_time = monotonic_clock::now();
   });
-  static const time::Time kWaitTime = time::Time::InSeconds(0.05);
+  static constexpr auto kWaitTime = chrono::milliseconds(50);
   started.Wait();
-  time::SleepFor(kWaitTime);
+  this_thread::sleep_for(kWaitTime);
   test_event_.Set();
   thread.join();
   EXPECT_GE(finish_time - start_time, kWaitTime);
 }
 
 TEST_F(EventTest, WaitTimeout) {
-  EXPECT_FALSE(test_event_.WaitTimeout(time::Time::InSeconds(0.05)));
+  EXPECT_FALSE(test_event_.WaitTimeout(chrono::milliseconds(50)));
 
-  time::Time start_time, finish_time;
+  monotonic_clock::time_point start_time, finish_time;
   // Without this, it sometimes manages to fail under tsan.
   Event started;
   ::std::thread thread([this, &start_time, &finish_time, &started]() {
-    start_time = time::Time::Now();
+    start_time = monotonic_clock::now();
     started.Set();
-    EXPECT_TRUE(test_event_.WaitTimeout(time::Time::InSeconds(0.5)));
-    finish_time = time::Time::Now();
+    EXPECT_TRUE(test_event_.WaitTimeout(chrono::milliseconds(500)));
+    finish_time = monotonic_clock::now();
   });
-  static const time::Time kWaitTime = time::Time::InSeconds(0.05);
+  constexpr auto kWaitTime = chrono::milliseconds(50);
   started.Wait();
-  time::SleepFor(kWaitTime);
+  this_thread::sleep_for(kWaitTime);
   test_event_.Set();
   thread.join();
   EXPECT_GE(finish_time - start_time, kWaitTime);
diff --git a/aos/common/logging/binary_log_writer.cc b/aos/common/logging/binary_log_writer.cc
index 10641fb..076d72d 100644
--- a/aos/common/logging/binary_log_writer.cc
+++ b/aos/common/logging/binary_log_writer.cc
@@ -1,27 +1,28 @@
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <errno.h>
-#include <time.h>
 #include <string.h>
-#include <string>
-#include <unistd.h>
 #include <sys/types.h>
-#include <pwd.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <mntent.h>
+#include <time.h>
+#include <unistd.h>
+#include <string>
 
+#include <chrono>
 #include <map>
 #include <unordered_set>
 
-#include "aos/common/logging/implementations.h"
-#include "aos/common/logging/binary_log_file.h"
-#include "aos/linux_code/init.h"
-#include "aos/linux_code/configuration.h"
-#include "aos/linux_code/ipc_lib/queue.h"
-#include "aos/common/queue_types.h"
 #include "aos/common/die.h"
+#include "aos/common/logging/binary_log_file.h"
+#include "aos/common/logging/implementations.h"
+#include "aos/common/queue_types.h"
 #include "aos/common/time.h"
+#include "aos/linux_code/configuration.h"
+#include "aos/linux_code/init.h"
+#include "aos/linux_code/ipc_lib/queue.h"
 
 namespace aos {
 namespace logging {
@@ -213,8 +214,7 @@
       // again so the queue can buffer up some logs. This avoids lots of context
       // switches and mutex contention which happens if we're constantly reading
       // new messages as they come in.
-      static constexpr auto kSleepTime = ::aos::time::Time::InSeconds(0.1);
-      ::aos::time::SleepFor(kSleepTime);
+      ::std::this_thread::sleep_for(::std::chrono::milliseconds(100));
       continue;
     }
 
diff --git a/aos/common/logging/implementations.cc b/aos/common/logging/implementations.cc
index 2f17f7a..697dec9 100644
--- a/aos/common/logging/implementations.cc
+++ b/aos/common/logging/implementations.cc
@@ -4,6 +4,7 @@
 #include <inttypes.h>
 
 #include <algorithm>
+#include <chrono>
 
 #include "aos/common/die.h"
 #include "aos/common/once.h"
@@ -16,6 +17,8 @@
 namespace logging {
 namespace {
 
+namespace chrono = ::std::chrono;
+
 // The root LogImplementation. It only logs to stderr/stdout.
 // Some of the things specified in the LogImplementation documentation doesn't
 // apply here (mostly the parts about being able to use LOG) because this is the
@@ -84,9 +87,14 @@
   memcpy(message->name, context->name, context->name_size);
   message->name_length = context->name_size;
 
-  time::Time now = time::Time::Now();
-  message->seconds = now.sec();
-  message->nseconds = now.nsec();
+  monotonic_clock::time_point monotonic_now = monotonic_clock::now();
+  message->seconds =
+      chrono::duration_cast<chrono::seconds>(monotonic_now.time_since_epoch())
+          .count();
+  message->nseconds =
+      chrono::duration_cast<chrono::nanoseconds>(
+          monotonic_now.time_since_epoch() - chrono::seconds(message->seconds))
+          .count();
 
   message->sequence = context->sequence++;
 }
@@ -325,9 +333,9 @@
 RawQueue *queue = NULL;
 
 int dropped_messages = 0;
-::aos::time::Time dropped_start, backoff_start;
+monotonic_clock::time_point dropped_start, backoff_start;
 // Wait this long after dropping a message before even trying to write any more.
-constexpr ::aos::time::Time kDropBackoff = ::aos::time::Time::InSeconds(0.1);
+constexpr chrono::milliseconds kDropBackoff = chrono::milliseconds(100);
 
 LogMessage *GetMessageOrDie() {
   LogMessage *message = static_cast<LogMessage *>(queue->GetMessage());
@@ -340,8 +348,8 @@
 
 void Write(LogMessage *msg) {
   if (__builtin_expect(dropped_messages > 0, false)) {
-    ::aos::time::Time message_time =
-        ::aos::time::Time(msg->seconds, msg->nseconds);
+    monotonic_clock::time_point message_time(
+        chrono::seconds(msg->seconds) + chrono::nanoseconds(msg->nseconds));
     if (message_time - backoff_start < kDropBackoff) {
       ++dropped_messages;
       queue->FreeMessage(msg);
@@ -349,10 +357,16 @@
     }
 
     LogMessage *dropped_message = GetMessageOrDie();
+    chrono::seconds dropped_start_sec = chrono::duration_cast<chrono::seconds>(
+        dropped_start.time_since_epoch());
+    chrono::nanoseconds dropped_start_nsec =
+        chrono::duration_cast<chrono::nanoseconds>(
+            dropped_start.time_since_epoch() - dropped_start_sec);
     internal::FillInMessageVarargs(
         ERROR, dropped_message,
         "%d logs starting at %" PRId32 ".%" PRId32 " dropped\n",
-        dropped_messages, dropped_start.sec(), dropped_start.nsec());
+        dropped_messages, static_cast<int32_t>(dropped_start_sec.count()),
+        static_cast<int32_t>(dropped_start_nsec.count()));
     if (queue->WriteMessage(dropped_message, RawQueue::kNonBlock)) {
       dropped_messages = 0;
     } else {
@@ -367,8 +381,9 @@
   }
   if (!queue->WriteMessage(msg, RawQueue::kNonBlock)) {
     if (dropped_messages == 0) {
-      dropped_start = backoff_start =
-          ::aos::time::Time(msg->seconds, msg->nseconds);
+      monotonic_clock::time_point message_time(
+          chrono::seconds(msg->seconds) + chrono::nanoseconds(msg->nseconds));
+      dropped_start = backoff_start = message_time;
     }
     ++dropped_messages;
   }
diff --git a/aos/common/logging/implementations_test.cc b/aos/common/logging/implementations_test.cc
index bbee5b7..aade0d1 100644
--- a/aos/common/logging/implementations_test.cc
+++ b/aos/common/logging/implementations_test.cc
@@ -1,7 +1,8 @@
-#include <string>
-
 #include <inttypes.h>
 
+#include <chrono>
+#include <string>
+
 #include "gtest/gtest.h"
 
 #include "aos/common/logging/implementations.h"
@@ -16,6 +17,8 @@
 namespace logging {
 namespace testing {
 
+namespace chrono = ::std::chrono;
+
 class TestLogImplementation : public SimpleLogImplementation {
   __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
   void DoLog(log_level level, const char *format, va_list ap) override {
@@ -168,23 +171,25 @@
   //static const long kTimingCycles = 5000000;
   static const long kTimingCycles = 5000;
 
-  time::Time start = time::Time::Now();
+  monotonic_clock::time_point start = monotonic_clock::now();
   for (long i = 0; i < kTimingCycles; ++i) {
     LOG(INFO, "a\n");
   }
-  time::Time end = time::Time::Now();
-  time::Time diff = end - start;
+  monotonic_clock::time_point end = monotonic_clock::now();
+  auto diff = end - start;
   printf("short message took %" PRId64 " nsec for %ld\n",
-         diff.ToNSec(), kTimingCycles);
+         chrono::duration_cast<chrono::nanoseconds>(diff).count(),
+         kTimingCycles);
 
-  start = time::Time::Now();
+  start = monotonic_clock::now();
   for (long i = 0; i < kTimingCycles; ++i) {
     LOG(INFO, "something longer than just \"a\" to log to test timing\n");
   }
-  end = time::Time::Now();
+  end = monotonic_clock::now();
   diff = end - start;
   printf("long message took %" PRId64 " nsec for %ld\n",
-         diff.ToNSec(), kTimingCycles);
+         chrono::duration_cast<chrono::nanoseconds>(diff).count(),
+         kTimingCycles);
 }
 
 TEST(LoggingPrintFormatTest, Time) {
diff --git a/aos/common/logging/log_streamer.cc b/aos/common/logging/log_streamer.cc
index ab37e02..74e680b 100644
--- a/aos/common/logging/log_streamer.cc
+++ b/aos/common/logging/log_streamer.cc
@@ -1,40 +1,47 @@
-#include <stdio.h>
-#include <stdlib.h>
 #include <errno.h>
-#include <time.h>
-#include <string.h>
-#include <string>
-#include <unistd.h>
-#include <sys/types.h>
-#include <pwd.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <chrono>
+#include <string>
 
+#include "aos/common/logging/implementations.h"
+#include "aos/common/logging/logging.h"
+#include "aos/common/time.h"
 #include "aos/linux_code/init.h"
 #include "aos/linux_code/ipc_lib/queue.h"
-#include "aos/common/logging/logging.h"
-#include "aos/common/logging/implementations.h"
-#include "aos/common/time.h"
 
 namespace aos {
 namespace logging {
 namespace linux_code {
 namespace {
 
+namespace chrono = ::std::chrono;
+
 int LogStreamerMain() {
   InitNRT();
 
   RawQueue *queue = GetLoggingQueue();
 
-  const time::Time now = time::Time::Now();
+  const monotonic_clock::time_point now = monotonic_clock::now();
+  chrono::seconds sec =
+      chrono::duration_cast<chrono::seconds>(now.time_since_epoch());
+  chrono::nanoseconds nsec =
+      chrono::duration_cast<chrono::nanoseconds>(now.time_since_epoch() - sec);
   printf("starting at %" PRId32 "s%" PRId32 "ns-----------------------------\n",
-         now.sec(), now.nsec());
+         static_cast<int32_t>(sec.count()), static_cast<int32_t>(nsec.count()));
 
   while (true) {
     const LogMessage *const msg = static_cast<const LogMessage *>(
         queue->ReadMessage(RawQueue::kNonBlock));
     if (msg == NULL) {
-      ::aos::time::SleepFor(::aos::time::Time::InSeconds(0.1));
+      ::std::this_thread::sleep_for(::std::chrono::milliseconds(100));
     } else {
       internal::PrintMessage(stdout, *msg);
 
diff --git a/aos/common/logging/replay.cc b/aos/common/logging/replay.cc
index 7180c96..6b55e51 100644
--- a/aos/common/logging/replay.cc
+++ b/aos/common/logging/replay.cc
@@ -1,9 +1,13 @@
 #include "aos/common/logging/replay.h"
 
+#include <chrono>
+
 namespace aos {
 namespace logging {
 namespace linux_code {
 
+namespace chrono = ::std::chrono;
+
 bool LogReplayer::ProcessMessage() {
   const LogFileMessageHeader *message = reader_->ReadNextMessage(false);
   if (message == nullptr) return true;
@@ -32,8 +36,9 @@
   if (handler == handlers_.end()) return false;
 
   handler->second->HandleStruct(
-      ::aos::time::Time(message->time_sec, message->time_nsec), type_id,
-      position,
+      monotonic_clock::time_point(chrono::seconds(message->time_sec) +
+                                  chrono::nanoseconds(message->time_nsec)),
+      type_id, position,
       message->message_size -
           (sizeof(type_id) + sizeof(message_length) + message_length));
   return false;
diff --git a/aos/common/logging/replay.h b/aos/common/logging/replay.h
index 38f7120..1a8418f 100644
--- a/aos/common/logging/replay.h
+++ b/aos/common/logging/replay.h
@@ -80,8 +80,9 @@
    public:
     virtual ~StructHandlerInterface() {}
 
-    virtual void HandleStruct(::aos::time::Time log_time, uint32_t type_id,
-                              const void *data, size_t data_size) = 0;
+    virtual void HandleStruct(::aos::monotonic_clock::time_point log_time,
+                              uint32_t type_id, const void *data,
+                              size_t data_size) = 0;
   };
 
   // Converts struct log messages to a message type and passes it to an
@@ -92,8 +93,9 @@
     TypedStructHandler(::std::function<void(const T &message)> handler)
         : handler_(handler) {}
 
-    void HandleStruct(::aos::time::Time log_time, uint32_t type_id,
-                      const void *data, size_t data_size) override {
+    void HandleStruct(::aos::monotonic_clock::time_point log_time,
+                      uint32_t type_id, const void *data,
+                      size_t data_size) override {
       CHECK_EQ(type_id, T::GetType()->id);
       T message;
       CHECK_EQ(data_size, T::Size());
diff --git a/aos/common/mutex_test.cc b/aos/common/mutex_test.cc
index 8cc4e73..3717109 100644
--- a/aos/common/mutex_test.cc
+++ b/aos/common/mutex_test.cc
@@ -1,25 +1,29 @@
 #include "aos/common/mutex.h"
 
-#include <sched.h>
 #include <math.h>
 #include <pthread.h>
+#include <sched.h>
 
+#include <chrono>
 #include <thread>
 
 #include "gtest/gtest.h"
 
-#include "aos/linux_code/ipc_lib/aos_sync.h"
 #include "aos/common/die.h"
+#include "aos/common/time.h"
 #include "aos/common/util/death_test_log_implementation.h"
 #include "aos/common/util/thread.h"
-#include "aos/common/time.h"
+#include "aos/linux_code/ipc_lib/aos_sync.h"
+#include "aos/linux_code/ipc_lib/core_lib.h"
 #include "aos/testing/test_logging.h"
 #include "aos/testing/test_shm.h"
-#include "aos/linux_code/ipc_lib/core_lib.h"
 
 namespace aos {
 namespace testing {
 
+namespace chrono = ::std::chrono;
+namespace this_thread = ::std::this_thread;
+
 class MutexTest : public ::testing::Test {
  public:
   Mutex test_mutex_;
@@ -169,8 +173,9 @@
 
 class AdderThread : public ::aos::util::Thread {
  public:
-  AdderThread(int *counter, Mutex *mutex, ::aos::time::Time sleep_before_time,
-              ::aos::time::Time sleep_after_time)
+  AdderThread(int *counter, Mutex *mutex,
+              monotonic_clock::duration sleep_before_time,
+              monotonic_clock::duration sleep_after_time)
       : counter_(counter),
         mutex_(mutex),
         sleep_before_time_(sleep_before_time),
@@ -178,15 +183,15 @@
 
  private:
   virtual void Run() override {
-    ::aos::time::SleepFor(sleep_before_time_);
+    this_thread::sleep_for(sleep_before_time_);
     MutexLocker locker(mutex_);
     ++(*counter_);
-    ::aos::time::SleepFor(sleep_after_time_);
+    this_thread::sleep_for(sleep_after_time_);
   }
 
   int *const counter_;
   Mutex *const mutex_;
-  const ::aos::time::Time sleep_before_time_, sleep_after_time_;
+  const monotonic_clock::duration sleep_before_time_, sleep_after_time_;
 };
 
 }  // namespace
@@ -196,10 +201,11 @@
 TEST_F(MutexTest, ThreadSanitizerContended) {
   int counter = 0;
   AdderThread threads[2]{
-      {&counter, &test_mutex_, ::aos::time::Time::InSeconds(0.2),
-       ::aos::time::Time::InSeconds(0)},
-      {&counter, &test_mutex_, ::aos::time::Time::InSeconds(0),
-       ::aos::time::Time::InSeconds(0)}, };
+      {&counter, &test_mutex_, chrono::milliseconds(200),
+       chrono::milliseconds(0)},
+      {&counter, &test_mutex_, chrono::milliseconds(0),
+       chrono::milliseconds(0)},
+  };
   for (auto &c : threads) {
     c.Start();
   }
@@ -235,10 +241,10 @@
 TEST_F(MutexTest, ThreadSanitizerUncontended) {
   int counter = 0;
   AdderThread threads[2]{
-      {&counter, &test_mutex_, ::aos::time::Time::InSeconds(0),
-       ::aos::time::Time::InSeconds(0)},
-      {&counter, &test_mutex_, ::aos::time::Time::InSeconds(0.2),
-       ::aos::time::Time::InSeconds(0)}, };
+      {&counter, &test_mutex_, chrono::milliseconds(0),
+       chrono::milliseconds(0)},
+      {&counter, &test_mutex_, chrono::milliseconds(200),
+       chrono::milliseconds(0)}, };
   for (auto &c : threads) {
     c.Start();
   }
diff --git a/aos/common/network/socket.cc b/aos/common/network/socket.cc
index b674ff1..80eca70 100644
--- a/aos/common/network/socket.cc
+++ b/aos/common/network/socket.cc
@@ -1,15 +1,18 @@
 #include "aos/common/network/socket.h"
 
-#include <string.h>
 #include <errno.h>
+#include <string.h>
 #include <sys/socket.h>
+#include <chrono>
 
-#include "aos/common/logging/logging.h"
 #include "aos/common/byteorder.h"
+#include "aos/common/logging/logging.h"
 
 namespace aos {
 namespace network {
 
+namespace chrono = ::std::chrono;
+
 int Socket::Connect(NetworkPort port, const char *address, int type) {
   last_ret_ = 0;
   if ((socket_ = socket(AF_INET, type, 0)) < 0) {
@@ -53,8 +56,13 @@
   return ret;
 }
 
-int Socket::Receive(void *buf, int length, time::Time timeout) {
-  timeval timeout_timeval = timeout.ToTimeval();
+int Socket::Receive(void *buf, int length, chrono::microseconds timeout) {
+  timeval timeout_timeval;
+  timeout_timeval.tv_sec = chrono::duration_cast<chrono::seconds>(timeout).count();
+  timeout_timeval.tv_usec =
+      chrono::duration_cast<chrono::microseconds>(
+          timeout - chrono::seconds(timeout_timeval.tv_sec))
+          .count();
   fd_set fds;
   FD_ZERO(&fds);
   FD_SET(socket_, &fds);
diff --git a/aos/common/network/socket.h b/aos/common/network/socket.h
index 9e8eaf5..9bda8aa 100644
--- a/aos/common/network/socket.h
+++ b/aos/common/network/socket.h
@@ -1,15 +1,15 @@
 #ifndef AOS_COMMON_NETWORK_SOCKET_H_
 #define AOS_COMMON_NETWORK_SOCKET_H_
 
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <sys/socket.h>
 #include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdlib.h>
 #include <unistd.h>
-#include <stdio.h>
+#include <chrono>
 
-#include "aos/common/time.h"
 #include "aos/common/network_port.h"
 
 namespace aos {
@@ -28,7 +28,7 @@
   // No timeout.
   int Receive(void *buf, int length);
   // timeout is relative
-  int Receive(void *buf, int length, time::Time timeout);
+  int Receive(void *buf, int length, ::std::chrono::microseconds timeout);
 
  protected:
   int Connect(NetworkPort port, const char *address, int type = SOCK_DGRAM);
diff --git a/aos/common/queue.cc b/aos/common/queue.cc
index 893e62b..ba85a72 100644
--- a/aos/common/queue.cc
+++ b/aos/common/queue.cc
@@ -1,37 +1,47 @@
 #include "aos/common/queue.h"
 
-#include "aos/common/byteorder.h"
 #include <inttypes.h>
+#include <chrono>
+
+#include "aos/common/byteorder.h"
 
 namespace aos {
 
-void Message::Zero() {
-  sent_time.set_sec(0);
-  sent_time.set_nsec(0);
-}
+namespace chrono = ::std::chrono;
+
+void Message::Zero() { sent_time = monotonic_clock::min_time; }
 
 size_t Message::Deserialize(const char *buffer) {
   int32_t sec;
   int32_t nsec;
   to_host(&buffer[0], &sec);
   to_host(&buffer[4], &nsec);
-  sent_time.set_sec(sec);
-  sent_time.set_nsec(nsec);
+  sent_time = monotonic_clock::time_point(chrono::seconds(sec) +
+                                          chrono::nanoseconds(nsec));
   return Size();
 }
 // Serializes the common fields into the buffer.
 size_t Message::Serialize(char *buffer) const {
   // TODO(aschuh): to_network shouldn't need a pointer.
-  int32_t sec = sent_time.sec();
-  int32_t nsec = sent_time.nsec();
+  int32_t sec =
+      chrono::duration_cast<chrono::seconds>(sent_time.time_since_epoch())
+          .count();
+  int32_t nsec = chrono::duration_cast<chrono::nanoseconds>(
+                     sent_time.time_since_epoch() - chrono::seconds(sec))
+                     .count();
   to_network(&sec, &buffer[0]);
   to_network(&nsec, &buffer[4]);
   return Size();
 }
 
 size_t Message::Print(char *buffer, int length) const {
-  return snprintf(buffer, length, "%" PRId32 ".%09" PRId32 "s",
-                  sent_time.sec(), sent_time.nsec());
+  int32_t sec =
+      chrono::duration_cast<chrono::seconds>(sent_time.time_since_epoch())
+          .count();
+  int32_t nsec = chrono::duration_cast<chrono::nanoseconds>(
+                     sent_time.time_since_epoch() - chrono::seconds(sec))
+                     .count();
+  return snprintf(buffer, length, "%" PRId32 ".%09" PRId32 "s", sec, nsec);
 }
 
 }  // namespace aos
diff --git a/aos/common/queue.h b/aos/common/queue.h
index 5f5d8b0..7f43a3e 100644
--- a/aos/common/queue.h
+++ b/aos/common/queue.h
@@ -16,16 +16,15 @@
 // thing for the whole thing.
 class Message {
  public:
-  typedef ::aos::time::Time Time;
   // The time that the message was sent at.
-  Time sent_time;
+  monotonic_clock::time_point sent_time;
 
-  Message() : sent_time(0, 0) {}
+  Message() : sent_time(monotonic_clock::min_time) {}
 
   // Zeros out the time.
   void Zero();
   // Returns the size of the common fields.
-  static size_t Size() { return sizeof(Time); }
+  static size_t Size() { return sizeof(sent_time); }
 
   // Deserializes the common fields from the buffer.
   size_t Deserialize(const char *buffer);
@@ -33,7 +32,7 @@
   size_t Serialize(char *buffer) const;
 
   // Populates sent_time with the current time.
-  void SetTimeToNow() { sent_time = Time::Now(); }
+  void SetTimeToNow() { sent_time = monotonic_clock::now(); }
 
   // Writes the contents of the message to the provided buffer.
   size_t Print(char *buffer, int length) const;
@@ -198,18 +197,11 @@
   void FetchAnother();
 
   // Returns the age of the message.
-  const time::Time Age() const {
-    return time::Time::Now() - queue_msg_->sent_time;
+  const monotonic_clock::duration Age() const {
+    return monotonic_clock::now() - queue_msg_->sent_time;
   }
 
-  // Returns true if the latest value in the queue is newer than age mseconds.
-  // DEPRECATED(brians): Use IsNewerThan(const time::Time&) instead.
-  bool IsNewerThanMS(int age) const {
-    // TODO(aschuh): Log very verbosely if something is _ever_ stale.
-    return IsNewerThan(time::Time::InMS(age));
-  }
-
-  bool IsNewerThan(const time::Time &age) const {
+  bool IsNewerThan(const monotonic_clock::duration age) const {
     return get() != nullptr && Age() < age;
   }
 
diff --git a/aos/common/queue_test.cc b/aos/common/queue_test.cc
index dc8c62c..eb109ba 100644
--- a/aos/common/queue_test.cc
+++ b/aos/common/queue_test.cc
@@ -1,20 +1,21 @@
 #include <unistd.h>
 
+#include <chrono>
 #include <memory>
 
 #include "gtest/gtest.h"
 
+#include "aos/common/die.h"
 #include "aos/common/test_queue.q.h"
 #include "aos/common/util/thread.h"
-#include "aos/common/die.h"
 #include "aos/testing/test_shm.h"
 
-using ::aos::time::Time;
-
 namespace aos {
 namespace common {
 namespace testing {
 
+namespace chrono = ::std::chrono;
+
 class QueueTest : public ::testing::Test {
  protected:
   void SetUp() override {
@@ -54,7 +55,7 @@
   usleep(50000);
   my_test_queue.MakeWithBuilder().test_bool(true).test_int(0x971).Send();
   t.Join();
-  EXPECT_LE(t.threaded_test_queue.Age(), time::Time::InMS(57));
+  EXPECT_LE(t.threaded_test_queue.Age(), chrono::milliseconds(57));
 }
 
 // Tests that we can send a message with the message pointer and get it back.
@@ -76,7 +77,7 @@
   ASSERT_TRUE(my_test_queue.FetchLatest());
   EXPECT_EQ(true, my_test_queue->test_bool);
   EXPECT_EQ(0x971, my_test_queue->test_int);
-  EXPECT_EQ(true, my_test_queue.IsNewerThanMS(10000));
+  EXPECT_EQ(true, my_test_queue.IsNewerThan(chrono::milliseconds(10000)));
 }
 
 // Tests that multiple queue instances don't break each other.
@@ -202,10 +203,9 @@
   my_test_queue.MakeWithBuilder().test_bool(true).test_int(0x971).Send();
 
   ASSERT_TRUE(my_test_queue.FetchLatest());
-  EXPECT_TRUE(my_test_queue.IsNewerThanMS(100));
-  const Time age = my_test_queue.Age();
-  EXPECT_EQ(0, age.sec());
-  EXPECT_GE(100000000, age.nsec());
+  EXPECT_TRUE(my_test_queue.IsNewerThan(chrono::milliseconds(100)));
+  const auto age = my_test_queue.Age();
+  EXPECT_GE(chrono::nanoseconds(100000000), age);
 }
 
 
@@ -257,8 +257,7 @@
 
   EXPECT_FALSE(msg.test_bool);
   EXPECT_EQ(0, msg.test_int);
-  EXPECT_EQ(0, msg.sent_time.sec());
-  EXPECT_EQ(0, msg.sent_time.nsec());
+  EXPECT_EQ(monotonic_clock::min_time, msg.sent_time);
 }
 
 TEST_F(MessageTest, Size) {
@@ -286,7 +285,8 @@
   char printdata[1024];
   msg.test_bool = true;
   msg.test_int = 2056;
-  msg.sent_time = Time(971, 254);
+  msg.sent_time = monotonic_clock::time_point(chrono::seconds(971) +
+                                              chrono::nanoseconds(254));
 
   std::string golden("971.000000254s, T, 2056");
   EXPECT_EQ(golden.size(), msg.Print(printdata, sizeof(printdata)));
@@ -304,7 +304,7 @@
 
 TEST_F(MessageTest, SetNow) {
   msg.SetTimeToNow();
-  EXPECT_LE(msg.sent_time - Time::Now(), Time::InMS(20));
+  EXPECT_LE(msg.sent_time - monotonic_clock::now(), chrono::milliseconds(20));
 }
 
 // Tests that EqualsNoTime works.
diff --git a/aos/common/time.cc b/aos/common/time.cc
index 7cfc4bc..e8bd25b 100644
--- a/aos/common/time.cc
+++ b/aos/common/time.cc
@@ -1,9 +1,10 @@
 #include "aos/common/time.h"
 
-#include <atomic>
-
-#include <string.h>
 #include <inttypes.h>
+#include <string.h>
+
+#include <atomic>
+#include <chrono>
 
 // We only use global_core from here, which is weak, so we don't really have a
 // dependency on it.
@@ -12,6 +13,8 @@
 #include "aos/common/logging/logging.h"
 #include "aos/common/mutex.h"
 
+namespace chrono = ::std::chrono;
+
 namespace std {
 namespace this_thread {
 template <>
@@ -57,34 +60,8 @@
 // Current time when time is mocked.
 monotonic_clock::time_point current_mock_time = monotonic_clock::epoch();
 
-// TODO(aschuh): This doesn't include SleepFor and SleepUntil.
-// TODO(aschuh): Create a clock source object and change the default?
-//  That would let me create a MockTime clock source.
-
-Time NowImpl(clockid_t clock) {
-  timespec temp;
-  if (clock_gettime(clock, &temp) != 0) {
-    PLOG(FATAL, "clock_gettime(%jd, %p) failed",
-         static_cast<uintmax_t>(clock), &temp);
-  }
-
-  const timespec offset = (&global_core == nullptr || global_core == nullptr ||
-                           global_core->mem_struct == nullptr)
-                              ? timespec{0, 0}
-                              : global_core->mem_struct->time_offset;
-  return Time(temp) + Time(offset);
-}
-
 }  // namespace
 
-const int32_t Time::kNSecInSec;
-const int32_t Time::kNSecInMSec;
-const int32_t Time::kNSecInUSec;
-const int32_t Time::kMSecInSec;
-const int32_t Time::kUSecInSec;
-
-const Time Time::kZero{0, 0};
-
 void EnableMockTime(monotonic_clock::time_point now) {
   MutexLocker time_mutex_locker(&time_mutex);
   mock_time_enabled = true;
@@ -112,162 +89,13 @@
   SetMockTime(monotonic_clock::now() + amount);
 }
 
-Time Time::Now(clockid_t clock) {
-  {
-    if (mock_time_enabled.load(::std::memory_order_relaxed)) {
-      MutexLocker time_mutex_locker(&time_mutex);
-      return Time::InNS(
-          ::std::chrono::duration_cast<::std::chrono::nanoseconds>(
-              current_mock_time.time_since_epoch()).count());
-    }
-  }
-  return NowImpl(clock);
-}
-
-void Time::CheckImpl(int32_t nsec) {
-  static_assert(aos::shm_ok<Time>::value,
-                "it should be able to go through shared memory");
-  if (nsec >= kNSecInSec || nsec < 0) {
-    LOG(FATAL, "0 <= nsec(%" PRId32 ") < %" PRId32 " isn't true.\n",
-        nsec, kNSecInSec);
-  }
-}
-
-Time &Time::operator+=(const Time &rhs) {
-  sec_ += rhs.sec_;
-  nsec_ += rhs.nsec_;
-  if (nsec_ >= kNSecInSec) {
-    nsec_ -= kNSecInSec;
-    sec_ += 1;
-  }
-  return *this;
-}
-const Time Time::operator+(const Time &rhs) const {
-  return Time(*this) += rhs;
-}
-Time &Time::operator-=(const Time &rhs) {
-  sec_ -= rhs.sec_;
-  nsec_ -= rhs.nsec_;
-  if (nsec_ < 0) {
-    nsec_ += kNSecInSec;
-    sec_ -= 1;
-  }
-  return *this;
-}
-const Time Time::operator-(const Time &rhs) const {
-  return Time(*this) -= rhs;
-}
-Time &Time::operator*=(int32_t rhs) {
-  const int64_t temp = static_cast<int64_t>(nsec_) *
-      static_cast<int64_t>(rhs);
-  sec_ *= rhs;  // better not overflow, or the result is just too big
-  nsec_ = temp % kNSecInSec;
-  sec_ += (temp - nsec_) / kNSecInSec;
-  if (nsec_ < 0) {
-    nsec_ += kNSecInSec;
-    sec_ -= 1;
-  }
-  return *this;
-}
-const Time Time::operator*(int32_t rhs) const {
-  return Time(*this) *= rhs;
-}
-Time &Time::operator/=(int32_t rhs) {
-  nsec_ = (sec_ % rhs) * (kNSecInSec / rhs) + nsec_ / rhs;
-  sec_ /= rhs;
-  if (nsec_ < 0) {
-    nsec_ += kNSecInSec;
-    sec_ -= 1;
-  }
-  return *this;
-}
-const Time Time::operator/(int32_t rhs) const {
-  return Time(*this) /= rhs;
-}
-double Time::operator/(const Time &rhs) const {
-  return ToSeconds() / rhs.ToSeconds();
-}
-Time &Time::operator%=(int32_t rhs) {
-  nsec_ = ToNSec() % rhs;
-  const int wraps = nsec_ / ((rhs / kNSecInSec + 1) * kNSecInSec);
-  sec_ = wraps + rhs / kNSecInSec;
-  nsec_ -= kNSecInSec * wraps;
-  if (nsec_ < 0) {
-    nsec_ += kNSecInSec;
-    sec_ -= 1;
-  }
-  return *this;
-}
-const Time Time::operator%(int32_t rhs) const {
-  return Time(*this) %= rhs;
-}
-
-const Time Time::operator-() const {
-  return Time(-sec_ - 1, kNSecInSec - nsec_);
-}
-
-bool Time::operator==(const Time &rhs) const {
-  return sec_ == rhs.sec_ && nsec_ == rhs.nsec_;
-}
-bool Time::operator!=(const Time &rhs) const {
-  return !(*this == rhs);
-}
-bool Time::operator<(const Time &rhs) const {
-  return sec_ < rhs.sec_ || (sec_ == rhs.sec_ && nsec_ < rhs.nsec_);
-}
-bool Time::operator>(const Time &rhs) const {
-  return sec_ > rhs.sec_ || (sec_ == rhs.sec_ && nsec_ > rhs.nsec_);
-}
-bool Time::operator<=(const Time &rhs) const {
-  return sec_ < rhs.sec_ || (sec_ == rhs.sec_ && nsec_ <= rhs.nsec_);
-}
-bool Time::operator>=(const Time &rhs) const {
-  return sec_ > rhs.sec_ || (sec_ == rhs.sec_ && nsec_ >= rhs.nsec_);
-}
-
-bool Time::IsWithin(const Time &other, int64_t amount) const {
-  const int64_t temp = ToNSec() - other.ToNSec();
-  return temp <= amount && temp >= -amount;
-}
-
-std::ostream &operator<<(std::ostream &os, const Time& time) {
-  return os << "Time{" << time.sec_ << "s, " << time.nsec_ << "ns}";
-}
-
-void SleepFor(const Time &time, clockid_t clock) {
-  timespec converted(time.ToTimespec()), remaining;
-  int failure = EINTR;
-  do {
-    // This checks whether the last time through the loop actually failed or got
-    // interrupted.
-    if (failure != EINTR) {
-      PELOG(FATAL, failure, "clock_nanosleep(%jd, 0, %p, %p) failed",
-            static_cast<intmax_t>(clock), &converted, &remaining);
-    }
-    failure = clock_nanosleep(clock, 0, &converted, &remaining);
-    memcpy(&converted, &remaining, sizeof(converted));
-  } while (failure != 0);
-}
-
-void SleepUntil(const Time &time, clockid_t clock) {
-  timespec converted(time.ToTimespec());
-  int failure;
-  while ((failure = clock_nanosleep(clock, TIMER_ABSTIME,
-                                    &converted, NULL)) != 0) {
-    if (failure != EINTR) {
-      PELOG(FATAL, failure, "clock_nanosleep(%jd, TIMER_ABSTIME, %p, NULL)"
-            " failed", static_cast<intmax_t>(clock), &converted);
-    }
-  }
-}
-
-void OffsetToNow(const Time &now) {
+void OffsetToNow(monotonic_clock::time_point now) {
   CHECK_NOTNULL(&global_core);
   CHECK_NOTNULL(global_core);
   CHECK_NOTNULL(global_core->mem_struct);
-  global_core->mem_struct->time_offset.tv_nsec = 0;
-  global_core->mem_struct->time_offset.tv_sec = 0;
-  global_core->mem_struct->time_offset = (now - Time::Now()).ToTimespec();
+  const auto offset = now - monotonic_clock::now();
+  global_core->mem_struct->time_offset =
+      chrono::duration_cast<chrono::nanoseconds>(offset).count();
 }
 
 }  // namespace time
@@ -287,8 +115,14 @@
     PLOG(FATAL, "clock_gettime(%jd, %p) failed",
          static_cast<uintmax_t>(CLOCK_MONOTONIC), &current_time);
   }
+  const chrono::nanoseconds offset =
+      (&global_core == nullptr || global_core == nullptr ||
+       global_core->mem_struct == nullptr)
+          ? chrono::nanoseconds(0)
+          : chrono::nanoseconds(global_core->mem_struct->time_offset);
+
   return time_point(::std::chrono::seconds(current_time.tv_sec) +
-                    ::std::chrono::nanoseconds(current_time.tv_nsec));
+                    ::std::chrono::nanoseconds(current_time.tv_nsec)) + offset;
 }
 
 
diff --git a/aos/common/time.h b/aos/common/time.h
index ab64916..e541932 100644
--- a/aos/common/time.h
+++ b/aos/common/time.h
@@ -52,244 +52,23 @@
 // Disables mocking time.
 void DisableMockTime();
 
-// A nice structure for representing times.
-// 0 <= nsec_ < kNSecInSec should always be true. All functions here will make
-// sure that that is true if it was on all inputs (including *this).
-//
-// Negative times are supported so that all of the normal arithmetic identities
-// work. nsec_ is still always positive.
-//
-// The arithmetic and comparison operators are overloaded because they make
-// complete sense and are very useful. The default copy and assignment stuff is
-// left because it works fine. Multiplication of Times by Times is
-// not implemented because I can't think of any uses for them and there are
-// multiple ways to do it. Division of Times by Times is implemented as the
-// ratio of them. Multiplication, division, and modulus of Times by integers are
-// implemented as interpreting the argument as nanoseconds. Modulus takes the
-// sign from the first operand.
-struct Time {
-#ifdef SWIG
-// All of the uses of constexpr here can safely be simply removed.
-// NOTE: This means that relying on the fact that constexpr implicitly makes
-// member functions const is not valid, so they all have to be explicitly marked
-// const.
-#define constexpr
-#endif  // SWIG
- public:
-  static const int32_t kNSecInSec = 1000000000;
-  static const int32_t kNSecInMSec = 1000000;
-  static const int32_t kNSecInUSec = 1000;
-  static const int32_t kMSecInSec = 1000;
-  static const int32_t kUSecInSec = 1000000;
-
-  static const Time kZero;
-
-  explicit constexpr Time(int32_t sec = 0, int32_t nsec = 0)
-      : sec_(sec), nsec_(CheckConstexpr(nsec)) {
-  }
-  #ifndef SWIG
-  explicit constexpr Time(const struct timespec &value)
-      : sec_(value.tv_sec), nsec_(CheckConstexpr(value.tv_nsec)) {
-  }
-  struct timespec ToTimespec() const {
-    struct timespec ans;
-    ans.tv_sec = sec_;
-    ans.tv_nsec = nsec_;
-    return ans;
-  }
-  explicit constexpr Time(const struct timeval &value)
-      : sec_(value.tv_sec), nsec_(CheckConstexpr(value.tv_usec * kNSecInUSec)) {
-  }
-  struct timeval ToTimeval() const {
-    struct timeval ans;
-    ans.tv_sec = sec_;
-    ans.tv_usec = nsec_ / kNSecInUSec;
-    return ans;
-  }
-  #endif  // SWIG
-
-  // CLOCK_MONOTONIC on linux and CLOCK_REALTIME on the cRIO because the
-  // cRIO doesn't have any others.
-  // CLOCK_REALTIME is the default realtime clock and CLOCK_MONOTONIC doesn't
-  // change when somebody changes the wall clock (like the ntp deamon or
-  // whatever). See clock_gettime(2) for details.
-  //
-  // This is the clock that code that just wants to sleep for a certain amount
-  // of time or measure how long something takes should use.
-  #ifndef __VXWORKS__
-  static const clockid_t kDefaultClock = CLOCK_MONOTONIC;
-  #else
-  static const clockid_t kDefaultClock = CLOCK_REALTIME;
-  #endif
-  // Creates a Time representing the current value of the specified clock or
-  // dies.
-  static Time Now(clockid_t clock = kDefaultClock);
-
-  // Constructs a Time representing seconds.
-  static constexpr Time InSeconds(double seconds) {
-    return (seconds < 0.0) ?
-        Time(static_cast<int32_t>(seconds) - 1,
-             (seconds - static_cast<int32_t>(seconds) + 1.0) * kNSecInSec) :
-        Time(static_cast<int32_t>(seconds),
-             (seconds - static_cast<int32_t>(seconds)) * kNSecInSec);
-  }
-
-  // Constructs a time representing microseconds.
-  static constexpr Time InNS(int64_t nseconds) {
-    return (nseconds < 0)
-               ? Time((nseconds - 1) / static_cast<int64_t>(kNSecInSec) - 1,
-                      (((nseconds - 1) % kNSecInSec) + 1) + kNSecInSec)
-               : Time(nseconds / static_cast<int64_t>(kNSecInSec),
-                      nseconds % kNSecInSec);
-  }
-
-  // Constructs a time representing microseconds.
-  static constexpr Time InUS(int useconds) {
-    return (useconds < 0)
-               ? Time((useconds + 1) / kUSecInSec - 1,
-                      (((useconds + 1) % kUSecInSec) - 1) * kNSecInUSec +
-                          kNSecInSec)
-               : Time(useconds / kUSecInSec,
-                      (useconds % kUSecInSec) * kNSecInUSec);
-  }
-
-  // Constructs a time representing mseconds.
-  static constexpr Time InMS(int mseconds) {
-    return (mseconds < 0)
-               ? Time((mseconds + 1) / kMSecInSec - 1,
-                      (((mseconds + 1) % kMSecInSec) - 1) * kNSecInMSec +
-                          kNSecInSec)
-               : Time(mseconds / kMSecInSec,
-                      (mseconds % kMSecInSec) * kNSecInMSec);
-  }
-
-  // Construct a time representing the period of hertz.
-  static constexpr ::std::chrono::nanoseconds FromRate(int hertz) {
-    return ::std::chrono::duration_cast<::std::chrono::nanoseconds>(
-               ::std::chrono::seconds(1)) /
-           hertz;
-  }
-
-  // Checks whether or not this time is within amount nanoseconds of other.
-  bool IsWithin(const Time &other, int64_t amount) const;
-
-  // Returns the time represented all in nanoseconds.
-  int64_t constexpr ToNSec() const {
-    return static_cast<int64_t>(sec_) * static_cast<int64_t>(kNSecInSec) +
-        static_cast<int64_t>(nsec_);
-  }
-#ifdef __VXWORKS__
-  // Returns the time represented all in system clock ticks. The system clock
-  // rate is retrieved using sysClkRateGet().
-  int ToTicks() const {
-    return ToNSec() / static_cast<int64_t>(kNSecInSec / sysClkRateGet());
-  }
-  // Constructs a Time representing ticks.
-  static Time InTicks(int ticks) {
-    return Time::InSeconds(static_cast<double>(ticks) / sysClkRateGet());
-  }
-#endif
-
-  // Returns the time represented in milliseconds.
-  int64_t constexpr ToMSec() const {
-    return static_cast<int64_t>(sec_) * static_cast<int64_t>(kMSecInSec) +
-        (static_cast<int64_t>(nsec_) / static_cast<int64_t>(kNSecInMSec));
-  }
-
-  // Returns the time represent in microseconds.
-  int64_t constexpr ToUSec() const {
-    return static_cast<int64_t>(sec_) * static_cast<int64_t>(kUSecInSec) +
-        (static_cast<int64_t>(nsec_) / static_cast<int64_t>(kNSecInUSec));
-  }
-
-  // Returns the time represented in fractional seconds.
-  double constexpr ToSeconds() const {
-    return static_cast<double>(sec_) + static_cast<double>(nsec_) / kNSecInSec;
-  }
-
-  #ifndef SWIG
-  Time &operator+=(const Time &rhs);
-  Time &operator-=(const Time &rhs);
-  Time &operator*=(int32_t rhs);
-  Time &operator/=(int32_t rhs);
-  Time &operator%=(int32_t rhs);
-  Time &operator%=(double rhs) = delete;
-  Time &operator*=(double rhs) = delete;
-  Time &operator/=(double rhs) = delete;
-  const Time operator*(double rhs) const = delete;
-  const Time operator/(double rhs) const = delete;
-  const Time operator%(double rhs) const = delete;
-  #endif
-  const Time operator+(const Time &rhs) const;
-  const Time operator-(const Time &rhs) const;
-  const Time operator*(int32_t rhs) const;
-  const Time operator/(int32_t rhs) const;
-  double operator/(const Time &rhs) const;
-  const Time operator%(int32_t rhs) const;
-
-  const Time operator-() const;
-
-  bool operator==(const Time &rhs) const;
-  bool operator!=(const Time &rhs) const;
-  bool operator<(const Time &rhs) const;
-  bool operator>(const Time &rhs) const;
-  bool operator<=(const Time &rhs) const;
-  bool operator>=(const Time &rhs) const;
-
-  #ifndef SWIG
-  // For gtest etc.
-  friend std::ostream &operator<<(std::ostream &os, const Time &time);
-  #endif  // SWIG
-
-  int32_t constexpr sec() const { return sec_; }
-  void set_sec(int32_t sec) { sec_ = sec; }
-  int32_t constexpr nsec() const { return nsec_; }
-  void set_nsec(int32_t nsec) {
-    nsec_ = nsec;
-    Check();
-  }
-
-  // Absolute value.
-  Time abs() const {
-    if (*this > Time(0, 0)) return *this;
-    if (nsec_ == 0) return Time(-sec_, 0);
-    return Time(-sec_ - 1, kNSecInSec - nsec_);
-  }
-
- private:
-  int32_t sec_, nsec_;
-
-  // LOG(FATAL)s if nsec is >= kNSecInSec or negative.
-  static void CheckImpl(int32_t nsec);
-  void Check() { CheckImpl(nsec_); }
-  // A constexpr version of CheckImpl that returns the given value when it
-  // succeeds or evaluates to non-constexpr and returns 0 when it fails.
-  // This will result in the usual LOG(FATAL) if this is used where it isn't
-  // required to be constexpr or a compile error if it is.
-  static constexpr int32_t CheckConstexpr(int32_t nsec) {
-    return (nsec >= kNSecInSec || nsec < 0) ? CheckImpl(nsec), 0 : nsec;
-  }
-
-#ifdef SWIG
-#undef constexpr
-#endif  // SWIG
-};
-
-// Sleeps for the amount of time represented by time counted by clock.
-void SleepFor(const Time &time, clockid_t clock = Time::kDefaultClock);
-// Sleeps until clock is at the time represented by time.
-void SleepUntil(const Time &time, clockid_t clock = Time::kDefaultClock);
-
-// Sets the global offset for all times so ::aos::time::Time::Now() will return
+// Sets the global offset for all times so monotonic_clock::now() will return
 // now.
 // There is no synchronization here, so this is only safe when only a single
 // task is running.
 // This is only allowed when the shared memory core infrastructure has been
 // initialized in this process.
-void OffsetToNow(const Time &now);
+void OffsetToNow(const monotonic_clock::time_point now);
 
-// RAII class that freezes Time::Now() (to avoid making large numbers of
-// syscalls to find the real time).
+// Construct a time representing the period of hertz.
+constexpr ::std::chrono::nanoseconds FromRate(int hertz) {
+  return ::std::chrono::duration_cast<::std::chrono::nanoseconds>(
+             ::std::chrono::seconds(1)) /
+         hertz;
+}
+
+// RAII class that freezes monotonic_clock::now() (to avoid making large numbers
+// of syscalls to find the real time).
 class TimeFreezer {
  public:
   TimeFreezer() { EnableMockTime(monotonic_clock::now()); }
diff --git a/aos/common/time_test.cc b/aos/common/time_test.cc
index e1811db..94102a2 100644
--- a/aos/common/time_test.cc
+++ b/aos/common/time_test.cc
@@ -11,251 +11,9 @@
 namespace time {
 namespace testing {
 
-TEST(TimeTest, timespecConversions) {
-  timespec start{1234, 5678};  // NOLINT
-  Time time(start);
-  EXPECT_EQ(start.tv_sec, static_cast<time_t>(time.sec()));
-  EXPECT_EQ(start.tv_nsec, time.nsec());
-  timespec end = time.ToTimespec();
-  EXPECT_EQ(start.tv_sec, end.tv_sec);
-  EXPECT_EQ(start.tv_nsec, end.tv_nsec);
-}
-
-TEST(TimeTest, timevalConversions) {
-  timeval start{1234, 5678};  // NOLINT
-  Time time(start);
-  EXPECT_EQ(start.tv_sec, static_cast<long>(time.sec()));
-  EXPECT_EQ(start.tv_usec, time.nsec() / Time::kNSecInUSec);
-  timeval end = time.ToTimeval();
-  EXPECT_EQ(start.tv_sec, end.tv_sec);
-  EXPECT_EQ(start.tv_usec, end.tv_usec);
-}
-
-TEST(TimeDeathTest, ConstructorChecking) {
-  logging::Init();
-  EXPECT_DEATH(
-      {
-        logging::AddImplementation(new util::DeathTestLogImplementation());
-        Time(0, -1);
-      },
-      ".*0 <= nsec\\(-1\\) < 10+ .*");
-  EXPECT_DEATH(
-      {
-        logging::AddImplementation(new util::DeathTestLogImplementation());
-        Time(0, Time::kNSecInSec);
-      },
-      ".*0 <= nsec\\(10+\\) < 10+ .*");
-}
-
-// It's kind of hard not to test Now and SleepFor at the same time.
-TEST(TimeTest, NowAndSleepFor) {
-  // without this, it tends to fail the first time (ends up sleeping for way
-  // longer than it should the second time, where it actually matters)
-  SleepFor(Time(0, Time::kNSecInSec / 10));
-  Time start = Time::Now();
-  static constexpr Time kSleepTime = Time(0, Time::kNSecInSec * 2 / 10);
-  SleepFor(kSleepTime);
-  Time difference = Time::Now() - start;
-  EXPECT_GE(difference, kSleepTime);
-  EXPECT_LT(difference, kSleepTime + Time(0, Time::kNSecInSec / 100));
-}
-
-TEST(TimeTest, AbsoluteSleep) {
-  Time start = Time::Now();
-  SleepFor(Time(0, Time::kNSecInSec / 10));
-  static constexpr Time kSleepTime = Time(0, Time::kNSecInSec * 2 / 10);
-  SleepUntil(start + kSleepTime);
-  Time difference = Time::Now() - start;
-  EXPECT_GE(difference, kSleepTime);
-  EXPECT_LT(difference, kSleepTime + Time(0, Time::kNSecInSec / 100));
-}
-
-TEST(TimeTest, Addition) {
-  Time t(54, 500);
-  EXPECT_EQ(MACRO_DARG(Time(54, 5500)), t + MACRO_DARG(Time(0, 5000)));
-  EXPECT_EQ(MACRO_DARG(Time(56, 500)), t + MACRO_DARG(Time(2, 0)));
-  EXPECT_EQ(MACRO_DARG(Time(57, 6500)), t + MACRO_DARG(Time(3, 6000)));
-  EXPECT_EQ(MACRO_DARG(Time(50, 300)),
-            t + MACRO_DARG(Time(-5, Time::kNSecInSec - 200)));
-  EXPECT_EQ(Time(-46, 500), t + Time(-100, 0));
-  EXPECT_EQ(Time(-47, Time::kNSecInSec - 500),
-            Time(-101, Time::kNSecInSec - 1000) + t);
-}
-TEST(TimeTest, Subtraction) {
-  Time t(54, 500);
-  EXPECT_EQ(MACRO_DARG(Time(54, 300)), t - MACRO_DARG(Time(0, 200)));
-  EXPECT_EQ(MACRO_DARG(Time(42, 500)), t - MACRO_DARG(Time(12, 0)));
-  EXPECT_EQ(MACRO_DARG(Time(50, 100)), t - MACRO_DARG(Time(4, 400)));
-  EXPECT_EQ(MACRO_DARG(Time(53, 600)),
-            t - MACRO_DARG(Time(0, Time::kNSecInSec - 100)));
-  EXPECT_EQ(MACRO_DARG(Time(55, 800)),
-            t - MACRO_DARG(Time(-2, Time::kNSecInSec - 300)));
-  EXPECT_EQ(Time(54, 5500), t - Time(-1, Time::kNSecInSec - 5000));
-  EXPECT_EQ(Time(-50, Time::kNSecInSec - 300),
-            Time(5, 200) - t);
-}
-
-TEST(TimeTest, Multiplication) {
-  Time t(54, Time::kNSecInSec / 3);
-  EXPECT_EQ(MACRO_DARG(Time(108, Time::kNSecInSec / 3 * 2)), t * 2);
-  EXPECT_EQ(MACRO_DARG(Time(271, Time::kNSecInSec / 3 * 2 - 1)), t * 5);
-  EXPECT_EQ(Time(-109, Time::kNSecInSec / 3 + 1), t * -2);
-  EXPECT_EQ(Time(-55, Time::kNSecInSec / 3 * 2 + 1), t * -1);
-  EXPECT_EQ(Time(-218, Time::kNSecInSec / 3 * 2 + 2), (t * -1) * 4);
-}
-TEST(TimeTest, DivisionByInt) {
-  EXPECT_EQ(Time(5, Time::kNSecInSec / 10 * 4 + 50), Time(54, 500) / 10);
-  EXPECT_EQ(Time(2, Time::kNSecInSec / 4 * 3),
-            Time(5, Time::kNSecInSec / 2) / 2);
-  EXPECT_EQ(Time(-3, Time::kNSecInSec / 4 * 3),
-            Time(-5, Time::kNSecInSec / 2) / 2);
-}
-TEST(TimeTest, DivisionByTime) {
-  EXPECT_DOUBLE_EQ(2, Time(10, 0) / Time(5, 0));
-  EXPECT_DOUBLE_EQ(9, Time(27, 0) / Time(3, 0));
-  EXPECT_DOUBLE_EQ(9.25, Time(37, 0) / Time(4, 0));
-  EXPECT_DOUBLE_EQ(5.25, Time(36, Time::kNSecInSec / 4 * 3) / Time(7, 0));
-  EXPECT_DOUBLE_EQ(-5.25, Time(-37, Time::kNSecInSec / 4) / Time(7, 0));
-  EXPECT_DOUBLE_EQ(-5.25, Time(36, Time::kNSecInSec / 4 * 3) / Time(-7, 0));
-}
-
-TEST(TimeTest, Negation) {
-  EXPECT_EQ(Time(-5, 1234), -Time(4, Time::kNSecInSec - 1234));
-  EXPECT_EQ(Time(5, Time::kNSecInSec * 2 / 3 + 1),
-            -Time(-6, Time::kNSecInSec / 3));
-}
-
-TEST(TimeTest, Comparisons) {
-  EXPECT_TRUE(Time(971, 254) > Time(971, 253));
-  EXPECT_TRUE(Time(971, 254) >= Time(971, 253));
-  EXPECT_TRUE(Time(971, 254) < Time(971, 255));
-  EXPECT_TRUE(Time(971, 254) <= Time(971, 255));
-  EXPECT_TRUE(Time(971, 254) >= Time(971, 253));
-  EXPECT_TRUE(Time(971, 254) <= Time(971, 254));
-  EXPECT_TRUE(Time(971, 254) >= Time(971, 254));
-  EXPECT_TRUE(Time(972, 254) > Time(971, 254));
-  EXPECT_TRUE(Time(971, 254) < Time(972, 254));
-
-  EXPECT_TRUE(Time(-971, 254) > Time(-971, 253));
-  EXPECT_TRUE(Time(-971, 254) >= Time(-971, 253));
-  EXPECT_TRUE(Time(-971, 254) < Time(-971, 255));
-  EXPECT_TRUE(Time(-971, 254) <= Time(-971, 255));
-  EXPECT_TRUE(Time(-971, 254) >= Time(-971, 253));
-  EXPECT_TRUE(Time(-971, 254) <= Time(-971, 254));
-  EXPECT_TRUE(Time(-971, 254) >= Time(-971, 254));
-  EXPECT_TRUE(Time(-972, 254) < Time(-971, 254));
-  EXPECT_TRUE(Time(-971, 254) > Time(-972, 254));
-}
-
-TEST(TimeTest, Within) {
-  EXPECT_TRUE(MACRO_DARG(Time(55, 5000).IsWithin(Time(55, 4900), 100)));
-  EXPECT_FALSE(MACRO_DARG(Time(55, 5000).IsWithin(Time(55, 4900), 99)));
-  EXPECT_TRUE(MACRO_DARG(Time(5, 0).IsWithin(Time(4, Time::kNSecInSec - 200),
-                                             250)));
-  EXPECT_TRUE(Time(-5, Time::kNSecInSec - 200).IsWithin(Time(-4, 0), 250));
-  EXPECT_TRUE(Time(-5, 200).IsWithin(Time(-5, 0), 250));
-}
-
-TEST(TimeTest, Modulus) {
-  EXPECT_EQ(MACRO_DARG(Time(0, Time::kNSecInSec / 10 * 2)),
-            MACRO_DARG(Time(50, 0) % (Time::kNSecInSec / 10 * 3)));
-  EXPECT_EQ(Time(-1, Time::kNSecInSec / 10 * 8),
-            Time(-50, 0) % (Time::kNSecInSec / 10 * 3));
-  EXPECT_EQ(Time(-1, Time::kNSecInSec / 10 * 8),
-            Time(-50, 0) % (-Time::kNSecInSec / 10 * 3));
-  EXPECT_EQ(Time(0, Time::kNSecInSec / 10 * 2),
-            Time(50, 0) % (-Time::kNSecInSec / 10 * 3));
-  EXPECT_EQ(Time(1, Time::kNSecInSec / 10),
-            Time(60, Time::kNSecInSec / 10) % (Time::kNSecInSec / 10 * 12));
-}
-
-TEST(TimeTest, InSeconds) {
-  EXPECT_EQ(MACRO_DARG(Time(2, Time::kNSecInSec / 100 * 55 - 1)),
-            Time::InSeconds(2.55));
-  EXPECT_EQ(MACRO_DARG(Time(-3, Time::kNSecInSec / 100 * 45)),
-            Time::InSeconds(-2.55));
-}
-
-TEST(TimeTest, ToSeconds) {
-  EXPECT_DOUBLE_EQ(13.23, Time::InSeconds(13.23).ToSeconds());
-  EXPECT_NEAR(-13.23, Time::InSeconds(-13.23).ToSeconds(),
-              1.0 / Time::kNSecInSec * 2);
-}
-
-TEST(TimeTest, InMS) {
-  Time t = Time::InMS(254971);
-  EXPECT_EQ(254, t.sec());
-  EXPECT_EQ(971000000, t.nsec());
-
-  Time t2 = Time::InMS(-254971);
-  EXPECT_EQ(-255, t2.sec());
-  EXPECT_EQ(Time::kNSecInSec - 971000000, t2.nsec());
-
-  Time t3 = Time::InMS(-1000);
-  EXPECT_EQ(-1, t3.sec());
-  EXPECT_EQ(0, t3.nsec());
-
-  Time t4 = Time::InMS(1000);
-  EXPECT_EQ(1, t4.sec());
-  EXPECT_EQ(0, t4.nsec());
-
-  Time t5 = Time::InMS(1001);
-  EXPECT_EQ(1, t5.sec());
-  EXPECT_EQ(Time::kNSecInMSec, t5.nsec());
-
-  Time t6 = Time::InMS(-1001);
-  EXPECT_EQ(-2, t6.sec());
-  EXPECT_EQ(Time::kNSecInSec - Time::kNSecInMSec, t6.nsec());
-
-  Time t7 = Time::InMS(-999);
-  EXPECT_EQ(-1, t7.sec());
-  EXPECT_EQ(Time::kNSecInMSec, t7.nsec());
-
-  Time t8 = Time::InMS(999);
-  EXPECT_EQ(0, t8.sec());
-  EXPECT_EQ(Time::kNSecInSec - Time::kNSecInMSec, t8.nsec());
-}
-
-TEST(TimeTest, ToMSec) {
-  EXPECT_EQ(254971, Time(254, 971000000).ToMSec());
-  EXPECT_EQ(-254971, Time(-255, Time::kNSecInSec - 971000000).ToMSec());
-}
-
-TEST(TimeTest, InNS) {
-  Time t = Time::InNS(static_cast<int64_t>(973254111971ll));
-  EXPECT_EQ(973, t.sec());
-  EXPECT_EQ(254111971, t.nsec());
-
-  Time t2 = Time::InNS(static_cast<int64_t>(-973254111971ll));
-  EXPECT_EQ(-974, t2.sec());
-  EXPECT_EQ(Time::kNSecInSec - 254111971, t2.nsec());
-}
-
-TEST(TimeTest, InUS) {
-  Time t = Time::InUS(254111971);
-  EXPECT_EQ(254, t.sec());
-  EXPECT_EQ(111971000, t.nsec());
-
-  Time t2 = Time::InUS(-254111971);
-  EXPECT_EQ(-255, t2.sec());
-  EXPECT_EQ(Time::kNSecInSec - 111971000, t2.nsec());
-}
-
-TEST(TimeTest, ToUSec) {
-  EXPECT_EQ(254000971, Time(254, 971000).ToUSec());
-  EXPECT_EQ(-254000971, Time(-255, Time::kNSecInSec - 971000).ToUSec());
-}
-
-TEST(TimeTest, Abs) {
-  EXPECT_EQ(MACRO_DARG(Time(971, 1114)), MACRO_DARG(Time(971, 1114).abs()));
-  EXPECT_EQ(MACRO_DARG(Time(253, Time::kNSecInSec * 0.3)),
-            MACRO_DARG(Time(-254, Time::kNSecInSec * 0.7).abs()));
-  EXPECT_EQ(MACRO_DARG(-Time(-971, 973).ToNSec()),
-            MACRO_DARG(Time(970, Time::kNSecInSec - 973).ToNSec()));
-}
 
 TEST(TimeTest, FromRate) {
-  EXPECT_EQ(::std::chrono::milliseconds(10), Time::FromRate(100));
+  EXPECT_EQ(::std::chrono::milliseconds(10), FromRate(100));
 }
 
 // Test the monotonic_clock and sleep_until functions.
diff --git a/aos/common/util/log_interval.h b/aos/common/util/log_interval.h
index 3a7a85f..8823341 100644
--- a/aos/common/util/log_interval.h
+++ b/aos/common/util/log_interval.h
@@ -12,7 +12,7 @@
 // A class to help with logging things that happen a lot only occasionally.
 //
 // Intended use {
-//   static LogInterval interval(::aos::time::Time::InSeconds(0.2));
+//   static LogInterval interval(::std::chrono::millseconds(200));
 //
 //   if (WantToLog()) {
 //     interval.WantToLog();
diff --git a/aos/common/util/phased_loop.cc b/aos/common/util/phased_loop.cc
index 9c81ffb..bea262d 100644
--- a/aos/common/util/phased_loop.cc
+++ b/aos/common/util/phased_loop.cc
@@ -3,13 +3,6 @@
 namespace aos {
 namespace time {
 
-void PhasedLoopXMS(int ms, int offset) {
-  const Time frequency = Time::InMS(ms);
-  SleepUntil((Time::Now() / static_cast<int32_t>(frequency.ToNSec())) *
-             static_cast<int32_t>(frequency.ToNSec()) +
-             frequency + Time::InUS(offset));
-}
-
 int PhasedLoop::Iterate(const monotonic_clock::time_point now) {
   const monotonic_clock::time_point next_time =
       monotonic_clock::time_point(
diff --git a/aos/common/util/phased_loop.h b/aos/common/util/phased_loop.h
index 7614ed2..fbfe954 100644
--- a/aos/common/util/phased_loop.h
+++ b/aos/common/util/phased_loop.h
@@ -8,11 +8,6 @@
 namespace aos {
 namespace time {
 
-// Will not be accurate if ms isn't a factor of 1000.
-// offset is in us.
-// DEPRECATED(Brian): Use PhasedLoop instead.
-void PhasedLoopXMS(int ms, int offset);
-
 // Handles sleeping until a fixed offset from some time interval.
 class PhasedLoop {
  public:
@@ -21,7 +16,7 @@
   //   1.1s
   //   ...
   //   10000.1s
-  // offset must be >= Time::kZero and < interval.
+  // offset must be >= chrono::seconds(0) and < interval.
   PhasedLoop(
       const monotonic_clock::duration interval,
       const monotonic_clock::duration offset = monotonic_clock::duration(0))
diff --git a/aos/linux_code/ipc_lib/ipc_comparison.cc b/aos/linux_code/ipc_lib/ipc_comparison.cc
index 73c0f9b..11373a5 100644
--- a/aos/linux_code/ipc_lib/ipc_comparison.cc
+++ b/aos/linux_code/ipc_lib/ipc_comparison.cc
@@ -1,31 +1,32 @@
 #include "third_party/gflags/include/gflags/gflags.h"
 
-#include <stdint.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <pthread.h>
+#include <fcntl.h>
+#include <mqueue.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdint.h>
+#include <sys/eventfd.h>
 #include <sys/msg.h>
 #include <sys/sem.h>
-#include <sys/eventfd.h>
-#include <semaphore.h>
-#include <mqueue.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
 
-#include <thread>
+#include <atomic>
+#include <chrono>
 #include <memory>
 #include <string>
-#include <atomic>
+#include <thread>
 
-#include "aos/common/logging/logging.h"
-#include "aos/common/logging/implementations.h"
-#include "aos/common/time.h"
-#include "aos/common/mutex.h"
-#include "aos/common/event.h"
 #include "aos/common/condition.h"
+#include "aos/common/event.h"
+#include "aos/common/logging/implementations.h"
+#include "aos/common/logging/logging.h"
+#include "aos/common/mutex.h"
+#include "aos/common/time.h"
 #include "aos/linux_code/init.h"
 #include "aos/linux_code/ipc_lib/queue.h"
 
@@ -40,6 +41,8 @@
 
 namespace aos {
 
+namespace chrono = ::std::chrono;
+
 // A generic interface for an object which can send some data to another thread
 // and back.
 //
@@ -882,7 +885,7 @@
     ping_ponger->Ping();
   }
 
-  const time::Time start = time::Time::Now();
+  const monotonic_clock::time_point start = monotonic_clock::now();
 
   for (int32_t i = 0; i < FLAGS_messages; ++i) {
     PingPongerInterface::Data *to_send = ping_ponger->PingData();
@@ -893,7 +896,7 @@
     }
   }
 
-  const time::Time end = time::Time::Now();
+  const monotonic_clock::time_point end = monotonic_clock::now();
 
   // Try to make sure the server thread gets past its check of done so our
   // Ping() down below doesn't hang. Kind of lame, but doing better would
@@ -906,13 +909,14 @@
   server.join();
 
   LOG(INFO, "Took %f seconds to send %" PRId32 " messages\n",
-      (end - start).ToSeconds(), FLAGS_messages);
-  const time::Time per_message = (end - start) / FLAGS_messages;
-  if (per_message.sec() > 0) {
+      chrono::duration_cast<chrono::duration<double>>(end - start).count(),
+      FLAGS_messages);
+  const chrono::nanoseconds per_message = (end - start) / FLAGS_messages;
+  if (per_message >= chrono::seconds(1)) {
     LOG(INFO, "More than 1 second per message ?!?\n");
   } else {
     LOG(INFO, "That is %" PRId32 " nanoseconds per message\n",
-        per_message.nsec());
+        static_cast<int>(per_message.count()));
   }
 
   return 0;
diff --git a/aos/linux_code/ipc_lib/ipc_stress_test.cc b/aos/linux_code/ipc_lib/ipc_stress_test.cc
index 2ca4628..1b4d22e 100644
--- a/aos/linux_code/ipc_lib/ipc_stress_test.cc
+++ b/aos/linux_code/ipc_lib/ipc_stress_test.cc
@@ -1,21 +1,22 @@
-#include <stdio.h>
-#include <unistd.h>
 #include <errno.h>
+#include <libgen.h>
+#include <stdio.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-#include <libgen.h>
+#include <unistd.h>
 
+#include <chrono>
 #include <string>
 
+#include "aos/common/die.h"
+#include "aos/common/libc/aos_strsignal.h"
+#include "aos/common/libc/dirname.h"
+#include "aos/common/logging/logging.h"
+#include "aos/common/mutex.h"
 #include "aos/common/time.h"
 #include "aos/common/type_traits.h"
-#include "aos/common/mutex.h"
 #include "aos/linux_code/ipc_lib/core_lib.h"
-#include "aos/common/die.h"
-#include "aos/common/libc/dirname.h"
-#include "aos/common/libc/aos_strsignal.h"
-#include "aos/common/logging/logging.h"
 #include "aos/testing/test_shm.h"
 
 // This runs all of the IPC-related tests in a bunch of parallel processes for a
@@ -34,6 +35,8 @@
 
 namespace aos {
 
+namespace chrono = ::std::chrono;
+
 // Each test is represented by the name of the test binary and then any
 // arguments to pass to it.
 // Using --gtest_filter is a bad idea because it seems to result in a lot of
@@ -55,12 +58,12 @@
 // How many test processes to run at a time.
 static const int kTesters = 100;
 // How long to test for.
-static constexpr time::Time kTestTime = time::Time::InSeconds(30);
+static constexpr monotonic_clock::duration kTestTime = chrono::seconds(30);
 
 // The structure that gets put into shared memory and then referenced by all of
 // the child processes.
 struct Shared {
-  Shared(const time::Time &stop_time)
+  Shared(const monotonic_clock::time_point stop_time)
     : stop_time(stop_time), total_iterations(0) {}
 
   // Synchronizes access to stdout/stderr to avoid interleaving failure
@@ -68,7 +71,7 @@
   Mutex output_mutex;
 
   // When to stop.
-  time::Time stop_time;
+  monotonic_clock::time_point stop_time;
 
   // The total number of iterations. Updated by each child as it finishes.
   int total_iterations;
@@ -128,7 +131,7 @@
   // same test at the same time for the whole test.
   const char *(*test)[kTestMaxArgs] = &kTests[getpid() % kTestsLength];
   int pipes[2];
-  while (time::Time::Now() < shared->stop_time) {
+  while (monotonic_clock::now() < shared->stop_time) {
     if (pipe(pipes) == -1) {
       PDie("pipe(%p) failed", &pipes);
     }
@@ -213,7 +216,7 @@
   ::aos::testing::TestSharedMemory my_shm_;
 
   Shared *shared = static_cast<Shared *>(shm_malloc(sizeof(Shared)));
-  new (shared) Shared(time::Time::Now() + kTestTime);
+  new (shared) Shared(monotonic_clock::now() + kTestTime);
 
   if (asprintf(const_cast<char **>(&shared->path),
                "%s/../tests", ::aos::libc::Dirname(argv[0]).c_str()) == -1) {
diff --git a/aos/linux_code/ipc_lib/raw_queue_test.cc b/aos/linux_code/ipc_lib/raw_queue_test.cc
index ec07a0b..0c341e3 100644
--- a/aos/linux_code/ipc_lib/raw_queue_test.cc
+++ b/aos/linux_code/ipc_lib/raw_queue_test.cc
@@ -4,6 +4,7 @@
 #include <sys/mman.h>
 #include <inttypes.h>
 
+#include <chrono>
 #include <ostream>
 #include <memory>
 #include <map>
@@ -28,6 +29,9 @@
 namespace aos {
 namespace testing {
 
+namespace chrono = ::std::chrono;
+namespace this_thread = ::std::this_thread;
+
 // The same constant from queue.cc. This will have to be updated if that one is.
 const int kExtraMessages = 20;
 
@@ -70,7 +74,7 @@
   };
   template<typename T>
   static void Hangs_(FunctionToCall<T> *const to_call) {
-    time::SleepFor(time::Time::InSeconds(0.01));
+    this_thread::sleep_for(chrono::milliseconds(10));
     ASSERT_EQ(1, futex_set(&to_call->started));
     to_call->result = ResultType::Called;
     to_call->function(to_call->arg, const_cast<char *>(to_call->failure));
@@ -78,9 +82,9 @@
   }
 
   // How long until a function is considered to have hung.
-  static constexpr time::Time kHangTime = time::Time::InSeconds(0.09);
+  static constexpr chrono::nanoseconds kHangTime = chrono::milliseconds(90);
   // How long to sleep after forking (for debugging).
-  static constexpr time::Time kForkSleep = time::Time::InSeconds(0);
+  static constexpr chrono::nanoseconds kForkSleep = chrono::milliseconds(0);
 
   // Represents a process that has been forked off. The destructor kills the
   // process and wait(2)s for it.
@@ -118,8 +122,19 @@
     enum class JoinResult {
       Finished, Hung, Error
     };
-    JoinResult Join(time::Time timeout = kHangTime) {
-      timespec done_timeout = (kForkSleep + timeout).ToTimespec();
+    JoinResult Join(chrono::nanoseconds timeout = kHangTime) {
+      struct timespec done_timeout;
+      {
+        auto full_timeout = kForkSleep + timeout;
+        ::std::chrono::seconds sec =
+            ::std::chrono::duration_cast<::std::chrono::seconds>(full_timeout);
+        ::std::chrono::nanoseconds nsec =
+            ::std::chrono::duration_cast<::std::chrono::nanoseconds>(
+                full_timeout - sec);
+        done_timeout.tv_sec = sec.count();
+        done_timeout.tv_nsec = nsec.count();
+      }
+
       switch (futex_wait_timeout(done_, &done_timeout)) {
         case 2:
           return JoinResult::Hung;
@@ -172,11 +187,10 @@
     const pid_t pid = fork();
     switch (pid) {
       case 0:  // child
-        if (kForkSleep != time::Time(0, 0)) {
-          LOG(INFO, "pid %jd sleeping for %ds%dns\n",
-              static_cast<intmax_t>(getpid()),
-              kForkSleep.sec(), kForkSleep.nsec());
-          time::SleepFor(kForkSleep);
+        if (kForkSleep != chrono::milliseconds(0)) {
+          LOG(INFO, "pid %jd sleeping for %" PRId64 "ns\n",
+              static_cast<intmax_t>(getpid()), kForkSleep.count());
+          this_thread::sleep_for(kForkSleep);
         }
         ::aos::testing::PreventExit();
         function(arg);
@@ -325,8 +339,8 @@
 char *RawQueueTest::fatal_failure;
 std::map<RawQueueTest::ChildID, RawQueueTest::ForkedProcess *>
     RawQueueTest::children_;
-constexpr time::Time RawQueueTest::kHangTime;
-constexpr time::Time RawQueueTest::kForkSleep;
+constexpr chrono::nanoseconds RawQueueTest::kHangTime;
+constexpr chrono::nanoseconds RawQueueTest::kForkSleep;
 
 typedef RawQueueTest RawQueueDeathTest;
 
diff --git a/aos/linux_code/ipc_lib/shared_mem_types.h b/aos/linux_code/ipc_lib/shared_mem_types.h
index 81fab60..07bb60e 100644
--- a/aos/linux_code/ipc_lib/shared_mem_types.h
+++ b/aos/linux_code/ipc_lib/shared_mem_types.h
@@ -28,12 +28,12 @@
   // the owner sets as soon as it finishes setting stuff up.
   aos_condition creation_condition;
 
-  // An offset from CLOCK_REALTIME to times for all the code.
+  // An offset from CLOCK_MONOTONIC to times for all the code in nanoseconds.
   // This is currently only set to non-zero by the log replay code.
   // There is no synchronization on this to avoid the overhead because it is
   // only updated with proper memory barriers when only a single task is
   // running.
-  struct timespec time_offset;
+  int64_t time_offset;
 
   struct aos_mutex msg_alloc_lock;
   void *msg_alloc;
diff --git a/aos/linux_code/starter/starter.cc b/aos/linux_code/starter/starter.cc
index 86d601e..57d90dd 100644
--- a/aos/linux_code/starter/starter.cc
+++ b/aos/linux_code/starter/starter.cc
@@ -55,6 +55,8 @@
 namespace aos {
 namespace starter {
 
+namespace chrono = ::std::chrono;
+
 // TODO(brians): split out the c++ libevent wrapper stuff into its own file(s)
 class EventBaseDeleter {
  public:
@@ -332,12 +334,21 @@
 }
 
 // Will call callback(arg) after time.
-void Timeout(time::Time time, void (*callback)(int, short, void *), void *arg) {
+void Timeout(monotonic_clock::duration time,
+             void (*callback)(int, short, void *), void *arg) {
   EventUniquePtr timeout(evtimer_new(libevent_base.get(), callback, arg));
-  struct timeval time_timeval = time.ToTimeval();
+  struct timeval time_timeval;
+  {
+    ::std::chrono::seconds sec =
+        ::std::chrono::duration_cast<::std::chrono::seconds>(time);
+    ::std::chrono::microseconds usec =
+        ::std::chrono::duration_cast<::std::chrono::microseconds>(time - sec);
+    time_timeval.tv_sec = sec.count();
+    time_timeval.tv_usec = usec.count();
+  }
   if (evtimer_add(timeout.release(), &time_timeval) != 0) {
-    LOG(FATAL, "evtimer_add(%p, %p) failed\n",
-        timeout.release(), &time_timeval);
+    LOG(FATAL, "evtimer_add(%p, %p) failed\n", timeout.release(),
+        &time_timeval);
   }
 }
 
@@ -383,11 +394,11 @@
   // restarted.
   void ProcessDied() {
     pid_ = -1;
-    restarts_.push(time::Time::Now());
+    restarts_.push(monotonic_clock::now());
     if (restarts_.size() > kMaxRestartsNumber) {
-      time::Time oldest = restarts_.front();
+      monotonic_clock::time_point oldest = restarts_.front();
       restarts_.pop();
-      if ((time::Time::Now() - oldest) <= kMaxRestartsTime) {
+      if (monotonic_clock::now() <= kMaxRestartsTime + oldest) {
         LOG(WARNING, "process %s getting restarted too often\n", name());
         Timeout(kResumeWait, StaticStart, this);
         return;
@@ -408,19 +419,20 @@
   };
 
   // How long to wait for a child to die nicely.
-  static constexpr time::Time kProcessDieTime = time::Time::InSeconds(2);
+  static constexpr chrono::nanoseconds kProcessDieTime = chrono::seconds(2);
 
   // How long to wait after the file is modified to restart it.
   // This is important because some programs like modifying the binaries by
   // writing them in little bits, which results in attempting to start partial
   // binaries without this.
-  static constexpr time::Time kRestartWaitTime = time::Time::InSeconds(1.5);
+  static constexpr chrono::nanoseconds kRestartWaitTime =
+      chrono::milliseconds(1500);
 
   // Only kMaxRestartsNumber restarts will be allowed in kMaxRestartsTime.
-  static constexpr time::Time kMaxRestartsTime = time::Time::InSeconds(4);
+  static constexpr chrono::nanoseconds kMaxRestartsTime = chrono::seconds(4);
   static const size_t kMaxRestartsNumber = 3;
   // How long to wait if it gets restarted too many times.
-  static constexpr time::Time kResumeWait = time::Time::InSeconds(5);
+  static constexpr chrono::nanoseconds kResumeWait = chrono::seconds(5);
 
   static void StaticFileModified(void *self) {
     static_cast<Child *>(self)->FileModified();
@@ -428,11 +440,21 @@
 
   void FileModified() {
     LOG(DEBUG, "file for %s modified\n", name());
-    struct timeval restart_time_timeval = kRestartWaitTime.ToTimeval();
+    struct timeval restart_time_timeval;
+    {
+      ::std::chrono::seconds sec =
+          ::std::chrono::duration_cast<::std::chrono::seconds>(
+              kRestartWaitTime);
+      ::std::chrono::microseconds usec =
+          ::std::chrono::duration_cast<::std::chrono::microseconds>(
+              kRestartWaitTime - sec);
+      restart_time_timeval.tv_sec = sec.count();
+      restart_time_timeval.tv_usec = usec.count();
+    }
     // This will reset the timeout again if it hasn't run yet.
     if (evtimer_add(restart_timeout.get(), &restart_time_timeval) != 0) {
-      LOG(FATAL, "evtimer_add(%p, %p) failed\n",
-          restart_timeout.get(), &restart_time_timeval);
+      LOG(FATAL, "evtimer_add(%p, %p) failed\n", restart_timeout.get(),
+          &restart_time_timeval);
     }
     waiting_to_restart.insert(this);
   }
@@ -551,7 +573,8 @@
   }
 
   // A history of the times that this process has been restarted.
-  std::queue<time::Time, std::list<time::Time>> restarts_;
+  std::queue<monotonic_clock::time_point,
+             std::list<monotonic_clock::time_point>> restarts_;
 
   // The currently running child's PID or NULL.
   pid_t pid_;
@@ -581,10 +604,10 @@
   DISALLOW_COPY_AND_ASSIGN(Child);
 };
 
-constexpr time::Time Child::kProcessDieTime;
-constexpr time::Time Child::kRestartWaitTime;
-constexpr time::Time Child::kMaxRestartsTime;
-constexpr time::Time Child::kResumeWait;
+constexpr chrono::nanoseconds Child::kProcessDieTime;
+constexpr chrono::nanoseconds Child::kRestartWaitTime;
+constexpr chrono::nanoseconds Child::kMaxRestartsTime;
+constexpr chrono::nanoseconds Child::kResumeWait;
 
 EventUniquePtr Child::restart_timeout;
 ::std::set<Child *> Child::waiting_to_restart;
@@ -592,8 +615,8 @@
 // Kills off the entire process group (including ourself).
 void KillChildren(bool try_nice) {
   if (try_nice) {
-    static const int kNiceStopSignal = SIGTERM;
-    static const time::Time kNiceWaitTime = time::Time::InSeconds(1);
+    static constexpr int kNiceStopSignal = SIGTERM;
+    static constexpr auto kNiceWaitTime = chrono::seconds(1);
 
     // Make sure that we don't just nicely stop ourself...
     sigset_t mask;
@@ -604,7 +627,7 @@
     kill(-getpid(), kNiceStopSignal);
 
     fflush(NULL);
-    time::SleepFor(kNiceWaitTime);
+    ::std::this_thread::sleep_for(kNiceWaitTime);
   }
 
   // Send SIGKILL to our whole process group, which will forcibly terminate any
diff --git a/aos/vision/events/epoll_events.cc b/aos/vision/events/epoll_events.cc
index 56b22e2..aaecdbf 100644
--- a/aos/vision/events/epoll_events.cc
+++ b/aos/vision/events/epoll_events.cc
@@ -57,10 +57,10 @@
  private:
   // Calculates the new timeout value to pass to epoll_wait.
   int CalculateTimeout() {
-    const ::aos::time::Time now = ::aos::time::Time::Now();
+    const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
     int r = -1;
     for (EpollWait *c : waits_) {
-      const int new_timeout = c->Recalculate(now);
+      const int new_timeout = c->Recalculate(monotonic_now);
       if (new_timeout >= 0) {
         if (r < 0 || new_timeout < r) {
           r = new_timeout;
diff --git a/aos/vision/events/epoll_events.h b/aos/vision/events/epoll_events.h
index f032e61..1cb6842 100644
--- a/aos/vision/events/epoll_events.h
+++ b/aos/vision/events/epoll_events.h
@@ -25,7 +25,7 @@
 
   // Sets this wait to end at new_time.
   // A negative new_time disables this wait.
-  void SetTime(const ::aos::time::Time &new_time) { time_ = new_time; }
+  void SetTime(const monotonic_clock::time_point new_time) { time_ = new_time; }
 
  private:
   // Calculates how long to wait starting at now and calls Done() if
@@ -33,21 +33,23 @@
   // Returns the number of milliseconds from now that this event will expire in.
   // Returns -1 if this wait is never going to expire.
   // Returns INT_MAX if this wait expires in longer than that.
-  int Recalculate(const ::aos::time::Time &now) {
-    if (time_ < ::aos::time::Time::kZero) return -1;
+  int Recalculate(const monotonic_clock::time_point now) {
+    if (time_ < monotonic_clock::epoch()) return -1;
     if (time_ <= now) {
       Done();
-      time_ = ::aos::time::Time(-1, 0);
+      time_ = monotonic_clock::time_point(::std::chrono::seconds(-1));
       return -1;
     }
-    if (time_ - now > ::aos::time::Time::InMS(INT_MAX)) {
+    if (time_ - now > ::std::chrono::milliseconds(INT_MAX)) {
       return INT_MAX;
     } else {
-      return (time_ - now).ToMSec();
+      return ::std::chrono::duration_cast<::std::chrono::milliseconds>(time_ -
+                                                                       now)
+          .count();
     }
   }
 
-  ::aos::time::Time time_ = ::aos::time::Time::kZero;
+  ::aos::monotonic_clock::time_point time_ = ::aos::monotonic_clock::epoch();
 
   friend class EpollLoop;
 };
diff --git a/frc971/control_loops/drivetrain/drivetrain_lib_test.cc b/frc971/control_loops/drivetrain/drivetrain_lib_test.cc
index d3ea2f0..21a968a 100644
--- a/frc971/control_loops/drivetrain/drivetrain_lib_test.cc
+++ b/frc971/control_loops/drivetrain/drivetrain_lib_test.cc
@@ -1,5 +1,6 @@
 #include <unistd.h>
 
+#include <chrono>
 #include <memory>
 
 #include "aos/common/controls/control_loop_test.h"
@@ -24,8 +25,8 @@
 namespace drivetrain {
 namespace testing {
 
-using ::aos::time::Time;
-
+namespace chrono = ::std::chrono;
+using ::aos::monotonic_clock;
 using ::y2016::control_loops::drivetrain::MakeDrivetrainPlant;
 
 // TODO(Comran): Make one that doesn't depend on the actual values for a
@@ -235,9 +236,9 @@
     SimulateTimestep(true);
   }
 
-  void RunForTime(const Time run_for) {
-    const auto end_time = Time::Now() + run_for;
-    while (Time::Now() < end_time) {
+  void RunForTime(monotonic_clock::duration run_for) {
+    const auto end_time = monotonic_clock::now() + run_for;
+    while (monotonic_clock::now() < end_time) {
       RunIteration();
     }
   }
@@ -261,7 +262,7 @@
       .left_goal(-1.0)
       .right_goal(1.0)
       .Send();
-  RunForTime(Time::InSeconds(2.0));
+  RunForTime(chrono::seconds(2));
   VerifyNearGoal();
 }
 
@@ -275,7 +276,7 @@
       .Send();
   drivetrain_motor_plant_.set_left_voltage_offset(1.0);
   drivetrain_motor_plant_.set_right_voltage_offset(1.0);
-  RunForTime(Time::InSeconds(1.5));
+  RunForTime(chrono::milliseconds(1500));
   VerifyNearGoal();
 }
 
@@ -311,7 +312,7 @@
 // Tests that never having a goal, but having driver's station messages, doesn't
 // break.
 TEST_F(DrivetrainTest, NoGoalWithRobotState) {
-  RunForTime(Time::InSeconds(0.1));
+  RunForTime(chrono::milliseconds(100));
 }
 
 // Tests that the robot successfully drives straight forward.
@@ -393,7 +394,8 @@
     goal.Send();
   }
 
-  while (Time::Now() < Time::InSeconds(6)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::seconds(6))) {
     RunIteration();
     ASSERT_TRUE(my_drivetrain_queue_.output.FetchLatest());
     EXPECT_NEAR(my_drivetrain_queue_.output->left_voltage,
@@ -423,7 +425,8 @@
     goal.Send();
   }
 
-  while (Time::Now() < Time::InSeconds(6)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::seconds(6))) {
     RunIteration();
     ASSERT_TRUE(my_drivetrain_queue_.output.FetchLatest());
     EXPECT_NEAR(my_drivetrain_queue_.output->left_voltage,
@@ -453,7 +456,8 @@
     goal.Send();
   }
 
-  while (Time::Now() < Time::InSeconds(3)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::seconds(3))) {
     RunIteration();
     ASSERT_TRUE(my_drivetrain_queue_.output.FetchLatest());
   }
@@ -471,7 +475,7 @@
       .quickturn(false)
       .Send();
 
-  RunForTime(Time::InSeconds(1.0));
+  RunForTime(chrono::seconds(1));
 
   my_drivetrain_queue_.goal.MakeWithBuilder()
       .control_loop_driving(false)
@@ -481,7 +485,7 @@
       .quickturn(false)
       .Send();
 
-  RunForTime(Time::InSeconds(1.0));
+  RunForTime(chrono::seconds(1));
 
   my_drivetrain_queue_.goal.MakeWithBuilder()
       .control_loop_driving(false)
@@ -491,7 +495,7 @@
       .quickturn(false)
       .Send();
 
-  RunForTime(Time::InSeconds(10.0));
+  RunForTime(chrono::seconds(10));
 
   {
     ::aos::ScopedMessagePtr<::frc971::control_loops::DrivetrainQueue::Goal>
@@ -508,8 +512,8 @@
     goal.Send();
   }
 
-  const auto end_time = Time::Now() + Time::InSeconds(4);
-  while (Time::Now() < end_time) {
+  const auto end_time = monotonic_clock::now() + chrono::seconds(4);
+  while (monotonic_clock::now() < end_time) {
     drivetrain_motor_plant_.SendPositionMessage();
     drivetrain_motor_.Iterate();
     drivetrain_motor_plant_.Simulate();
diff --git a/frc971/control_loops/voltage_cap/voltage_cap_test.cc b/frc971/control_loops/voltage_cap/voltage_cap_test.cc
index 4bee640..23e2f34 100644
--- a/frc971/control_loops/voltage_cap/voltage_cap_test.cc
+++ b/frc971/control_loops/voltage_cap/voltage_cap_test.cc
@@ -7,8 +7,6 @@
 #include "aos/common/queue.h"
 #include "aos/testing/test_shm.h"
 
-using ::aos::time::Time;
-
 namespace frc971 {
 namespace control_loops {
 namespace testing {
diff --git a/frc971/control_loops/zeroed_joint.h b/frc971/control_loops/zeroed_joint.h
index f25434f..fcfd29f 100644
--- a/frc971/control_loops/zeroed_joint.h
+++ b/frc971/control_loops/zeroed_joint.h
@@ -135,12 +135,11 @@
 
   ZeroedJoint(StateFeedbackLoop<3, 1, 1> loop)
       : loop_(new ZeroedStateFeedbackLoop<kNumZeroSensors>(loop, this)),
-        last_good_time_(0, 0),
+        last_good_time_(::aos::monotonic_clock::min_time()),
         state_(UNINITIALIZED),
         error_count_(0),
         zero_offset_(0.0),
-        capped_goal_(false) {
-  }
+        capped_goal_(false) {}
 
   // Copies the provided configuration data locally.
   void set_config_data(const ConfigurationData &config_data) {
@@ -191,14 +190,14 @@
   friend class testing::WristTest_NoWindupPositive_Test;
   friend class testing::WristTest_NoWindupNegative_Test;
 
-  static const ::aos::time::Time kRezeroTime;
+  static constexpr ::aos::monotonic_clock::duration kRezeroTime;
 
   // The state feedback control loop to talk to.
   ::std::unique_ptr<ZeroedStateFeedbackLoop<kNumZeroSensors>> loop_;
 
   ConfigurationData config_data_;
 
-  ::aos::time::Time last_good_time_;
+  ::aos::monotonic_clock::time_point last_good_time_;
 
   // Returns the index of the first active sensor, or -1 if none are active.
   int ActiveSensorIndex(
@@ -262,8 +261,8 @@
 };
 
 template <int kNumZeroSensors>
-const ::aos::time::Time ZeroedJoint<kNumZeroSensors>::kRezeroTime =
-    ::aos::time::Time::InSeconds(2);
+constexpr ::aos::monotonic_clock::duration
+    ZeroedJoint<kNumZeroSensors>::kRezeroTime = ::std::chrono::seconds(2);
 
 template <int kNumZeroSensors>
 /*static*/ const double ZeroedJoint<kNumZeroSensors>::dt = 0.01;
@@ -283,7 +282,7 @@
     output_enabled = false;
     LOG(WARNING, "err_count is %d so disabling\n", error_count_);
 
-    if ((::aos::time::Time::Now() - last_good_time_) > kRezeroTime) {
+    if (::aos::monotonic_clock::now() > kRezeroTime + last_good_time_) {
       LOG(WARNING, "err_count is %d (or 1st time) so forcing a re-zero\n",
           error_count_);
       state_ = UNINITIALIZED;
@@ -291,7 +290,7 @@
     }
   }
   if (position != NULL) {
-    last_good_time_ = ::aos::time::Time::Now();
+    last_good_time_ = ::aos::monotonic_clock::now();
     error_count_ = 0;
   }
 
diff --git a/frc971/wpilib/ADIS16448.cc b/frc971/wpilib/ADIS16448.cc
index cf1a6f8..ec219cc 100644
--- a/frc971/wpilib/ADIS16448.cc
+++ b/frc971/wpilib/ADIS16448.cc
@@ -5,18 +5,21 @@
 
 #include <inttypes.h>
 #include <math.h>
+#include <chrono>
 
 #include "aos/common/logging/queue_logging.h"
 #include "aos/common/messages/robot_state.q.h"
 #include "aos/common/time.h"
 #include "aos/linux_code/init.h"
-
 #include "frc971/wpilib/imu.q.h"
 #include "frc971/zeroing/averager.h"
 
 namespace frc971 {
 namespace wpilib {
 
+using ::aos::monotonic_clock;
+namespace chrono = ::std::chrono;
+
 template <uint8_t size>
 bool ADIS16448::DoTransaction(uint8_t to_send[size], uint8_t to_receive[size]) {
   switch (spi_->Transaction(to_send, to_receive, size)) {
@@ -128,7 +131,7 @@
 
   // Try to initialize repeatedly as long as we're supposed to be running.
   while (run_ && !Initialize()) {
-    ::aos::time::SleepFor(::aos::time::Time::InMS(50));
+    ::std::this_thread::sleep_for(::std::chrono::milliseconds(50));
   }
   LOG(INFO, "IMU initialized successfully\n");
 
@@ -150,7 +153,7 @@
       }
     }
     got_an_interrupt = true;
-    const ::aos::time::Time read_time = ::aos::time::Time::Now();
+    const monotonic_clock::time_point read_time = monotonic_clock::now();
 
     uint8_t to_send[2 * 14], to_receive[2 * 14];
     memset(&to_send[0], 0, sizeof(to_send));
@@ -188,7 +191,9 @@
 
     auto message = imu_values.MakeMessage();
     message->fpga_timestamp = dio1_->ReadRisingTimestamp();
-    message->monotonic_timestamp_ns = read_time.ToNSec();
+    message->monotonic_timestamp_ns =
+        chrono::duration_cast<chrono::nanoseconds>(read_time.time_since_epoch())
+            .count();
 
     message->gyro_x =
         ConvertValue(&to_receive[4], kGyroLsbDegreeSecond * M_PI / 180.0);
@@ -364,7 +369,7 @@
   {
     uint16_t value;
     do {
-      ::aos::time::SleepFor(::aos::time::Time::InMS(10));
+      ::std::this_thread::sleep_for(::std::chrono::milliseconds(10));
       if (!ReadRegister(kMscCtrlAddress, &value)) return false;
     } while ((value & (1 << 10)) != 0);
   }
diff --git a/frc971/wpilib/gyro_interface.cc b/frc971/wpilib/gyro_interface.cc
index 6b3ab40..9b7bb8b 100644
--- a/frc971/wpilib/gyro_interface.cc
+++ b/frc971/wpilib/gyro_interface.cc
@@ -1,6 +1,7 @@
 #include "frc971/wpilib/gyro_interface.h"
 
 #include <inttypes.h>
+#include <chrono>
 
 #include "aos/common/logging/logging.h"
 #include "aos/common/time.h"
@@ -35,7 +36,7 @@
   }
 
   // Wait for it to assert the fault conditions before reading them.
-  ::aos::time::SleepFor(::aos::time::Time::InMS(50));
+  ::std::this_thread::sleep_for(::std::chrono::milliseconds(50));
 
   if (!DoTransaction(0x20000000, &result)) {
     LOG(WARNING, "failed to clear latched non-fault data\n");
diff --git a/frc971/wpilib/gyro_sender.cc b/frc971/wpilib/gyro_sender.cc
index 8cfdc39..9acb6fc 100644
--- a/frc971/wpilib/gyro_sender.cc
+++ b/frc971/wpilib/gyro_sender.cc
@@ -1,6 +1,11 @@
 #include "frc971/wpilib/gyro_sender.h"
 
+#include <fcntl.h>
 #include <inttypes.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <chrono>
 
 #include "aos/common/logging/logging.h"
 #include "aos/common/logging/queue_logging.h"
@@ -16,13 +21,15 @@
 namespace wpilib {
 
 GyroSender::GyroSender() {}
+namespace chrono = ::std::chrono;
+using ::aos::monotonic_clock;
 
 void GyroSender::operator()() {
   ::aos::SetCurrentThreadName("Gyro");
 
   // Try to initialize repeatedly as long as we're supposed to be running.
   while (run_ && !gyro_.InitializeGyro()) {
-    ::aos::time::SleepFor(::aos::time::Time::InMS(50));
+    ::std::this_thread::sleep_for(::std::chrono::milliseconds(50));
   }
   LOG(INFO, "gyro initialized successfully\n");
 
diff --git a/frc971/wpilib/interrupt_edge_counting.cc b/frc971/wpilib/interrupt_edge_counting.cc
index 4bdb2d2..5c10b89 100644
--- a/frc971/wpilib/interrupt_edge_counting.cc
+++ b/frc971/wpilib/interrupt_edge_counting.cc
@@ -1,5 +1,7 @@
 #include "frc971/wpilib/interrupt_edge_counting.h"
 
+#include <chrono>
+
 #include "aos/common/time.h"
 #include "aos/linux_code/init.h"
 
@@ -64,7 +66,7 @@
 
     // Wait more than the amount of time it takes for a digital input change
     // to go from visible to software to having triggered an interrupt.
-    ::aos::time::SleepFor(::aos::time::Time::InUS(120));
+    ::std::this_thread::sleep_for(::std::chrono::microseconds(120));
 
     if (TryFinishingIteration()) return;
   }
diff --git a/frc971/wpilib/loop_output_handler.cc b/frc971/wpilib/loop_output_handler.cc
index 310b3e3..59770be 100644
--- a/frc971/wpilib/loop_output_handler.cc
+++ b/frc971/wpilib/loop_output_handler.cc
@@ -2,8 +2,9 @@
 
 #include <sys/timerfd.h>
 
-#include <thread>
+#include <chrono>
 #include <functional>
+#include <thread>
 
 #include "aos/linux_code/init.h"
 #include "aos/common/messages/robot_state.q.h"
@@ -11,7 +12,9 @@
 namespace frc971 {
 namespace wpilib {
 
-LoopOutputHandler::LoopOutputHandler(const ::aos::time::Time &timeout)
+namespace chrono = ::std::chrono;
+
+LoopOutputHandler::LoopOutputHandler(::std::chrono::nanoseconds timeout)
     : watchdog_(this, timeout) {}
 
 void LoopOutputHandler::operator()() {
@@ -44,12 +47,12 @@
 }
 
 LoopOutputHandler::Watchdog::Watchdog(LoopOutputHandler *handler,
-                                      const ::aos::time::Time &timeout)
+                                      ::std::chrono::nanoseconds timeout)
     : handler_(handler),
       timeout_(timeout),
-      timerfd_(timerfd_create(::aos::time::Time::kDefaultClock, 0)) {
+      timerfd_(timerfd_create(CLOCK_MONOTONIC, 0)) {
   if (timerfd_.get() == -1) {
-    PLOG(FATAL, "timerfd_create(Time::kDefaultClock, 0)");
+    PLOG(FATAL, "timerfd_create(CLOCK_MONOTONIC, 0)");
   }
 }
 
@@ -65,7 +68,11 @@
 
 void LoopOutputHandler::Watchdog::Reset() {
   itimerspec value = itimerspec();
-  value.it_value = timeout_.ToTimespec();
+  value.it_value.tv_sec = chrono::duration_cast<chrono::seconds>(timeout_).count();
+  value.it_value.tv_nsec =
+      chrono::duration_cast<chrono::nanoseconds>(
+          timeout_ - chrono::seconds(value.it_value.tv_sec))
+          .count();
   PCHECK(timerfd_settime(timerfd_.get(), 0, &value, nullptr));
 }
 
diff --git a/frc971/wpilib/loop_output_handler.h b/frc971/wpilib/loop_output_handler.h
index 144093d..14a5cc5 100644
--- a/frc971/wpilib/loop_output_handler.h
+++ b/frc971/wpilib/loop_output_handler.h
@@ -22,7 +22,7 @@
 class LoopOutputHandler {
  public:
   LoopOutputHandler(
-      const ::aos::time::Time &timeout = ::aos::time::Time::InSeconds(0.10));
+      ::std::chrono::nanoseconds timeout = ::std::chrono::milliseconds(100));
 
   void Quit() { run_ = false; }
 
@@ -54,7 +54,7 @@
   // LoopOutputHandler whenever the timerfd expires.
   class Watchdog {
    public:
-    Watchdog(LoopOutputHandler *handler, const ::aos::time::Time &timeout);
+    Watchdog(LoopOutputHandler *handler, ::std::chrono::nanoseconds timeout);
 
     void operator()();
 
@@ -65,7 +65,7 @@
    private:
     LoopOutputHandler *const handler_;
 
-    const ::aos::time::Time timeout_;
+    const ::std::chrono::nanoseconds timeout_;
 
     ::aos::ScopedFD timerfd_;
 
diff --git a/y2012/wpilib/wpilib_interface.cc b/y2012/wpilib/wpilib_interface.cc
index dd0f7ca..8493496 100644
--- a/y2012/wpilib/wpilib_interface.cc
+++ b/y2012/wpilib/wpilib_interface.cc
@@ -73,12 +73,6 @@
          (3.5 /*wheel diameter*/ * 2.54 / 100.0 * M_PI) * 2.0 / 2.0;
 }
 
-static const double kMaximumEncoderPulsesPerSecond =
-    5600.0 /* free speed RPM */ * 14.0 / 48.0 /* bottom gear reduction */ *
-    18.0 / 32.0 /* big belt reduction */ *
-    18.0 / 66.0 /* top gear reduction */ * 48.0 / 18.0 /* encoder gears */ /
-    60.0 /* seconds / minute */ * 256.0 /* CPR */;
-
 class SensorReader {
  public:
   SensorReader() {}
diff --git a/y2014/actors/drivetrain_actor.cc b/y2014/actors/drivetrain_actor.cc
index c0ee47b..7ab4f3d 100644
--- a/y2014/actors/drivetrain_actor.cc
+++ b/y2014/actors/drivetrain_actor.cc
@@ -50,8 +50,10 @@
   turn_profile.set_maximum_velocity(params.maximum_turn_velocity *
                                     control_loops::drivetrain::kRobotRadius);
 
+  ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
+                                      ::std::chrono::milliseconds(5) / 2);
   while (true) {
-    ::aos::time::PhasedLoopXMS(5, 2500);
+    phased_loop.SleepUntilNext();
 
     ::frc971::control_loops::drivetrain_queue.status.FetchLatest();
     if (::frc971::control_loops::drivetrain_queue.status.get()) {
diff --git a/y2014/actors/drivetrain_actor_main.cc b/y2014/actors/drivetrain_actor_main.cc
index 4cc0070..4ecd1ab 100644
--- a/y2014/actors/drivetrain_actor_main.cc
+++ b/y2014/actors/drivetrain_actor_main.cc
@@ -4,8 +4,6 @@
 #include "y2014/actors/drivetrain_action.q.h"
 #include "y2014/actors/drivetrain_actor.h"
 
-using ::aos::time::Time;
-
 int main(int /*argc*/, char * /*argv*/[]) {
   ::aos::Init(-1);
 
diff --git a/y2014/actors/shoot_actor_main.cc b/y2014/actors/shoot_actor_main.cc
index 1d33404..96fd8ea 100644
--- a/y2014/actors/shoot_actor_main.cc
+++ b/y2014/actors/shoot_actor_main.cc
@@ -4,8 +4,6 @@
 #include "y2014/actors/shoot_action.q.h"
 #include "y2014/actors/shoot_actor.h"
 
-using ::aos::time::Time;
-
 int main(int /*argc*/, char * /*argv*/[]) {
   ::aos::Init(-1);
 
diff --git a/y2014/autonomous/auto.cc b/y2014/autonomous/auto.cc
index 5860407..e7f7697 100644
--- a/y2014/autonomous/auto.cc
+++ b/y2014/autonomous/auto.cc
@@ -1,5 +1,6 @@
 #include <stdio.h>
 
+#include <chrono>
 #include <memory>
 
 #include "aos/common/util/phased_loop.h"
@@ -22,12 +23,20 @@
 #include "y2014/queues/hot_goal.q.h"
 #include "y2014/queues/profile_params.q.h"
 
-using ::aos::time::Time;
-
 namespace y2014 {
 namespace autonomous {
+namespace chrono = ::std::chrono;
+namespace this_thread = ::std::this_thread;
+using ::aos::monotonic_clock;
 
-namespace time = ::aos::time;
+namespace {
+
+double DoubleSeconds(monotonic_clock::duration duration) {
+  return ::std::chrono::duration_cast<::std::chrono::duration<double>>(duration)
+      .count();
+}
+
+}  // namespace
 
 static double left_initial_position, right_initial_position;
 
@@ -73,9 +82,11 @@
     LOG(ERROR, "No action, not waiting\n");
     return;
   }
+  ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(10),
+                                      ::std::chrono::milliseconds(10) / 2);
   while (true) {
     // Poll the running bit and auto done bits.
-    ::aos::time::PhasedLoopXMS(10, 5000);
+    phased_loop.SleepUntilNext();
     if (!action->Running() || ShouldExitAuto()) {
       return;
     }
@@ -221,8 +232,10 @@
 
 void WaitUntilClawDone() {
   while (true) {
+    ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(10),
+                                        ::std::chrono::milliseconds(10) / 2);
     // Poll the running bit and auto done bits.
-    ::aos::time::PhasedLoopXMS(10, 5000);
+    phased_loop.SleepUntilNext();
     control_loops::claw_queue.status.FetchLatest();
     control_loops::claw_queue.goal.FetchLatest();
     if (ShouldExitAuto()) {
@@ -345,7 +358,7 @@
   static const double kPickupDistance = 0.5;
   static const double kTurnAngle = 0.3;
 
-  ::aos::time::Time start_time = ::aos::time::Time::Now();
+  monotonic_clock::time_point start_time = monotonic_clock::now();
   LOG(INFO, "Handling auto mode\n");
 
   AutoVersion auto_version;
@@ -380,27 +393,27 @@
 
   ResetDrivetrain();
 
-  time::SleepFor(time::Time::InSeconds(0.1));
+  this_thread::sleep_for(chrono::milliseconds(100));
   if (ShouldExitAuto()) return;
   InitializeEncoders();
 
   // Turn the claw on, keep it straight up until the ball has been grabbed.
   LOG(INFO, "Claw going up at %f\n",
-      (::aos::time::Time::Now() - start_time).ToSeconds());
+      DoubleSeconds(monotonic_clock::now() - start_time));
   PositionClawVertically(12.0, 4.0);
   SetShotPower(115.0);
 
   // Wait for the ball to enter the claw.
-  time::SleepFor(time::Time::InSeconds(0.25));
+  this_thread::sleep_for(chrono::milliseconds(250));
   if (ShouldExitAuto()) return;
   LOG(INFO, "Readying claw for shot at %f\n",
-      (::aos::time::Time::Now() - start_time).ToSeconds());
+      DoubleSeconds(monotonic_clock::now() - start_time));
 
   {
     if (ShouldExitAuto()) return;
     // Drive to the goal.
     auto drivetrain_action = SetDriveGoal(-kShootDistance, drive_params);
-    time::SleepFor(time::Time::InSeconds(0.75));
+    this_thread::sleep_for(chrono::milliseconds(750));
     PositionClawForShot();
     LOG(INFO, "Waiting until drivetrain is finished\n");
     WaitUntilDoneOrCanceled(::std::move(drivetrain_action));
@@ -430,21 +443,20 @@
   } else if (auto_version == AutoVersion::kSingleHot) {
     do {
       // TODO(brians): Wait for next message with timeout or something.
-      ::aos::time::SleepFor(::aos::time::Time::InSeconds(0.003));
+      this_thread::sleep_for(chrono::milliseconds(3));
       hot_goal_decoder.Update(false);
       if (ShouldExitAuto()) return;
     } while (!hot_goal_decoder.left_triggered() &&
-             (::aos::time::Time::Now() - start_time) <
-                 ::aos::time::Time::InSeconds(9));
+             (monotonic_clock::now() - start_time) < chrono::seconds(9));
   } else if (auto_version == AutoVersion::kStraight) {
-    time::SleepFor(time::Time::InSeconds(0.4));
+    this_thread::sleep_for(chrono::milliseconds(400));
   }
 
   // Shoot.
   LOG(INFO, "Shooting at %f\n",
-      (::aos::time::Time::Now() - start_time).ToSeconds());
+      DoubleSeconds(monotonic_clock::now() - start_time));
   Shoot();
-  time::SleepFor(time::Time::InSeconds(0.05));
+  this_thread::sleep_for(chrono::milliseconds(50));
 
   if (auto_version == AutoVersion::kDoubleHot) {
     if (ShouldExitAuto()) return;
@@ -454,7 +466,7 @@
     if (ShouldExitAuto()) return;
   } else if (auto_version == AutoVersion::kSingleHot) {
     LOG(INFO, "auto done at %f\n",
-        (::aos::time::Time::Now() - start_time).ToSeconds());
+        DoubleSeconds(monotonic_clock::now() - start_time));
     PositionClawVertically(0.0, 0.0);
     return;
   }
@@ -463,7 +475,7 @@
     if (ShouldExitAuto()) return;
     // Intake the new ball.
     LOG(INFO, "Claw ready for intake at %f\n",
-        (::aos::time::Time::Now() - start_time).ToSeconds());
+        DoubleSeconds(monotonic_clock::now() - start_time));
     PositionClawBackIntake();
     auto drivetrain_action =
         SetDriveGoal(kShootDistance + kPickupDistance, drive_params);
@@ -471,7 +483,7 @@
     WaitUntilDoneOrCanceled(::std::move(drivetrain_action));
     if (ShouldExitAuto()) return;
     LOG(INFO, "Wait for the claw at %f\n",
-        (::aos::time::Time::Now() - start_time).ToSeconds());
+        DoubleSeconds(monotonic_clock::now() - start_time));
     WaitUntilClawDone();
     if (ShouldExitAuto()) return;
   }
@@ -479,10 +491,10 @@
   // Drive back.
   {
     LOG(INFO, "Driving back at %f\n",
-        (::aos::time::Time::Now() - start_time).ToSeconds());
+        DoubleSeconds(monotonic_clock::now() - start_time));
     auto drivetrain_action =
         SetDriveGoal(-(kShootDistance + kPickupDistance), drive_params);
-    time::SleepFor(time::Time::InSeconds(0.3));
+    this_thread::sleep_for(chrono::milliseconds(300));
     hot_goal_decoder.ResetCounts();
     if (ShouldExitAuto()) return;
     PositionClawUpClosed();
@@ -515,17 +527,17 @@
     WaitUntilDoneOrCanceled(::std::move(drivetrain_action));
     if (ShouldExitAuto()) return;
   } else if (auto_version == AutoVersion::kStraight) {
-    time::SleepFor(time::Time::InSeconds(0.4));
+    this_thread::sleep_for(chrono::milliseconds(400));
   }
 
   LOG(INFO, "Shooting at %f\n",
-      (::aos::time::Time::Now() - start_time).ToSeconds());
+      DoubleSeconds(monotonic_clock::now() - start_time));
   // Shoot
   Shoot();
   if (ShouldExitAuto()) return;
 
   // Get ready to zero when we come back up.
-  time::SleepFor(time::Time::InSeconds(0.05));
+  this_thread::sleep_for(chrono::milliseconds(50));
   PositionClawVertically(0.0, 0.0);
 }
 
diff --git a/y2014/autonomous/auto_main.cc b/y2014/autonomous/auto_main.cc
index bf3acf8..747747a 100644
--- a/y2014/autonomous/auto_main.cc
+++ b/y2014/autonomous/auto_main.cc
@@ -6,8 +6,6 @@
 #include "frc971/autonomous/auto.q.h"
 #include "y2014/autonomous/auto.h"
 
-using ::aos::time::Time;
-
 int main(int /*argc*/, char * /*argv*/[]) {
   ::aos::Init(-1);
 
@@ -24,12 +22,15 @@
       LOG(INFO, "Got another auto packet\n");
     }
     LOG(INFO, "Starting auto mode\n");
-    ::aos::time::Time start_time = ::aos::time::Time::Now();
+    ::aos::monotonic_clock::time_point start_time =
+        ::aos::monotonic_clock::now();
     ::y2014::autonomous::HandleAuto();
 
-    ::aos::time::Time elapsed_time = ::aos::time::Time::Now() - start_time;
+    auto elapsed_time = ::aos::monotonic_clock::now() - start_time;
     LOG(INFO, "Auto mode exited in %f, waiting for it to finish.\n",
-        elapsed_time.ToSeconds());
+        ::std::chrono::duration_cast<::std::chrono::duration<double>>(
+            elapsed_time)
+            .count());
     while (::frc971::autonomous::autonomous->run_auto) {
       ::frc971::autonomous::autonomous.FetchNextBlocking();
       LOG(INFO, "Got another auto packet\n");
diff --git a/y2014/control_loops/claw/claw_lib_test.cc b/y2014/control_loops/claw/claw_lib_test.cc
index 8a92bce..4079da4 100644
--- a/y2014/control_loops/claw/claw_lib_test.cc
+++ b/y2014/control_loops/claw/claw_lib_test.cc
@@ -1,17 +1,15 @@
 #include <unistd.h>
 
+#include <chrono>
 #include <memory>
 
-#include "aos/common/network/team_number.h"
 #include "aos/common/controls/control_loop_test.h"
-
-#include "y2014/control_loops/claw/claw.q.h"
-#include "y2014/control_loops/claw/claw.h"
-#include "y2014/constants.h"
-#include "y2014/control_loops/claw/claw_motor_plant.h"
-
+#include "aos/common/network/team_number.h"
 #include "gtest/gtest.h"
-
+#include "y2014/constants.h"
+#include "y2014/control_loops/claw/claw.h"
+#include "y2014/control_loops/claw/claw.q.h"
+#include "y2014/control_loops/claw/claw_motor_plant.h"
 
 namespace y2014 {
 namespace control_loops {
@@ -20,6 +18,8 @@
 using ::y2014::control_loops::claw::MakeClawPlant;
 using ::frc971::HallEffectStruct;
 using ::y2014::control_loops::HalfClawPosition;
+using ::aos::monotonic_clock;
+namespace chrono = ::std::chrono;
 
 typedef enum {
 	TOP_CLAW = 0,
@@ -288,7 +288,8 @@
       .bottom_angle(::std::nan(""))
       .separation_angle(::std::nan(""))
       .Send();
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(5)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::seconds(5))) {
     claw_motor_plant_.SendPositionMessage();
     claw_motor_.Iterate();
     claw_motor_plant_.Simulate();
@@ -302,7 +303,8 @@
       .bottom_angle(0.1)
       .separation_angle(0.2)
       .Send();
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(5)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::seconds(5))) {
     claw_motor_plant_.SendPositionMessage();
     claw_motor_.Iterate();
     claw_motor_plant_.Simulate();
@@ -400,7 +402,8 @@
       .bottom_angle(0.1)
       .separation_angle(0.2)
       .Send();
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(7)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::seconds(7))) {
     claw_motor_plant_.SendPositionMessage();
     claw_motor_.Iterate();
     claw_motor_plant_.Simulate();
@@ -511,15 +514,17 @@
 
 class WindupClawTest : public ClawTest {
  protected:
-  void TestWindup(ClawMotor::CalibrationMode mode, ::aos::time::Time start_time, double offset) {
+  void TestWindup(ClawMotor::CalibrationMode mode,
+                  monotonic_clock::time_point start_time, double offset) {
     int capped_count = 0;
     const constants::Values& values = constants::GetValues();
     bool kicked = false;
     bool measured = false;
-    while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(7)) {
+    while (monotonic_clock::now() <
+           monotonic_clock::time_point(chrono::seconds(7))) {
       claw_motor_plant_.SendPositionMessage();
-      if (::aos::time::Time::Now() >= start_time &&
-          mode == claw_motor_.mode() && !kicked) {
+      if (monotonic_clock::now() >= start_time && mode == claw_motor_.mode() &&
+          !kicked) {
         EXPECT_EQ(mode, claw_motor_.mode());
         // Move the zeroing position far away and verify that it gets moved
         // back.
@@ -578,8 +583,8 @@
       .separation_angle(0.2)
       .Send();
 
-  TestWindup(ClawMotor::UNKNOWN_LOCATION, ::aos::time::Time::InSeconds(1.0),
-             971.0);
+  TestWindup(ClawMotor::UNKNOWN_LOCATION,
+             monotonic_clock::time_point(chrono::seconds(1)), 971.0);
 
   VerifyNearGoal();
 }
@@ -592,8 +597,8 @@
       .separation_angle(0.2)
       .Send();
 
-  TestWindup(ClawMotor::UNKNOWN_LOCATION, ::aos::time::Time::InSeconds(1.0),
-             -971.0);
+  TestWindup(ClawMotor::UNKNOWN_LOCATION,
+             monotonic_clock::time_point(chrono::seconds(1)), -971.0);
 
   VerifyNearGoal();
 }
@@ -606,8 +611,8 @@
       .separation_angle(0.2)
       .Send();
 
-  TestWindup(ClawMotor::FINE_TUNE_BOTTOM, ::aos::time::Time::InSeconds(2.0),
-             -971.0);
+  TestWindup(ClawMotor::FINE_TUNE_BOTTOM,
+             monotonic_clock::time_point(chrono::seconds(2)), -971.0);
 
   VerifyNearGoal();
 }
diff --git a/y2014/control_loops/shooter/shooter_lib_test.cc b/y2014/control_loops/shooter/shooter_lib_test.cc
index e1efc1c..9248725 100644
--- a/y2014/control_loops/shooter/shooter_lib_test.cc
+++ b/y2014/control_loops/shooter/shooter_lib_test.cc
@@ -11,9 +11,8 @@
 #include "y2014/control_loops/shooter/unaugmented_shooter_motor_plant.h"
 #include "y2014/constants.h"
 
-using ::aos::time::Time;
-
 namespace chrono = ::std::chrono;
+using ::aos::monotonic_clock;
 
 namespace y2014 {
 namespace control_loops {
@@ -363,7 +362,8 @@
 // Tests that the shooter zeros correctly and goes to a position.
 TEST_F(ShooterTest, GoesToValue) {
   shooter_queue_.goal.MakeWithBuilder().shot_power(70.0).Send();
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(2)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::seconds(2))) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
     shooter_motor_plant_.Simulate();
@@ -380,7 +380,8 @@
 // Tests that the shooter zeros correctly and goes to a position.
 TEST_F(ShooterTest, Fire) {
   shooter_queue_.goal.MakeWithBuilder().shot_power(70.0).Send();
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(1.2)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::milliseconds(1200))) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
     shooter_motor_plant_.Simulate();
@@ -393,7 +394,8 @@
       .Send();
 
   bool hit_fire = false;
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(5.2)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::milliseconds(5200))) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
     shooter_motor_plant_.Simulate();
@@ -420,7 +422,8 @@
 // Tests that the shooter zeros correctly and goes to a position.
 TEST_F(ShooterTest, FireLong) {
   shooter_queue_.goal.MakeWithBuilder().shot_power(70.0).Send();
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(1.5)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::milliseconds(1500))) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
     shooter_motor_plant_.Simulate();
@@ -430,7 +433,8 @@
   shooter_queue_.goal.MakeWithBuilder().shot_requested(true).Send();
 
   bool hit_fire = false;
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(5.5)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::milliseconds(5500))) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
     shooter_motor_plant_.Simulate();
@@ -455,7 +459,8 @@
 // power.
 TEST_F(ShooterTest, LoadTooFar) {
   shooter_queue_.goal.MakeWithBuilder().shot_power(500.0).Send();
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(1.6)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::milliseconds(1600))) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
     shooter_motor_plant_.Simulate();
@@ -470,7 +475,8 @@
 // Tests that the shooter zeros correctly and goes to a position.
 TEST_F(ShooterTest, MoveGoal) {
   shooter_queue_.goal.MakeWithBuilder().shot_power(70.0).Send();
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(1.5)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::milliseconds(1500))) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
     shooter_motor_plant_.Simulate();
@@ -479,7 +485,8 @@
   EXPECT_EQ(ShooterMotor::STATE_READY, shooter_motor_.state());
   shooter_queue_.goal.MakeWithBuilder().shot_power(14.0).Send();
 
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(1.0)) {
+  while (::aos::monotonic_clock::now() <
+         ::aos::monotonic_clock::time_point(chrono::seconds(1))) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
     shooter_motor_plant_.Simulate();
@@ -496,7 +503,8 @@
 
 TEST_F(ShooterTest, Unload) {
   shooter_queue_.goal.MakeWithBuilder().shot_power(70.0).Send();
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(1.5)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::milliseconds(1500))) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
     shooter_motor_plant_.Simulate();
@@ -505,7 +513,8 @@
   EXPECT_EQ(ShooterMotor::STATE_READY, shooter_motor_.state());
   shooter_queue_.goal.MakeWithBuilder().unload_requested(true).Send();
 
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(8.0) &&
+  while (monotonic_clock::now() <
+             monotonic_clock::time_point(chrono::seconds(8)) &&
          shooter_motor_.state() != ShooterMotor::STATE_READY_UNLOAD) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
@@ -521,7 +530,8 @@
 // Tests that it rezeros while unloading.
 TEST_F(ShooterTest, RezeroWhileUnloading) {
   shooter_queue_.goal.MakeWithBuilder().shot_power(70.0).Send();
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(1.5)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::milliseconds(1500))) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
     shooter_motor_plant_.Simulate();
@@ -530,7 +540,8 @@
   EXPECT_EQ(ShooterMotor::STATE_READY, shooter_motor_.state());
 
   shooter_motor_.shooter_.offset_ += 0.01;
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(2.0)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::seconds(2))) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
     shooter_motor_plant_.Simulate();
@@ -539,7 +550,8 @@
 
   shooter_queue_.goal.MakeWithBuilder().unload_requested(true).Send();
 
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(10.0) &&
+  while (::aos::monotonic_clock::now() <
+             ::aos::monotonic_clock::time_point(chrono::seconds(10)) &&
          shooter_motor_.state() != ShooterMotor::STATE_READY_UNLOAD) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
@@ -555,7 +567,8 @@
 // Tests that the shooter zeros correctly and goes to a position.
 TEST_F(ShooterTest, UnloadWindupNegative) {
   shooter_queue_.goal.MakeWithBuilder().shot_power(70.0).Send();
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(1.5)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::milliseconds(1500))) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
     shooter_motor_plant_.Simulate();
@@ -566,7 +579,8 @@
 
   int kicked_delay = 20;
   int capped_goal_count = 0;
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(9.5) &&
+  while (monotonic_clock::now() <
+             monotonic_clock::time_point(chrono::milliseconds(9500)) &&
          shooter_motor_.state() != ShooterMotor::STATE_READY_UNLOAD) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
@@ -594,7 +608,8 @@
 // Tests that the shooter zeros correctly and goes to a position.
 TEST_F(ShooterTest, UnloadWindupPositive) {
   shooter_queue_.goal.MakeWithBuilder().shot_power(70.0).Send();
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(1.5)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::milliseconds(1500))) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
     shooter_motor_plant_.Simulate();
@@ -605,7 +620,8 @@
 
   int kicked_delay = 20;
   int capped_goal_count = 0;
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(9.5) &&
+  while (monotonic_clock::now() <
+             monotonic_clock::time_point(chrono::milliseconds(9500)) &&
          shooter_motor_.state() != ShooterMotor::STATE_READY_UNLOAD) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
@@ -638,7 +654,8 @@
 TEST_F(ShooterTest, StartsOnDistal) {
   Reinitialize(HallEffectMiddle(constants::GetValues().shooter.pusher_distal));
   shooter_queue_.goal.MakeWithBuilder().shot_power(70.0).Send();
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(2.0)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::seconds(2))) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
     shooter_motor_plant_.Simulate();
@@ -658,7 +675,8 @@
   Reinitialize(
       HallEffectMiddle(constants::GetValues().shooter.pusher_proximal));
   shooter_queue_.goal.MakeWithBuilder().shot_power(70.0).Send();
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(3.0)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::seconds(3))) {
     shooter_motor_plant_.SendPositionMessage();
     shooter_motor_.Iterate();
     shooter_motor_plant_.Simulate();
@@ -687,7 +705,8 @@
   bool initialized = false;
   Reinitialize(start_pos);
   shooter_queue_.goal.MakeWithBuilder().shot_power(120.0).Send();
-  while (::aos::time::Time::Now() < ::aos::time::Time::InSeconds(2.0)) {
+  while (monotonic_clock::now() <
+         monotonic_clock::time_point(chrono::seconds(2))) {
     shooter_motor_plant_.SendPositionMessage(!initialized, plunger_back, latch, brake);
     initialized = true;
     shooter_motor_.Iterate();
diff --git a/y2014/hot_goal_reader.cc b/y2014/hot_goal_reader.cc
index 0b24f22..6c76c12 100644
--- a/y2014/hot_goal_reader.cc
+++ b/y2014/hot_goal_reader.cc
@@ -72,8 +72,9 @@
       fd_set fds;
       FD_ZERO(&fds);
       FD_SET(connection, &fds);
-      struct timeval timeout_timeval =
-          ::aos::time::Time::InSeconds(1).ToTimeval();
+      struct timeval timeout_timeval;
+      timeout_timeval.tv_sec = 1;
+      timeout_timeval.tv_usec = 0;
       switch (
           select(connection + 1, &fds, nullptr, nullptr, &timeout_timeval)) {
         case 1: {
diff --git a/y2014_bot3/actions/drivetrain_action_main.cc b/y2014_bot3/actions/drivetrain_action_main.cc
index d68a3bc..6a897e1 100644
--- a/y2014_bot3/actions/drivetrain_action_main.cc
+++ b/y2014_bot3/actions/drivetrain_action_main.cc
@@ -1,12 +1,10 @@
 #include <stdio.h>
 
-#include "aos/linux_code/init.h"
 #include "aos/common/logging/logging.h"
+#include "aos/linux_code/init.h"
 #include "bot3/actions/drivetrain_action.h"
 #include "frc971/actions/drivetrain_action.q.h"
 
-using ::aos::time::Time;
-
 int main(int /*argc*/, char * /*argv*/[]) {
   ::aos::Init();
 
diff --git a/y2014_bot3/autonomous/auto.cc b/y2014_bot3/autonomous/auto.cc
index 80f2b09..90d8457 100644
--- a/y2014_bot3/autonomous/auto.cc
+++ b/y2014_bot3/autonomous/auto.cc
@@ -1,25 +1,25 @@
 #include <stdio.h>
 
+#include <chrono>
 #include <memory>
 
-#include "aos/common/util/phased_loop.h"
-#include "aos/common/time.h"
-#include "aos/common/util/trapezoid_profile.h"
 #include "aos/common/logging/logging.h"
 #include "aos/common/logging/queue_logging.h"
-
+#include "aos/common/time.h"
+#include "aos/common/util/phased_loop.h"
+#include "aos/common/util/trapezoid_profile.h"
 #include "frc971/control_loops/drivetrain/drivetrain.q.h"
 #include "y2014_bot3/autonomous/auto.q.h"
 #include "y2014_bot3/control_loops/rollers/rollers.q.h"
 
-using ::aos::time::Time;
 using ::frc971::control_loops::drivetrain_queue;
 using ::y2014_bot3::control_loops::rollers_queue;
 
 namespace y2014_bot3 {
 namespace autonomous {
 
-namespace time = ::aos::time;
+namespace chrono = ::std::chrono;
+using ::aos::monotonic_clock;
 
 static double left_initial_position, right_initial_position;
 
@@ -54,8 +54,10 @@
 }
 
 void HandleAuto() {
-  ::aos::time::Time start_time = ::aos::time::Time::Now();
-  LOG(INFO, "Starting auto mode at %f\n", start_time.ToSeconds());
+  monotonic_clock::time_point start_time = monotonic_clock::now();
+  LOG(INFO, "Starting auto mode at %f\n",
+      chrono::duration_cast<chrono::duration<double>>(
+          start_time.time_since_epoch()).count());
 
   // TODO(comran): Add various options for different autos down below.
   ResetDrivetrain();
@@ -73,7 +75,7 @@
       .right_goal(right_initial_position)
       .right_velocity_goal(0)
       .Send();
-  time::SleepFor(time::Time::InSeconds(2.0));
+  ::std::this_thread::sleep_for(chrono::seconds(2));
 
   ::frc971::control_loops::drivetrain_queue.goal.MakeWithBuilder()
       .control_loop_driving(false)
diff --git a/y2014_bot3/autonomous/auto_main.cc b/y2014_bot3/autonomous/auto_main.cc
index d0b1952..32c8cca 100644
--- a/y2014_bot3/autonomous/auto_main.cc
+++ b/y2014_bot3/autonomous/auto_main.cc
@@ -6,8 +6,6 @@
 #include "y2014_bot3/autonomous/auto.q.h"
 #include "y2014_bot3/autonomous/auto.h"
 
-using ::aos::time::Time;
-
 int main(int /*argc*/, char * /*argv*/[]) {
   ::aos::Init(-1);
 
@@ -24,12 +22,15 @@
       LOG(INFO, "Got another auto packet\n");
     }
     LOG(INFO, "Starting auto mode\n");
-    ::aos::time::Time start_time = ::aos::time::Time::Now();
+    ::aos::monotonic_clock::time_point start_time =
+        ::aos::monotonic_clock::now();
     ::y2014_bot3::autonomous::HandleAuto();
 
-    ::aos::time::Time elapsed_time = ::aos::time::Time::Now() - start_time;
+    auto elapsed_time = ::aos::monotonic_clock::now() - start_time;
     LOG(INFO, "Auto mode exited in %f, waiting for it to finish.\n",
-        elapsed_time.ToSeconds());
+        ::std::chrono::duration_cast<::std::chrono::duration<double>>(
+            elapsed_time)
+            .count());
     while (::y2014_bot3::autonomous::autonomous->run_auto) {
       ::y2014_bot3::autonomous::autonomous.FetchNextBlocking();
       LOG(INFO, "Got another auto packet\n");
diff --git a/y2014_bot3/output/motor_writer.cc b/y2014_bot3/output/motor_writer.cc
index bbabff4..c623dba 100644
--- a/y2014_bot3/output/motor_writer.cc
+++ b/y2014_bot3/output/motor_writer.cc
@@ -20,9 +20,10 @@
 
 class MotorWriter : public ::aos::MotorOutput {
   // Maximum age of an output packet before the motors get zeroed instead.
-  static const int kOutputMaxAgeMS = 20;
-  static constexpr ::aos::time::Time kOldLogInterval =
-      ::aos::time::Time::InSeconds(0.5);
+  static constexpr chrono::milliseconds kOutputMaxAge =
+      chrono::milliseconds(20);
+  static constexpr chrono::milliseconds kOldLogInterval =
+      chrono::milliseconds(500);
 
   double Cap(double value, double max) {
     if (value > max) return max;
@@ -39,7 +40,7 @@
     if (true) {
       static auto &drivetrain = ::bot3::control_loops::drivetrain.output;
       drivetrain.FetchLatest();
-      if (drivetrain.IsNewerThanMS(kOutputMaxAgeMS)) {
+      if (drivetrain.IsNewerThan(kOutputMaxAge)) {
         LOG_STRUCT(DEBUG, "will output", *drivetrain);
         SetPWMOutput(5, drivetrain->right_voltage / 12.0, kTalonBounds);
         SetPWMOutput(2, -drivetrain->left_voltage / 12.0, kTalonBounds);
@@ -56,7 +57,7 @@
     {
       static auto &rollers = ::bot3::control_loops::rollers.output;
       rollers.FetchLatest();
-      if (rollers.IsNewerThanMS(kOutputMaxAgeMS)) {
+      if (rollers.IsNewerThan(kOutputMaxAge)) {
         LOG_STRUCT(DEBUG, "will output", *rollers);
         // There are two motors for each of these.
         SetPWMOutput(3, rollers->front_intake_voltage / 12.0, kTalonBounds);
@@ -108,7 +109,7 @@
   uint8_t output_check_ = 0;
 };
 
-constexpr ::aos::time::Time MotorWriter::kOldLogInterval;
+constexpr chrono::milliseconds MotorWriter::kOldLogInterval;
 
 }  // namespace output
 }  // namespace bot3
diff --git a/y2015/BUILD b/y2015/BUILD
index 84d9e14..748fde6 100644
--- a/y2015/BUILD
+++ b/y2015/BUILD
@@ -12,6 +12,7 @@
   deps = [
     '//aos/common/logging',
     '//aos/common:once',
+    '//aos/common:time',
     '//aos/common/network:team_number',
     '//frc971/control_loops:state_feedback_loop',
     '//frc971:shifter_hall_effect',
diff --git a/y2015/actors/BUILD b/y2015/actors/BUILD
index 9452202..e28cbfc 100644
--- a/y2015/actors/BUILD
+++ b/y2015/actors/BUILD
@@ -123,26 +123,6 @@
   ],
 )
 
-cc_test(
-  name = 'score_action_test',
-  srcs = [
-    'score_actor_test.cc',
-  ],
-  deps = [
-    '//aos/testing:googletest',
-    '//aos/testing:test_shm',
-    '//aos/common/logging:queue_logging',
-    '//aos/common:queues',
-    '//aos/common:time',
-    '//aos/linux_code:init',
-    '//aos/common/actions:action_lib',
-    '//y2015/control_loops/fridge:fridge_queue',
-    '//frc971/control_loops:team_number_test_environment',
-    ':score_action_queue',
-    ':score_action_lib',
-  ],
-)
-
 queue_library(
   name = 'pickup_action_queue',
   srcs = [
@@ -424,27 +404,6 @@
   ],
 )
 
-cc_test(
-  name = 'stack_action_test',
-  srcs = [
-    'stack_actor_test.cc',
-  ],
-  deps = [
-    '//aos/testing:googletest',
-    '//aos/testing:test_shm',
-    '//aos/common/logging:queue_logging',
-    '//aos/common:queues',
-    '//aos/common:time',
-    '//aos/linux_code:init',
-    '//aos/common/actions:action_lib',
-    '//aos/common/controls:control_loop_test',
-    '//y2015/control_loops/fridge:fridge_queue',
-    '//frc971/control_loops:team_number_test_environment',
-    ':stack_action_queue',
-    ':stack_action_lib',
-  ],
-)
-
 cc_library(
   name = 'stack_action_lib',
   srcs = [
diff --git a/y2015/actors/drivetrain_actor.cc b/y2015/actors/drivetrain_actor.cc
index 945d923..8772af7 100644
--- a/y2015/actors/drivetrain_actor.cc
+++ b/y2015/actors/drivetrain_actor.cc
@@ -47,8 +47,10 @@
   turn_profile.set_maximum_velocity(params.maximum_turn_velocity *
                                     constants::GetValues().turn_width / 2.0);
 
+  ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
+                                      ::std::chrono::milliseconds(5) / 2);
   while (true) {
-    ::aos::time::PhasedLoopXMS(5, 2500);
+    phased_loop.SleepUntilNext();
 
     drivetrain_queue.status.FetchLatest();
     if (drivetrain_queue.status.get()) {
diff --git a/y2015/actors/drivetrain_actor_main.cc b/y2015/actors/drivetrain_actor_main.cc
index 76519f2..a51cb48 100644
--- a/y2015/actors/drivetrain_actor_main.cc
+++ b/y2015/actors/drivetrain_actor_main.cc
@@ -4,8 +4,6 @@
 #include "y2015/actors/drivetrain_action.q.h"
 #include "y2015/actors/drivetrain_actor.h"
 
-using ::aos::time::Time;
-
 int main(int /*argc*/, char * /*argv*/[]) {
   ::aos::Init(-1);
 
diff --git a/y2015/actors/held_to_lift_actor.cc b/y2015/actors/held_to_lift_actor.cc
index 942488d..913d172 100644
--- a/y2015/actors/held_to_lift_actor.cc
+++ b/y2015/actors/held_to_lift_actor.cc
@@ -90,13 +90,13 @@
   }
 
   {
+    ::aos::time::PhasedLoop phased_loop(::aos::controls::kLoopFrequency,
+                                        ::std::chrono::milliseconds(5) / 2);
     ::std::unique_ptr<LiftAction> lift_action =
         MakeLiftAction(params.lift_params);
     lift_action->Start();
     while (lift_action->Running()) {
-      ::aos::time::PhasedLoopXMS(chrono::duration_cast<chrono::milliseconds>(
-                                     ::aos::controls::kLoopFrequency).count(),
-                                 2500);
+      phased_loop.SleepUntilNext();
 
       if (ShouldCancel()) {
         lift_action->Cancel();
diff --git a/y2015/actors/pickup_actor.cc b/y2015/actors/pickup_actor.cc
index 3aa0c18..0aa1c58 100644
--- a/y2015/actors/pickup_actor.cc
+++ b/y2015/actors/pickup_actor.cc
@@ -1,11 +1,12 @@
 #include "y2015/actors/pickup_actor.h"
 
+#include <chrono>
 #include <cmath>
 
-#include "aos/common/logging/logging.h"
 #include "aos/common/controls/control_loop.h"
-#include "aos/common/util/phased_loop.h"
+#include "aos/common/logging/logging.h"
 #include "aos/common/time.h"
+#include "aos/common/util/phased_loop.h"
 #include "y2015/control_loops/claw/claw.q.h"
 
 namespace y2015 {
@@ -19,6 +20,8 @@
 constexpr double kClawMoveUpAcceleration = 25.0;
 }  // namespace
 
+namespace chrono = ::std::chrono;
+using ::aos::monotonic_clock;
 using ::y2015::control_loops::claw_queue;
 
 PickupActor::PickupActor(PickupActionQueueGroup* queues)
@@ -91,13 +94,14 @@
   }
 
   // Pull in for params.intake_time.
-  ::aos::time::Time end_time =
-      ::aos::time::Time::Now() + aos::time::Time::InSeconds(params.intake_time);
-  while ( ::aos::time::Time::Now() <= end_time) {
-    ::aos::time::PhasedLoopXMS(
-        ::std::chrono::duration_cast<::std::chrono::milliseconds>(
-            ::aos::controls::kLoopFrequency).count(),
-        2500);
+  monotonic_clock::time_point end_time =
+      monotonic_clock::now() +
+      chrono::duration_cast<chrono::nanoseconds>(
+          chrono::duration<double>(params.intake_time));
+  ::aos::time::PhasedLoop phased_loop(::aos::controls::kLoopFrequency,
+                                      ::std::chrono::milliseconds(5) / 2);
+  while (monotonic_clock::now() <= end_time) {
+    phased_loop.SleepUntilNext();
     if (ShouldCancel()) return true;
   }
 
diff --git a/y2015/actors/score_actor.cc b/y2015/actors/score_actor.cc
index 92ddfac..d485af5 100644
--- a/y2015/actors/score_actor.cc
+++ b/y2015/actors/score_actor.cc
@@ -68,10 +68,10 @@
     return false;
   }
 
+  ::aos::time::PhasedLoop phased_loop(::aos::controls::kLoopFrequency,
+                                      ::std::chrono::milliseconds(5) / 2);
   while (true) {
-    ::aos::time::PhasedLoopXMS(chrono::duration_cast<chrono::milliseconds>(
-                                   ::aos::controls::kLoopFrequency).count(),
-                               2500);
+    phased_loop.SleepUntilNext();
     if (ShouldCancel()) {
       return true;
     }
@@ -94,29 +94,31 @@
 
   bool started_lowering = false;
 
-  while (true) {
-    ::aos::time::PhasedLoopXMS(chrono::duration_cast<chrono::milliseconds>(
-                                   ::aos::controls::kLoopFrequency).count(),
-                               2500);
-    if (ShouldCancel()) {
-      return true;
-    }
-    // Round the moving out corner and start setting down.
-    if (params.place_the_stack && !started_lowering) {
-      if (CurrentGoalX() < params.horizontal_start_lowering) {
-        if (!SendGoal(params.horizontal_move_target, params.place_height, true,
-                      kSlowMaxXVelocity, kFastMaxYVelocity,
-                      kSlowMaxXAcceleration, kMaxYAcceleration)) {
-          LOG(ERROR, "Sending fridge message failed.\n");
-          return false;
-        }
-        started_lowering = true;
+  {
+    ::aos::time::PhasedLoop phased_loop(::aos::controls::kLoopFrequency,
+                                        ::std::chrono::milliseconds(5) / 2);
+    while (true) {
+      phased_loop.SleepUntilNext();
+      if (ShouldCancel()) {
+        return true;
       }
-    }
+      // Round the moving out corner and start setting down.
+      if (params.place_the_stack && !started_lowering) {
+        if (CurrentGoalX() < params.horizontal_start_lowering) {
+          if (!SendGoal(params.horizontal_move_target, params.place_height,
+                        true, kSlowMaxXVelocity, kFastMaxYVelocity,
+                        kSlowMaxXAcceleration, kMaxYAcceleration)) {
+            LOG(ERROR, "Sending fridge message failed.\n");
+            return false;
+          }
+          started_lowering = true;
+        }
+      }
 
-    if (NearHorizontalGoal(params.horizontal_move_target)) {
-      LOG(INFO, "reached goal\n");
-      break;
+      if (NearHorizontalGoal(params.horizontal_move_target)) {
+        LOG(INFO, "reached goal\n");
+        break;
+      }
     }
   }
 
@@ -134,16 +136,18 @@
     return false;
   }
 
-  while (true) {
-    ::aos::time::PhasedLoopXMS(chrono::duration_cast<chrono::milliseconds>(
-                                   ::aos::controls::kLoopFrequency).count(),
-                               2500);
-    if (ShouldCancel()) {
-      return true;
-    }
+  {
+    ::aos::time::PhasedLoop phased_loop(::aos::controls::kLoopFrequency,
+                                        chrono::microseconds(2500));
+    while (true) {
+      phased_loop.SleepUntilNext();
+      if (ShouldCancel()) {
+        return true;
+      }
 
-    if (NearGoal(params.horizontal_move_target, params.place_height)) {
-      break;
+      if (NearGoal(params.horizontal_move_target, params.place_height)) {
+        break;
+      }
     }
   }
 
@@ -165,10 +169,10 @@
   }
 
   bool has_lifted = false;
+  ::aos::time::PhasedLoop phased_loop(::aos::controls::kLoopFrequency,
+                                      chrono::microseconds(2500));
   while (true) {
-    ::aos::time::PhasedLoopXMS(chrono::duration_cast<chrono::milliseconds>(
-                                   ::aos::controls::kLoopFrequency).count(),
-                               2500);
+    phased_loop.SleepUntilNext();
     if (ShouldCancel()) {
       return true;
     }
diff --git a/y2015/actors/score_actor_test.cc b/y2015/actors/score_actor_test.cc
deleted file mode 100644
index 25d1bc2..0000000
--- a/y2015/actors/score_actor_test.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-#include <unistd.h>
-
-#include <memory>
-
-#include "gtest/gtest.h"
-#include "aos/common/queue.h"
-#include "aos/testing/test_shm.h"
-#include "aos/common/actions/actor.h"
-#include "y2015/actors/score_action.q.h"
-#include "y2015/actors/score_actor.h"
-#include "y2015/control_loops/fridge/fridge.q.h"
-#include "frc971/control_loops/team_number_test_environment.h"
-
-using ::aos::time::Time;
-
-namespace y2015 {
-namespace actors {
-namespace testing {
-
-using ::y2015::control_loops::fridge::fridge_queue;
-
-class ScoreActionTest : public ::testing::Test {
- protected:
-  ScoreActionTest() {
-    y2015::actors::score_action.goal.Clear();
-    y2015::actors::score_action.status.Clear();
-    fridge_queue.status.Clear();
-    fridge_queue.goal.Clear();
-  }
-
-  virtual ~ScoreActionTest() {
-    y2015::actors::score_action.goal.Clear();
-    y2015::actors::score_action.status.Clear();
-    fridge_queue.status.Clear();
-    fridge_queue.goal.Clear();
-  }
-
-  // Bring up and down Core.
-  ::aos::testing::TestSharedMemory my_shm_;
-};
-
-// Tests that cancel stops not only the score action, but also the underlying
-// profile action.
-TEST_F(ScoreActionTest, PlaceTheStackCancel) {
-  ScoreActor score(&y2015::actors::score_action);
-
-  y2015::actors::score_action.goal.MakeWithBuilder().run(true).Send();
-
-  // Tell it the fridge is zeroed.
-  ASSERT_TRUE(fridge_queue.status.MakeWithBuilder()
-                  .zeroed(true)
-                  .angle(0.0)
-                  .height(0.0)
-                  .Send());
-
-  // do the action and it will post to the goal queue
-  score.WaitForActionRequest();
-
-  // the action has started, so now cancel it and it should cancel
-  // the underlying profile
-  y2015::actors::score_action.goal.MakeWithBuilder().run(false).Send();
-
-  // let the action start running, if we return from this call it has worked.
-  const ScoreParams params = {true, true, 0.14, 0.13, -0.7, -0.7, -0.10, -0.5, 0.1};
-  score.RunAction(params);
-
-  SUCCEED();
-}
-
-// Tests that cancel stops not only the score action, but also the underlying
-// profile action.
-TEST_F(ScoreActionTest, MoveStackIntoPositionCancel) {
-  ScoreActor score(&y2015::actors::score_action);
-
-  y2015::actors::score_action.goal.MakeWithBuilder().run(true).Send();
-
-  // Tell it the fridge is zeroed.
-  ASSERT_TRUE(fridge_queue.status.MakeWithBuilder()
-                  .zeroed(true)
-                  .angle(0.0)
-                  .height(0.0)
-                  .Send());
-
-  // do the action and it will post to the goal queue
-  score.WaitForActionRequest();
-
-  // the action has started, so now cancel it and it should cancel
-  // the underlying profile
-  y2015::actors::score_action.goal.MakeWithBuilder().run(false).Send();
-
-  // let the action start running, if we return from this call it has worked.
-  const ScoreParams params = {false, true, 0.14, 0.13, -0.7, -0.7, -0.10, -0.5, 0.1};
-  score.RunAction(params);
-
-  SUCCEED();
-}
-
-}  // namespace testing
-}  // namespace actors
-}  // namespace y2015
diff --git a/y2015/actors/stack_actor_test.cc b/y2015/actors/stack_actor_test.cc
deleted file mode 100644
index c62b6ce..0000000
--- a/y2015/actors/stack_actor_test.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-#include <unistd.h>
-
-#include <memory>
-
-#include "gtest/gtest.h"
-#include "aos/common/queue.h"
-#include "aos/testing/test_shm.h"
-#include "aos/common/actions/actor.h"
-#include "y2015/actors/stack_action.q.h"
-#include "y2015/actors/stack_actor.h"
-#include "y2015/control_loops/fridge/fridge.q.h"
-
-#include "aos/common/controls/control_loop_test.h"
-#include "frc971/control_loops/team_number_test_environment.h"
-
-using ::aos::time::Time;
-
-namespace y2015 {
-namespace actors {
-namespace testing {
-
-using ::y2015::control_loops::fridge::fridge_queue;
-
-class StackActionTest : public ::testing::Test {
- protected:
-  StackActionTest() {
-    y2015::actors::stack_action.goal.Clear();
-    y2015::actors::stack_action.status.Clear();
-    fridge_queue.status.Clear();
-    fridge_queue.goal.Clear();
-  }
-
-  virtual ~StackActionTest() {
-    y2015::actors::stack_action.goal.Clear();
-    y2015::actors::stack_action.status.Clear();
-    fridge_queue.status.Clear();
-    fridge_queue.goal.Clear();
-  }
-
-  // Bring up and down Core.
-  ::aos::testing::TestSharedMemory my_shm_;
-};
-
-// Tests that cancel stops not only the stack action, but the underlying profile
-// action.
-TEST_F(StackActionTest, StackCancel) {
-  StackActor stack(&y2015::actors::stack_action);
-
-  y2015::actors::stack_action.goal.MakeWithBuilder().run(true).Send();
-
-  // tell it the fridge is zeroed
-  fridge_queue.status.MakeWithBuilder()
-      .zeroed(true)
-      .angle(0.0)
-      .height(0.0)
-      .Send();
-
-  // do the action and it will post to the goal queue
-  stack.WaitForActionRequest();
-
-  // the action has started, so now cancel it and it should cancel
-  // the underlying profile
-  y2015::actors::stack_action.goal.MakeWithBuilder().run(false).Send();
-
-  // let the action start running, if we return from this call it has worked.
-  StackParams s;
-  stack.RunAction(s);
-
-  SUCCEED();
-}
-
-}  // namespace testing
-}  // namespace actors
-}  // namespace y2015
diff --git a/y2015/actors/stack_and_hold_actor.cc b/y2015/actors/stack_and_hold_actor.cc
index e12b54c..1b94703 100644
--- a/y2015/actors/stack_and_hold_actor.cc
+++ b/y2015/actors/stack_and_hold_actor.cc
@@ -79,10 +79,10 @@
     ::std::unique_ptr<StackAction> stack_action =
         MakeStackAction(stack_params);
     stack_action->Start();
+    ::aos::time::PhasedLoop phased_loop(::aos::controls::kLoopFrequency,
+                                        ::std::chrono::milliseconds(5) / 2);
     while (stack_action->Running()) {
-      ::aos::time::PhasedLoopXMS(chrono::duration_cast<chrono::milliseconds>(
-                                     ::aos::controls::kLoopFrequency).count(),
-                                 2500);
+      phased_loop.SleepUntilNext();
 
       if (ShouldCancel()) {
         stack_action->Cancel();
diff --git a/y2015/actors/stack_and_lift_actor.cc b/y2015/actors/stack_and_lift_actor.cc
index 24eb11e..8bf3633 100644
--- a/y2015/actors/stack_and_lift_actor.cc
+++ b/y2015/actors/stack_and_lift_actor.cc
@@ -39,10 +39,10 @@
     ::std::unique_ptr<StackAction> stack_action =
         MakeStackAction(stack_params);
     stack_action->Start();
+    ::aos::time::PhasedLoop phased_loop(::aos::controls::kLoopFrequency,
+                                        ::std::chrono::milliseconds(5) / 2);
     while (stack_action->Running()) {
-      ::aos::time::PhasedLoopXMS(chrono::duration_cast<chrono::milliseconds>(
-                                     ::aos::controls::kLoopFrequency).count(),
-                                 2500);
+      phased_loop.SleepUntilNext();
 
       if (ShouldCancel()) {
         stack_action->Cancel();
@@ -80,10 +80,10 @@
     lift_params.pack_claw_angle = claw_goal_start;
     ::std::unique_ptr<LiftAction> lift_action = MakeLiftAction(lift_params);
     lift_action->Start();
+    ::aos::time::PhasedLoop phased_loop(::aos::controls::kLoopFrequency,
+                                        ::std::chrono::milliseconds(5) / 2);
     while (lift_action->Running()) {
-      ::aos::time::PhasedLoopXMS(chrono::duration_cast<chrono::milliseconds>(
-                                     ::aos::controls::kLoopFrequency).count(),
-                                 2500);
+      phased_loop.SleepUntilNext();
 
       if (ShouldCancel()) {
         lift_action->Cancel();
diff --git a/y2015/autonomous/auto.cc b/y2015/autonomous/auto.cc
index 198cc97..4df613d 100644
--- a/y2015/autonomous/auto.cc
+++ b/y2015/autonomous/auto.cc
@@ -1,29 +1,32 @@
 #include <stdio.h>
 
+#include <chrono>
 #include <memory>
 
-#include "aos/common/util/phased_loop.h"
-#include "aos/common/time.h"
-#include "aos/common/util/trapezoid_profile.h"
 #include "aos/common/logging/logging.h"
 #include "aos/common/logging/queue_logging.h"
-
+#include "aos/common/time.h"
+#include "aos/common/util/phased_loop.h"
+#include "aos/common/util/trapezoid_profile.h"
 #include "frc971/autonomous/auto.q.h"
-#include "y2015/autonomous/auto.q.h"
-#include "y2015/constants.h"
 #include "frc971/control_loops/drivetrain/drivetrain.q.h"
 #include "y2015/actors/drivetrain_actor.h"
-#include "y2015/control_loops/claw/claw.q.h"
-#include "y2015/control_loops/fridge/fridge.q.h"
+#include "y2015/actors/held_to_lift_actor.h"
 #include "y2015/actors/pickup_actor.h"
 #include "y2015/actors/stack_actor.h"
-#include "y2015/actors/held_to_lift_actor.h"
+#include "y2015/autonomous/auto.q.h"
+#include "y2015/constants.h"
+#include "y2015/control_loops/claw/claw.q.h"
+#include "y2015/control_loops/fridge/fridge.q.h"
 
-using ::aos::time::Time;
 using ::frc971::control_loops::drivetrain_queue;
 using ::y2015::control_loops::claw_queue;
 using ::y2015::control_loops::fridge::fridge_queue;
 
+namespace chrono = ::std::chrono;
+namespace this_thread = ::std::this_thread;
+using ::aos::monotonic_clock;
+
 namespace y2015 {
 namespace autonomous {
 
@@ -86,9 +89,11 @@
     LOG(ERROR, "No action, not waiting\n");
     return;
   }
+  ::aos::time::PhasedLoop phased_loop(chrono::milliseconds(5),
+                                      chrono::microseconds(2500));
   while (true) {
     // Poll the running bit and auto done bits.
-    ::aos::time::PhasedLoopXMS(5, 2500);
+    phased_loop.SleepUntilNext();
     if (!action->Running() || ShouldExitAuto()) {
       return;
     }
@@ -338,14 +343,14 @@
   LOG(INFO, "Sucking in tote.\n");
   SetClawState(0.0, 6.0, true, kInstantaneousClaw);
 
-  time::SleepFor(time::Time::InSeconds(0.7));
+  this_thread::sleep_for(chrono::milliseconds(700));
   LOG(INFO, "Done sucking in tote\n");
 
   // Now pick it up
   pickup = actors::MakePickupAction(pickup_params);
   pickup->Start();
 
-  time::SleepFor(time::Time::InSeconds(0.9));
+  this_thread::sleep_for(chrono::milliseconds(900));
   // Start turning.
   LOG(INFO, "Turning in place\n");
   drive = SetDriveGoal(0.0, kFastDrive, -0.23, kStackingFirstTurn);
@@ -379,7 +384,7 @@
   LOG(INFO, "Lowering the claw to knock the tote\n");
   SetClawStateNoWait(0.0, 0.0, true, kFastClaw);
 
-  time::SleepFor(time::Time::InSeconds(0.1));
+  this_thread::sleep_for(chrono::milliseconds(100));
   if (ShouldExitAuto()) return;
 
   WaitUntilDoneOrCanceled(::std::move(drive));
@@ -421,12 +426,12 @@
   if (ShouldExitAuto()) return;
 
   if (ShouldExitAuto()) return;
-  time::SleepFor(time::Time::InSeconds(0.30));
+  this_thread::sleep_for(chrono::milliseconds(300));
   if (ShouldExitAuto()) return;
 
   SetClawStateNoWait(0.0, 4.0, true, kFastClaw);
   if (ShouldExitAuto()) return;
-  time::SleepFor(time::Time::InSeconds(0.10));
+  this_thread::sleep_for(chrono::milliseconds(100));
 
   WaitUntilDoneOrCanceled(::std::move(lift));
   if (ShouldExitAuto()) return;
@@ -439,7 +444,7 @@
   pickup = actors::MakePickupAction(pickup_params);
   pickup->Start();
 
-  time::SleepFor(time::Time::InSeconds(1.0));
+  this_thread::sleep_for(chrono::seconds(1));
   if (ShouldExitAuto()) return;
 
   // Start turning.
@@ -478,7 +483,7 @@
   // Lift the fridge.
   MoveFridge(0.0, 0.3, true, kFridgeXProfile, kFridgeYProfile);
 
-  time::SleepFor(time::Time::InSeconds(0.1));
+  this_thread::sleep_for(chrono::milliseconds(100));
   if (ShouldExitAuto()) return;
 
   WaitUntilDoneOrCanceled(::std::move(drive));
@@ -503,7 +508,7 @@
   SetClawState(0.0, 7.0, true, kFastClaw);
   if (ShouldExitAuto()) return;
 
-  time::SleepFor(time::Time::InSeconds(0.2));
+  this_thread::sleep_for(chrono::milliseconds(200));
   if (ShouldExitAuto()) return;
 
   WaitUntilDoneOrCanceled(::std::move(drive));
@@ -514,7 +519,7 @@
   //StepDrive(2.5, -1.4);
   drive = SetDriveGoal(2.5, kRaceDrive, -1.4, kRaceTurn);
 
-  time::SleepFor(time::Time::InSeconds(0.5));
+  this_thread::sleep_for(chrono::milliseconds(500));
 
   LOG(INFO, "Moving totes out\n");
   MoveFridge(0.6, 0.32, true, kFridgeXProfile, kFridgeYProfile);
@@ -528,7 +533,7 @@
   WaitForFridge();
   if (ShouldExitAuto()) return;
 
-  time::SleepFor(time::Time::InSeconds(0.1));
+  this_thread::sleep_for(chrono::milliseconds(100));
 
   if (ShouldExitAuto()) return;
 
@@ -550,30 +555,33 @@
   if (ShouldExitAuto()) return;
 }
 
-void GrabberForTime(double voltage, double wait_time) {
-  ::aos::time::Time now = ::aos::time::Time::Now();
-  ::aos::time::Time end_time = now + time::Time::InSeconds(wait_time);
-  LOG(INFO, "Starting to grab at %f for %f seconds\n", voltage, wait_time);
+void GrabberForTime(double voltage, monotonic_clock::duration wait_time) {
+  monotonic_clock::time_point now = monotonic_clock::now();
+  monotonic_clock::time_point end_time = now + wait_time;
+  LOG(INFO, "Starting to grab at %f for %f seconds\n", voltage,
+      chrono::duration_cast<chrono::duration<double>>(wait_time).count());
+  ::aos::time::PhasedLoop phased_loop(chrono::milliseconds(5),
+                                      chrono::microseconds(2500));
   while (true) {
     autonomous::can_control.MakeWithBuilder().can_voltage(voltage).Send();
     // Poll the running bit and auto done bits.
     if (ShouldExitAuto()) {
       return;
     }
-    if (::aos::time::Time::Now() > end_time) {
+    if (monotonic_clock::now() > end_time) {
       LOG(INFO, "Done grabbing\n");
       return;
     }
-    ::aos::time::PhasedLoopXMS(5, 2500);
+    phased_loop.SleepUntilNext();
   }
 }
 
 void CanGrabberAuto() {
   ResetDrivetrain();
-  GrabberForTime(12.0, 0.18);
+  GrabberForTime(12.0, chrono::milliseconds(180));
   if (ShouldExitAuto()) return;
 
-  //GrabberForTime(4.0, 0.10);
+  //GrabberForTime(4.0, chrono::milliseconds(100));
   if (ShouldExitAuto()) return;
   InitializeEncoders();
   ResetDrivetrain();
@@ -588,15 +596,17 @@
       .right_goal(right_initial_position + 1.5)
       .right_velocity_goal(0)
       .Send();
-  GrabberForTime(12.0, 0.02);
+  GrabberForTime(12.0, chrono::milliseconds(20));
 
-  GrabberForTime(4.0, 14.0);
+  GrabberForTime(4.0, chrono::seconds(14));
   if (ShouldExitAuto()) return;
 }
 
 void HandleAuto() {
-  ::aos::time::Time start_time = ::aos::time::Time::Now();
-  LOG(INFO, "Starting auto mode at %f\n", start_time.ToSeconds());
+  monotonic_clock::time_point start_time = monotonic_clock::now();
+  LOG(INFO, "Starting auto mode at %f\n",
+      chrono::duration_cast<chrono::duration<double>>(
+          start_time.time_since_epoch()).count());
   //TripleCanAuto();
   CanGrabberAuto();
 }
diff --git a/y2015/autonomous/auto_main.cc b/y2015/autonomous/auto_main.cc
index d9437d1..c5e07d6 100644
--- a/y2015/autonomous/auto_main.cc
+++ b/y2015/autonomous/auto_main.cc
@@ -1,13 +1,12 @@
 #include <stdio.h>
+#include <chrono>
 
+#include "aos/common/logging/logging.h"
 #include "aos/common/time.h"
 #include "aos/linux_code/init.h"
-#include "aos/common/logging/logging.h"
 #include "frc971/autonomous/auto.q.h"
 #include "y2015/autonomous/auto.h"
 
-using ::aos::time::Time;
-
 int main(int /*argc*/, char * /*argv*/[]) {
   ::aos::Init(-1);
 
@@ -24,12 +23,15 @@
       LOG(INFO, "Got another auto packet\n");
     }
     LOG(INFO, "Starting auto mode\n");
-    ::aos::time::Time start_time = ::aos::time::Time::Now();
+    ::aos::monotonic_clock::time_point start_time =
+        ::aos::monotonic_clock::now();
     ::y2015::autonomous::HandleAuto();
 
-    ::aos::time::Time elapsed_time = ::aos::time::Time::Now() - start_time;
+    auto elapsed_time = ::aos::monotonic_clock::now() - start_time;
     LOG(INFO, "Auto mode exited in %f, waiting for it to finish.\n",
-        elapsed_time.ToSeconds());
+        ::std::chrono::duration_cast<::std::chrono::duration<double>>(
+            elapsed_time)
+            .count());
     while (::frc971::autonomous::autonomous->run_auto) {
       ::frc971::autonomous::autonomous.FetchNextBlocking();
       LOG(INFO, "Got another auto packet\n");
diff --git a/y2015/constants.cc b/y2015/constants.cc
index 7ccb020..5b02a25 100644
--- a/y2015/constants.cc
+++ b/y2015/constants.cc
@@ -127,7 +127,8 @@
 const double kArmLength = 0.7366;
 
 // TODO(danielp): All these values might need to change.
-const double kClawPistonSwitchTime = 0.4;
+constexpr ::aos::monotonic_clock::duration kClawPistonSwitchTime =
+    ::std::chrono::milliseconds(400);
 const double kClawZeroingRange = 0.3;
 
 const Values *DoGetValuesForTeam(uint16_t team) {
diff --git a/y2015/constants.h b/y2015/constants.h
index eed5616..8cefe7e 100644
--- a/y2015/constants.h
+++ b/y2015/constants.h
@@ -3,9 +3,10 @@
 
 #include <stdint.h>
 
+#include "aos/common/time.h"
+#include "frc971/constants.h"
 #include "frc971/control_loops/state_feedback_loop.h"
 #include "frc971/shifter_hall_effect.h"
-#include "frc971/constants.h"
 
 namespace y2015 {
 namespace constants {
@@ -76,7 +77,7 @@
 
     // Time between sending commands to claw opening pistons and them reaching
     // the new state.
-    double piston_switch_time;
+    ::aos::monotonic_clock::duration piston_switch_time;
     // How far on either side we look for the index pulse before we give up.
     double zeroing_range;
   };
diff --git a/y2015/control_loops/claw/claw.cc b/y2015/control_loops/claw/claw.cc
index b4a5a7b..987bb5e 100644
--- a/y2015/control_loops/claw/claw.cc
+++ b/y2015/control_loops/claw/claw.cc
@@ -1,18 +1,19 @@
 #include "y2015/control_loops/claw/claw.h"
 
 #include <algorithm>
+#include <chrono>
 
 #include "aos/common/controls/control_loops.q.h"
 #include "aos/common/logging/logging.h"
-
+#include "aos/common/time.h"
+#include "aos/common/util/trapezoid_profile.h"
 #include "y2015/constants.h"
 #include "y2015/control_loops/claw/claw_motor_plant.h"
-#include "aos/common/util/trapezoid_profile.h"
 
 namespace y2015 {
 namespace control_loops {
 
-using ::aos::time::Time;
+using ::aos::monotonic_clock;
 namespace chrono = ::std::chrono;
 
 constexpr double kZeroingVoltage = 4.0;
@@ -33,7 +34,7 @@
 
 Claw::Claw(control_loops::ClawQueue *claw)
     : aos::controls::ControlLoop<control_loops::ClawQueue>(claw),
-      last_piston_edge_(Time::Now()),
+      last_piston_edge_(monotonic_clock::min_time),
       claw_loop_(new ClawCappedStateFeedbackLoop(
           ::y2015::control_loops::claw::MakeClawLoop())),
       claw_estimator_(constants::GetValues().claw.zeroing),
@@ -273,7 +274,7 @@
       }
     }
     if (output->rollers_closed != last_rollers_closed_) {
-      last_piston_edge_ = Time::Now();
+      last_piston_edge_ = monotonic_clock::now();
     }
   }
 
@@ -296,11 +297,12 @@
 
   if (output) {
     status->rollers_open = !output->rollers_closed &&
-                           ((Time::Now() - last_piston_edge_).ToSeconds() >=
-                            values.claw.piston_switch_time);
-    status->rollers_closed = output->rollers_closed &&
-                             ((Time::Now() - last_piston_edge_).ToSeconds() >=
-                              values.claw.piston_switch_time);
+                           (monotonic_clock::now() >=
+                            values.claw.piston_switch_time + last_piston_edge_);
+    status->rollers_closed =
+        output->rollers_closed &&
+        (monotonic_clock::now() >=
+         values.claw.piston_switch_time + last_piston_edge_);
   } else {
     status->rollers_open = false;
     status->rollers_closed = false;
diff --git a/y2015/control_loops/claw/claw.h b/y2015/control_loops/claw/claw.h
index 58c3cc1..324f9f3 100644
--- a/y2015/control_loops/claw/claw.h
+++ b/y2015/control_loops/claw/claw.h
@@ -87,7 +87,7 @@
   State state_ = UNINITIALIZED;
 
   // The time when we last changed the claw piston state.
-  ::aos::time::Time last_piston_edge_;
+  ::aos::monotonic_clock::time_point last_piston_edge_;
 
   // The state feedback control loop to talk to.
   ::std::unique_ptr<ClawCappedStateFeedbackLoop> claw_loop_;
diff --git a/y2015/control_loops/claw/claw_lib_test.cc b/y2015/control_loops/claw/claw_lib_test.cc
index b38a2ee..ed82322 100644
--- a/y2015/control_loops/claw/claw_lib_test.cc
+++ b/y2015/control_loops/claw/claw_lib_test.cc
@@ -1,24 +1,26 @@
 #include <math.h>
 #include <unistd.h>
 
+#include <chrono>
 #include <memory>
 
-#include "gtest/gtest.h"
+#include "aos/common/controls/control_loop_test.h"
 #include "aos/common/queue.h"
 #include "aos/common/time.h"
-#include "aos/common/controls/control_loop_test.h"
-#include "y2015/control_loops/claw/claw.q.h"
-#include "y2015/control_loops/claw/claw.h"
 #include "frc971/control_loops/position_sensor_sim.h"
-#include "y2015/constants.h"
 #include "frc971/control_loops/team_number_test_environment.h"
-
-using ::aos::time::Time;
+#include "gtest/gtest.h"
+#include "y2015/constants.h"
+#include "y2015/control_loops/claw/claw.h"
+#include "y2015/control_loops/claw/claw.q.h"
 
 namespace y2015 {
 namespace control_loops {
 namespace testing {
 
+namespace chrono = ::std::chrono;
+using ::aos::monotonic_clock;
+
 // Class which simulates the claw and sends out queue messages with the
 // position.
 class ClawSimulation {
@@ -37,21 +39,20 @@
   }
 
   void InitializePosition(double start_pos) {
-    InitializePosition(start_pos,
-        constants::GetValues().claw.zeroing.measured_index_position);
+    InitializePosition(
+        start_pos, constants::GetValues().claw.zeroing.measured_index_position);
   }
 
   void InitializePosition(double start_pos, double index_pos) {
-    InitializePosition(start_pos,
+    InitializePosition(
+        start_pos,
         // This gives us a standard deviation of ~9 degrees on the pot noise.
-        constants::GetValues().claw.zeroing.index_difference / 10.0,
-        index_pos);
+        constants::GetValues().claw.zeroing.index_difference / 10.0, index_pos);
   }
 
   // Do specific initialization for the sensors.
-  void InitializePosition(double start_pos,
-                         double pot_noise_stddev,
-                         double index_pos) {
+  void InitializePosition(double start_pos, double pot_noise_stddev,
+                          double index_pos) {
     // Update internal state.
     claw_plant_->mutable_X(0, 0) = start_pos;
     // Zero velocity.
@@ -63,7 +64,7 @@
   // Sends a queue message with the position.
   void SendPositionMessage() {
     ::aos::ScopedMessagePtr<control_loops::ClawQueue::Position> position =
-      claw_queue_.position.MakeMessage();
+        claw_queue_.position.MakeMessage();
     pot_and_encoder_.GetSensorValues(&position->joint);
     position.Send();
   }
@@ -106,9 +107,7 @@
   void VerifyNearGoal() {
     claw_queue_.goal.FetchLatest();
     claw_queue_.status.FetchLatest();
-    EXPECT_NEAR(claw_queue_.goal->angle,
-                claw_queue_.status->angle,
-                10.0);
+    EXPECT_NEAR(claw_queue_.goal->angle, claw_queue_.status->angle, 10.0);
 
     EXPECT_TRUE(claw_queue_.status->zeroed);
     EXPECT_FALSE(claw_queue_.status->estopped);
@@ -126,9 +125,9 @@
   }
 
   // Runs iterations until the specified amount of simulated time has elapsed.
-  void RunForTime(const Time &run_for, bool enabled = true) {
-    const auto start_time = Time::Now();
-    while (Time::Now() < start_time + run_for) {
+  void RunForTime(monotonic_clock::duration run_for, bool enabled = true) {
+    const auto start_time = monotonic_clock::now();
+    while (monotonic_clock::now() < start_time + run_for) {
       RunIteration(enabled);
     }
   }
@@ -147,10 +146,10 @@
 TEST_F(ClawTest, DoesNothing) {
   const auto &values = constants::GetValues();
   ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder()
-      .angle(values.claw.wrist.lower_limit)
-      .Send());
+                  .angle(values.claw.wrist.lower_limit)
+                  .Send());
 
-  RunForTime(Time::InSeconds(6));
+  RunForTime(chrono::seconds(6));
 
   // We should not have moved.
   VerifyNearGoal();
@@ -162,11 +161,9 @@
 // Tests that the loop zeroing works with normal values.
 TEST_F(ClawTest, Zeroes) {
   // It should zero itself if we run it for awhile.
-  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder()
-      .angle(M_PI / 4.0)
-      .Send());
+  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder().angle(M_PI / 4.0).Send());
 
-  RunForTime(Time::InSeconds(6));
+  RunForTime(chrono::seconds(6));
 
   ASSERT_TRUE(claw_queue_.status.FetchLatest());
   EXPECT_TRUE(claw_queue_.status->zeroed);
@@ -180,13 +177,11 @@
   claw_plant_.InitializePosition(values.claw.wrist.lower_limit,
                                  values.claw.wrist.upper_limit);
 
-  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder()
-      .angle(M_PI / 4.0)
-      .Send());
+  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder().angle(M_PI / 4.0).Send());
 
   // The zeroing is going to take its sweet time on this one, so we had better
   // run it for longer.
-  RunForTime(Time::InMS(12000));
+  RunForTime(chrono::milliseconds(12000));
 
   ASSERT_TRUE(claw_queue_.status.FetchLatest());
   EXPECT_FALSE(claw_queue_.status->zeroed);
@@ -195,11 +190,9 @@
 
 // Tests that we can reach a reasonable goal.
 TEST_F(ClawTest, ReachesGoal) {
-  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder()
-      .angle(M_PI / 4.0)
-      .Send());
+  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder().angle(M_PI / 4.0).Send());
 
-  RunForTime(Time::InSeconds(6));
+  RunForTime(chrono::seconds(6));
 
   VerifyNearGoal();
 }
@@ -209,26 +202,24 @@
   const auto &values = constants::GetValues();
   // Upper limit
   ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder()
-      .angle(values.claw.wrist.upper_hard_limit + 5.0)
-      .Send());
+                  .angle(values.claw.wrist.upper_hard_limit + 5.0)
+                  .Send());
 
-  RunForTime(Time::InSeconds(7));
+  RunForTime(chrono::seconds(7));
 
   claw_queue_.status.FetchLatest();
-  EXPECT_NEAR(values.claw.wrist.upper_limit,
-              claw_queue_.status->angle,
+  EXPECT_NEAR(values.claw.wrist.upper_limit, claw_queue_.status->angle,
               2.0 * M_PI / 180.0);
 
   // Lower limit.
   ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder()
-      .angle(values.claw.wrist.lower_hard_limit - 5.0)
-      .Send());
+                  .angle(values.claw.wrist.lower_hard_limit - 5.0)
+                  .Send());
 
-  RunForTime(Time::InMS(6000));
+  RunForTime(chrono::milliseconds(6000));
 
   claw_queue_.status.FetchLatest();
-  EXPECT_NEAR(values.claw.wrist.lower_limit,
-              claw_queue_.status->angle,
+  EXPECT_NEAR(values.claw.wrist.lower_limit, claw_queue_.status->angle,
               2.0 * M_PI / 180.0);
 }
 
@@ -236,10 +227,8 @@
 TEST_F(ClawTest, LowerHardstopStartup) {
   claw_plant_.InitializePosition(
       constants::GetValues().claw.wrist.lower_hard_limit);
-  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder()
-      .angle(M_PI / 4.0)
-      .Send());
-  RunForTime(Time::InSeconds(6));
+  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder().angle(M_PI / 4.0).Send());
+  RunForTime(chrono::seconds(6));
 
   VerifyNearGoal();
 }
@@ -248,67 +237,56 @@
 TEST_F(ClawTest, UpperHardstopStartup) {
   claw_plant_.InitializePosition(
       constants::GetValues().claw.wrist.upper_hard_limit);
-  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder()
-      .angle(M_PI / 4.0)
-      .Send());
+  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder().angle(M_PI / 4.0).Send());
   // Zeroing will take a long time here.
-  RunForTime(Time::InSeconds(15));
+  RunForTime(chrono::seconds(15));
 
   VerifyNearGoal();
 }
 
-
 // Tests that not having a goal doesn't break anything.
-TEST_F(ClawTest, NoGoal) {
-  RunForTime(Time::InMS(50));
-}
+TEST_F(ClawTest, NoGoal) { RunForTime(chrono::milliseconds(50)); }
 
 // Tests that a WPILib reset results in rezeroing.
 TEST_F(ClawTest, WpilibReset) {
-  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder()
-      .angle(M_PI / 4.0)
-      .Send());
+  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder().angle(M_PI / 4.0).Send());
 
-  RunForTime(Time::InSeconds(6));
+  RunForTime(chrono::seconds(6));
   VerifyNearGoal();
 
   SimulateSensorReset();
-  RunForTime(Time::InMS(100));
+  RunForTime(chrono::milliseconds(100));
   ASSERT_TRUE(claw_queue_.status.FetchLatest());
   EXPECT_NE(Claw::RUNNING, claw_queue_.status->state);
 
   // Once again, it's going to take us awhile to rezero since we moved away from
   // our index pulse.
-  RunForTime(Time::InSeconds(6));
+  RunForTime(chrono::seconds(6));
   VerifyNearGoal();
 }
 
 // Tests that internal goals don't change while disabled.
 TEST_F(ClawTest, DisabledGoal) {
-  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder()
-      .angle(M_PI / 4.0)
-      .Send());
+  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder().angle(M_PI / 4.0).Send());
 
-  RunForTime(Time::InMS(100), false);
+  RunForTime(chrono::milliseconds(100), false);
   EXPECT_EQ(0.0, claw_.claw_goal_);
 
   // Now make sure they move correctly.
-  RunForTime(Time::InMS(1000), true);
+  RunForTime(chrono::milliseconds(1000), true);
   EXPECT_NE(0.0, claw_.claw_goal_);
 }
 
 // Tests that the claw zeroing goals don't wind up too far.
 TEST_F(ClawTest, GoalPositiveWindup) {
-  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder()
-      .angle(M_PI / 4.0)
-      .Send());
+  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder().angle(M_PI / 4.0).Send());
 
   while (claw_.state() != Claw::ZEROING) {
     RunIteration();
   }
 
   // Kick it.
-  RunForTime(Time::InMS(50));
+  RunForTime(chrono::milliseconds(50));
   const double orig_claw_goal = claw_.claw_goal_;
   claw_.claw_goal_ += 100.0;
 
@@ -322,16 +300,14 @@
 
 // Tests that the claw zeroing goals don't wind up too far.
 TEST_F(ClawTest, GoalNegativeWindup) {
-  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder()
-      .angle(M_PI / 4.0)
-      .Send());
+  ASSERT_TRUE(claw_queue_.goal.MakeWithBuilder().angle(M_PI / 4.0).Send());
 
   while (claw_.state() != Claw::ZEROING) {
     RunIteration();
   }
 
   // Kick it.
-  RunForTime(Time::InMS(50));
+  RunForTime(chrono::milliseconds(50));
   double orig_claw_goal = claw_.claw_goal_;
   claw_.claw_goal_ -= 100.0;
 
diff --git a/y2015/control_loops/fridge/fridge_lib_test.cc b/y2015/control_loops/fridge/fridge_lib_test.cc
index 2378622..6acc983 100644
--- a/y2015/control_loops/fridge/fridge_lib_test.cc
+++ b/y2015/control_loops/fridge/fridge_lib_test.cc
@@ -3,27 +3,30 @@
 #include <math.h>
 #include <unistd.h>
 
+#include <chrono>
 #include <memory>
 
-#include "gtest/gtest.h"
-#include "aos/common/queue.h"
-#include "aos/common/time.h"
 #include "aos/common/commonmath.h"
 #include "aos/common/controls/control_loop_test.h"
-#include "y2015/util/kinematics.h"
+#include "aos/common/queue.h"
+#include "aos/common/time.h"
 #include "frc971/control_loops/position_sensor_sim.h"
+#include "frc971/control_loops/team_number_test_environment.h"
+#include "gtest/gtest.h"
+#include "y2015/constants.h"
 #include "y2015/control_loops/fridge/arm_motor_plant.h"
 #include "y2015/control_loops/fridge/elevator_motor_plant.h"
 #include "y2015/control_loops/fridge/fridge.q.h"
-#include "y2015/constants.h"
-#include "frc971/control_loops/team_number_test_environment.h"
-
-using ::aos::time::Time;
+#include "y2015/util/kinematics.h"
 
 namespace y2015 {
 namespace control_loops {
 namespace fridge {
 namespace testing {
+
+namespace chrono = ::std::chrono;
+using ::aos::monotonic_clock;
+
 // Class which simulates the fridge and sends out queue messages with the
 // position.
 class FridgeSimulation {
@@ -263,9 +266,10 @@
   }
 
   // Runs iterations until the specified amount of simulated time has elapsed.
-  void RunForTime(const Time &run_for, bool enabled = true) {
-    const auto start_time = Time::Now();
-    while (Time::Now() < start_time + run_for) {
+  void RunForTime(const monotonic_clock::duration run_for,
+                  bool enabled = true) {
+    const auto start_time = monotonic_clock::now();
+    while (monotonic_clock::now() < start_time + run_for) {
       RunIteration(enabled);
     }
   }
@@ -297,7 +301,7 @@
                   .Send());
 
   // Run a few iterations.
-  RunForTime(Time::InSeconds(5));
+  RunForTime(chrono::seconds(5));
 
   VerifyNearGoal();
 }
@@ -324,7 +328,7 @@
                   .Send());
 
   // Give it a lot of time to get there.
-  RunForTime(Time::InSeconds(5));
+  RunForTime(chrono::seconds(5));
 
   VerifyNearGoal();
 }
@@ -344,7 +348,7 @@
                   .Send());
 
   // Give it a lot of time to get there.
-  RunForTime(Time::InSeconds(5));
+  RunForTime(chrono::seconds(5));
 
   VerifyNearGoal();
 }
@@ -364,7 +368,7 @@
                   .max_angular_acceleration(20)
                   .Send());
 
-  RunForTime(Time::InSeconds(10));
+  RunForTime(chrono::seconds(10));
 
   // Check that we are near our soft limit.
   fridge_queue_.status.FetchLatest();
@@ -385,7 +389,7 @@
                   .max_angular_acceleration(20)
                   .Send());
 
-  RunForTime(Time::InSeconds(10));
+  RunForTime(chrono::seconds(10));
 
   // Check that we are near our soft limit.
   fridge_queue_.status.FetchLatest();
@@ -405,7 +409,7 @@
       .max_angular_velocity(20)
       .max_angular_acceleration(20)
       .Send();
-  RunForTime(Time::InSeconds(5));
+  RunForTime(chrono::seconds(5));
 
   VerifyNearGoal();
 }
@@ -420,7 +424,7 @@
       constants::GetValues().fridge.arm.lower_hard_limit);
   fridge_queue_.goal.MakeWithBuilder().angle(0.0).height(0.4).Send();
   // We have to wait for it to put the elevator in a safe position as well.
-  RunForTime(Time::InMS(8000));
+  RunForTime(chrono::milliseconds(8000));
 
   VerifyNearGoal();
 }
@@ -434,7 +438,7 @@
       constants::GetValues().fridge.arm.upper_hard_limit,
       constants::GetValues().fridge.arm.upper_hard_limit);
   fridge_queue_.goal.MakeWithBuilder().angle(0.0).height(0.4).Send();
-  RunForTime(Time::InMS(5000));
+  RunForTime(chrono::milliseconds(5000));
 
   VerifyNearGoal();
 }
@@ -525,7 +529,7 @@
 
   EXPECT_EQ(Fridge::ZEROING_ELEVATOR, fridge_.state());
 
-  RunForTime(Time::InSeconds(5));
+  RunForTime(chrono::seconds(5));
   VerifyNearGoal();
 }
 
@@ -551,7 +555,7 @@
 
   EXPECT_EQ(Fridge::ZEROING_ELEVATOR, fridge_.state());
 
-  RunForTime(Time::InSeconds(5));
+  RunForTime(chrono::seconds(5));
   VerifyNearGoal();
 }
 
@@ -564,14 +568,14 @@
       constants::GetValues().fridge.arm.upper_hard_limit,
       constants::GetValues().fridge.arm.upper_hard_limit);
   fridge_queue_.goal.MakeWithBuilder().angle(0.03).height(0.45).Send();
-  RunForTime(Time::InMS(5000));
+  RunForTime(chrono::milliseconds(5000));
 
   EXPECT_EQ(Fridge::RUNNING, fridge_.state());
   VerifyNearGoal();
   SimulateSensorReset();
-  RunForTime(Time::InMS(100));
+  RunForTime(chrono::milliseconds(100));
   EXPECT_NE(Fridge::RUNNING, fridge_.state());
-  RunForTime(Time::InMS(6000));
+  RunForTime(chrono::milliseconds(6000));
   EXPECT_EQ(Fridge::RUNNING, fridge_.state());
   VerifyNearGoal();
 }
@@ -580,12 +584,12 @@
 TEST_F(FridgeTest, DisabledGoalTest) {
   fridge_queue_.goal.MakeWithBuilder().angle(0.03).height(0.45).Send();
 
-  RunForTime(Time::InMS(100), false);
+  RunForTime(chrono::milliseconds(100), false);
   EXPECT_EQ(0.0, fridge_.elevator_goal_);
   EXPECT_EQ(0.0, fridge_.arm_goal_);
 
   // Now make sure they move correctly
-  RunForTime(Time::InMS(4000), true);
+  RunForTime(chrono::milliseconds(4000), true);
   EXPECT_NE(0.0, fridge_.elevator_goal_);
   EXPECT_NE(0.0, fridge_.arm_goal_);
 }
@@ -599,7 +603,7 @@
   }
 
   // Kick it.
-  RunForTime(Time::InMS(50));
+  RunForTime(chrono::milliseconds(50));
   double orig_fridge_goal = fridge_.elevator_goal_;
   fridge_.elevator_goal_ += 100.0;
 
@@ -623,7 +627,7 @@
   }
 
   // Kick it.
-  RunForTime(Time::InMS(50));
+  RunForTime(chrono::milliseconds(50));
   double orig_fridge_goal = fridge_.arm_goal_;
   fridge_.arm_goal_ += 100.0;
 
@@ -644,7 +648,7 @@
   }
 
   // Kick it.
-  RunForTime(Time::InMS(50));
+  RunForTime(chrono::milliseconds(50));
   double orig_fridge_goal = fridge_.elevator_goal_;
   fridge_.elevator_goal_ -= 100.0;
 
@@ -665,7 +669,7 @@
   }
 
   // Kick it.
-  RunForTime(Time::InMS(50));
+  RunForTime(chrono::milliseconds(50));
   double orig_fridge_goal = fridge_.arm_goal_;
   fridge_.arm_goal_ -= 100.0;
 
@@ -679,7 +683,7 @@
 
 // Tests that the loop zeroes when run for a while.
 TEST_F(FridgeTest, ZeroNoGoal) {
-  RunForTime(Time::InSeconds(5));
+  RunForTime(chrono::seconds(5));
 
   EXPECT_EQ(Fridge::RUNNING, fridge_.state());
 }
@@ -692,9 +696,9 @@
       values.fridge.elevator.lower_hard_limit);
   fridge_plant_.InitializeArmPosition(M_PI / 4.0);
 
-  const auto start_time = Time::Now();
+  const auto start_time = monotonic_clock::now();
   double last_arm_goal = fridge_.arm_goal_;
-  while (Time::Now() < start_time + Time::InMS(4000)) {
+  while (monotonic_clock::now() < start_time + chrono::milliseconds(4000)) {
     RunIteration();
 
     if (fridge_.state() != Fridge::ZEROING_ELEVATOR) {
@@ -721,7 +725,7 @@
   fridge_plant_.set_arm_power_error(1.0);
   fridge_queue_.goal.MakeWithBuilder().angle(0.0).height(0.4).Send();
 
-  RunForTime(Time::InMS(8000));
+  RunForTime(chrono::milliseconds(8000));
 
   VerifyNearGoal();
 }
diff --git a/y2015/http_status/http_status.cc b/y2015/http_status/http_status.cc
index 7d5093a..1b79555 100644
--- a/y2015/http_status/http_status.cc
+++ b/y2015/http_status/http_status.cc
@@ -1,5 +1,6 @@
 #include "y2015/http_status/http_status.h"
 
+#include <chrono>
 #include <iostream>
 #include <sstream>
 #include <string>
@@ -22,6 +23,9 @@
 namespace y2015 {
 namespace http_status {
 
+using ::aos::monotonic_clock;
+namespace chrono = ::std::chrono;
+
 // TODO(comran): Make some of these separate libraries & document them better.
 
 HTTPStatusMessage::HTTPStatusMessage()
@@ -33,13 +37,13 @@
 void HTTPStatusMessage::NextSample() {
   int32_t adjusted_index = GetIndex(sample_id_);
 
-  ::aos::time::Time time_now = ::aos::time::Time::Now();
+  const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
 
   if (sample_id_ < overflow_id_) {
-    sample_times_.emplace_back(time_now);
+    sample_times_.emplace_back(monotonic_now);
     data_values_.emplace_back(::std::vector<double>());
   } else {
-    sample_times_[adjusted_index] = time_now;
+    sample_times_[adjusted_index] = monotonic_now;
   }
 
   sample_id_++;
@@ -122,7 +126,10 @@
 
     int32_t adjusted_index = GetIndex(cur_sample);
 
-    message << cur_sample << "%" << sample_times_.at(adjusted_index).ToSeconds()
+    message << cur_sample << "%"
+            << chrono::duration_cast<chrono::duration<double>>(
+                   sample_times_.at(adjusted_index).time_since_epoch())
+                   .count()
             << "%";
     for (int32_t cur_measure = 0;
          cur_measure < static_cast<int32_t>(data_names_.size());
@@ -216,8 +223,10 @@
 void DataCollector::operator()() {
   ::aos::SetCurrentThreadName("HTTPStatusData");
 
+  ::aos::time::PhasedLoop phased_loop(chrono::milliseconds(5),
+                                      chrono::microseconds(0));
   while (run_) {
-    ::aos::time::PhasedLoopXMS(5, 0);
+    phased_loop.SleepUntilNext();
     RunIteration();
   }
 }
diff --git a/y2015/http_status/http_status.h b/y2015/http_status/http_status.h
index b7b3b4c..7e6383f 100644
--- a/y2015/http_status/http_status.h
+++ b/y2015/http_status/http_status.h
@@ -55,7 +55,7 @@
   // Vectors of vectors to store samples at indexes determined by GetIndex.
   ::std::vector<::std::string> data_names_;
   ::std::vector<::std::vector<double>> data_values_;
-  ::std::vector<::aos::time::Time> sample_times_;
+  ::std::vector<::aos::monotonic_clock::time_point> sample_times_;
 
   int32_t sample_id_;          // Last sample id used.
   int32_t measure_index_;      // Last measure index used.
diff --git a/y2015/wpilib/wpilib_interface.cc b/y2015/wpilib/wpilib_interface.cc
index a6dab4d..0c643b4 100644
--- a/y2015/wpilib/wpilib_interface.cc
+++ b/y2015/wpilib/wpilib_interface.cc
@@ -68,6 +68,7 @@
 using ::frc971::wpilib::PneumaticsToLog;
 using ::y2015::control_loops::claw_queue;
 using ::y2015::control_loops::fridge::fridge_queue;
+namespace chrono = ::std::chrono;
 
 namespace y2015 {
 namespace wpilib {
@@ -251,8 +252,8 @@
     wrist_encoder_.Start();
     dma_synchronizer_->Start();
 
-    ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
-                                        ::std::chrono::milliseconds(4));
+    ::aos::time::PhasedLoop phased_loop(chrono::milliseconds(5),
+                                        chrono::milliseconds(4));
 
     ::aos::SetCurrentThreadRealtimePriority(40);
     while (run_) {
@@ -428,8 +429,8 @@
     ::aos::SetCurrentThreadName("Solenoids");
     ::aos::SetCurrentThreadRealtimePriority(27);
 
-    ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(20),
-                                        ::std::chrono::milliseconds(1));
+    ::aos::time::PhasedLoop phased_loop(chrono::milliseconds(20),
+                                        chrono::milliseconds(1));
 
     while (run_) {
       {
@@ -505,7 +506,7 @@
 
 class CanWriter : public LoopOutputHandler {
  public:
-  CanWriter() : LoopOutputHandler(::aos::time::Time::InSeconds(0.10)) {}
+  CanWriter() : LoopOutputHandler(chrono::milliseconds(100)) {}
 
   void set_can_talon(::std::unique_ptr<Talon> t) {
     can_talon_ = ::std::move(t);
diff --git a/y2015_bot3/actors/drivetrain_actor.cc b/y2015_bot3/actors/drivetrain_actor.cc
index 44b21ee..313a818 100644
--- a/y2015_bot3/actors/drivetrain_actor.cc
+++ b/y2015_bot3/actors/drivetrain_actor.cc
@@ -52,8 +52,10 @@
   turn_profile.set_maximum_velocity(params.maximum_turn_velocity *
                                     kDrivetrainTurnWidth / 2.0);
 
+  ::aos::time::PhasedLoop phased_loop(chrono::milliseconds(5),
+                                      chrono::microseconds(2500));
   while (true) {
-    ::aos::time::PhasedLoopXMS(5, 2500);
+    phased_loop.SleepUntilNext();
 
     drivetrain_queue.status.FetchLatest();
     if (drivetrain_queue.status.get()) {
diff --git a/y2015_bot3/actors/drivetrain_actor_main.cc b/y2015_bot3/actors/drivetrain_actor_main.cc
index a31b233..d12d61a 100644
--- a/y2015_bot3/actors/drivetrain_actor_main.cc
+++ b/y2015_bot3/actors/drivetrain_actor_main.cc
@@ -4,8 +4,6 @@
 #include "y2015_bot3/actors/drivetrain_action.q.h"
 #include "y2015_bot3/actors/drivetrain_actor.h"
 
-using ::aos::time::Time;
-
 int main(int /*argc*/, char * /*argv*/[]) {
   ::aos::Init(-1);
 
diff --git a/y2015_bot3/autonomous/auto.cc b/y2015_bot3/autonomous/auto.cc
index 0eaf921..35ad8d2 100644
--- a/y2015_bot3/autonomous/auto.cc
+++ b/y2015_bot3/autonomous/auto.cc
@@ -16,7 +16,6 @@
 #include "y2015_bot3/control_loops/intake/intake.q.h"
 #include "y2015_bot3/control_loops/drivetrain/drivetrain_base.h"
 
-using ::aos::time::Time;
 using ::frc971::control_loops::drivetrain_queue;
 using ::y2015_bot3::control_loops::intake_queue;
 using ::y2015_bot3::control_loops::elevator_queue;
@@ -29,8 +28,9 @@
   double acceleration;
 };
 
-namespace time = ::aos::time;
+using ::aos::monotonic_clock;
 namespace actors = ::frc971::actors;
+namespace chrono = ::std::chrono;
 
 const ProfileParams kFastDrive = {3.0, 3.5};
 const ProfileParams kLastDrive = {4.0, 4.0};
@@ -99,9 +99,11 @@
     LOG(ERROR, "No action, not waiting\n");
     return;
   }
+  ::aos::time::PhasedLoop phased_loop(chrono::milliseconds(5),
+                                      chrono::microseconds(2500));
   while (true) {
+    phased_loop.SleepUntilNext();
     // Poll the running bit and auto done bits.
-    ::aos::time::PhasedLoopXMS(5, 2500);
     if (!action->Running() || ShouldExitAuto()) {
       return;
     }
@@ -126,11 +128,14 @@
   }
 }
 
-void GrabberForTime(double voltage, double wait_time) {
-  ::aos::time::Time now = ::aos::time::Time::Now();
-  ::aos::time::Time end_time = now + time::Time::InSeconds(wait_time);
-  LOG(INFO, "Starting to grab at %f for %f seconds\n", voltage, wait_time);
+void GrabberForTime(double voltage, monotonic_clock::duration wait_time) {
+  monotonic_clock::time_point monotonic_now = monotonic_clock::now();
+  monotonic_clock::time_point end_time = monotonic_now + wait_time;
+  LOG(INFO, "Starting to grab at %f for %f seconds\n", voltage,
+      chrono::duration_cast<chrono::duration<double>>(wait_time).count());
 
+  ::aos::time::PhasedLoop phased_loop(chrono::milliseconds(5),
+                                      chrono::microseconds(2500));
   while (true) {
     autonomous::can_grabber_control.MakeWithBuilder()
         .can_grabber_voltage(voltage).can_grabbers(false).Send();
@@ -139,11 +144,11 @@
     if (ShouldExitAuto()) {
       return;
     }
-    if (::aos::time::Time::Now() > end_time) {
+    if (monotonic_clock::now() > end_time) {
       LOG(INFO, "Done grabbing\n");
       return;
     }
-    ::aos::time::PhasedLoopXMS(5, 2500);
+    phased_loop.SleepUntilNext();
   }
 }
 
@@ -152,8 +157,8 @@
   ResetDrivetrain();
 
   // Launch can grabbers.
-  //GrabberForTime(12.0, 0.26);
-  GrabberForTime(6.0, 0.40);
+  // GrabberForTime(12.0, chrono::milliseconds(260));
+  GrabberForTime(6.0, chrono::milliseconds(400));
   if (ShouldExitAuto()) return;
   InitializeEncoders();
   ResetDrivetrain();
@@ -192,18 +197,18 @@
       .right_goal(right_initial_position + kMoveBackDistance)
       .right_velocity_goal(0)
       .Send();
-  GrabberForTime(12.0, 0.02);
+  GrabberForTime(12.0, chrono::milliseconds(20));
   if (ShouldExitAuto()) return;
 
   // We shouldn't need as much power at this point, so lower the can grabber
   // voltages to avoid damaging the motors due to stalling.
-  GrabberForTime(4.0, 0.75);
+  GrabberForTime(4.0, chrono::milliseconds(750));
   if (ShouldExitAuto()) return;
-  GrabberForTime(-3.0, 0.25);
+  GrabberForTime(-3.0, chrono::milliseconds(250));
   if (ShouldExitAuto()) return;
-  GrabberForTime(-12.0, 1.0);
+  GrabberForTime(-12.0, chrono::milliseconds(1000));
   if (ShouldExitAuto()) return;
-  GrabberForTime(-3.0, 12.0);
+  GrabberForTime(-3.0, chrono::milliseconds(12000));
 }
 
 const ProfileParams kElevatorProfile = {1.0, 5.0};
@@ -312,7 +317,7 @@
 }
 
 void TripleCanAuto() {
-  ::aos::time::Time start_time = ::aos::time::Time::Now();
+  monotonic_clock::time_point start_time = monotonic_clock::now();
 
   ::std::unique_ptr<::frc971::actors::DrivetrainAction> drive;
   InitializeEncoders();
@@ -428,15 +433,17 @@
       LOG(INFO, "Got the tote!\n");
       break;
     }
-    if ((::aos::time::Time::Now() - start_time) > time::Time::InSeconds(15.0)) {
+    if (monotonic_clock::now() > chrono::seconds(15) + start_time) {
       LOG(INFO, "Out of time\n");
       break;
     }
   }
 
-  ::aos::time::Time end_time = ::aos::time::Time::Now();
+  monotonic_clock::time_point end_time = monotonic_clock::now();
   LOG(INFO, "Ended auto with %f to spare\n",
-      (time::Time::InSeconds(15.0) - (end_time - start_time)).ToSeconds());
+      chrono::duration_cast<chrono::duration<double>>(chrono::seconds(15) -
+                                                      (end_time - start_time))
+          .count());
   if (!intake_queue.goal.MakeWithBuilder().movement(0.0).claw_closed(true)
           .Send()) {
     LOG(ERROR, "Sending intake goal failed.\n");
@@ -444,8 +451,11 @@
 }
 
 void HandleAuto() {
-  ::aos::time::Time start_time = ::aos::time::Time::Now();
-  LOG(INFO, "Starting auto mode at %f\n", start_time.ToSeconds());
+  monotonic_clock::time_point start_time = monotonic_clock::now();
+  LOG(INFO, "Starting auto mode at %f\n",
+      chrono::duration_cast<chrono::duration<double>>(
+          start_time.time_since_epoch())
+          .count());
 
   // TODO(comran): Add various options for different autos down below.
   //CanGrabberAuto();
diff --git a/y2015_bot3/autonomous/auto_main.cc b/y2015_bot3/autonomous/auto_main.cc
index 2c006e0..1357d7c 100644
--- a/y2015_bot3/autonomous/auto_main.cc
+++ b/y2015_bot3/autonomous/auto_main.cc
@@ -6,8 +6,6 @@
 #include "y2015_bot3/autonomous/auto.q.h"
 #include "y2015_bot3/autonomous/auto.h"
 
-using ::aos::time::Time;
-
 int main(int /*argc*/, char * /*argv*/[]) {
   ::aos::Init(-1);
 
@@ -24,12 +22,15 @@
       LOG(INFO, "Got another auto packet\n");
     }
     LOG(INFO, "Starting auto mode\n");
-    ::aos::time::Time start_time = ::aos::time::Time::Now();
+    const ::aos::monotonic_clock::time_point start_time =
+        ::aos::monotonic_clock::now();
     ::y2015_bot3::autonomous::HandleAuto();
 
-    ::aos::time::Time elapsed_time = ::aos::time::Time::Now() - start_time;
+    const auto elapsed_time = ::aos::monotonic_clock::now() - start_time;
     LOG(INFO, "Auto mode exited in %f, waiting for it to finish.\n",
-        elapsed_time.ToSeconds());
+        ::std::chrono::duration_cast<::std::chrono::duration<double>>(
+            elapsed_time)
+            .count());
     while (::y2015_bot3::autonomous::autonomous->run_auto) {
       ::y2015_bot3::autonomous::autonomous.FetchNextBlocking();
       LOG(INFO, "Got another auto packet\n");
diff --git a/y2015_bot3/control_loops/intake/intake_lib_test.cc b/y2015_bot3/control_loops/intake/intake_lib_test.cc
index 1c8b604..d311d5c 100644
--- a/y2015_bot3/control_loops/intake/intake_lib_test.cc
+++ b/y2015_bot3/control_loops/intake/intake_lib_test.cc
@@ -3,17 +3,20 @@
 #include <math.h>
 #include <unistd.h>
 
+#include <chrono>
+
 #include "gtest/gtest.h"
 #include "aos/common/queue.h"
 #include "aos/common/controls/control_loop_test.h"
 #include "y2015_bot3/control_loops/intake/intake.q.h"
 
-using ::aos::time::Time;
-
 namespace y2015_bot3 {
 namespace control_loops {
 namespace testing {
 
+namespace chrono = ::std::chrono;
+using ::aos::monotonic_clock;
+
 // Class which simulates the elevator and sends out queue messages with the
 // position.
 class IntakeSimulation {
@@ -60,9 +63,9 @@
   }
 
   // Runs iterations until the specified amount of simulated time has elapsed.
-  void RunForTime(double run_for, bool enabled = true) {
-    const auto start_time = Time::Now();
-    while (Time::Now() < start_time + Time::InSeconds(run_for)) {
+  void RunForTime(monotonic_clock::duration run_for, bool enabled = true) {
+    const auto start_time = monotonic_clock::now();
+    while (monotonic_clock::now() < start_time + run_for) {
       RunIteration(enabled);
     }
   }
@@ -84,7 +87,7 @@
                   .Send());
 
   // Run for a bit.
-  RunForTime(1.0);
+  RunForTime(chrono::seconds(1));
 
   ASSERT_TRUE(queue_.output.FetchLatest());
   EXPECT_EQ(queue_.output->intake, 0.0);
@@ -97,7 +100,7 @@
                   .Send());
 
   // Run for a bit.
-  RunForTime(1.0);
+  RunForTime(chrono::seconds(1));
 
   ASSERT_TRUE(queue_.output.FetchLatest());
   EXPECT_GT(queue_.output->intake, 0.0);
@@ -110,7 +113,7 @@
                   .Send());
 
   // Run for a bit.
-  RunForTime(1.0);
+  RunForTime(chrono::seconds(1));
 
   ASSERT_TRUE(queue_.output.FetchLatest());
   EXPECT_LT(queue_.output->intake, 0.0);
diff --git a/y2015_bot3/wpilib/wpilib_interface.cc b/y2015_bot3/wpilib/wpilib_interface.cc
index edd2428..b92d02b 100644
--- a/y2015_bot3/wpilib/wpilib_interface.cc
+++ b/y2015_bot3/wpilib/wpilib_interface.cc
@@ -67,6 +67,8 @@
 namespace y2015_bot3 {
 namespace wpilib {
 
+namespace chrono = ::std::chrono;
+
 double drivetrain_translate(int32_t in) {
   return static_cast<double>(in) / (256.0 /*cpr*/ * 4.0 /*4x*/) *
          ::y2015_bot3::control_loops::drivetrain::kDrivetrainEncoderRatio *
@@ -137,8 +139,8 @@
         &DriverStation::GetInstance();
 #endif
 
-    ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
-                                        ::std::chrono::milliseconds(4));
+    ::aos::time::PhasedLoop phased_loop(chrono::milliseconds(5),
+                                        chrono::milliseconds(4));
 
     ::aos::SetCurrentThreadRealtimePriority(40);
     while (run_) {
@@ -242,8 +244,8 @@
     ::aos::SetCurrentThreadName("Solenoids");
     ::aos::SetCurrentThreadRealtimePriority(27);
 
-    ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(20),
-                                        ::std::chrono::milliseconds(1));
+    ::aos::time::PhasedLoop phased_loop(chrono::milliseconds(20),
+                                        chrono::milliseconds(1));
 
     while (run_) {
       {
@@ -423,7 +425,7 @@
 // Writes out can grabber voltages.
 class CanGrabberWriter : public LoopOutputHandler {
  public:
-  CanGrabberWriter() : LoopOutputHandler(::aos::time::Time::InSeconds(0.05)) {}
+  CanGrabberWriter() : LoopOutputHandler(chrono::milliseconds(50)) {}
 
   void set_can_grabber_talon1(::std::unique_ptr<Talon> t) {
     can_grabber_talon1_ = ::std::move(t);
diff --git a/y2016/actors/autonomous_actor.cc b/y2016/actors/autonomous_actor.cc
index f298420..5194b2d 100644
--- a/y2016/actors/autonomous_actor.cc
+++ b/y2016/actors/autonomous_actor.cc
@@ -19,6 +19,9 @@
 namespace y2016 {
 namespace actors {
 using ::frc971::control_loops::drivetrain_queue;
+using ::aos::monotonic_clock;
+namespace chrono = ::std::chrono;
+namespace this_thread = ::std::this_thread;
 
 namespace {
 const ProfileParameters kSlowDrive = {0.8, 2.5};
@@ -40,6 +43,11 @@
 const ProfileParameters kTwoBallReturnSlow = {3.0, 2.5};
 const ProfileParameters kTwoBallBallPickup = {2.0, 1.75};
 const ProfileParameters kTwoBallBallPickupAccel = {2.0, 2.5};
+
+double DoubleSeconds(monotonic_clock::duration duration) {
+  return ::std::chrono::duration_cast<::std::chrono::duration<double>>(duration)
+      .count();
+}
 }  // namespace
 
 AutonomousActor::AutonomousActor(actors::AutonomousActionQueueGroup *s)
@@ -438,16 +446,16 @@
 }
 
 void AutonomousActor::WaitForAlignedWithVision(
-    ::aos::time::Time align_duration) {
+    chrono::nanoseconds align_duration) {
   bool vision_valid = false;
   double last_angle = 0.0;
   int ready_to_fire = 0;
 
   ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
                                       ::std::chrono::milliseconds(5) / 2);
-  ::aos::time::Time end_time =
-      ::aos::time::Time::Now() + align_duration;
-  while (end_time > ::aos::time::Time::Now()) {
+  monotonic_clock::time_point end_time =
+      monotonic_clock::now() + align_duration;
+  while (end_time > monotonic_clock::now()) {
     if (ShouldCancel()) break;
 
     ::y2016::vision::vision_status.FetchLatest();
@@ -674,7 +682,7 @@
   LOG(INFO, "Waiting for the superstructure\n");
   WaitForSuperstructure();
 
-  ::aos::time::SleepFor(::aos::time::Time::InSeconds(0.5));
+  this_thread::sleep_for(chrono::milliseconds(500));
 
   if (ShouldCancel()) return;
   LOG(INFO, "Triggering the vision actor\n");
@@ -683,13 +691,13 @@
   // Wait for the drive base to be aligned with the target and make sure that
   // the shooter is up to speed.
   LOG(INFO, "Waiting for vision to be aligned\n");
-  WaitForAlignedWithVision(aos::time::Time::InSeconds(2));
+  WaitForAlignedWithVision(chrono::milliseconds(2000));
   if (ShouldCancel()) return;
   LOG(INFO, "Waiting for shooter to be up to speed\n");
   WaitForShooterSpeed();
   if (ShouldCancel()) return;
 
-  ::aos::time::SleepFor(::aos::time::Time::InSeconds(0.3));
+  this_thread::sleep_for(chrono::milliseconds(300));
   LOG(INFO, "Shoot!\n");
   Shoot();
 
@@ -822,7 +830,7 @@
 }
 
 void AutonomousActor::TwoBallAuto() {
-  aos::time::Time start_time = aos::time::Time::Now();
+  monotonic_clock::time_point start_time = monotonic_clock::now();
   OpenShooter();
   MoveSuperstructure(0.10, -0.010, 0.0, {8.0, 60.0}, {4.0, 10.0}, {10.0, 25.0},
                      false, 12.0);
@@ -831,7 +839,7 @@
 
   WaitForIntake();
   LOG(INFO, "Intake done at %f seconds, starting to drive\n",
-      (aos::time::Time::Now() - start_time).ToSeconds());
+      DoubleSeconds(monotonic_clock::now() - start_time));
   if (ShouldCancel()) return;
   const double kDriveDistance = 5.05;
   StartDrive(-kDriveDistance, 0.0, kTwoBallLowDrive, kSlowTurn);
@@ -846,12 +854,12 @@
     const bool ball_detected = ::y2016::sensors::ball_detector->voltage > 2.5;
     first_ball_there = ball_detected;
     LOG(INFO, "Saw the ball: %d at %f\n", first_ball_there,
-        (aos::time::Time::Now() - start_time).ToSeconds());
+        DoubleSeconds(monotonic_clock::now() - start_time));
   }
   MoveSuperstructure(0.10, -0.010, 0.0, {8.0, 40.0}, {4.0, 10.0}, {10.0, 25.0},
                      false, 0.0);
   LOG(INFO, "Shutting off rollers at %f seconds, starting to straighten out\n",
-      (aos::time::Time::Now() - start_time).ToSeconds());
+      DoubleSeconds(monotonic_clock::now() - start_time));
   StartDrive(0.0, -0.4, kTwoBallLowDrive, kSwerveTurn);
   MoveSuperstructure(-0.05, -0.010, 0.0, {8.0, 40.0}, {4.0, 10.0}, {10.0, 25.0},
                      false, 0.0);
@@ -871,7 +879,7 @@
 
   if (!WaitForDriveDone()) return;
   LOG(INFO, "First shot done driving at %f seconds\n",
-      (aos::time::Time::Now() - start_time).ToSeconds());
+      DoubleSeconds(monotonic_clock::now() - start_time));
 
   WaitForSuperstructureProfile();
 
@@ -881,8 +889,8 @@
   WaitForShooterSpeed();
   if (ShouldCancel()) return;
 
-  constexpr double kVisionExtra = 0.0;
-  WaitForAlignedWithVision(aos::time::Time::InSeconds(0.5 + kVisionExtra));
+  constexpr chrono::milliseconds kVisionExtra{0};
+  WaitForAlignedWithVision(chrono::milliseconds(500) + kVisionExtra);
   BackLongShotTwoBallFinish();
   WaitForSuperstructureProfile();
   if (ShouldCancel()) return;
@@ -894,7 +902,7 @@
   }
 
   LOG(INFO, "First shot at %f seconds\n",
-      (aos::time::Time::Now() - start_time).ToSeconds());
+      DoubleSeconds(monotonic_clock::now() - start_time));
   if (ShouldCancel()) return;
 
   SetShooterSpeed(0.0);
@@ -914,7 +922,7 @@
 
   if (!WaitForDriveNear(0.06, kDoNotTurnCare)) return;
   LOG(INFO, "At Low Bar %f\n",
-      (aos::time::Time::Now() - start_time).ToSeconds());
+      DoubleSeconds(monotonic_clock::now() - start_time));
 
   OpenShooter();
   constexpr double kSecondBallAfterBarDrive = 2.10;
@@ -932,7 +940,7 @@
                      false, 12.0);
 
   LOG(INFO, "Done backing up %f\n",
-      (aos::time::Time::Now() - start_time).ToSeconds());
+      DoubleSeconds(monotonic_clock::now() - start_time));
 
   constexpr double kDriveBackDistance = 5.15 - 0.4;
   StartDrive(-kDriveBackDistance, 0.0, kTwoBallLowDrive, kFinishTurn);
@@ -941,7 +949,7 @@
 
   StartDrive(0.0, -kBallSmallWallTurn, kTwoBallLowDrive, kFinishTurn);
   LOG(INFO, "Straightening up at %f\n",
-      (aos::time::Time::Now() - start_time).ToSeconds());
+      DoubleSeconds(monotonic_clock::now() - start_time));
 
   CloseIfBall();
   if (!WaitForDriveNear(kDriveBackDistance - 2.3, kDoNotTurnCare)) return;
@@ -952,7 +960,7 @@
     if (!ball_detected) {
       if (!WaitForDriveDone()) return;
       LOG(INFO, "Aborting, no ball %f\n",
-          (aos::time::Time::Now() - start_time).ToSeconds());
+          DoubleSeconds(monotonic_clock::now() - start_time));
       return;
     }
   }
@@ -969,7 +977,7 @@
 
   if (!WaitForDriveDone()) return;
   LOG(INFO, "Second shot done driving at %f seconds\n",
-      (aos::time::Time::Now() - start_time).ToSeconds());
+      DoubleSeconds(monotonic_clock::now() - start_time));
   WaitForSuperstructure();
   AlignWithVisionGoal();
   if (ShouldCancel()) return;
@@ -980,27 +988,29 @@
   // 2.2 with 0.4 of vision.
   // 1.8 without any vision.
   LOG(INFO, "Going to vision align at %f\n",
-      (aos::time::Time::Now() - start_time).ToSeconds());
-  WaitForAlignedWithVision(start_time + aos::time::Time::InSeconds(13.5 + kVisionExtra * 2) -
-                           aos::time::Time::Now());
+      DoubleSeconds(monotonic_clock::now() - start_time));
+  WaitForAlignedWithVision(
+      (start_time + chrono::milliseconds(13500) + kVisionExtra * 2) -
+      monotonic_clock::now());
   BackLongShotTwoBallFinish();
   WaitForSuperstructureProfile();
   if (ShouldCancel()) return;
-  LOG(INFO, "Shoot at %f\n", (aos::time::Time::Now() - start_time).ToSeconds());
+  LOG(INFO, "Shoot at %f\n",
+      DoubleSeconds(monotonic_clock::now() - start_time));
   Shoot();
 
   LOG(INFO, "Second shot at %f seconds\n",
-      (aos::time::Time::Now() - start_time).ToSeconds());
+      DoubleSeconds(monotonic_clock::now() - start_time));
   if (ShouldCancel()) return;
 
   SetShooterSpeed(0.0);
   LOG(INFO, "Folding superstructure back down\n");
   TuckArm(true, false);
-  LOG(INFO, "Shot %f\n", (aos::time::Time::Now() - start_time).ToSeconds());
+  LOG(INFO, "Shot %f\n", DoubleSeconds(monotonic_clock::now() - start_time));
 
   WaitForSuperstructureLow();
 
-  LOG(INFO, "Done %f\n", (aos::time::Time::Now() - start_time).ToSeconds());
+  LOG(INFO, "Done %f\n", DoubleSeconds(monotonic_clock::now() - start_time));
 }
 
 void AutonomousActor::StealAndMoveOverBy(double distance) {
@@ -1024,7 +1034,7 @@
 }
 
 bool AutonomousActor::RunAction(const actors::AutonomousActionParams &params) {
-  aos::time::Time start_time = aos::time::Time::Now();
+  monotonic_clock::time_point start_time = monotonic_clock::now();
   LOG(INFO, "Starting autonomous action with mode %" PRId32 "\n", params.mode);
 
   InitializeEncoders();
@@ -1166,7 +1176,7 @@
   StartDrive(0.5, 0.0, kMoatDrive, kFastTurn);
   if (!WaitForDriveDone()) return true;
 
-  LOG(INFO, "Done %f\n", (aos::time::Time::Now() - start_time).ToSeconds());
+  LOG(INFO, "Done %f\n", DoubleSeconds(monotonic_clock::now() - start_time));
 
   ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
                                       ::std::chrono::milliseconds(5) / 2);
diff --git a/y2016/actors/autonomous_actor.h b/y2016/actors/autonomous_actor.h
index 9a26731..7cf932a 100644
--- a/y2016/actors/autonomous_actor.h
+++ b/y2016/actors/autonomous_actor.h
@@ -1,15 +1,15 @@
 #ifndef Y2016_ACTORS_AUTONOMOUS_ACTOR_H_
 #define Y2016_ACTORS_AUTONOMOUS_ACTOR_H_
 
+#include <chrono>
 #include <memory>
 
-#include "aos/common/actions/actor.h"
 #include "aos/common/actions/actions.h"
-
-#include "y2016/actors/autonomous_action.q.h"
-#include "y2016/actors/vision_align_actor.h"
+#include "aos/common/actions/actor.h"
 #include "frc971/control_loops/drivetrain/drivetrain.q.h"
 #include "frc971/control_loops/drivetrain/drivetrain_config.h"
+#include "y2016/actors/autonomous_action.q.h"
+#include "y2016/actors/vision_align_actor.h"
 
 namespace y2016 {
 namespace actors {
@@ -111,7 +111,7 @@
   void Shoot();
 
   void AlignWithVisionGoal();
-  void WaitForAlignedWithVision(aos::time::Time align_duration);
+  void WaitForAlignedWithVision(::std::chrono::nanoseconds align_duration);
 
   void TwoBallAuto();
 
diff --git a/y2016/actors/autonomous_actor_main.cc b/y2016/actors/autonomous_actor_main.cc
index 8f0b305..6f01e65 100644
--- a/y2016/actors/autonomous_actor_main.cc
+++ b/y2016/actors/autonomous_actor_main.cc
@@ -4,8 +4,6 @@
 #include "y2016/actors/autonomous_action.q.h"
 #include "y2016/actors/autonomous_actor.h"
 
-using ::aos::time::Time;
-
 int main(int /*argc*/, char * /*argv*/ []) {
   ::aos::Init(-1);
 
diff --git a/y2016/actors/superstructure_actor_main.cc b/y2016/actors/superstructure_actor_main.cc
index a6da2a2..0b3c4be 100644
--- a/y2016/actors/superstructure_actor_main.cc
+++ b/y2016/actors/superstructure_actor_main.cc
@@ -4,8 +4,6 @@
 #include "y2016/actors/superstructure_action.q.h"
 #include "y2016/actors/superstructure_actor.h"
 
-using ::aos::time::Time;
-
 int main(int /*argc*/, char* /*argv*/ []) {
   ::aos::Init(-1);
 
diff --git a/y2016/actors/vision_align_actor_main.cc b/y2016/actors/vision_align_actor_main.cc
index ccd4734..17fdc0a 100644
--- a/y2016/actors/vision_align_actor_main.cc
+++ b/y2016/actors/vision_align_actor_main.cc
@@ -4,8 +4,6 @@
 #include "y2016/actors/vision_align_action.q.h"
 #include "y2016/actors/vision_align_actor.h"
 
-using ::aos::time::Time;
-
 int main(int /*argc*/, char* /*argv*/ []) {
   ::aos::Init(-1);
 
diff --git a/y2016/control_loops/superstructure/superstructure_lib_test.cc b/y2016/control_loops/superstructure/superstructure_lib_test.cc
index 1efdfcf..e95267c 100644
--- a/y2016/control_loops/superstructure/superstructure_lib_test.cc
+++ b/y2016/control_loops/superstructure/superstructure_lib_test.cc
@@ -2,22 +2,22 @@
 
 #include <unistd.h>
 
+#include <chrono>
 #include <memory>
 
-#include "gtest/gtest.h"
-#include "aos/common/queue.h"
-#include "aos/common/controls/control_loop_test.h"
 #include "aos/common/commonmath.h"
+#include "aos/common/controls/control_loop_test.h"
+#include "aos/common/queue.h"
 #include "aos/common/time.h"
 #include "frc971/control_loops/position_sensor_sim.h"
 #include "frc971/control_loops/team_number_test_environment.h"
-#include "y2016/control_loops/superstructure/superstructure.q.h"
-#include "y2016/control_loops/superstructure/intake_plant.h"
+#include "gtest/gtest.h"
 #include "y2016/control_loops/superstructure/arm_plant.h"
+#include "y2016/control_loops/superstructure/intake_plant.h"
+#include "y2016/control_loops/superstructure/superstructure.q.h"
 
 #include "y2016/constants.h"
 
-using ::aos::time::Time;
 using ::frc971::control_loops::PositionSensorSimulator;
 
 namespace y2016 {
@@ -25,6 +25,9 @@
 namespace superstructure {
 namespace testing {
 
+namespace chrono = ::std::chrono;
+using ::aos::monotonic_clock;
+
 class ArmPlant : public StateFeedbackPlant<4, 2, 2> {
  public:
   explicit ArmPlant(StateFeedbackPlant<4, 2, 2> &&other)
@@ -284,10 +287,10 @@
   }
 
   // Runs iterations until the specified amount of simulated time has elapsed.
-  void RunForTime(const Time &run_for, bool enabled = true) {
-    const auto start_time = Time::Now();
-    while (Time::Now() < start_time + run_for) {
-      const auto loop_start_time = Time::Now();
+  void RunForTime(monotonic_clock::duration run_for, bool enabled = true) {
+    const auto start_time = monotonic_clock::now();
+    while (monotonic_clock::now() < start_time + run_for) {
+      const auto loop_start_time = monotonic_clock::now();
       double begin_shoulder_velocity =
           superstructure_plant_.shoulder_angular_velocity();
       double begin_intake_velocity =
@@ -295,7 +298,9 @@
       double begin_wrist_velocity =
           superstructure_plant_.wrist_angular_velocity();
       RunIteration(enabled);
-      const double loop_time = (Time::Now() - loop_start_time).ToSeconds();
+      const double loop_time =
+          chrono::duration_cast<chrono::duration<double>>(
+              monotonic_clock::now() - loop_start_time).count();
       const double shoulder_acceleration =
           (superstructure_plant_.shoulder_angular_velocity() -
            begin_shoulder_velocity) /
@@ -398,7 +403,7 @@
                   .Send());
 
   // TODO(phil): Send a goal of some sort.
-  RunForTime(Time::InSeconds(5));
+  RunForTime(chrono::seconds(5));
   VerifyNearGoal();
 }
 
@@ -418,7 +423,7 @@
                   .Send());
 
   // Give it a lot of time to get there.
-  RunForTime(Time::InSeconds(8));
+  RunForTime(chrono::seconds(8));
 
   VerifyNearGoal();
 }
@@ -438,7 +443,7 @@
                   .max_angular_velocity_wrist(20)
                   .max_angular_acceleration_wrist(20)
                   .Send());
-  RunForTime(Time::InSeconds(10));
+  RunForTime(chrono::seconds(10));
 
   // Check that we are near our soft limit.
   superstructure_queue_.status.FetchLatest();
@@ -463,7 +468,7 @@
                   .max_angular_acceleration_wrist(20)
                   .Send());
 
-  RunForTime(Time::InSeconds(10));
+  RunForTime(chrono::seconds(10));
 
   // Check that we are near our soft limit.
   superstructure_queue_.status.FetchLatest();
@@ -488,7 +493,7 @@
                   .max_angular_acceleration_wrist(20)
                   .Send());
 
-  RunForTime(Time::InSeconds(10));
+  RunForTime(chrono::seconds(10));
 
   // Check that we are near our soft limit.
   superstructure_queue_.status.FetchLatest();
@@ -513,14 +518,14 @@
                   .max_angular_acceleration_wrist(20)
                   .Send());
 
-  RunForTime(Time::InSeconds(10));
+  RunForTime(chrono::seconds(10));
 
   VerifyNearGoal();
 }
 
 // Tests that the loop zeroes when run for a while without a goal.
 TEST_F(SuperstructureTest, ZeroNoGoal) {
-  RunForTime(Time::InSeconds(5));
+  RunForTime(chrono::seconds(5));
 
   EXPECT_EQ(Superstructure::RUNNING, superstructure_.state());
 }
@@ -543,7 +548,7 @@
                                constants::Values::kShoulderRange.upper)
                   .Send());
   // We have to wait for it to put the elevator in a safe position as well.
-  RunForTime(Time::InSeconds(15));
+  RunForTime(chrono::seconds(15));
 
   VerifyNearGoal();
 }
@@ -561,8 +566,9 @@
                   .angle_shoulder(constants::Values::kShoulderRange.lower)
                   .angle_wrist(0.0)
                   .Send());
-  // We have to wait for it to put the elevator in a safe position as well.
-  RunForTime(Time::InSeconds(20));
+  // We have to wait for it to put the superstructure in a safe position as
+  // well.
+  RunForTime(chrono::seconds(20));
 
   VerifyNearGoal();
 }
@@ -581,14 +587,14 @@
                   .angle_shoulder(constants::Values::kShoulderRange.upper)
                   .angle_wrist(0.0)
                   .Send());
-  RunForTime(Time::InSeconds(15));
+  RunForTime(chrono::seconds(15));
 
   EXPECT_EQ(Superstructure::RUNNING, superstructure_.state());
   VerifyNearGoal();
   SimulateSensorReset();
-  RunForTime(Time::InMS(100));
+  RunForTime(chrono::milliseconds(100));
   EXPECT_NE(Superstructure::RUNNING, superstructure_.state());
-  RunForTime(Time::InMS(10000));
+  RunForTime(chrono::milliseconds(10000));
   EXPECT_EQ(Superstructure::RUNNING, superstructure_.state());
   VerifyNearGoal();
 }
@@ -605,13 +611,13 @@
           .angle_wrist(constants::Values::kWristRange.lower + 0.03)
           .Send());
 
-  RunForTime(Time::InMS(100), false);
+  RunForTime(chrono::milliseconds(100), false);
   EXPECT_EQ(0.0, superstructure_.intake_.goal(0, 0));
   EXPECT_EQ(0.0, superstructure_.arm_.goal(0, 0));
   EXPECT_EQ(0.0, superstructure_.arm_.goal(2, 0));
 
   // Now make sure they move correctly
-  RunForTime(Time::InMS(4000), true);
+  RunForTime(chrono::milliseconds(4000), true);
   EXPECT_NE(0.0, superstructure_.intake_.goal(0, 0));
   EXPECT_NE(0.0, superstructure_.arm_.goal(0, 0));
   EXPECT_NE(0.0, superstructure_.arm_.goal(2, 0));
@@ -678,7 +684,7 @@
     EXPECT_EQ(Superstructure::DISABLED_INITIALIZED, superstructure_.state());
   }
 
-  RunForTime(Time::InSeconds(10));
+  RunForTime(chrono::seconds(10));
   EXPECT_EQ(Superstructure::RUNNING, superstructure_.state());
 }
 
@@ -742,7 +748,7 @@
     EXPECT_EQ(Superstructure::DISABLED_INITIALIZED, superstructure_.state());
   }
 
-  RunForTime(Time::InSeconds(10));
+  RunForTime(chrono::seconds(10));
   EXPECT_EQ(Superstructure::LANDING_RUNNING, superstructure_.state());
 }
 
@@ -771,7 +777,7 @@
       .angle_wrist(0.0)
       .Send();
 
-  RunForTime(Time::InSeconds(8));
+  RunForTime(chrono::seconds(8));
 
   VerifyNearGoal();
 }
@@ -792,15 +798,15 @@
       .Send();
 
   // Run disabled for 2 seconds
-  RunForTime(Time::InSeconds(2), false);
+  RunForTime(chrono::seconds(2), false);
   EXPECT_EQ(Superstructure::DISABLED_INITIALIZED, superstructure_.state());
 
   superstructure_plant_.set_power_error(1.0, 1.5, 1.0);
 
-  RunForTime(Time::InSeconds(1), false);
+  RunForTime(chrono::seconds(1), false);
 
   EXPECT_EQ(Superstructure::SLOW_RUNNING, superstructure_.state());
-  RunForTime(Time::InSeconds(2), true);
+  RunForTime(chrono::seconds(2), true);
 
   VerifyNearGoal();
 }
@@ -839,7 +845,7 @@
                   .max_angular_acceleration_wrist(20)
                   .Send());
 
-  RunForTime(Time::InSeconds(6));
+  RunForTime(chrono::seconds(6));
   EXPECT_EQ(Superstructure::RUNNING, superstructure_.state());
 
   VerifyNearGoal();
@@ -862,7 +868,7 @@
   set_peak_intake_acceleration(1.10);
   set_peak_shoulder_acceleration(1.20);
   set_peak_wrist_acceleration(1.10);
-  RunForTime(Time::InSeconds(6));
+  RunForTime(chrono::seconds(6));
 
   VerifyNearGoal();
 }
@@ -881,7 +887,7 @@
                   .max_angular_acceleration_wrist(20)
                   .Send());
 
-  RunForTime(Time::InSeconds(6));
+  RunForTime(chrono::seconds(6));
   EXPECT_EQ(Superstructure::RUNNING, superstructure_.state());
 
   VerifyNearGoal();
@@ -901,7 +907,7 @@
   set_peak_intake_acceleration(1.20);
   set_peak_shoulder_acceleration(1.20);
   set_peak_wrist_acceleration(1.20);
-  RunForTime(Time::InSeconds(4));
+  RunForTime(chrono::seconds(4));
 
   VerifyNearGoal();
 }
@@ -923,7 +929,7 @@
           .max_angular_acceleration_wrist(20)
           .Send());
 
-  RunForTime(Time::InSeconds(6));
+  RunForTime(chrono::seconds(6));
   EXPECT_EQ(Superstructure::RUNNING, superstructure_.state());
 
   VerifyNearGoal();
@@ -946,7 +952,7 @@
   set_peak_intake_acceleration(1.05);
   set_peak_shoulder_acceleration(1.05);
   set_peak_wrist_acceleration(1.05);
-  RunForTime(Time::InSeconds(4));
+  RunForTime(chrono::seconds(4));
 
   VerifyNearGoal();
 }
@@ -968,7 +974,7 @@
           .max_angular_acceleration_wrist(20)
           .Send());
 
-  RunForTime(Time::InSeconds(6));
+  RunForTime(chrono::seconds(6));
   EXPECT_EQ(Superstructure::RUNNING, superstructure_.state());
 
   VerifyNearGoal();
@@ -990,7 +996,7 @@
   set_peak_intake_velocity(4.65);
   set_peak_shoulder_velocity(1.00);
   set_peak_wrist_velocity(1.00);
-  RunForTime(Time::InSeconds(4));
+  RunForTime(chrono::seconds(4));
 
   VerifyNearGoal();
 }
@@ -1010,7 +1016,7 @@
                   .max_angular_acceleration_wrist(20)
                   .Send());
 
-  RunForTime(Time::InSeconds(6));
+  RunForTime(chrono::seconds(6));
   EXPECT_EQ(Superstructure::RUNNING, superstructure_.state());
 
   VerifyNearGoal();
@@ -1030,7 +1036,7 @@
   set_peak_intake_velocity(1.0);
   set_peak_shoulder_velocity(5.5);
   set_peak_wrist_velocity(1.0);
-  RunForTime(Time::InSeconds(4));
+  RunForTime(chrono::seconds(4));
 
   VerifyNearGoal();
 }
@@ -1053,7 +1059,7 @@
           .max_angular_acceleration_wrist(20)
           .Send());
 
-  RunForTime(Time::InSeconds(6));
+  RunForTime(chrono::seconds(6));
   EXPECT_EQ(Superstructure::RUNNING, superstructure_.state());
 
   VerifyNearGoal();
@@ -1076,7 +1082,7 @@
   set_peak_intake_velocity(1.0);
   set_peak_shoulder_velocity(1.0);
   set_peak_wrist_velocity(10.2);
-  RunForTime(Time::InSeconds(4));
+  RunForTime(chrono::seconds(4));
 
   VerifyNearGoal();
 }
@@ -1096,7 +1102,7 @@
           .angle_wrist(0.0)                                         // Stowed
           .Send());
 
-  RunForTime(Time::InSeconds(15));
+  RunForTime(chrono::seconds(15));
 
   ASSERT_TRUE(
       superstructure_queue_.goal.MakeWithBuilder()
@@ -1105,7 +1111,7 @@
           .angle_wrist(M_PI / 2.0)     // down
           .Send());
 
-  RunForTime(Time::InSeconds(5));
+  RunForTime(chrono::seconds(5));
 
   superstructure_queue_.status.FetchLatest();
   ASSERT_TRUE(superstructure_queue_.status.get() != nullptr);
@@ -1133,7 +1139,7 @@
           .angle_wrist(M_PI)     // forward
           .Send());
 
-  RunForTime(Time::InSeconds(5));
+  RunForTime(chrono::seconds(5));
   VerifyNearGoal();
 }
 
@@ -1150,7 +1156,7 @@
                   .angle_wrist(M_PI)  // intentionally asking for forward
                   .Send());
 
-  RunForTime(Time::InSeconds(15));
+  RunForTime(chrono::seconds(15));
 
   superstructure_queue_.status.FetchLatest();
   ASSERT_TRUE(superstructure_queue_.status.get() != nullptr);
@@ -1173,7 +1179,7 @@
                   .angle_wrist(0.0)
                   .Send());
 
-  RunForTime(Time::InSeconds(6));
+  RunForTime(chrono::seconds(6));
   VerifyNearGoal();
 
   // Since we're explicitly checking for collisions, we don't want to fail the
@@ -1186,7 +1192,7 @@
   while (!collided()) {
     RunIteration(false);
   }
-  RunForTime(Time::InSeconds(0.5), false);  // Move a bit further down.
+  RunForTime(chrono::milliseconds(500), false);  // Move a bit further down.
 
   ASSERT_TRUE(collided());
   EXPECT_EQ(Superstructure::SLOW_RUNNING, superstructure_.state());
@@ -1194,7 +1200,7 @@
 
   // Make sure that the collision avoidance will properly move the limbs out of
   // the collision area.
-  RunForTime(Time::InSeconds(10));
+  RunForTime(chrono::seconds(10));
   ASSERT_FALSE(collided());
   EXPECT_EQ(Superstructure::RUNNING, superstructure_.state());
 }
@@ -1208,7 +1214,7 @@
                   .angle_wrist(0.0)
                   .Send());
 
-  RunForTime(Time::InSeconds(6));
+  RunForTime(chrono::seconds(6));
   VerifyNearGoal();
 
   // Since we're explicitly checking for collisions, we don't want to fail the
@@ -1227,7 +1233,7 @@
   // Make sure that the collision avoidance will properly move the limbs out of
   // the collision area.
   superstructure_plant_.set_power_error(0.0, 0.0, 0.0);
-  RunForTime(Time::InSeconds(3));
+  RunForTime(chrono::seconds(3));
   ASSERT_FALSE(collided());
   EXPECT_EQ(Superstructure::LANDING_RUNNING, superstructure_.state());
 }
@@ -1245,17 +1251,17 @@
                   .angle_wrist(0.0)  // intentionally asking for forward
                   .Send());
 
-  RunForTime(Time::InSeconds(6));
+  RunForTime(chrono::seconds(6));
   VerifyNearGoal();
 
   // If we are near the bottom of the range, we won't have enough power to
   // compensate for the offset.  This means that we fail if we get to the goal.
   superstructure_plant_.set_power_error(
       0.0, -Superstructure::kLandingShoulderDownVoltage, 0.0);
-  RunForTime(Time::InSeconds(2));
+  RunForTime(chrono::seconds(2));
   superstructure_plant_.set_power_error(
       0.0, -2.0 * Superstructure::kLandingShoulderDownVoltage, 0.0);
-  RunForTime(Time::InSeconds(2));
+  RunForTime(chrono::seconds(2));
   EXPECT_LE(constants::Values::kShoulderRange.lower,
             superstructure_queue_.goal->angle_shoulder);
 }
@@ -1268,7 +1274,7 @@
                   .angle_shoulder(M_PI * 0.25)
                   .angle_wrist(0.0)
                   .Send());
-  RunForTime(Time::InSeconds(8));
+  RunForTime(chrono::seconds(8));
 
   // Tell it to land in the bellypan as fast as possible.
   ASSERT_TRUE(superstructure_queue_.goal.MakeWithBuilder()
@@ -1291,7 +1297,7 @@
            Superstructure::kShoulderTransitionToLanded);
 
   set_peak_shoulder_velocity(0.55);
-  RunForTime(Time::InSeconds(4));
+  RunForTime(chrono::seconds(4));
 }
 
 // Make sure that we quickly take off from a land.
@@ -1302,7 +1308,7 @@
                   .angle_shoulder(0.0)
                   .angle_wrist(0.0)
                   .Send());
-  RunForTime(Time::InSeconds(8));
+  RunForTime(chrono::seconds(8));
 
   // Tell it to take off as fast as possible.
   ASSERT_TRUE(superstructure_queue_.goal.MakeWithBuilder()
diff --git a/y2016/dashboard/dashboard.cc b/y2016/dashboard/dashboard.cc
index 16ad077..798c08b 100644
--- a/y2016/dashboard/dashboard.cc
+++ b/y2016/dashboard/dashboard.cc
@@ -1,11 +1,12 @@
 #include "y2016/dashboard/dashboard.h"
 
+#include <chrono>
+#include <complex>
 #include <iostream>
 #include <sstream>
 #include <string>
 #include <thread>
 #include <vector>
-#include <complex>
 
 #include "seasocks/Server.h"
 
@@ -22,6 +23,8 @@
 
 #include "y2016/dashboard/embedded.h"
 
+namespace chrono = ::std::chrono;
+
 namespace y2016 {
 namespace dashboard {
 namespace big_indicator {
@@ -139,7 +142,7 @@
 
   size_t index = GetIndex(sample_id_);
 
-  ItemDatapoint datapoint{value, ::aos::time::Time::Now()};
+  ItemDatapoint datapoint{value, ::aos::monotonic_clock::now()};
   if (measure_index_ >= sample_items_.size()) {
     // New item in our data table.
     ::std::vector<ItemDatapoint> datapoints;
@@ -194,9 +197,12 @@
     if (static_cast<size_t>(adjusted_index) <
         sample_items_.at(0).datapoints.size()) {
       message << cur_sample << "%"
-              << sample_items_.at(0)
-                     .datapoints.at(adjusted_index)
-                     .time.ToSeconds() << "%";  // Send time.
+              << chrono::duration_cast<chrono::duration<double>>(
+                     sample_items_.at(0)
+                         .datapoints.at(adjusted_index)
+                         .time.time_since_epoch())
+                     .count()
+              << "%";  // Send time.
       // Add comma-separated list of data points.
       for (size_t cur_measure = 0; cur_measure < sample_items_.size();
            cur_measure++) {
@@ -220,8 +226,10 @@
 void DataCollector::operator()() {
   ::aos::SetCurrentThreadName("DashboardData");
 
+  ::aos::time::PhasedLoop phased_loop(chrono::milliseconds(100),
+                                      chrono::seconds(0));
   while (run_) {
-    ::aos::time::PhasedLoopXMS(100, 0);
+    phased_loop.SleepUntilNext();
     RunIteration();
   }
 }
diff --git a/y2016/dashboard/dashboard.h b/y2016/dashboard/dashboard.h
index 003820c..e093cb9 100644
--- a/y2016/dashboard/dashboard.h
+++ b/y2016/dashboard/dashboard.h
@@ -52,7 +52,7 @@
 
   struct ItemDatapoint {
     double value;
-    ::aos::time::Time time;
+    ::aos::monotonic_clock::time_point time;
   };
 
   struct SampleItem {
diff --git a/y2016/vision/target_receiver.cc b/y2016/vision/target_receiver.cc
index 802c6e7..7ade8e7 100644
--- a/y2016/vision/target_receiver.cc
+++ b/y2016/vision/target_receiver.cc
@@ -201,8 +201,7 @@
       status.FetchAnother();
 
       ::aos::MutexLocker locker(&lock_);
-      data_[data_index_].time = monotonic_clock::time_point(
-          chrono::nanoseconds(status->sent_time.ToNSec()));
+      data_[data_index_].time = status->sent_time;
       data_[data_index_].left = status->estimated_left_position;
       data_[data_index_].right = status->estimated_right_position;
       ++data_index_;
diff --git a/y2016/vision/vision.q b/y2016/vision/vision.q
index 872c9ae..47906dc 100644
--- a/y2016/vision/vision.q
+++ b/y2016/vision/vision.q
@@ -23,7 +23,7 @@
   // The angle in radians of the bottom of the target.
   double angle;
 
-  // Capture time of the angle using the clock behind Time::Now().
+  // Capture time of the angle using the clock behind monotonic_clock::now().
   int64_t target_time;
 
   // The estimated positions of both sides of the drivetrain when the frame
diff --git a/y2016_bot3/actors/autonomous_actor_main.cc b/y2016_bot3/actors/autonomous_actor_main.cc
index 43cbbe8..8009a74 100644
--- a/y2016_bot3/actors/autonomous_actor_main.cc
+++ b/y2016_bot3/actors/autonomous_actor_main.cc
@@ -4,8 +4,6 @@
 #include "y2016_bot3/actors/autonomous_action.q.h"
 #include "y2016_bot3/actors/autonomous_actor.h"
 
-using ::aos::time::Time;
-
 int main(int /*argc*/, char * /*argv*/ []) {
   ::aos::Init(-1);
 
diff --git a/y2016_bot3/wpilib/wpilib_interface.cc b/y2016_bot3/wpilib/wpilib_interface.cc
index 3d7d8ce..5204aea 100644
--- a/y2016_bot3/wpilib/wpilib_interface.cc
+++ b/y2016_bot3/wpilib/wpilib_interface.cc
@@ -171,7 +171,7 @@
     dma_synchronizer_->Start();
 
     ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
-                                        ::std::chrono::milliseconds(4));
+                                        ::std::chrono::milliseconds(0));
 
     ::aos::SetCurrentThreadRealtimePriority(40);
     while (run_) {