diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index 01b87b425d..f8bb345f22 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/Ryujinx.HLE/HOS/Horizon.cs
@@ -199,7 +199,7 @@ namespace Ryujinx.HLE.HOS
 
             // TODO: use set:sys (and set external clock source id from settings)
             // TODO: use "time!standard_steady_clock_rtc_update_interval_minutes" and implement a worker thread to be accurate.
-            SteadyClockCore.Instance.ConfigureSetupValue();
+            StandardSteadyClockCore.Instance.ConfigureSetupValue();
 
             if (Services.Set.NxSettings.Settings.TryGetValue("time!standard_network_clock_sufficient_accuracy_minutes", out object standardNetworkClockSufficientAccuracyMinutes))
             {
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs
index 860f5ad2bb..c70819c003 100644
--- a/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/ClockTypes.cs
@@ -7,6 +7,8 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
     [StructLayout(LayoutKind.Sequential)]
     struct TimeSpanType
     {
+        private const long NanoSecondsPerSecond = 1000000000;
+
         public long NanoSeconds;
 
         public TimeSpanType(long nanoSeconds)
@@ -16,12 +18,17 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
 
         public long ToSeconds()
         {
-            return NanoSeconds / 1000000000;
+            return NanoSeconds / NanoSecondsPerSecond;
+        }
+
+        public static TimeSpanType FromSeconds(long seconds)
+        {
+            return new TimeSpanType(seconds * NanoSecondsPerSecond);
         }
 
         public static TimeSpanType FromTicks(ulong ticks, ulong frequency)
         {
-            return new TimeSpanType((long)ticks * 1000000000 / (long)frequency);
+            return FromSeconds((long)ticks / (long)frequency);
         }
     }
 
@@ -59,4 +66,40 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
         public long                 Offset;
         public SteadyClockTimePoint SteadyTimePoint;
     }
+
+    [StructLayout(LayoutKind.Sequential, Size = 0xD0)]
+    struct ClockSnapshot
+    {
+        public SystemClockContext     UserContext;
+        public SystemClockContext     NetworkContext;
+        public long                   UserTime;
+        public long                   NetworkTime;
+        public CalendarTime           UserCalendarTime;
+        public CalendarTime           NetworkCalendarTime;
+        public CalendarAdditionalInfo UserCalendarAdditionalTime;
+        public CalendarAdditionalInfo NetworkCalendarAdditionalTime;
+        public SteadyClockTimePoint   SteadyClockTimePoint;
+
+        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x24)]
+        public char[] LocationName;
+
+        [MarshalAs(UnmanagedType.I1)]
+        public bool   IsAutomaticCorrectionEnabled;
+        public byte   Type;
+        public ushort Unknown;
+
+        public static ResultCode GetCurrentTime(out long currentTime, SteadyClockTimePoint steadyClockTimePoint, SystemClockContext context)
+        {
+            currentTime = 0;
+
+            if (steadyClockTimePoint.ClockSourceId == context.SteadyTimePoint.ClockSourceId)
+            {
+                currentTime = steadyClockTimePoint.TimePoint + context.Offset;
+
+                return ResultCode.Success;
+            }
+
+            return ResultCode.TimeMismatch;
+        }
+    }
 }
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockCore.cs
new file mode 100644
index 0000000000..8e9073a40a
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/EphemeralNetworkSystemClockCore.cs
@@ -0,0 +1,27 @@
+namespace Ryujinx.HLE.HOS.Services.Time.Clock
+{
+    class EphemeralNetworkSystemClockCore : SystemClockCore
+    {
+        private static EphemeralNetworkSystemClockCore _instance;
+
+        public static EphemeralNetworkSystemClockCore Instance
+        {
+            get
+            {
+                if (_instance == null)
+                {
+                    _instance = new EphemeralNetworkSystemClockCore(TickBasedSteadyClockCore.Instance);
+                }
+
+                return _instance;
+            }
+        }
+
+        public EphemeralNetworkSystemClockCore(SteadyClockCore steadyClockCore) : base(steadyClockCore) { }
+
+        public override ResultCode Flush(SystemClockContext context)
+        {
+            return ResultCode.Success;
+        }
+    }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs
index 16550199b3..a172797608 100644
--- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardLocalSystemClockCore.cs
@@ -1,34 +1,23 @@
-using Ryujinx.HLE.HOS.Kernel.Threading;
-
-namespace Ryujinx.HLE.HOS.Services.Time.Clock
+namespace Ryujinx.HLE.HOS.Services.Time.Clock
 {
     class StandardLocalSystemClockCore : SystemClockCore
     {
-        private SteadyClockCore    _steadyClockCore;
-        private SystemClockContext _context;
-
-        private static StandardLocalSystemClockCore instance;
+        private static StandardLocalSystemClockCore _instance;
 
         public static StandardLocalSystemClockCore Instance
         {
             get
             {
-                if (instance == null)
+                if (_instance == null)
                 {
-                    instance = new StandardLocalSystemClockCore(SteadyClockCore.Instance);
+                    _instance = new StandardLocalSystemClockCore(StandardSteadyClockCore.Instance);
                 }
 
-                return instance;
+                return _instance;
             }
         }
 
-        public StandardLocalSystemClockCore(SteadyClockCore steadyClockCore)
-        {
-            _steadyClockCore = steadyClockCore;
-            _context         = new SystemClockContext();
-
-            _context.SteadyTimePoint.ClockSourceId = steadyClockCore.GetClockSourceId();
-        }
+        public StandardLocalSystemClockCore(StandardSteadyClockCore steadyClockCore) : base(steadyClockCore) {}
 
         public override ResultCode Flush(SystemClockContext context)
         {
@@ -36,24 +25,5 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
 
             return ResultCode.Success;
         }
-
-        public override SteadyClockCore GetSteadyClockCore()
-        {
-            return _steadyClockCore;
-        }
-
-        public override ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context)
-        {
-            context = _context;
-
-            return ResultCode.Success;
-        }
-
-        public override ResultCode SetSystemClockContext(SystemClockContext context)
-        {
-            _context = context;
-
-            return ResultCode.Success;
-        }
     }
 }
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs
index c00f460ef5..5037fb6006 100644
--- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs
@@ -1,35 +1,28 @@
-using System;
-using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.HLE.HOS.Kernel.Threading;
 
 namespace Ryujinx.HLE.HOS.Services.Time.Clock
 {
     class StandardNetworkSystemClockCore : SystemClockCore
     {
-        private SteadyClockCore    _steadyClockCore;
-        private SystemClockContext _context;
         private TimeSpanType       _standardNetworkClockSufficientAccuracy;
 
-        private static StandardNetworkSystemClockCore instance;
+        private static StandardNetworkSystemClockCore _instance;
 
         public static StandardNetworkSystemClockCore Instance
         {
             get
             {
-                if (instance == null)
+                if (_instance == null)
                 {
-                    instance = new StandardNetworkSystemClockCore(SteadyClockCore.Instance);
+                    _instance = new StandardNetworkSystemClockCore(StandardSteadyClockCore.Instance);
                 }
 
-                return instance;
+                return _instance;
             }
         }
 
-        public StandardNetworkSystemClockCore(SteadyClockCore steadyClockCore)
+        public StandardNetworkSystemClockCore(StandardSteadyClockCore steadyClockCore) : base(steadyClockCore)
         {
-            _steadyClockCore = steadyClockCore;
-            _context         = new SystemClockContext();
-
-            _context.SteadyTimePoint.ClockSourceId  = steadyClockCore.GetClockSourceId();
             _standardNetworkClockSufficientAccuracy = new TimeSpanType(0);
         }
 
@@ -40,25 +33,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
             return ResultCode.Success;
         }
 
-        public override SteadyClockCore GetSteadyClockCore()
-        {
-            return _steadyClockCore;
-        }
-
-        public override ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context)
-        {
-            context = _context;
-
-            return ResultCode.Success;
-        }
-
-        public override ResultCode SetSystemClockContext(SystemClockContext context)
-        {
-            _context = context;
-
-            return ResultCode.Success;
-        }
-
         public bool IsStandardNetworkSystemClockAccuracySufficient(KThread thread)
         {
             SteadyClockCore      steadyClockCore  = GetSteadyClockCore();
@@ -66,7 +40,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
 
             bool isStandardNetworkClockSufficientAccuracy = false;
 
-            if (_context.SteadyTimePoint.GetSpanBetween(currentTimePoint, out long outSpan) == ResultCode.Success)
+            ResultCode result = GetSystemClockContext(thread, out SystemClockContext context);
+
+            if (result == ResultCode.Success && context.SteadyTimePoint.GetSpanBetween(currentTimePoint, out long outSpan) == ResultCode.Success)
             {
                 isStandardNetworkClockSufficientAccuracy = outSpan * 1000000000 < _standardNetworkClockSufficientAccuracy.NanoSeconds;
             }
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs
new file mode 100644
index 0000000000..fea5bf2f6b
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs
@@ -0,0 +1,107 @@
+using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.HLE.HOS.Services.Bpc;
+
+namespace Ryujinx.HLE.HOS.Services.Time.Clock
+{
+    class StandardSteadyClockCore : SteadyClockCore
+    {
+        private long         _setupValue;
+        private ResultCode   _setupResultCode;
+        private bool         _isRtcResetDetected;
+        private TimeSpanType _testOffset;
+        private TimeSpanType _internalOffset;
+
+        private static StandardSteadyClockCore _instance;
+
+        public static StandardSteadyClockCore Instance
+        {
+            get
+            {
+                if (_instance == null)
+                {
+                    _instance = new StandardSteadyClockCore();
+                }
+
+                return _instance;
+            }
+        }
+
+        private StandardSteadyClockCore()
+        {
+            _testOffset     = new TimeSpanType(0);
+            _internalOffset = new TimeSpanType(0);
+        }
+
+        public override SteadyClockTimePoint GetTimePoint(KThread thread)
+        {
+            SteadyClockTimePoint result = new SteadyClockTimePoint
+            {
+                TimePoint     = 0,
+                ClockSourceId = GetClockSourceId()
+            };
+
+            TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.ThreadState.CntpctEl0, thread.Context.ThreadState.CntfrqEl0);
+
+            result.TimePoint = _setupValue + ticksTimeSpan.ToSeconds();
+
+            return result;
+        }
+
+        public override TimeSpanType GetTestOffset()
+        {
+            return _testOffset;
+        }
+
+        public override void SetTestOffset(TimeSpanType testOffset)
+        {
+            _testOffset = testOffset;
+        }
+
+        public override ResultCode GetRtcValue(out ulong rtcValue)
+        {
+            return (ResultCode)IRtcManager.GetExternalRtcValue(out rtcValue);
+        }
+
+        public bool IsRtcResetDetected()
+        {
+            return _isRtcResetDetected;
+        }
+
+        public override TimeSpanType GetInternalOffset()
+        {
+            return _internalOffset;
+        }
+
+        public override void SetInternalOffset(TimeSpanType internalOffset)
+        {
+            _internalOffset = internalOffset;
+        }
+
+        public override ResultCode GetSetupResultValue()
+        {
+            return _setupResultCode;
+        }
+
+        public void ConfigureSetupValue()
+        {
+            int retry = 0;
+
+            ResultCode result = ResultCode.Success;
+
+            while (retry < 20)
+            {
+                result = (ResultCode)IRtcManager.GetExternalRtcValue(out ulong rtcValue);
+
+                if (result == ResultCode.Success)
+                {
+                    _setupValue = (long)rtcValue;
+                    break;
+                }
+
+                retry++;
+            }
+
+            _setupResultCode = result;
+        }
+    }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs
index 00f296ad07..c98b0064b6 100644
--- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs
@@ -8,22 +8,22 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
         private StandardNetworkSystemClockCore _networkSystemClockCore;
         private bool                           _autoCorrectionEnabled;
 
-        private static StandardUserSystemClockCore instance;
+        private static StandardUserSystemClockCore _instance;
 
         public static StandardUserSystemClockCore Instance
         {
             get
             {
-                if (instance == null)
+                if (_instance == null)
                 {
-                    instance = new StandardUserSystemClockCore(StandardLocalSystemClockCore.Instance, StandardNetworkSystemClockCore.Instance);
+                    _instance = new StandardUserSystemClockCore(StandardLocalSystemClockCore.Instance, StandardNetworkSystemClockCore.Instance);
                 }
 
-                return instance;
+                return _instance;
             }
         }
 
-        public StandardUserSystemClockCore(StandardLocalSystemClockCore localSystemClockCore, StandardNetworkSystemClockCore networkSystemClockCore)
+        public StandardUserSystemClockCore(StandardLocalSystemClockCore localSystemClockCore, StandardNetworkSystemClockCore networkSystemClockCore) : base(localSystemClockCore.GetSteadyClockCore())
         {
             _localSystemClockCore   = localSystemClockCore;
             _networkSystemClockCore = networkSystemClockCore;
@@ -35,11 +35,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
             return ResultCode.NotImplemented;
         }
 
-        public override SteadyClockCore GetSteadyClockCore()
-        {
-            return _localSystemClockCore.GetSteadyClockCore();
-        }
-
         public override ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context)
         {
             ResultCode result = ApplyAutomaticCorrection(thread, false);
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs
index e661ab5380..54d9accf4f 100644
--- a/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs
@@ -1,54 +1,16 @@
 using Ryujinx.HLE.HOS.Kernel.Threading;
-using Ryujinx.HLE.HOS.Services.Bpc;
 using Ryujinx.HLE.Utilities;
 using System;
 
 namespace Ryujinx.HLE.HOS.Services.Time.Clock
 {
-    class SteadyClockCore
+    abstract class SteadyClockCore
     {
-        private long         _setupValue;
-        private ResultCode   _setupResultCode;
-        private bool         _isRtcResetDetected;
-        private TimeSpanType _testOffset;
-        private TimeSpanType _internalOffset;
-        private UInt128      _clockSourceId;
+        private UInt128 _clockSourceId;
 
-        private static SteadyClockCore instance;
-
-        public static SteadyClockCore Instance
+        public SteadyClockCore()
         {
-            get
-            {
-                if (instance == null)
-                {
-                    instance = new SteadyClockCore();
-                }
-
-                return instance;
-            }
-        }
-
-        private SteadyClockCore()
-        {
-            _testOffset     = new TimeSpanType(0);
-            _internalOffset = new TimeSpanType(0);
-            _clockSourceId  = new UInt128(Guid.NewGuid().ToByteArray());
-        }
-
-        private SteadyClockTimePoint GetTimePoint(KThread thread)
-        {
-            SteadyClockTimePoint result = new SteadyClockTimePoint
-            {
-                TimePoint     = 0,
-                ClockSourceId = _clockSourceId
-            };
-
-            TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.ThreadState.CntpctEl0, thread.Context.ThreadState.CntfrqEl0);
-
-            result.TimePoint = _setupValue + ticksTimeSpan.ToSeconds();
-
-            return result;
+            _clockSourceId = new UInt128(Guid.NewGuid().ToByteArray());
         }
 
         public UInt128 GetClockSourceId()
@@ -56,76 +18,45 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
             return _clockSourceId;
         }
 
+        public virtual TimeSpanType GetTestOffset()
+        {
+            return new TimeSpanType(0);
+        }
+
+        public virtual void SetTestOffset(TimeSpanType testOffset) {}
+
+        public virtual ResultCode GetRtcValue(out ulong rtcValue)
+        {
+            rtcValue = 0;
+
+            return ResultCode.NotImplemented;
+        }
+
+        public virtual ResultCode GetSetupResultValue()
+        {
+            return ResultCode.NotImplemented;
+        }
+
+        public virtual TimeSpanType GetInternalOffset()
+        {
+            return new TimeSpanType(0);
+        }
+
+        public virtual void SetInternalOffset(TimeSpanType internalOffset) {}
+
+        public virtual SteadyClockTimePoint GetTimePoint(KThread thread)
+        {
+            throw new NotImplementedException();
+        }
+
         public SteadyClockTimePoint GetCurrentTimePoint(KThread thread)
         {
             SteadyClockTimePoint result = GetTimePoint(thread);
 
-            result.TimePoint += _testOffset.ToSeconds();
-            result.TimePoint += _internalOffset.ToSeconds();
+            result.TimePoint += GetTestOffset().ToSeconds();
+            result.TimePoint += GetInternalOffset().ToSeconds();
 
             return result;
         }
-
-        public TimeSpanType GetTestOffset()
-        {
-            return _testOffset;
-        }
-
-        public void SetTestOffset(TimeSpanType testOffset)
-        {
-            _testOffset = testOffset;
-        }
-
-        public ResultCode GetRtcValue(out ulong rtcValue)
-        {
-            return (ResultCode)IRtcManager.GetExternalRtcValue(out rtcValue);
-        }
-
-        public bool IsRtcResetDetected()
-        {
-            return _isRtcResetDetected;
-        }
-
-        public ResultCode GetSetupResultCode()
-        {
-            return _setupResultCode;
-        }
-
-        public TimeSpanType GetInternalOffset()
-        {
-            return _internalOffset;
-        }
-
-        public void SetInternalOffset(TimeSpanType internalOffset)
-        {
-            _internalOffset = internalOffset;
-        }
-
-        public ResultCode GetSetupResultValue()
-        {
-            return _setupResultCode;
-        }
-
-        public void ConfigureSetupValue()
-        {
-            int retry = 0;
-
-            ResultCode result = ResultCode.Success;
-
-            while (retry < 20)
-            {
-                result = (ResultCode)IRtcManager.GetExternalRtcValue(out ulong rtcValue);
-
-                if (result == ResultCode.Success)
-                {
-                    _setupValue = (long)rtcValue;
-                    break;
-                }
-
-                retry++;
-            }
-
-            _setupResultCode = result;
-        }
     }
 }
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs
index d3a056e438..52f3c9083c 100644
--- a/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs
@@ -4,11 +4,35 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
 {
     abstract class SystemClockCore
     {
-        public abstract SteadyClockCore GetSteadyClockCore();
+        private SteadyClockCore    _steadyClockCore;
+        private SystemClockContext _context;
 
-        public abstract ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context);
+        public SystemClockCore(SteadyClockCore steadyClockCore)
+        {
+            _steadyClockCore = steadyClockCore;
+            _context         = new SystemClockContext();
 
-        public abstract ResultCode SetSystemClockContext(SystemClockContext context);
+            _context.SteadyTimePoint.ClockSourceId = steadyClockCore.GetClockSourceId();
+        }
+
+        public virtual SteadyClockCore GetSteadyClockCore()
+        {
+            return _steadyClockCore;
+        }
+
+        public virtual ResultCode GetSystemClockContext(KThread thread, out SystemClockContext context)
+        {
+            context = _context;
+
+            return ResultCode.Success;
+        }
+
+        public virtual ResultCode SetSystemClockContext(SystemClockContext context)
+        {
+            _context = context;
+
+            return ResultCode.Success;
+        }
 
         public abstract ResultCode Flush(SystemClockContext context);
 
diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs
new file mode 100644
index 0000000000..7a69b014bc
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs
@@ -0,0 +1,40 @@
+using Ryujinx.Common;
+using Ryujinx.HLE.HOS.Kernel.Threading;
+
+namespace Ryujinx.HLE.HOS.Services.Time.Clock
+{
+    class TickBasedSteadyClockCore : SteadyClockCore
+    {
+        private static TickBasedSteadyClockCore _instance;
+
+        public static TickBasedSteadyClockCore Instance
+        {
+            get
+            {
+                if (_instance == null)
+                {
+                    _instance = new TickBasedSteadyClockCore();
+                }
+
+                return _instance;
+            }
+        }
+
+        private TickBasedSteadyClockCore() {}
+
+        public override SteadyClockTimePoint GetTimePoint(KThread thread)
+        {
+            SteadyClockTimePoint result = new SteadyClockTimePoint
+            {
+                TimePoint     = 0,
+                ClockSourceId = GetClockSourceId()
+            };
+
+            TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.ThreadState.CntpctEl0, thread.Context.ThreadState.CntfrqEl0);
+
+            result.TimePoint = ticksTimeSpan.ToSeconds();
+
+            return result;
+        }
+    }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs
index 8c5ae65c6c..9ee038d586 100644
--- a/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/IStaticService.cs
@@ -1,7 +1,13 @@
+using Ryujinx.Common;
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.HOS.Services.Time.Clock;
+using Ryujinx.HLE.HOS.Services.Time.TimeZone;
 using System;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
 
 namespace Ryujinx.HLE.HOS.Services.Time
 {
@@ -66,6 +72,15 @@ namespace Ryujinx.HLE.HOS.Services.Time
             return ResultCode.Success;
         }
 
+        [Command(5)] // 4.0.0+
+        // GetEphemeralNetworkSystemClock() -> object<nn::timesrv::detail::service::ISystemClock>
+        public ResultCode GetEphemeralNetworkSystemClock(ServiceCtx context)
+        {
+            MakeObject(context, new ISystemClock(StandardNetworkSystemClockCore.Instance, false));
+
+            return ResultCode.Success;
+        }
+
         [Command(20)] // 6.0.0+
         // GetSharedMemoryNativeHandle() -> handle<copy>
         public ResultCode GetSharedMemoryNativeHandle(ServiceCtx context)
@@ -116,16 +131,202 @@ namespace Ryujinx.HLE.HOS.Services.Time
         }
 
         [Command(300)] // 4.0.0+
-        // CalculateMonotonicSystemClockBaseTimePoint(nn::time::SystemClockContext) -> u64
+        // CalculateMonotonicSystemClockBaseTimePoint(nn::time::SystemClockContext) -> s64
         public ResultCode CalculateMonotonicSystemClockBaseTimePoint(ServiceCtx context)
         {
-            // TODO: reimplement this
-            long timeOffset              = (long)(DateTime.UtcNow - StartupDate).TotalSeconds;
-            long systemClockContextEpoch = context.RequestData.ReadInt64();
+            SystemClockContext   otherContext     = context.RequestData.ReadStruct<SystemClockContext>();
+            SteadyClockTimePoint currentTimePoint = StandardSteadyClockCore.Instance.GetCurrentTimePoint(context.Thread);
 
-            context.ResponseData.Write(timeOffset + systemClockContextEpoch);
+            ResultCode result = ResultCode.TimeMismatch;
+
+            if (currentTimePoint.ClockSourceId == otherContext.SteadyTimePoint.ClockSourceId)
+            {
+                TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(context.Thread.Context.ThreadState.CntpctEl0, context.Thread.Context.ThreadState.CntfrqEl0);
+                long         baseTimePoint = otherContext.Offset + currentTimePoint.TimePoint - ticksTimeSpan.ToSeconds();
+
+                context.ResponseData.Write(baseTimePoint);
+
+                result = 0;
+            }
+
+            return result;
+        }
+
+        [Command(400)] // 4.0.0+
+        // GetClockSnapshot(u8) -> buffer<nn::time::sf::ClockSnapshot, 0x1a>
+        public ResultCode GetClockSnapshot(ServiceCtx context)
+        {
+            byte type = context.RequestData.ReadByte();
+
+            ResultCode result = StandardUserSystemClockCore.Instance.GetSystemClockContext(context.Thread, out SystemClockContext userContext);
+
+            if (result == ResultCode.Success)
+            {
+                result = StandardNetworkSystemClockCore.Instance.GetSystemClockContext(context.Thread, out SystemClockContext networkContext);
+
+                if (result == ResultCode.Success)
+                {
+                    result = GetClockSnapshotFromSystemClockContextInternal(context.Thread, userContext, networkContext, type, out ClockSnapshot clockSnapshot);
+
+                    if (result == ResultCode.Success)
+                    {
+                        WriteClockSnapshotFromBuffer(context, context.Request.RecvListBuff[0], clockSnapshot);
+                    }
+                }
+            }
+
+            return result;
+        }
+
+        [Command(401)] // 4.0.0+
+        // GetClockSnapshotFromSystemClockContext(u8, nn::time::SystemClockContext, nn::time::SystemClockContext) -> buffer<nn::time::sf::ClockSnapshot, 0x1a>
+        public ResultCode GetClockSnapshotFromSystemClockContext(ServiceCtx context)
+        {
+            byte type = context.RequestData.ReadByte();
+
+            context.RequestData.BaseStream.Position += 7;
+
+            SystemClockContext userContext    = context.RequestData.ReadStruct<SystemClockContext>();
+            SystemClockContext networkContext = context.RequestData.ReadStruct<SystemClockContext>();
+
+            ResultCode result = GetClockSnapshotFromSystemClockContextInternal(context.Thread, userContext, networkContext, type, out ClockSnapshot clockSnapshot);
+
+            if (result == ResultCode.Success)
+            {
+                WriteClockSnapshotFromBuffer(context, context.Request.RecvListBuff[0], clockSnapshot);
+            }
+
+            return result;
+        }
+
+        [Command(500)] // 4.0.0+
+        // CalculateStandardUserSystemClockDifferenceByUser(buffer<nn::time::sf::ClockSnapshot, 0x19>, buffer<nn::time::sf::ClockSnapshot, 0x19>) -> nn::TimeSpanType
+        public ResultCode CalculateStandardUserSystemClockDifferenceByUser(ServiceCtx context)
+        {
+
+            ClockSnapshot clockSnapshotA = ReadClockSnapshotFromBuffer(context, context.Request.ExchangeBuff[0]);
+            ClockSnapshot clockSnapshotB = ReadClockSnapshotFromBuffer(context, context.Request.ExchangeBuff[1]);
+            TimeSpanType  difference     = TimeSpanType.FromSeconds(clockSnapshotB.UserContext.Offset - clockSnapshotA.UserContext.Offset);
+
+            if (clockSnapshotB.UserContext.SteadyTimePoint.ClockSourceId != clockSnapshotA.UserContext.SteadyTimePoint.ClockSourceId || (clockSnapshotB.IsAutomaticCorrectionEnabled && clockSnapshotA.IsAutomaticCorrectionEnabled))
+            {
+                difference = new TimeSpanType(0);
+            }
+
+            context.ResponseData.Write(difference.NanoSeconds);
 
             return ResultCode.Success;
         }
+
+        [Command(501)] // 4.0.0+
+        // CalculateSpanBetween(buffer<nn::time::sf::ClockSnapshot, 0x19>, buffer<nn::time::sf::ClockSnapshot, 0x19>) -> nn::TimeSpanType
+        public ResultCode CalculateSpanBetween(ServiceCtx context)
+        {
+            ClockSnapshot clockSnapshotA = ReadClockSnapshotFromBuffer(context, context.Request.ExchangeBuff[0]);
+            ClockSnapshot clockSnapshotB = ReadClockSnapshotFromBuffer(context, context.Request.ExchangeBuff[1]);
+
+            TimeSpanType result;
+
+            ResultCode resultCode = clockSnapshotA.SteadyClockTimePoint.GetSpanBetween(clockSnapshotB.SteadyClockTimePoint, out long timeSpan);
+
+            if (resultCode != ResultCode.Success)
+            {
+                resultCode = ResultCode.TimeNotFound;
+
+                if (clockSnapshotA.NetworkTime != 0 && clockSnapshotB.NetworkTime != 0)
+                {
+                    result     = TimeSpanType.FromSeconds(clockSnapshotB.NetworkTime - clockSnapshotA.NetworkTime);
+                    resultCode = ResultCode.Success;
+                }
+                else
+                {
+                    return resultCode;
+                }
+            }
+            else
+            {
+                result = TimeSpanType.FromSeconds(timeSpan);
+            }
+
+            context.ResponseData.Write(result.NanoSeconds);
+
+            return resultCode;
+        }
+
+        private ResultCode GetClockSnapshotFromSystemClockContextInternal(KThread thread, SystemClockContext userContext, SystemClockContext networkContext, byte type, out ClockSnapshot clockSnapshot)
+        {
+            clockSnapshot = new ClockSnapshot();
+
+            SteadyClockCore      steadyClockCore  = StandardSteadyClockCore.Instance;
+            SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(thread);
+
+            clockSnapshot.IsAutomaticCorrectionEnabled = StandardUserSystemClockCore.Instance.IsAutomaticCorrectionEnabled();
+            clockSnapshot.UserContext                  = userContext;
+            clockSnapshot.NetworkContext               = networkContext;
+
+            char[] tzName       = TimeZoneManager.Instance.GetDeviceLocationName().ToCharArray();
+            char[] locationName = new char[0x24];
+
+            Array.Copy(tzName, locationName, tzName.Length);
+
+            clockSnapshot.LocationName = locationName;
+
+            ResultCode result = ClockSnapshot.GetCurrentTime(out clockSnapshot.UserTime, currentTimePoint, clockSnapshot.UserContext);
+
+            if (result == ResultCode.Success)
+            {
+                result = TimeZoneManager.Instance.ToCalendarTimeWithMyRules(clockSnapshot.UserTime, out CalendarInfo userCalendarInfo);
+
+                if (result == ResultCode.Success)
+                {
+                    clockSnapshot.UserCalendarTime           = userCalendarInfo.Time;
+                    clockSnapshot.UserCalendarAdditionalTime = userCalendarInfo.AdditionalInfo;
+
+                    if (ClockSnapshot.GetCurrentTime(out clockSnapshot.NetworkTime, currentTimePoint, clockSnapshot.NetworkContext) != ResultCode.Success)
+                    {
+                        clockSnapshot.NetworkTime = 0;
+                    }
+
+                    result = TimeZoneManager.Instance.ToCalendarTimeWithMyRules(clockSnapshot.NetworkTime, out CalendarInfo networkCalendarInfo);
+
+                    if (result == ResultCode.Success)
+                    {
+                        clockSnapshot.NetworkCalendarTime           = networkCalendarInfo.Time;
+                        clockSnapshot.NetworkCalendarAdditionalTime = networkCalendarInfo.AdditionalInfo;
+                        clockSnapshot.Type                          = type;
+
+                        // Probably a version field?
+                        clockSnapshot.Unknown = 0;
+                    }
+                }
+            }
+
+            return result;
+        }
+
+        private ClockSnapshot ReadClockSnapshotFromBuffer(ServiceCtx context, IpcBuffDesc ipcDesc)
+        {
+            Debug.Assert(ipcDesc.Size == Marshal.SizeOf<ClockSnapshot>());
+
+            using (BinaryReader bufferReader = new BinaryReader(new MemoryStream(context.Memory.ReadBytes(ipcDesc.Position, ipcDesc.Size))))
+            {
+                return bufferReader.ReadStruct<ClockSnapshot>();
+            }
+        }
+
+        private void WriteClockSnapshotFromBuffer(ServiceCtx context, IpcRecvListBuffDesc ipcDesc, ClockSnapshot clockSnapshot)
+        {
+            Debug.Assert(ipcDesc.Size == Marshal.SizeOf<ClockSnapshot>());
+
+            MemoryStream memory = new MemoryStream((int)ipcDesc.Size);
+
+            using (BinaryWriter bufferWriter = new BinaryWriter(memory))
+            {
+                bufferWriter.WriteStruct(clockSnapshot);
+            }
+
+            context.Memory.WriteBytes(ipcDesc.Position, memory.ToArray());
+            memory.Dispose();
+        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs b/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs
index 2772b45d66..7e3edcef9b 100644
--- a/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/ISteadyClock.cs
@@ -9,7 +9,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
         // GetCurrentTimePoint() -> nn::time::SteadyClockTimePoint
         public ResultCode GetCurrentTimePoint(ServiceCtx context)
         {
-            SteadyClockTimePoint currentTimePoint = SteadyClockCore.Instance.GetCurrentTimePoint(context.Thread);
+            SteadyClockTimePoint currentTimePoint = StandardSteadyClockCore.Instance.GetCurrentTimePoint(context.Thread);
 
             context.ResponseData.WriteStruct(currentTimePoint);
 
@@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
         // GetTestOffset() -> nn::TimeSpanType
         public ResultCode GetTestOffset(ServiceCtx context)
         {
-            context.ResponseData.WriteStruct(SteadyClockCore.Instance.GetTestOffset());
+            context.ResponseData.WriteStruct(StandardSteadyClockCore.Instance.GetTestOffset());
 
             return ResultCode.Success;
         }
@@ -31,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
         {
             TimeSpanType testOffset = context.RequestData.ReadStruct<TimeSpanType>();
 
-            SteadyClockCore.Instance.SetTestOffset(testOffset);
+            StandardSteadyClockCore.Instance.SetTestOffset(testOffset);
 
             return 0;
         }
@@ -40,7 +40,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
         // GetRtcValue() -> u64
         public ResultCode GetRtcValue(ServiceCtx context)
         {
-            ResultCode result = SteadyClockCore.Instance.GetRtcValue(out ulong rtcValue);
+            ResultCode result = StandardSteadyClockCore.Instance.GetRtcValue(out ulong rtcValue);
 
             if (result == ResultCode.Success)
             {
@@ -54,7 +54,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
         // IsRtcResetDetected() -> bool
         public ResultCode IsRtcResetDetected(ServiceCtx context)
         {
-            context.ResponseData.Write(SteadyClockCore.Instance.IsRtcResetDetected());
+            context.ResponseData.Write(StandardSteadyClockCore.Instance.IsRtcResetDetected());
 
             return ResultCode.Success;
         }
@@ -63,7 +63,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
         // GetSetupResultValue() -> u32
         public ResultCode GetSetupResultValue(ServiceCtx context)
         {
-            context.ResponseData.Write((uint)SteadyClockCore.Instance.GetSetupResultCode());
+            context.ResponseData.Write((uint)StandardSteadyClockCore.Instance.GetSetupResultValue());
 
             return ResultCode.Success;
         }
@@ -72,7 +72,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
         // GetInternalOffset() -> nn::TimeSpanType
         public ResultCode GetInternalOffset(ServiceCtx context)
         {
-            context.ResponseData.WriteStruct(SteadyClockCore.Instance.GetInternalOffset());
+            context.ResponseData.WriteStruct(StandardSteadyClockCore.Instance.GetInternalOffset());
 
             return ResultCode.Success;
         }
@@ -83,7 +83,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
         {
             TimeSpanType internalOffset = context.RequestData.ReadStruct<TimeSpanType>();
 
-            SteadyClockCore.Instance.SetInternalOffset(internalOffset);
+            StandardSteadyClockCore.Instance.SetInternalOffset(internalOffset);
 
             return ResultCode.Success;
         }
diff --git a/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs b/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs
index 74182428b2..895bb1f3e3 100644
--- a/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/ITimeZoneService.cs
@@ -56,7 +56,6 @@ namespace Ryujinx.HLE.HOS.Services.Time
         // LoadLocationNameList(u32 index) -> (u32 outCount, buffer<nn::time::LocationName, 6>)
         public ResultCode LoadLocationNameList(ServiceCtx context)
         {
-            // TODO: fix logic to use index
             uint index          = context.RequestData.ReadUInt32();
             long bufferPosition = context.Request.ReceiveBuff[0].Position;
             long bufferSize     = context.Request.ReceiveBuff[0].Size;