diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7718cde3..cfc75a10 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## [0.9.2] - Unreleased
+
+## Features
+
+- [#1172](https://github.com/ClementTsang/bottom/pull/1172): Support human times for `time_delta` and `default_time_value`.
+
 ## [0.9.1] - 2023-05-14
 
 ## Bug Fixes
diff --git a/Cargo.lock b/Cargo.lock
index a0c3d88d..1f035890 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -136,7 +136,7 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bottom"
-version = "0.9.1"
+version = "0.9.2"
 dependencies = [
  "anyhow",
  "assert_cmd",
diff --git a/Cargo.toml b/Cargo.toml
index 71141942..f637c690 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "bottom"
-version = "0.9.1"
+version = "0.9.2"
 authors = ["Clement Tsang <cjhtsang@uwaterloo.ca>"]
 edition = "2021"
 repository = "https://github.com/ClementTsang/bottom"
diff --git a/src/options.rs b/src/options.rs
index 5644ddcc..367d6233 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -57,8 +57,8 @@ pub struct ConfigFlags {
     pub whole_word: Option<bool>,
     pub regex: Option<bool>,
     pub basic: Option<bool>,
-    pub default_time_value: Option<u64>,
-    pub time_delta: Option<u64>,
+    pub default_time_value: Option<String>,
+    pub time_delta: Option<String>,
     pub autohide_time: Option<bool>,
     pub hide_time: Option<bool>,
     pub default_widget_type: Option<String>,
@@ -582,20 +582,27 @@ fn get_show_average_cpu(matches: &ArgMatches, config: &Config) -> bool {
     true
 }
 
-/// FIXME: Let this accept human times.
+fn try_parse_ms(s: &str) -> error::Result<u64> {
+    if let Ok(val) = humantime::parse_duration(s) {
+        Ok(val.as_millis().try_into()?)
+    } else if let Ok(val) = s.parse::<u64>() {
+        Ok(val)
+    } else {
+        Err(BottomError::ConfigError(
+            "could not parse as a valid 64-bit unsigned integer or a human time".to_string(),
+        ))
+    }
+}
+
 fn get_default_time_value(
     matches: &ArgMatches, config: &Config, retention_ms: u64,
 ) -> error::Result<u64> {
     let default_time =
         if let Some(default_time_value) = matches.get_one::<String>("default_time_value") {
-            default_time_value.parse::<u64>().map_err(|_| {
-                BottomError::ConfigError(
-                    "could not parse as a valid 64-bit unsigned integer".to_string(),
-                )
-            })?
+            try_parse_ms(default_time_value)?
         } else if let Some(flags) = &config.flags {
-            if let Some(default_time_value) = flags.default_time_value {
-                default_time_value
+            if let Some(default_time_value) = &flags.default_time_value {
+                try_parse_ms(default_time_value)?
             } else {
                 DEFAULT_TIME_MILLISECONDS
             }
@@ -621,14 +628,10 @@ fn get_time_interval(
     matches: &ArgMatches, config: &Config, retention_ms: u64,
 ) -> error::Result<u64> {
     let time_interval = if let Some(time_interval) = matches.get_one::<String>("time_delta") {
-        time_interval.parse::<u64>().map_err(|_| {
-            BottomError::ConfigError(
-                "could not parse as a valid 64-bit unsigned integer".to_string(),
-            )
-        })?
+        try_parse_ms(time_interval)?
     } else if let Some(flags) = &config.flags {
-        if let Some(time_interval) = flags.time_delta {
-            time_interval
+        if let Some(time_interval) = &flags.time_delta {
+            try_parse_ms(time_interval)?
         } else {
             TIME_CHANGE_MILLISECONDS
         }
@@ -869,8 +872,135 @@ fn get_retention_ms(matches: &ArgMatches, config: &Config) -> error::Result<u64>
 mod test {
     use clap::ArgMatches;
 
-    use super::{get_color_scheme, get_widget_layout, Config};
-    use crate::{app::App, canvas::canvas_styling::CanvasStyling};
+    use super::{get_color_scheme, get_time_interval, get_widget_layout, Config};
+    use crate::{
+        app::App,
+        canvas::canvas_styling::CanvasStyling,
+        options::{get_default_time_value, try_parse_ms, ConfigFlags},
+    };
+
+    #[test]
+    fn verify_try_parse_ms() {
+        let a = "100s";
+        let b = "100";
+        let c = "1 min";
+        let d = "1 hour 1 min";
+
+        assert_eq!(try_parse_ms(a), Ok(100 * 1000));
+        assert_eq!(try_parse_ms(b), Ok(100));
+        assert_eq!(try_parse_ms(c), Ok(60 * 1000));
+        assert_eq!(try_parse_ms(d), Ok(3660 * 1000));
+
+        let a_bad = "1 test";
+        let b_bad = "-100";
+
+        assert!(try_parse_ms(a_bad).is_err());
+        assert!(try_parse_ms(b_bad).is_err());
+    }
+
+    #[test]
+    fn matches_human_times() {
+        let config = Config::default();
+        let app = crate::clap::build_app();
+
+        {
+            let app = app.clone();
+            let delta_args = vec!["btm", "--time_delta", "2 min"];
+            let matches = app.get_matches_from(delta_args);
+
+            assert_eq!(
+                get_time_interval(&matches, &config, 60 * 60 * 1000),
+                Ok(2 * 60 * 1000)
+            );
+        }
+
+        {
+            let default_time_args = vec!["btm", "--default_time_value", "300s"];
+            let matches = app.get_matches_from(default_time_args);
+
+            assert_eq!(
+                get_default_time_value(&matches, &config, 60 * 60 * 1000),
+                Ok(5 * 60 * 1000)
+            );
+        }
+    }
+
+    #[test]
+    fn matches_number_times() {
+        let config = Config::default();
+        let app = crate::clap::build_app();
+
+        {
+            let app = app.clone();
+            let delta_args = vec!["btm", "--time_delta", "120000"];
+            let matches = app.get_matches_from(delta_args);
+
+            assert_eq!(
+                get_time_interval(&matches, &config, 60 * 60 * 1000),
+                Ok(2 * 60 * 1000)
+            );
+        }
+
+        {
+            let default_time_args = vec!["btm", "--default_time_value", "300000"];
+            let matches = app.get_matches_from(default_time_args);
+
+            assert_eq!(
+                get_default_time_value(&matches, &config, 60 * 60 * 1000),
+                Ok(5 * 60 * 1000)
+            );
+        }
+    }
+
+    #[test]
+    fn config_human_times() {
+        let app = crate::clap::build_app();
+        let matches = app.get_matches_from(["btm"]);
+
+        let mut config = Config::default();
+        let flags = ConfigFlags {
+            time_delta: Some("2 min".to_string()),
+            default_time_value: Some("300s".to_string()),
+            ..Default::default()
+        };
+
+        config.flags = Some(flags);
+
+        assert_eq!(
+            get_time_interval(&matches, &config, 60 * 60 * 1000),
+            Ok(2 * 60 * 1000)
+        );
+
+        assert_eq!(
+            get_default_time_value(&matches, &config, 60 * 60 * 1000),
+            Ok(5 * 60 * 1000)
+        );
+    }
+
+    #[test]
+    fn config_number_times() {
+        let app = crate::clap::build_app();
+        let matches = app.get_matches_from(["btm"]);
+
+        let mut config = Config::default();
+        let flags = ConfigFlags {
+            time_delta: Some("120000".to_string()),
+            default_time_value: Some("300000".to_string()),
+            ..Default::default()
+        };
+
+        config.flags = Some(flags);
+
+        assert_eq!(
+            get_time_interval(&matches, &config, 60 * 60 * 1000),
+            Ok(2 * 60 * 1000)
+        );
+
+        assert_eq!(
+            get_default_time_value(&matches, &config, 60 * 60 * 1000),
+            Ok(5 * 60 * 1000)
+        );
+    }
 
     fn create_app(mut config: Config, matches: ArgMatches) -> App {
         let (layout, id, ty) = get_widget_layout(&matches, &config).unwrap();