diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,18 @@
 Changelog
 =========
 
+Version 0.2.6.0
+---------------
+
+*December 3, 2019*
+
+<https://github.com/mstksg/advent-of-code-api/releases/tag/v0.2.6.0>
+
+*   Add `aocServerTime` to get the current time for AoC servers.
+*   Fix cacheing rules for global leaderboard (was previously not saving or
+    invalidating cache properly) also for prompt (will not invalidate
+    part1-only caches if there is no session key)
+
 Version 0.2.5.0
 ---------------
 
diff --git a/advent-of-code-api.cabal b/advent-of-code-api.cabal
--- a/advent-of-code-api.cabal
+++ b/advent-of-code-api.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 47b5a0fa5ec3911f9afa108c1f723d2716f225a23091507886305ff551fdca08
+-- hash: 11039e11778c64e34a0031b4251a99a15470033e3dafd1962b1db1a02bcab593
 
 name:           advent-of-code-api
-version:        0.2.5.0
+version:        0.2.6.0
 synopsis:       Advent of Code REST API bindings and servant API
 description:    Haskell bindings for Advent of Code REST API and a servant API.  Please use
                 responsibly! See README.md or "Advent" module for an introduction and
diff --git a/src/Advent.hs b/src/Advent.hs
--- a/src/Advent.hs
+++ b/src/Advent.hs
@@ -9,6 +9,7 @@
 {-# LANGUAGE RecordWildCards    #-}
 {-# LANGUAGE StandaloneDeriving #-}
 {-# LANGUAGE TupleSections      #-}
+{-# LANGUAGE TypeApplications   #-}
 {-# LANGUAGE TypeInType         #-}
 {-# LANGUAGE ViewPatterns       #-}
 
@@ -63,6 +64,7 @@
   -- ** Day
   , mkDay, mkDay_, dayInt, pattern DayInt, _DayInt
   , aocDay
+  , aocServerTime
   -- ** Part
   , partChar, partInt
   -- ** Leaderboard
@@ -138,12 +140,20 @@
 data AoC :: Type -> Type where
     -- | Fetch prompts for a given day.  Returns a 'Map' of 'Part's and
     -- their associated promps, as HTML.
+    --
+    -- _Cacheing rules_: Is cached on a per-day basis.  An empty session
+    -- key is given, it will be happy with only having Part 1 cached.  If
+    -- a non-empty session key is given, it will trigger a cache
+    -- invalidation on every request until both Part 1 and Part 2 are
+    -- received.
     AoCPrompt
         :: Day
         -> AoC (Map Part Text)
 
     -- | Fetch input, as plaintext.  Returned verbatim.  Be aware that
     -- input might contain trailing newlines.
+    --
+    -- /Cacheing rules/: Is cached forever, per day per session key.
     AoCInput :: Day -> AoC Text
 
     -- | Submit a plaintext answer (the 'String') to a given day and part.
@@ -152,6 +162,8 @@
     -- __WARNING__: Answers are not length-limited.  Answers are stripped
     -- of leading and trailing whitespace and run through 'URI.encode'
     -- before submitting.
+    --
+    -- /Cacheing rules/: Is never cached.
     AoCSubmit
         :: Day
         -> Part
@@ -174,6 +186,9 @@
     -- you set up automation for this, please do not use it more than once
     -- per day.
     --
+    -- /Cacheing rules/: Is never cached, so please use responsibly (see
+    -- note above).
+    --
     -- @since 0.2.0.0
     AoCLeaderboard
         :: Integer
@@ -186,7 +201,7 @@
     -- when using this.  If you automate this, please do not fetch any more
     -- often than necessary.
     --
-    -- Calls to this will be cached if a full leaderboard is observed.
+    -- /Cacheing rules/: Will be cached if a full leaderboard is observed.
     --
     -- @since 0.2.3.0
     AoCDailyLeaderboard
@@ -200,7 +215,8 @@
     -- when using this.  If you automate this, please do not fetch any more
     -- often than necessary.
     --
-    -- Calls to this will be cached if fetched after each event ends.
+    -- /Cacheing rules/: Will not cache if an event is ongoing, but will be
+    -- cached if received after the event is over.
     --
     -- @since 0.2.3.0
     AoCGlobalLeaderboard
@@ -344,7 +360,10 @@
           Just fp -> cacheing (cacheDir </> fp) $
                        if _aForce
                          then noCache
-                         else saverLoader (not eventOver) a
+                         else saverLoader
+                                (not (null _aSessionKey))
+                                (not eventOver)
+                                a
 
     cacher . runExceptT $ do
       forM_ (aocDay a) $ \d -> do
@@ -389,10 +408,11 @@
 
 
 saverLoader
-    :: Bool             -- ^ is the event ongoing (True) or over (False)?
+    :: Bool             -- ^ is there a non-empty session token?
+    -> Bool             -- ^ is the event ongoing (True) or over (False)?
     -> AoC a
     -> SaverLoader (Either AoCError a)
-saverLoader evt = \case
+saverLoader validToken evt = \case
     AoCPrompt{} -> SL { _slSave = either (const Nothing) (Just . encodeMap)
                       , _slLoad = \str ->
                           let mp     = decodeMap str
@@ -411,15 +431,20 @@
             guard $ fullDailyBoard r
             pure $ Right r
         }
-    AoCGlobalLeaderboard{}
-      | evt       -> noCache
-      | otherwise -> SL
-          { _slSave = either (const Nothing) (Just . TL.toStrict . TL.decodeUtf8 . A.encode)
-          , _slLoad = fmap Right . A.decode . TL.encodeUtf8 . TL.fromStrict
-          }
+    AoCGlobalLeaderboard{} -> SL
+        { _slSave = either
+                        (const Nothing)
+                        (Just . TL.toStrict . TL.decodeUtf8 . A.encode @(Bool, GlobalLeaderboard) . (evt,))
+        , _slLoad = \str -> do
+            (evt', lb) <- A.decode @(Bool, GlobalLeaderboard) . TL.encodeUtf8 . TL.fromStrict $ str
+            guard $ not evt'        -- only load cache if evt' is false: it was saved in a non-evt time
+            pure $ Right lb
+        }
   where
     expectedParts :: Set Part
-    expectedParts = S.fromDistinctAscList [Part1 ..]
+    expectedParts
+      | validToken = S.singleton Part1
+      | otherwise  = S.fromDistinctAscList [Part1 ..]
     sep = ">>>>>>>>>"
     encodeMap mp = T.intercalate "\n" . concat $
                             [ maybeToList $ M.lookup Part1 mp
@@ -454,6 +479,14 @@
     -> UTCTime
 challengeReleaseTime y d = UTCTime (fromGregorian y 12 (fromIntegral (dayInt d)))
                                    (5 * 60 * 60)
+
+-- | Utility to get the current time on AoC servers.  Basically just gets the current
+-- time in Eastern Standard Time.  This is only as accurate as your
+-- machine's actual time --- it doesn't actually do anything networked.
+--
+-- @since 0.2.6.0
+aocServerTime :: IO LocalTime
+aocServerTime = utcToLocalTime (read "EST") <$> getCurrentTime
 
 strip :: String -> String
 strip = T.unpack . T.strip . T.pack
