diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,11 @@
 # Revision history for net-spider
 
+## 0.3.3.0  -- 2019-10-13
+
+### Interval module
+
+* Add `secSince` and `secUntil` functions.
+
 ## 0.3.2.1  -- 2019-10-04
 
 * Confirm test with `hashable-1.3.0.0`.
diff --git a/net-spider.cabal b/net-spider.cabal
--- a/net-spider.cabal
+++ b/net-spider.cabal
@@ -1,5 +1,5 @@
 name:                   net-spider
-version:                0.3.2.1
+version:                0.3.3.0
 author:                 Toshio Ito <debug.ito@gmail.com>
 maintainer:             Toshio Ito <debug.ito@gmail.com>
 license:                BSD3
diff --git a/src/NetSpider/Interval.hs b/src/NetSpider/Interval.hs
--- a/src/NetSpider/Interval.hs
+++ b/src/NetSpider/Interval.hs
@@ -18,14 +18,17 @@
     parseTimeIntervalEnd,
     parseIntervalEnd,
     -- * Utility
-    secUpTo
+    secUpTo,
+    secSince,
+    secUntil
   ) where
 
 import Data.ExtendedReal (Extended(..))
 import Data.Int (Int64)
 import Data.Interval (Interval, interval, (<=..<=), (<..<=), (<=..<), (<..<))
+import qualified Data.Interval as Interval
 
-import NetSpider.Timestamp (Timestamp, addSec, parseTimestamp)
+import NetSpider.Timestamp (Timestamp, addSec, parseTimestamp, fromEpochMillisecond)
 
 -- | Upper or lower end of 'Interval'. The 'Bool' field is 'True' if
 -- the end is inclusive.
@@ -106,3 +109,42 @@
   where
     start = addSec (-len) end
 
+-- | @d `secSince` ts@ returns the time interval of length @d@ seconds
+-- from the timestamp @ts@. If @ts@ is inclusive (exclusive), the end
+-- of the interval is exclusive (inclusive), respectively.
+--
+-- >>> 60 `secSince` (Finite $ fromEpochMillisecond 1000, True)
+-- Finite (Timestamp {epochTime = 1000, timeZone = Nothing}) <=..< Finite (Timestamp {epochTime = 61000, timeZone = Nothing})
+-- >>> 60 `secSince` (Finite $ fromEpochMillisecond 1000, False)
+-- Finite (Timestamp {epochTime = 1000, timeZone = Nothing}) <..<= Finite (Timestamp {epochTime = 61000, timeZone = Nothing})
+-- >>> 60 `secSince` (PosInf, False)
+-- empty
+-- >>> 60 `secSince` (NegInf, False)
+-- empty
+--
+-- @since 0.3.3.0
+secSince :: Int64 -- ^ duration in seconds
+         -> IntervalEnd Timestamp -- ^ the start of the interval
+         -> Interval Timestamp
+secSince len start@(Finite start_ts, inc) = interval start (Finite $ addSec len start_ts, not inc)
+secSince _ _ = Interval.empty
+
+-- | @d `secUntil` ts@ returns the time interval of length @d@ seconds
+-- up to the timestamp @ts@. If @ts@ is inclusive (exclusive), the
+-- start of the interval is exclusive (inclusive), respectively.
+-- 
+-- >>> 60 `secUntil` (Finite $ fromEpochMillisecond 150000, True)
+-- Finite (Timestamp {epochTime = 90000, timeZone = Nothing}) <..<= Finite (Timestamp {epochTime = 150000, timeZone = Nothing})
+-- >>> 60 `secUntil` (Finite $ fromEpochMillisecond 150000, False)
+-- Finite (Timestamp {epochTime = 90000, timeZone = Nothing}) <=..< Finite (Timestamp {epochTime = 150000, timeZone = Nothing})
+-- >>> 60 `secUntil` (PosInf, False)
+-- empty
+-- >>> 60 `secUntil` (NegInf, False)
+-- empty
+--
+-- @since 0.3.3.0
+secUntil :: Int64 -- ^ duration in seconds
+         -> IntervalEnd Timestamp -- ^ the end of the interval
+         -> Interval Timestamp
+secUntil len end@(Finite end_ts, inc) = interval (Finite $ addSec (-len) end_ts, not inc) end
+secUntil _ _ = Interval.empty
