Repository: diesel-rs/diesel (language: rust)

Issue:
Invalid MSRV
## Setup

### Versions

- **Rust:** `1.56.0` (as per `rust-toolchain`)
- **Diesel:** `5c0452eae52ebd5ec28f489ce1d395c4330936c2`
- **Database:** N/A
- **Operating System** Linux

### Feature Flags

- **diesel:** N/A

## Problem Description

Unable to cargo check the codebase:

```
info: syncing channel updates for '1.56.0-x86_64-unknown-linux-gnu'
info: latest update on 2021-10-21, rust version 1.56.0 (09c42c458 2021-10-18)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
info: downloading component 'rust-std'
info: downloading component 'rustc'
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: installing component 'clippy'
info: installing component 'rust-docs'
info: installing component 'rust-std'
info: installing component 'rustc'
info: installing component 'rustfmt'
    Updating crates.io index
  Downloaded dotenvy v0.15.1
  Downloaded clap_complete v3.2.3
  Downloaded clap v3.2.11
  Downloaded libsqlite3-sys v0.24.2
  Downloaded 4 crates (5.0 MB) in 1.12s (largest was `libsqlite3-sys` at 4.8 MB)
error: package `clap_complete v3.2.3` cannot be built because it requires rustc 1.56.1 or newer, while the currently active rustc version is 1.56.0
```


Discussion / hints:
Thanks for reporting this issue.

Just for the record: I do not consider this to be an issue with our MSRV, as we define MSRV as that's the rust version where diesel builds with some set of supported dependency versions. We test this by using cargos minimal-version dependency version resolution algorithm. 
Fair enough. Should I close the PR?
I think it's fine to update the rust version used in `rust-toolchain` as we have a independent check for the minimal supported rust version on the CI. I've also noted that this now needs at least 1.57 due to some other dependency + the update to the CI job might not be required anymore, as I've already done this as part of some other PR. I might be open to just switch to the latest stable release for the `rust-toolchain` version to prevent such issues from happening in the future, although that might bring other issues with breaking the clippy/rustfmt job if a new stable rust release is done.

Fix patch:
diff --git a/.github/workflows/benches.yml b/.github/workflows/benches.yml
index b2959c011133..ea77542cc111 100644
--- a/.github/workflows/benches.yml
+++ b/.github/workflows/benches.yml
@@ -45,23 +45,13 @@ jobs:
           echo 'DATABASE_URL=mysql://root:root@localhost/diesel_test' >> $GITHUB_ENV
 
       - name: Install rust toolchain
-        uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: stable
-          override: true
+        uses: dtolnay/rust-toolchain@stable
 
       - name: Install critcmp
-        uses: actions-rs/cargo@v1
-        with:
-          command: install
-          args: critcmp
+        run: cargo +stable install critcmp
 
       - name: Benchmark changes
-        uses: actions-rs/cargo@v1
-        with:
-          command: bench
-          args: --manifest-path diesel_bench/Cargo.toml --no-default-features --features "${{matrix.backend}}" -- --save-baseline changes
+        run: cargo +stable bench --manifest-path diesel_bench/Cargo.toml --no-default-features --features "${{matrix.backend}}" -- --save-baseline changes
 
       - name: Checkout master
         run: |
@@ -69,10 +59,7 @@ jobs:
           git reset --hard origin/master
 
       - name: Benchmark master
-        uses: actions-rs/cargo@v1
-        with:
-          command: bench
-          args: --manifest-path diesel_bench/Cargo.toml --no-default-features --features "${{matrix.backend}}" -- --save-baseline master
+        run: cargo +stable bench --manifest-path diesel_bench/Cargo.toml --no-default-features --features "${{matrix.backend}}" -- --save-baseline master
 
       - name: Critcmp
         run: |
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7ead1e69a92b..f25f847c5a32 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -192,135 +192,107 @@ jobs:
           echo "MYSQLCLIENT_LIB_DIR=C:\tools\mysql\current\lib" >> $GITHUB_ENV
 
       - name: Install rust toolchain
-        uses: actions-rs/toolchain@v1
+        uses: dtolnay/rust-toolchain@master
         with:
-          profile: minimal
           toolchain: ${{ matrix.rust }}
-          override: true
+
       - name: Rust version check
-        uses: actions-rs/cargo@v1
-        with:
-          command: version
+        shell: bash
+        run: |
+          cargo +${{ matrix.rust }} --version
+          rustc +${{ matrix.rust }} --version
 
       - name: Test diesel (nightly)
         if: matrix.rust == 'nightly'
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --manifest-path diesel/Cargo.toml --no-default-features --features "${{ matrix.backend }} unstable extras i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+        shell: bash
+        run: cargo +${{ matrix.rust }} test --manifest-path diesel/Cargo.toml --no-default-features --features "${{ matrix.backend }} unstable extras i-implement-a-third-party-backend-and-opt-into-breaking-changes"
 
       - name: Test diesel
-        if: matrix.rust != 'nightly'
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --manifest-path diesel/Cargo.toml --no-default-features --features "${{ matrix.backend }} extras r2d2"
+        if: matrix.rust == 'stable'
+        shell: bash
+        run: cargo +${{ matrix.rust }} test --manifest-path diesel/Cargo.toml --no-default-features --features "${{ matrix.backend }} extras r2d2"
 
       - name: Test diesel (with-deprecated)
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --manifest-path diesel/Cargo.toml --no-default-features --features "${{ matrix.backend }} extras with-deprecated"
+        if: matrix.rust == 'beta'
+        shell: bash
+        run: cargo +${{ matrix.rust }} test --manifest-path diesel/Cargo.toml --no-default-features --features "${{ matrix.backend }} extras with-deprecated"
 
       - name: Test diesel-derives (nightly)
         if: matrix.rust == 'nightly'
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --manifest-path diesel_derives/Cargo.toml --no-default-features --features "diesel/${{ matrix.backend }} diesel/unstable"
+        shell: bash
+        run: cargo +${{ matrix.rust }} test --manifest-path diesel_derives/Cargo.toml --no-default-features --features "diesel/${{ matrix.backend }} diesel/unstable"
 
       - name: Test diesel-derives
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --manifest-path diesel_derives/Cargo.toml --no-default-features --features "diesel/${{ matrix.backend }}"
+        shell: bash
+        run: cargo +${{ matrix.rust }} test --manifest-path diesel_derives/Cargo.toml --no-default-features --features "diesel/${{ matrix.backend }}"
 
       - name: Test diesel-cli
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --manifest-path diesel_cli/Cargo.toml --no-default-features --features "${{ matrix.backend }}"
+        shell: bash
+        run: cargo +${{ matrix.rust }} test --manifest-path diesel_cli/Cargo.toml --no-default-features --features "${{ matrix.backend }}"
 
       - name: Test diesel examples
         shell: bash
+        env:
+          BACKEND: ${{ matrix.backend }}
         run: |
-          (cd examples/${{ matrix.backend }} && BACKEND=${{ matrix.backend }} ./test_all)
+           (cd examples/${{ matrix.backend }} && rustup run ${{ matrix.rust }} bash test_all)
 
       - name: Test migrations-internals
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --manifest-path diesel_migrations/migrations_internals/Cargo.toml
+        shell: bash
+        run: cargo +${{ matrix.rust }} test --manifest-path diesel_migrations/migrations_internals/Cargo.toml
 
       - name: Test migrations-macros
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "diesel/${{ matrix.backend }} ${{ matrix.backend }}"
+        shell: bash
+        run: cargo +${{ matrix.rust }} test --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "diesel/${{ matrix.backend }} ${{ matrix.backend }}"
 
       - name: Test diesel_migrations
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --manifest-path diesel_migrations/Cargo.toml --features "${{ matrix.backend }} diesel/${{ matrix.backend }}"
+        shell: bash
+        run: cargo +${{ matrix.rust }} test --manifest-path diesel_migrations/Cargo.toml --features "${{ matrix.backend }} diesel/${{ matrix.backend }}"
 
       - name: Run diesel_tests (nightly)
-        if: matrix.run == 'nightly'
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --manifest-path diesel_tests/Cargo.toml --no-default-features --features "${{ matrix.backend }} unstable"
+        if: matrix.rust == 'nightly'
+        shell: bash
+        run: cargo +${{ matrix.rust }} test --manifest-path diesel_tests/Cargo.toml --no-default-features --features "${{ matrix.backend }} unstable"
 
       - name: Run diesel_tests (beta)
-        if: matrix.run == 'beta'
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --manifest-path diesel_tests/Cargo.toml --no-default-features --features "${{ matrix.backend }},returning_clauses_for_sqlite_3_35"
+        if: matrix.rust == 'beta'
+        shell: bash
+        run: cargo +${{ matrix.rust }} test --manifest-path diesel_tests/Cargo.toml --no-default-features --features "${{ matrix.backend }} returning_clauses_for_sqlite_3_35 libsqlite3-sys/bundled"
 
       - name: Run diesel_tests
-        if: matrix.run == 'stable'
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --manifest-path diesel_tests/Cargo.toml --no-default-features --features "${{ matrix.backend }}"
+        if: matrix.rust == 'stable'
+        shell: bash
+        run: cargo +${{ matrix.rust }} test --manifest-path diesel_tests/Cargo.toml --no-default-features --features "${{ matrix.backend }}"
 
       - name: Run diesel_dynamic_schema tests
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --manifest-path diesel_dynamic_schema/Cargo.toml --no-default-features --features "${{ matrix.backend }} diesel/${{ matrix.backend }}"
+        shell: bash
+        run: cargo +${{ matrix.rust }} test --manifest-path diesel_dynamic_schema/Cargo.toml --no-default-features --features "${{ matrix.backend }} diesel/${{ matrix.backend }}"
 
       - name: Run diesel_benches
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --manifest-path diesel_bench/Cargo.toml --no-default-features --features "${{ matrix.backend }}" --bench benchmarks
+        shell: bash
+        run: cargo +${{ matrix.rust }} test --manifest-path diesel_bench/Cargo.toml --no-default-features --features "${{ matrix.backend }}" --bench benchmarks
 
       - name: Run rustdoc (nightly)
-        if: matrix.run == 'nightly'
-        uses: actions-rs/cargo@v1
-        with:
-          command: doc
-          args: --manifest-path diesel/Cargo.toml --no-deps --no-default-features --features "${{ matrix.backend }} unstable i-implement-a-third-party-backend-and-opt-into-breaking-changes"
+        if: matrix.rust == 'nightly'
+        shell: bash
+        run: cargo +${{ matrix.rust }} doc --manifest-path diesel/Cargo.toml --no-deps --no-default-features --features "${{ matrix.backend }} unstable i-implement-a-third-party-backend-and-opt-into-breaking-changes extras"
 
       - name: Run rustdoc
-        if: matrix.run != 'nightly'
-        uses: actions-rs/cargo@v1
-        with:
-          command: doc
-          args: --manifest-path diesel/Cargo.toml --no-deps --no-default-features --features "${{ matrix.backend }}"
+        if: matrix.rust == 'stable'
+        shell: bash
+        run: cargo +${{ matrix.rust }} doc --manifest-path diesel/Cargo.toml --no-deps --no-default-features --features "${{ matrix.backend }}"
+
+      - name: Run rustdoc (with-deprecated)
+        if: matrix.rust == 'beta'
+        shell: bash
+        run: cargo +${{ matrix.rust }} doc --manifest-path diesel/Cargo.toml --no-deps --no-default-features --features "${{ matrix.backend }} with-deprecated"
 
   compile_tests:
     name: Compiletests
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
-        with:
-          toolchain: 1.56.0
-          profile: minimal
-          override: true
+      - uses: dtolnay/rust-toolchain@1.56.0
       - name: Cache cargo registry
         uses: actions/cache@v3
         with:
@@ -335,22 +307,17 @@ jobs:
           sudo apt-get -y install libsqlite3-dev libpq-dev libmysqlclient-dev
 
       - name: Run compile tests
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --manifest-path diesel_compile_tests/Cargo.toml
+        shell: bash
+        run: cargo +1.56.0 test --manifest-path diesel_compile_tests/Cargo.toml
 
   rustfmt_and_clippy:
     name: Check rustfmt style && run clippy
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
+      - uses: dtolnay/rust-toolchain@stable
         with:
-          toolchain: 1.57.0
-          profile: minimal
           components: clippy, rustfmt
-          override: true
       - name: Cache cargo registry
         uses: actions/cache@v2
         with:
@@ -377,63 +344,57 @@ jobs:
 
       - name: Run clippy
         run: |
-          cargo clippy --tests --manifest-path diesel_derives/Cargo.toml --features "postgres diesel/postgres"
-          cargo clippy --tests --manifest-path diesel/Cargo.toml --features "postgres"
-          cargo clippy --tests --manifest-path diesel_dynamic_schema/Cargo.toml --features "postgres diesel/postgres"
-          cargo clippy --tests --manifest-path diesel_migrations/migrations_internals/Cargo.toml
-          cargo clippy --tests --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "postgres diesel/postgres"
-          cargo clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "postgres diesel/postgres"
-          cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "postgres" --no-default-features
-          cargo clippy --tests --manifest-path diesel_tests/Cargo.toml --features "postgres"
-          cargo clippy --tests --manifest-path examples/postgres/getting_started_step_1/Cargo.toml
-          cargo clippy --tests --manifest-path examples/postgres/getting_started_step_2/Cargo.toml
-          cargo clippy --tests --manifest-path examples/postgres/getting_started_step_3/Cargo.toml
-          cargo clippy --tests --manifest-path examples/postgres/advanced-blog-cli/Cargo.toml
-          cargo clippy --tests --manifest-path examples/postgres/all_about_inserts/Cargo.toml
-          cargo clippy --tests --manifest-path examples/postgres/all_about_updates/Cargo.toml
-          cargo clippy --tests --manifest-path examples/postgres/custom_types/Cargo.toml
-
-          cargo clippy --tests --manifest-path diesel_derives/Cargo.toml --features "sqlite diesel/sqlite"
-          cargo clippy --tests --manifest-path diesel/Cargo.toml --features "sqlite"
-          cargo clippy --tests --manifest-path diesel_dynamic_schema/Cargo.toml --features "sqlite diesel/sqlite"
-          cargo clippy --tests --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "sqlite diesel/sqlite"
-          cargo clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "sqlite diesel/sqlite"
-          cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "sqlite" --no-default-features
-          cargo clippy --tests --manifest-path diesel_tests/Cargo.toml --features "sqlite"
-          cargo clippy --tests --manifest-path examples/sqlite/getting_started_step_1/Cargo.toml
-          cargo clippy --tests --manifest-path examples/sqlite/getting_started_step_2/Cargo.toml
-          cargo clippy --tests --manifest-path examples/sqlite/getting_started_step_3/Cargo.toml
-          cargo clippy --tests --manifest-path examples/sqlite/all_about_inserts/Cargo.toml
-
-          cargo clippy --tests --manifest-path diesel_derives/Cargo.toml --features "mysql diesel/mysql"
-          cargo clippy --tests --manifest-path diesel/Cargo.toml --features "mysql"
-          cargo clippy --tests --manifest-path diesel_dynamic_schema/Cargo.toml --features "mysql diesel/mysql"
-          cargo clippy --tests --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "mysql diesel/mysql"
-          cargo clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "mysql diesel/mysql"
-          cargo clippy --tests --manifest-path diesel_cli/Cargo.toml --features "mysql" --no-default-features
-          cargo clippy --tests --manifest-path diesel_tests/Cargo.toml --features "mysql"
-          cargo clippy --tests --manifest-path examples/mysql/getting_started_step_1/Cargo.toml
-          cargo clippy --tests --manifest-path examples/mysql/getting_started_step_2/Cargo.toml
-          cargo clippy --tests --manifest-path examples/mysql/getting_started_step_3/Cargo.toml
-          cargo clippy --tests --manifest-path examples/mysql/all_about_inserts/Cargo.toml
+          cargo +stable clippy --tests --manifest-path diesel_derives/Cargo.toml --features "postgres diesel/postgres"
+          cargo +stable clippy --tests --manifest-path diesel/Cargo.toml --features "postgres"
+          cargo +stable clippy --tests --manifest-path diesel_dynamic_schema/Cargo.toml --features "postgres diesel/postgres"
+          cargo +stable clippy --tests --manifest-path diesel_migrations/migrations_internals/Cargo.toml
+          cargo +stable clippy --tests --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "postgres diesel/postgres"
+          cargo +stable clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "postgres diesel/postgres"
+          cargo +stable clippy --tests --manifest-path diesel_cli/Cargo.toml --features "postgres" --no-default-features
+          cargo +stable clippy --tests --manifest-path diesel_tests/Cargo.toml --features "postgres"
+          cargo +stable clippy --tests --manifest-path examples/postgres/getting_started_step_1/Cargo.toml
+          cargo +stable clippy --tests --manifest-path examples/postgres/getting_started_step_2/Cargo.toml
+          cargo +stable clippy --tests --manifest-path examples/postgres/getting_started_step_3/Cargo.toml
+          cargo +stable clippy --tests --manifest-path examples/postgres/advanced-blog-cli/Cargo.toml
+          cargo +stable clippy --tests --manifest-path examples/postgres/all_about_inserts/Cargo.toml
+          cargo +stable clippy --tests --manifest-path examples/postgres/all_about_updates/Cargo.toml
+          cargo +stable clippy --tests --manifest-path examples/postgres/custom_types/Cargo.toml
+
+          cargo +stable clippy --tests --manifest-path diesel_derives/Cargo.toml --features "sqlite diesel/sqlite"
+          cargo +stable clippy --tests --manifest-path diesel/Cargo.toml --features "sqlite"
+          cargo +stable clippy --tests --manifest-path diesel_dynamic_schema/Cargo.toml --features "sqlite diesel/sqlite"
+          cargo +stable clippy --tests --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "sqlite diesel/sqlite"
+          cargo +stable clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "sqlite diesel/sqlite"
+          cargo +stable clippy --tests --manifest-path diesel_cli/Cargo.toml --features "sqlite" --no-default-features
+          cargo +stable clippy --tests --manifest-path diesel_tests/Cargo.toml --features "sqlite"
+          cargo +stable clippy --tests --manifest-path examples/sqlite/getting_started_step_1/Cargo.toml
+          cargo +stable clippy --tests --manifest-path examples/sqlite/getting_started_step_2/Cargo.toml
+          cargo +stable clippy --tests --manifest-path examples/sqlite/getting_started_step_3/Cargo.toml
+          cargo +stable clippy --tests --manifest-path examples/sqlite/all_about_inserts/Cargo.toml
+
+          cargo +stable clippy --tests --manifest-path diesel_derives/Cargo.toml --features "mysql diesel/mysql"
+          cargo +stable clippy --tests --manifest-path diesel/Cargo.toml --features "mysql"
+          cargo +stable clippy --tests --manifest-path diesel_dynamic_schema/Cargo.toml --features "mysql diesel/mysql"
+          cargo +stable clippy --tests --manifest-path diesel_migrations/migrations_macros/Cargo.toml --features "mysql diesel/mysql"
+          cargo +stable clippy --tests --manifest-path diesel_migrations/Cargo.toml --features "mysql diesel/mysql"
+          cargo +stable clippy --tests --manifest-path diesel_cli/Cargo.toml --features "mysql" --no-default-features
+          cargo +stable clippy --tests --manifest-path diesel_tests/Cargo.toml --features "mysql"
+          cargo +stable clippy --tests --manifest-path examples/mysql/getting_started_step_1/Cargo.toml
+          cargo +stable clippy --tests --manifest-path examples/mysql/getting_started_step_2/Cargo.toml
+          cargo +stable clippy --tests --manifest-path examples/mysql/getting_started_step_3/Cargo.toml
+          cargo +stable clippy --tests --manifest-path examples/mysql/all_about_inserts/Cargo.toml
 
       - name: Check formating
-        uses: actions-rs/cargo@v1
-        with:
-          command: fmt
-          args: --all -- --check
+        run: cargo +stable fmt --all -- --check
 
   sqlite_bundled:
     name: Check sqlite bundled + Sqlite with asan
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
+      - uses: dtolnay/rust-toolchain@nightly
         with:
-          toolchain: nightly
-          profile: minimal
-          override: true
-          components: rust-src
+          components: "rust-src"
       - name: Cache cargo registry
         uses: actions/cache@v2
         with:
@@ -443,34 +404,30 @@ jobs:
           key: sqlite_bundled-cargo-${{ hashFiles('**/Cargo.toml') }}
 
       - name: Test diesel-cli
-        uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --manifest-path diesel_cli/Cargo.toml --no-default-features --features "sqlite-bundled"
+        run: cargo +nightly test --manifest-path diesel_cli/Cargo.toml --no-default-features --features "sqlite-bundled"
 
       - name: Run diesel_tests with ASAN enabled
         env:
           RUSTFLAGS: -Zsanitizer=address
           ASAN_OPTIONS: detect_stack_use_after_return=1
-        run: cargo -Z build-std test --manifest-path diesel_tests/Cargo.toml --no-default-features --features "sqlite libsqlite3-sys libsqlite3-sys/bundled libsqlite3-sys/with-asan" --target x86_64-unknown-linux-gnu
+        run: cargo +nightly -Z build-std test --manifest-path diesel_tests/Cargo.toml --no-default-features --features "sqlite libsqlite3-sys libsqlite3-sys/bundled libsqlite3-sys/with-asan" --target x86_64-unknown-linux-gnu
 
       - name: Run diesel tests with ASAN enabled
         env:
           RUSTDOCFLAGS: -Zsanitizer=address
           RUSTFLAGS: -Zsanitizer=address
           ASAN_OPTIONS: detect_stack_use_after_return=1
-        run: cargo -Z build-std test --manifest-path diesel/Cargo.toml --no-default-features --features "sqlite extras libsqlite3-sys libsqlite3-sys/bundled libsqlite3-sys/with-asan" --target x86_64-unknown-linux-gnu
+        run: cargo +nightly -Z build-std test --manifest-path diesel/Cargo.toml --no-default-features --features "sqlite extras libsqlite3-sys libsqlite3-sys/bundled libsqlite3-sys/with-asan" --target x86_64-unknown-linux-gnu
 
   minimal_rust_version:
     name: Check Minimal supported rust version (1.56.0)
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
-        with:
-          toolchain: 1.56.0
-          profile: minimal
-          override: true
+      - uses: dtolnay/rust-toolchain@1.56.0
+      - uses: dtolnay/rust-toolchain@nightly
+      - uses: taiki-e/install-action@cargo-hack
+      - uses: taiki-e/install-action@cargo-minimal-versions
       - name: Cache cargo registry
         uses: actions/cache@v2
         with:
@@ -482,14 +439,13 @@ jobs:
         run: |
           sudo apt-get update
           sudo apt-get -y install libsqlite3-dev libpq-dev libmysqlclient-dev
-      - name: Use minimal dependencies
-        run: |
-          RUSTC_BOOTSTRAP=1 cargo update -Z minimal-versions
-
-      - name: Check building with rust 1.54.0
-        uses: actions-rs/cargo@v1
-        with:
-          command: check
-          # This example pulls generic-array v0.14.1 that cannot compile with rustc 1.40.0.
-          # We could exclude it as it won't affect our MSRV.
-          args: --all --exclude=advanced-blog-cli
+      - name: Check diesel_derives
+        run: cargo +1.56.0 minimal-versions check -p diesel_derives --all-features
+      - name: Check diesel
+        run: cargo +1.56.0 minimal-versions check -p diesel --features "postgres mysql sqlite extras"
+      - name: Check diesel_dynamic_schema
+        run: cargo +1.56.0 minimal-versions check -p diesel-dynamic-schema --all-features
+      - name: Check diesel_migrations
+        run: cargo +1.56.0 minimal-versions check -p diesel_migrations --all-features
+      - name: Check diesel_cli
+        run: cargo +1.56.0 minimal-versions check -p diesel_cli --all-features
diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml
index 4262b78525c8..e54b45f7967e 100644
--- a/.github/workflows/doc.yml
+++ b/.github/workflows/doc.yml
@@ -27,11 +27,7 @@ jobs:
       shell: bash
       run: |
         echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
-    - uses: actions-rs/toolchain@v1
-      with:
-        toolchain: nightly
-        profile: minimal
-        override: true
+    - uses: dtolnay/rust-toolchain@nightly
     - name: Install dependencies
       run: |
         sudo apt-get update
diff --git a/.github/workflows/metrics.yml b/.github/workflows/metrics.yml
index 1cf5d7315977..57f58153a432 100644
--- a/.github/workflows/metrics.yml
+++ b/.github/workflows/metrics.yml
@@ -58,32 +58,19 @@ jobs:
           echo 'DATABASE_URL=mysql://root:root@localhost/diesel_test' >> $GITHUB_ENV
 
       - name: Install rust toolchain
-        uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: stable
-          override: true
+        uses: dtolnay/rust-toolchain@stable
 
       - name: Run Benchmarks (Postgres)
         if: matrix.backend == 'postgres'
-        uses: actions-rs/cargo@v1
-        with:
-          command: bench
-          args: --manifest-path diesel_bench/Cargo.toml --no-default-features --features "${{matrix.backend}} sqlx-bench sqlx/${{matrix.backend}} rust_postgres futures sea-orm sea-orm/sqlx-${{matrix.backend}} criterion/async_tokio quaint quaint/postgresql quaint/serde-support serde diesel-async diesel-async/${{matrix.backend}}"
+        run: cargo +stable bench --manifest-path diesel_bench/Cargo.toml --no-default-features --features "${{matrix.backend}} sqlx-bench sqlx/${{matrix.backend}} rust_postgres futures sea-orm sea-orm/sqlx-${{matrix.backend}} criterion/async_tokio quaint quaint/postgresql quaint/serde-support serde diesel-async diesel-async/${{matrix.backend}}"
 
       - name: Run Benchmarks (Sqlite)
         if: matrix.backend == 'sqlite'
-        uses: actions-rs/cargo@v1
-        with:
-          command: bench
-          args: --manifest-path diesel_bench/Cargo.toml --no-default-features --features "${{matrix.backend}} sqlx-bench sqlx/${{matrix.backend}} tokio rusqlite futures sea-orm sea-orm/sqlx-${{matrix.backend}} criterion/async_tokio"
+        run: cargo +stable bench --manifest-path diesel_bench/Cargo.toml --no-default-features --features "${{matrix.backend}} sqlx-bench sqlx/${{matrix.backend}} tokio rusqlite futures sea-orm sea-orm/sqlx-${{matrix.backend}} criterion/async_tokio"
 
       - name: Run Benchmarks (Mysql)
         if: matrix.backend == 'mysql'
-        uses: actions-rs/cargo@v1
-        with:
-          command: bench
-          args: --manifest-path diesel_bench/Cargo.toml --no-default-features --features "${{matrix.backend}} sqlx-bench sqlx/${{matrix.backend}} tokio rustorm rustorm/with-${{matrix.backend}} rustorm_dao rust_mysql futures sea-orm sea-orm/sqlx-${{matrix.backend}} criterion/async_tokio quaint quaint/mysql quaint/serde-support serde diesel-async diesel-async/${{matrix.backend}}"
+        run: cargo +stable bench --manifest-path diesel_bench/Cargo.toml --no-default-features --features "${{matrix.backend}} sqlx-bench sqlx/${{matrix.backend}} tokio rustorm rustorm/with-${{matrix.backend}} rustorm_dao rust_mysql futures sea-orm sea-orm/sqlx-${{matrix.backend}} criterion/async_tokio quaint quaint/mysql quaint/serde-support serde diesel-async diesel-async/${{matrix.backend}}"
 
       - name: Push metrics
         env:
@@ -96,6 +83,7 @@ jobs:
           ssh-keyscan github.com >> ~/.ssh/known_hosts
           echo "${{ secrets.METRIC_ACCESS_KEY }}" >> ~/.ssh/id_ed25519
           chmod 600 ~/.ssh/id_ed25519
+          rm diesel_bench/target/release -rf
 
           git clone --depth 1 git@github.com:diesel-rs/metrics.git
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 55cec9f0c8d7..3cc42035cd15 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,6 +25,9 @@ values by iterator from the database.
 * We've added support for loading values using libpq's row-by-row mode via 
 the new iterator interface
 
+* Adds `Timestamp`, `Timestamptz` support for appropriate types for `time v0.3.9`.
+  This feature enables using the `time` crate as an alternative to `chrono`.
+
 ### Fixed
 
 * Updated `ipnetwork` to allow version 0.20.
diff --git a/diesel/Cargo.toml b/diesel/Cargo.toml
index 6e0603e42daa..c970038326a6 100644
--- a/diesel/Cargo.toml
+++ b/diesel/Cargo.toml
@@ -33,6 +33,7 @@ bigdecimal = { version = ">=0.0.13, < 0.4.0", optional = true }
 bitflags = { version = "1.2.0", optional = true }
 r2d2 = { version = ">= 0.8.2, < 0.9.0", optional = true }
 itoa = { version = "1.0.0", optional = true }
+time = { version = "0.3.9", optional = true, features = ["macros", "formatting", "parsing"] }
 
 [dependencies.diesel_derives]
 version = "~2.0.0-rc.1"
@@ -46,7 +47,7 @@ quickcheck = "1.0.3"
 
 [features]
 default = ["with-deprecated", "32-column-tables"]
-extras = ["chrono", "serde_json", "uuid", "network-address", "numeric", "r2d2"]
+extras = ["chrono", "time", "serde_json", "uuid", "network-address", "numeric", "r2d2"]
 unstable = ["diesel_derives/nightly"]
 large-tables = ["32-column-tables"]
 huge-tables = ["64-column-tables"]
@@ -54,6 +55,10 @@ huge-tables = ["64-column-tables"]
 64-column-tables = ["32-column-tables", "diesel_derives/64-column-tables"]
 128-column-tables = ["64-column-tables", "diesel_derives/128-column-tables"]
 postgres = ["pq-sys", "postgres_backend"]
+# If we bumped the diesel MSRV to 1.60, we could eliminate the `time` "formatting" and "parsing" features
+# from the main import and instead put them into the `sqlite` dependency here, as
+# sqlite = ["libsqlite3-sys", "diesel_derives/sqlite", "time?/formatting", "time?/parsing"]
+# https://doc.rust-lang.org/cargo/reference/features.html#dependency-features
 sqlite = ["libsqlite3-sys", "diesel_derives/sqlite"]
 mysql = ["mysqlclient-sys", "url", "percent-encoding", "bitflags", "mysql_backend"]
 without-deprecated = ["diesel_derives/without-deprecated"]
diff --git a/diesel/src/mysql/connection/stmt/iterator.rs b/diesel/src/mysql/connection/stmt/iterator.rs
index cb307d3d8b97..078fa54d0375 100644
--- a/diesel/src/mysql/connection/stmt/iterator.rs
+++ b/diesel/src/mysql/connection/stmt/iterator.rs
@@ -225,6 +225,7 @@ impl<'a> Field<'a, Mysql> for MysqlField<'a> {
 }
 
 #[test]
+#[allow(clippy::drop_non_drop)] // we want to explicitly extend lifetimes here
 fn fun_with_row_iters() {
     crate::table! {
         #[allow(unused_parens)]
diff --git a/diesel/src/mysql/types/date_and_time.rs b/diesel/src/mysql/types/date_and_time/chrono.rs
similarity index 59%
rename from diesel/src/mysql/types/date_and_time.rs
rename to diesel/src/mysql/types/date_and_time/chrono.rs
index 7479a689a41e..821792f0cc2c 100644
--- a/diesel/src/mysql/types/date_and_time.rs
+++ b/diesel/src/mysql/types/date_and_time/chrono.rs
@@ -1,140 +1,12 @@
-#[cfg(feature = "chrono")]
-use chrono::*;
-use std::io::Write;
+use ::chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike};
 use std::os::raw as libc;
-use std::{mem, slice};
 
-use crate::deserialize::{self, FromSql, FromSqlRow};
-use crate::expression::AsExpression;
+use crate::deserialize::{self, FromSql};
 use crate::mysql::{Mysql, MysqlValue};
-use crate::serialize::{self, IsNull, Output, ToSql};
+use crate::serialize::{self, Output, ToSql};
 use crate::sql_types::{Date, Datetime, Time, Timestamp};
 
-// This is a type from libmysqlclient
-// we have our own copy here to not break the
-// public API as soon as this type changes
-// in the mysqlclient-sys dependency
-/// Corresponding rust representation of the
-/// [MYSQL_TIME](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html)
-/// struct from libmysqlclient
-#[repr(C)]
-#[derive(Debug, Clone, Copy, AsExpression, FromSqlRow)]
-#[non_exhaustive]
-#[diesel(sql_type = Timestamp)]
-#[diesel(sql_type = Time)]
-#[diesel(sql_type = Date)]
-#[diesel(sql_type = Datetime)]
-pub struct MysqlTime {
-    /// [Year field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#af585231d3ed0bc2fa389856e61e15d4e)
-    pub year: libc::c_uint,
-    /// [Month field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#ad3e92bddbd9ccf2e50117bdd51c235a2)
-    pub month: libc::c_uint,
-    /// [Day field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#ad51088bd5ab4ddc02e62d778d71ed808)
-    pub day: libc::c_uint,
-    /// [Hour field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#a7717a9c4de23a22863fe9c20b0706274)
-    pub hour: libc::c_uint,
-    /// [Minute field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#acfad0dafd22da03a527c58fdebfa9d14)
-    pub minute: libc::c_uint,
-    /// [Second field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#a4cceb29d1a457f2ea961ce0d893814da)
-    pub second: libc::c_uint,
-    /// [Microseconds](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#a2e0fddb071af25ff478d16dc5514ba71)
-    pub second_part: libc::c_ulong,
-    /// [Is this a negative timestamp](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#af13161fbff85e4fe0ec9cd49b6eac1b8)
-    pub neg: bool,
-    /// [Timestamp type](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#a5331236f9b527a6e6b5f23d7c8058665)
-    pub time_type: MysqlTimestampType,
-    /// [Time zone displacement specified is seconds](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#a07f3c8e1989c9805ba919d2120c8fed4)
-    pub time_zone_displacement: libc::c_int,
-}
-
-impl MysqlTime {
-    /// Construct a new instance of [MysqlTime]
-    #[allow(clippy::too_many_arguments)]
-    pub fn new(
-        year: libc::c_uint,
-        month: libc::c_uint,
-        day: libc::c_uint,
-        hour: libc::c_uint,
-        minute: libc::c_uint,
-        second: libc::c_uint,
-        second_part: libc::c_ulong,
-        neg: bool,
-        time_type: MysqlTimestampType,
-        time_zone_displacement: libc::c_int,
-    ) -> Self {
-        Self {
-            year,
-            month,
-            day,
-            hour,
-            minute,
-            second,
-            second_part,
-            neg,
-            time_type,
-            time_zone_displacement,
-        }
-    }
-}
-
-// This is a type from libmysqlclient
-// we have our own copy here to not break the
-// public API as soon as this type changes
-// in the mysqlclient-sys dependency
-/// Rust representation of
-/// [enum_mysql_timestamp_type](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73)
-#[derive(PartialEq, Debug, Copy, Clone)]
-#[repr(transparent)]
-pub struct MysqlTimestampType(libc::c_int);
-
-impl MysqlTimestampType {
-    /// Rust representation of
-    /// [MYSQL_TIMESTAMP_NONE](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73ace26c6b7d67a27c905dbcd130b3bd807)
-    pub const MYSQL_TIMESTAMP_NONE: MysqlTimestampType = MysqlTimestampType(-2);
-    /// Rust representation of
-    /// [MYSQL_TIMESTAMP_ERROR](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73a3518624dcc1eaca8d816c52aa7528f72)
-    pub const MYSQL_TIMESTAMP_ERROR: MysqlTimestampType = MysqlTimestampType(-1);
-    /// Rust representation of
-    /// [MYSQL_TIMESTAMP_DATE](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73a9e0845dc169b1f0056d2ffa3780c3f4e)
-    pub const MYSQL_TIMESTAMP_DATE: MysqlTimestampType = MysqlTimestampType(0);
-    /// Rust representation of
-    /// [MYSQL_TIMESTAMP_DATETIME](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73a8f6d8f066ea6ea77280c6a0baf063ce1)
-    pub const MYSQL_TIMESTAMP_DATETIME: MysqlTimestampType = MysqlTimestampType(1);
-    /// Rust representation of
-    /// [MYSQL_TIMESTAMP_TIME](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73a283c50fa3c62a2e17ad5173442edbbb9)
-    pub const MYSQL_TIMESTAMP_TIME: MysqlTimestampType = MysqlTimestampType(2);
-    /// Rust representation of
-    /// [MYSQL_TIMESTAMP_DATETIME_TZ](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73a7afc91f565961eb5f3beebfebe7243a2)
-    pub const MYSQL_TIMESTAMP_DATETIME_TZ: MysqlTimestampType = MysqlTimestampType(3);
-}
-
-macro_rules! mysql_time_impls {
-    ($ty:ty) => {
-        #[cfg(feature = "mysql_backend")]
-        impl ToSql<$ty, Mysql> for MysqlTime {
-            fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
-                let bytes = unsafe {
-                    let bytes_ptr = self as *const MysqlTime as *const u8;
-                    slice::from_raw_parts(bytes_ptr, mem::size_of::<MysqlTime>())
-                };
-                out.write_all(bytes)?;
-                Ok(IsNull::No)
-            }
-        }
-
-        #[cfg(feature = "mysql_backend")]
-        impl FromSql<$ty, Mysql> for MysqlTime {
-            fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
-                value.time_value()
-            }
-        }
-    };
-}
-
-mysql_time_impls!(Datetime);
-mysql_time_impls!(Timestamp);
-mysql_time_impls!(Time);
-mysql_time_impls!(Date);
+use super::{MysqlTime, MysqlTimestampType};
 
 #[cfg(all(feature = "chrono", feature = "mysql_backend"))]
 impl ToSql<Datetime, Mysql> for NaiveDateTime {
@@ -258,7 +130,7 @@ impl FromSql<Date, Mysql> for NaiveDate {
     }
 }
 
-#[cfg(all(test, feature = "chrono"))]
+#[cfg(test)]
 mod tests {
     extern crate chrono;
     extern crate dotenvy;
diff --git a/diesel/src/mysql/types/date_and_time/mod.rs b/diesel/src/mysql/types/date_and_time/mod.rs
new file mode 100644
index 000000000000..113552d4f546
--- /dev/null
+++ b/diesel/src/mysql/types/date_and_time/mod.rs
@@ -0,0 +1,140 @@
+use std::io::Write;
+use std::os::raw as libc;
+use std::{mem, slice};
+
+use crate::deserialize::{self, FromSql, FromSqlRow};
+use crate::expression::AsExpression;
+use crate::mysql::{Mysql, MysqlValue};
+use crate::serialize::{self, IsNull, Output, ToSql};
+use crate::sql_types::{Date, Datetime, Time, Timestamp};
+
+#[cfg(feature = "chrono")]
+mod chrono;
+#[cfg(feature = "time")]
+mod time;
+
+// This is a type from libmysqlclient
+// we have our own copy here to not break the
+// public API as soon as this type changes
+// in the mysqlclient-sys dependency
+/// Corresponding rust representation of the
+/// [MYSQL_TIME](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html)
+/// struct from libmysqlclient
+#[repr(C)]
+#[derive(Debug, Clone, Copy, AsExpression, FromSqlRow)]
+#[non_exhaustive]
+#[diesel(sql_type = Timestamp)]
+#[diesel(sql_type = Time)]
+#[diesel(sql_type = Date)]
+#[diesel(sql_type = Datetime)]
+pub struct MysqlTime {
+    /// [Year field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#af585231d3ed0bc2fa389856e61e15d4e)
+    pub year: libc::c_uint,
+    /// [Month field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#ad3e92bddbd9ccf2e50117bdd51c235a2)
+    pub month: libc::c_uint,
+    /// [Day field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#ad51088bd5ab4ddc02e62d778d71ed808)
+    pub day: libc::c_uint,
+    /// [Hour field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#a7717a9c4de23a22863fe9c20b0706274)
+    pub hour: libc::c_uint,
+    /// [Minute field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#acfad0dafd22da03a527c58fdebfa9d14)
+    pub minute: libc::c_uint,
+    /// [Second field](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#a4cceb29d1a457f2ea961ce0d893814da)
+    pub second: libc::c_uint,
+    /// [Microseconds](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#a2e0fddb071af25ff478d16dc5514ba71)
+    pub second_part: libc::c_ulong,
+    /// [Is this a negative timestamp](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#af13161fbff85e4fe0ec9cd49b6eac1b8)
+    pub neg: bool,
+    /// [Timestamp type](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#a5331236f9b527a6e6b5f23d7c8058665)
+    pub time_type: MysqlTimestampType,
+    /// [Time zone displacement specified is seconds](https://dev.mysql.com/doc/dev/mysql-server/latest/structMYSQL__TIME.html#a07f3c8e1989c9805ba919d2120c8fed4)
+    pub time_zone_displacement: libc::c_int,
+}
+
+impl MysqlTime {
+    /// Construct a new instance of [MysqlTime]
+    #[allow(clippy::too_many_arguments)]
+    pub fn new(
+        year: libc::c_uint,
+        month: libc::c_uint,
+        day: libc::c_uint,
+        hour: libc::c_uint,
+        minute: libc::c_uint,
+        second: libc::c_uint,
+        second_part: libc::c_ulong,
+        neg: bool,
+        time_type: MysqlTimestampType,
+        time_zone_displacement: libc::c_int,
+    ) -> Self {
+        Self {
+            year,
+            month,
+            day,
+            hour,
+            minute,
+            second,
+            second_part,
+            neg,
+            time_type,
+            time_zone_displacement,
+        }
+    }
+}
+
+// This is a type from libmysqlclient
+// we have our own copy here to not break the
+// public API as soon as this type changes
+// in the mysqlclient-sys dependency
+/// Rust representation of
+/// [enum_mysql_timestamp_type](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73)
+#[derive(PartialEq, Debug, Copy, Clone)]
+#[repr(transparent)]
+pub struct MysqlTimestampType(libc::c_int);
+
+impl MysqlTimestampType {
+    /// Rust representation of
+    /// [MYSQL_TIMESTAMP_NONE](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73ace26c6b7d67a27c905dbcd130b3bd807)
+    pub const MYSQL_TIMESTAMP_NONE: MysqlTimestampType = MysqlTimestampType(-2);
+    /// Rust representation of
+    /// [MYSQL_TIMESTAMP_ERROR](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73a3518624dcc1eaca8d816c52aa7528f72)
+    pub const MYSQL_TIMESTAMP_ERROR: MysqlTimestampType = MysqlTimestampType(-1);
+    /// Rust representation of
+    /// [MYSQL_TIMESTAMP_DATE](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73a9e0845dc169b1f0056d2ffa3780c3f4e)
+    pub const MYSQL_TIMESTAMP_DATE: MysqlTimestampType = MysqlTimestampType(0);
+    /// Rust representation of
+    /// [MYSQL_TIMESTAMP_DATETIME](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73a8f6d8f066ea6ea77280c6a0baf063ce1)
+    pub const MYSQL_TIMESTAMP_DATETIME: MysqlTimestampType = MysqlTimestampType(1);
+    /// Rust representation of
+    /// [MYSQL_TIMESTAMP_TIME](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73a283c50fa3c62a2e17ad5173442edbbb9)
+    pub const MYSQL_TIMESTAMP_TIME: MysqlTimestampType = MysqlTimestampType(2);
+    /// Rust representation of
+    /// [MYSQL_TIMESTAMP_DATETIME_TZ](https://dev.mysql.com/doc/dev/mysql-server/latest/mysql__time_8h.html#aa633db8da896a5a0cc00ffcfb7477e73a7afc91f565961eb5f3beebfebe7243a2)
+    pub const MYSQL_TIMESTAMP_DATETIME_TZ: MysqlTimestampType = MysqlTimestampType(3);
+}
+
+macro_rules! mysql_time_impls {
+    ($ty:ty) => {
+        #[cfg(feature = "mysql_backend")]
+        impl ToSql<$ty, Mysql> for MysqlTime {
+            fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
+                let bytes = unsafe {
+                    let bytes_ptr = self as *const MysqlTime as *const u8;
+                    slice::from_raw_parts(bytes_ptr, mem::size_of::<MysqlTime>())
+                };
+                out.write_all(bytes)?;
+                Ok(IsNull::No)
+            }
+        }
+
+        #[cfg(feature = "mysql_backend")]
+        impl FromSql<$ty, Mysql> for MysqlTime {
+            fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
+                value.time_value()
+            }
+        }
+    };
+}
+
+mysql_time_impls!(Datetime);
+mysql_time_impls!(Timestamp);
+mysql_time_impls!(Time);
+mysql_time_impls!(Date);
diff --git a/diesel/src/mysql/types/date_and_time/time.rs b/diesel/src/mysql/types/date_and_time/time.rs
new file mode 100644
index 000000000000..0553835c7548
--- /dev/null
+++ b/diesel/src/mysql/types/date_and_time/time.rs
@@ -0,0 +1,332 @@
+use ::time::{
+    Date as NaiveDate, Month, OffsetDateTime, PrimitiveDateTime, Time as NaiveTime, UtcOffset,
+};
+use std::convert::TryInto;
+use std::os::raw as libc;
+
+use crate::deserialize::{self, FromSql};
+use crate::mysql::{Mysql, MysqlValue};
+use crate::serialize::{self, Output, ToSql};
+use crate::sql_types::{Date, Datetime, Time, Timestamp};
+
+use super::{MysqlTime, MysqlTimestampType};
+
+fn to_time(dt: MysqlTime) -> Result<NaiveTime, Box<dyn std::error::Error>> {
+    for (name, field) in [
+        ("year", dt.year),
+        ("month", dt.month),
+        ("day", dt.day),
+        ("offset", dt.time_zone_displacement as u32),
+    ] {
+        if field != 0 {
+            return Err(format!("Unable to convert {:?} to time: {} must be 0", dt, name).into());
+        }
+    }
+
+    let hour: u8 = dt.hour.try_into()?;
+    let minute: u8 = dt.minute.try_into()?;
+    let second: u8 = dt.second.try_into()?;
+    let microsecond: u32 = dt.second_part.try_into()?;
+
+    Ok(NaiveTime::from_hms_micro(
+        hour,
+        minute,
+        second,
+        microsecond,
+    )?)
+}
+
+fn to_datetime(dt: MysqlTime) -> Result<OffsetDateTime, Box<dyn std::error::Error>> {
+    let year: i32 = dt.year.try_into()?;
+    let month: u8 = dt.month.try_into()?;
+    let month: Month = month.try_into()?;
+    let day: u8 = dt.day.try_into()?;
+    let hour: u8 = dt.hour.try_into()?;
+    let minute: u8 = dt.minute.try_into()?;
+    let second: u8 = dt.second.try_into()?;
+    let microsecond: u32 = dt.second_part.try_into()?;
+    let offset = UtcOffset::from_whole_seconds(dt.time_zone_displacement)?;
+
+    Ok(PrimitiveDateTime::new(
+        NaiveDate::from_calendar_date(year, month, day)?,
+        NaiveTime::from_hms_micro(hour, minute, second, microsecond)?,
+    )
+    .assume_offset(offset))
+}
+
+fn to_primitive_datetime(dt: OffsetDateTime) -> PrimitiveDateTime {
+    let dt = dt.to_offset(UtcOffset::UTC);
+    PrimitiveDateTime::new(dt.date(), dt.time())
+}
+
+// Mysql datetime column has a wider range than timestamp column, so let's implement the fundamental operations in terms of datetime.
+#[cfg(all(feature = "time", feature = "mysql_backend"))]
+impl ToSql<Datetime, Mysql> for PrimitiveDateTime {
+    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
+        let mysql_time = MysqlTime {
+            year: self.year() as libc::c_uint,
+            month: self.month() as libc::c_uint,
+            day: self.day() as libc::c_uint,
+            hour: self.hour() as libc::c_uint,
+            minute: self.minute() as libc::c_uint,
+            second: self.second() as libc::c_uint,
+            second_part: libc::c_ulong::from(self.microsecond()),
+            neg: false,
+            time_type: MysqlTimestampType::MYSQL_TIMESTAMP_DATETIME,
+            time_zone_displacement: 0,
+        };
+
+        <MysqlTime as ToSql<Timestamp, Mysql>>::to_sql(&mysql_time, &mut out.reborrow())
+    }
+}
+
+#[cfg(all(feature = "time", feature = "mysql_backend"))]
+impl FromSql<Datetime, Mysql> for PrimitiveDateTime {
+    fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
+        let mysql_time = <MysqlTime as FromSql<Timestamp, Mysql>>::from_sql(bytes)?;
+
+        to_datetime(mysql_time)
+            .map(to_primitive_datetime)
+            .map_err(|err| format!("Cannot parse this date: {:?}: {}", mysql_time, err).into())
+    }
+}
+
+// We can implement timestamps in terms of datetimes
+#[cfg(all(feature = "time", feature = "mysql_backend"))]
+impl ToSql<Timestamp, Mysql> for PrimitiveDateTime {
+    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
+        <PrimitiveDateTime as ToSql<Datetime, Mysql>>::to_sql(self, out)
+    }
+}
+
+#[cfg(all(feature = "time", feature = "mysql_backend"))]
+impl FromSql<Timestamp, Mysql> for PrimitiveDateTime {
+    fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
+        <PrimitiveDateTime as FromSql<Datetime, Mysql>>::from_sql(bytes)
+    }
+}
+
+// Delegate offset datetimes in terms of UTC primitive datetimes; this stores everything in the DB as UTC
+#[cfg(all(feature = "time", feature = "mysql_backend"))]
+impl ToSql<Datetime, Mysql> for OffsetDateTime {
+    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
+        let prim = to_primitive_datetime(*self);
+        <PrimitiveDateTime as ToSql<Datetime, Mysql>>::to_sql(&prim, &mut out.reborrow())
+    }
+}
+
+#[cfg(all(feature = "time", feature = "mysql_backend"))]
+impl FromSql<Datetime, Mysql> for OffsetDateTime {
+    fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
+        let prim = <PrimitiveDateTime as FromSql<Datetime, Mysql>>::from_sql(bytes)?;
+        Ok(prim.assume_offset(UtcOffset::UTC))
+    }
+}
+
+// delegate timestamp column to datetime colum for offset datetimes
+#[cfg(all(feature = "time", feature = "mysql_backend"))]
+impl ToSql<Timestamp, Mysql> for OffsetDateTime {
+    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
+        <OffsetDateTime as ToSql<Datetime, Mysql>>::to_sql(self, out)
+    }
+}
+
+#[cfg(all(feature = "time", feature = "mysql_backend"))]
+impl FromSql<Timestamp, Mysql> for OffsetDateTime {
+    fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
+        <OffsetDateTime as FromSql<Datetime, Mysql>>::from_sql(bytes)
+    }
+}
+
+#[cfg(all(feature = "time", feature = "mysql_backend"))]
+impl ToSql<Time, Mysql> for NaiveTime {
+    fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, Mysql>) -> serialize::Result {
+        let mysql_time = MysqlTime {
+            hour: self.hour() as libc::c_uint,
+            minute: self.minute() as libc::c_uint,
+            second: self.second() as libc::c_uint,
+            day: 0,
+            month: 0,
+            second_part: 0,
+            year: 0,
+            neg: false,
+            time_type: MysqlTimestampType::MYSQL_TIMESTAMP_TIME,
+            time_zone_displacement: 0,
+        };
+
+        <MysqlTime as ToSql<Time, Mysql>>::to_sql(&mysql_time, &mut out.reborrow())
+    }
+}
+
+#[cfg(all(feature = "time", feature = "mysql_backend"))]
+impl FromSql<Time, Mysql> for NaiveTime {
+    fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
+        let mysql_time = <MysqlTime as FromSql<Time, Mysql>>::from_sql(bytes)?;
+
+        to_time(mysql_time)
+            .map_err(|err| format!("Unable to convert {:?} to time: {}", mysql_time, err).into())
+    }
+}
+
+#[cfg(all(feature = "time", feature = "mysql_backend"))]
+impl ToSql<Date, Mysql> for NaiveDate {
+    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
+        let mysql_time = MysqlTime {
+            year: self.year() as libc::c_uint,
+            month: self.month() as libc::c_uint,
+            day: self.day() as libc::c_uint,
+            hour: 0,
+            minute: 0,
+            second: 0,
+            second_part: 0,
+            neg: false,
+            time_type: MysqlTimestampType::MYSQL_TIMESTAMP_DATE,
+            time_zone_displacement: 0,
+        };
+
+        <MysqlTime as ToSql<Date, Mysql>>::to_sql(&mysql_time, &mut out.reborrow())
+    }
+}
+
+#[cfg(all(feature = "time", feature = "mysql_backend"))]
+impl FromSql<Date, Mysql> for NaiveDate {
+    fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
+        let mysql_time = <MysqlTime as FromSql<Date, Mysql>>::from_sql(bytes)?;
+
+        to_datetime(mysql_time)
+            .map_err(|err| format!("Unable to convert {:?} to time: {}", mysql_time, err).into())
+            .and_then(|dt| {
+                let prim = to_primitive_datetime(dt);
+                if prim.time() == NaiveTime::MIDNIGHT {
+                    Ok(prim.date())
+                } else {
+                    Err(format!("Unable to convert {:?} to date: non-0 time part", prim).into())
+                }
+            })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    extern crate dotenvy;
+    extern crate time;
+
+    use ::time::{
+        macros::{date, datetime, time},
+        Date as NaiveDate, Duration, OffsetDateTime, Time as NaiveTime,
+    };
+
+    use super::to_primitive_datetime;
+
+    use crate::dsl::{now, sql};
+    use crate::prelude::*;
+    use crate::select;
+    use crate::sql_types::{Date, Datetime, Time, Timestamp};
+    use crate::test_helpers::connection;
+
+    #[test]
+    fn unix_epoch_encodes_correctly() {
+        let connection = &mut connection();
+        let time = datetime!(1970-1-1 0:0:0);
+        let query = select(sql::<Timestamp>("CAST('1970-01-01' AS DATETIME)").eq(time));
+        assert!(query.get_result::<bool>(connection).unwrap());
+        let query = select(sql::<Datetime>("CAST('1970-01-01' AS DATETIME)").eq(time));
+        assert!(query.get_result::<bool>(connection).unwrap());
+    }
+
+    #[test]
+    fn unix_epoch_decodes_correctly() {
+        let connection = &mut connection();
+        let time = datetime!(1970-1-1 0:0:0);
+        let epoch_from_sql =
+            select(sql::<Timestamp>("CAST('1970-01-01' AS DATETIME)")).get_result(connection);
+        assert_eq!(Ok(time), epoch_from_sql);
+        let epoch_from_sql =
+            select(sql::<Datetime>("CAST('1970-01-01' AS DATETIME)")).get_result(connection);
+        assert_eq!(Ok(time), epoch_from_sql);
+    }
+
+    #[test]
+    fn times_relative_to_now_encode_correctly() {
+        let connection = &mut connection();
+        let time = to_primitive_datetime(OffsetDateTime::now_utc()) + Duration::days(1);
+        let query = select(now.lt(time));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let time = to_primitive_datetime(OffsetDateTime::now_utc()) - Duration::days(1);
+        let query = select(now.gt(time));
+        assert!(query.get_result::<bool>(connection).unwrap());
+    }
+
+    #[test]
+    fn times_of_day_encode_correctly() {
+        let connection = &mut connection();
+
+        let midnight = time!(0:0:0);
+        let query = select(sql::<Time>("CAST('00:00:00' AS TIME)").eq(midnight));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let noon = time!(12:0:0);
+        let query = select(sql::<Time>("CAST('12:00:00' AS TIME)").eq(noon));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let roughly_half_past_eleven = time!(23:37:4);
+        let query = select(sql::<Time>("CAST('23:37:04' AS TIME)").eq(roughly_half_past_eleven));
+        assert!(query.get_result::<bool>(connection).unwrap());
+    }
+
+    #[test]
+    fn times_of_day_decode_correctly() {
+        let connection = &mut connection();
+        let midnight = time!(0:0:0);
+        let query = select(sql::<Time>("CAST('00:00:00' AS TIME)"));
+        assert_eq!(Ok(midnight), query.get_result::<NaiveTime>(connection));
+
+        let noon = time!(12:0:0);
+        let query = select(sql::<Time>("CAST('12:00:00' AS TIME)"));
+        assert_eq!(Ok(noon), query.get_result::<NaiveTime>(connection));
+
+        let roughly_half_past_eleven = time!(23:37:4);
+        let query = select(sql::<Time>("CAST('23:37:04' AS TIME)"));
+        assert_eq!(
+            Ok(roughly_half_past_eleven),
+            query.get_result::<NaiveTime>(connection)
+        );
+    }
+
+    #[test]
+    fn dates_encode_correctly() {
+        let connection = &mut connection();
+        let january_first_2000 = date!(2000 - 1 - 1);
+        let query = select(sql::<Date>("CAST('2000-1-1' AS DATE)").eq(january_first_2000));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let january_first_2018 = date!(2018 - 1 - 1);
+        let query = select(sql::<Date>("CAST('2018-1-1' AS DATE)").eq(january_first_2018));
+        assert!(query.get_result::<bool>(connection).unwrap());
+    }
+
+    #[test]
+    fn dates_decode_correctly() {
+        let connection = &mut connection();
+        let january_first_2000 = date!(2000 - 1 - 1);
+        let query = select(sql::<Date>("CAST('2000-1-1' AS DATE)"));
+        assert_eq!(
+            Ok(january_first_2000),
+            query.get_result::<NaiveDate>(connection)
+        );
+
+        let january_first_2018 = date!(2018 - 1 - 1);
+        let query = select(sql::<Date>("CAST('2018-1-1' AS DATE)"));
+        assert_eq!(
+            Ok(january_first_2018),
+            query.get_result::<NaiveDate>(connection)
+        );
+
+        crate::sql_query("SET sql_mode = (SELECT REPLACE(@@sql_mode, 'NO_ZERO_DATE,', ''))")
+            .execute(connection)
+            .unwrap();
+        let query = select(sql::<Date>("CAST('0000-00-00' AS DATE)"));
+        assert!(query.get_result::<NaiveDate>(connection).is_err());
+    }
+}
diff --git a/diesel/src/mysql/types/mod.rs b/diesel/src/mysql/types/mod.rs
index 1e6ef65addec..c60a8fc0e53b 100644
--- a/diesel/src/mysql/types/mod.rs
+++ b/diesel/src/mysql/types/mod.rs
@@ -219,10 +219,14 @@ impl HasSqlType<Unsigned<BigInt>> for Mysql {
 /// ### [`ToSql`] impls
 ///
 /// - [`chrono::NaiveDateTime`] with `feature = "chrono"`
+/// - [`time::PrimitiveDateTime`] with `feature = "time"`
+/// - [`time::OffsetDateTime`] with `feature = "time"`
 ///
 /// ### [`FromSql`] impls
 ///
 /// - [`chrono::NaiveDateTime`] with `feature = "chrono"`
+/// - [`time::PrimitiveDateTime`] with `feature = "time"`
+/// - [`time::OffsetDateTime`] with `feature = "time"`
 ///
 /// [`ToSql`]: crate::serialize::ToSql
 /// [`FromSql`]: crate::deserialize::FromSql
@@ -234,6 +238,22 @@ impl HasSqlType<Unsigned<BigInt>> for Mysql {
     not(feature = "chrono"),
     doc = " [`chrono::NaiveDateTime`]: https://docs.rs/chrono/0.4.19/chrono/naive/struct.NaiveDateTime.html"
 )]
+#[cfg_attr(
+    feature = "time",
+    doc = " [`time::PrimitiveDateTime`]: time::PrimitiveDateTime"
+)]
+#[cfg_attr(
+    not(feature = "time"),
+    doc = " [`time::PrimitiveDateTime`]: https://docs.rs/time/0.3.9/time/struct.PrimitiveDateTime.html"
+)]
+#[cfg_attr(
+    feature = "time",
+    doc = " [`time::OffsetDateTime`]: time::OffsetDateTime"
+)]
+#[cfg_attr(
+    not(feature = "time"),
+    doc = " [`time::OffsetDateTime`]: https://docs.rs/time/0.3.9/time/struct.OffsetDateTime.html"
+)]
 #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)]
 #[diesel(mysql_type(name = "DateTime"))]
 #[cfg(feature = "mysql_backend")]
diff --git a/diesel/src/pg/types/date_and_time/mod.rs b/diesel/src/pg/types/date_and_time/mod.rs
index abc8d5ec99fc..ef87d78eea6c 100644
--- a/diesel/src/pg/types/date_and_time/mod.rs
+++ b/diesel/src/pg/types/date_and_time/mod.rs
@@ -11,6 +11,8 @@ mod chrono;
 #[cfg(feature = "quickcheck")]
 mod quickcheck_impls;
 mod std_time;
+#[cfg(feature = "time")]
+mod time;
 
 #[cfg(feature = "postgres_backend")]
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, AsExpression, FromSqlRow)]
diff --git a/diesel/src/pg/types/date_and_time/time.rs b/diesel/src/pg/types/date_and_time/time.rs
new file mode 100644
index 000000000000..f75b56978026
--- /dev/null
+++ b/diesel/src/pg/types/date_and_time/time.rs
@@ -0,0 +1,305 @@
+//! This module makes it possible to map `time` date and time values to postgres `Date`
+//! and `Timestamp` fields. It is enabled with the `time` feature.
+
+extern crate time;
+
+use self::time::{
+    macros::{date, datetime},
+    Date as NaiveDate, Duration, OffsetDateTime, PrimitiveDateTime, Time as NaiveTime, UtcOffset,
+};
+
+use super::{PgDate, PgTime, PgTimestamp};
+use crate::deserialize::{self, FromSql};
+use crate::pg::{Pg, PgValue};
+use crate::serialize::{self, Output, ToSql};
+use crate::sql_types::{Date, Time, Timestamp, Timestamptz};
+
+// Postgres timestamps start from January 1st 2000.
+const PG_EPOCH: PrimitiveDateTime = datetime!(2000-1-1 0:00:00);
+
+#[cfg(all(feature = "time", feature = "postgres_backend"))]
+impl FromSql<Timestamp, Pg> for PrimitiveDateTime {
+    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
+        let PgTimestamp(offset) = FromSql::<Timestamp, Pg>::from_sql(bytes)?;
+        match PG_EPOCH.checked_add(Duration::microseconds(offset)) {
+            Some(v) => Ok(v),
+            None => {
+                let message = "Tried to deserialize a timestamp that is too large for Time";
+                Err(message.into())
+            }
+        }
+    }
+}
+
+#[cfg(all(feature = "time", feature = "postgres_backend"))]
+impl ToSql<Timestamp, Pg> for PrimitiveDateTime {
+    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
+        let micros = (*self - PG_EPOCH).whole_microseconds();
+        if micros > (i64::MAX as i128) {
+            let error_message = format!("{:?} as microseconds is too large to fit in an i64", self);
+            return Err(error_message.into());
+        }
+        let micros = micros as i64;
+        ToSql::<Timestamp, Pg>::to_sql(&PgTimestamp(micros), &mut out.reborrow())
+    }
+}
+
+#[cfg(all(feature = "time", feature = "postgres_backend"))]
+impl FromSql<Timestamptz, Pg> for PrimitiveDateTime {
+    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
+        FromSql::<Timestamp, Pg>::from_sql(bytes)
+    }
+}
+
+#[cfg(all(feature = "time", feature = "postgres_backend"))]
+impl ToSql<Timestamptz, Pg> for PrimitiveDateTime {
+    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
+        ToSql::<Timestamp, Pg>::to_sql(self, out)
+    }
+}
+
+#[cfg(all(feature = "time", feature = "postgres_backend"))]
+impl FromSql<Timestamptz, Pg> for OffsetDateTime {
+    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
+        let primitive_date_time = <PrimitiveDateTime as FromSql<Timestamptz, Pg>>::from_sql(bytes)?;
+        Ok(primitive_date_time.assume_utc())
+    }
+}
+
+#[cfg(all(feature = "time", feature = "postgres_backend"))]
+impl ToSql<Timestamptz, Pg> for OffsetDateTime {
+    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
+        let as_utc = self.to_offset(UtcOffset::UTC);
+        let primitive_date_time = PrimitiveDateTime::new(as_utc.date(), as_utc.time());
+        ToSql::<Timestamptz, Pg>::to_sql(&primitive_date_time, &mut out.reborrow())
+    }
+}
+
+#[cfg(all(feature = "time", feature = "postgres_backend"))]
+impl ToSql<Time, Pg> for NaiveTime {
+    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
+        let duration = *self - NaiveTime::MIDNIGHT;
+        // microseconds in a day cannot overflow i64
+        let micros = duration.whole_microseconds() as i64;
+        ToSql::<Time, Pg>::to_sql(&PgTime(micros), &mut out.reborrow())
+    }
+}
+
+#[cfg(all(feature = "time", feature = "postgres_backend"))]
+impl FromSql<Time, Pg> for NaiveTime {
+    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
+        let PgTime(offset) = FromSql::<Time, Pg>::from_sql(bytes)?;
+        let duration = Duration::microseconds(offset);
+        Ok(NaiveTime::MIDNIGHT + duration)
+    }
+}
+
+const PG_EPOCH_DATE: NaiveDate = date!(2000 - 1 - 1);
+
+#[cfg(all(feature = "time", feature = "postgres_backend"))]
+impl ToSql<Date, Pg> for NaiveDate {
+    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
+        let days_since_epoch = (*self - PG_EPOCH_DATE).whole_days();
+        ToSql::<Date, Pg>::to_sql(&PgDate(days_since_epoch as i32), &mut out.reborrow())
+    }
+}
+
+#[cfg(all(feature = "time", feature = "postgres_backend"))]
+impl FromSql<Date, Pg> for NaiveDate {
+    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
+        let PgDate(offset) = FromSql::<Date, Pg>::from_sql(bytes)?;
+        match PG_EPOCH_DATE.checked_add(Duration::days(i64::from(offset))) {
+            Some(date) => Ok(date),
+            None => {
+                let error_message =
+                    format!("Time can only represent dates up to {:?}", NaiveDate::MAX);
+                Err(error_message.into())
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    extern crate dotenvy;
+
+    use crate::dsl::{now, sql};
+    use crate::prelude::*;
+    use crate::select;
+    use crate::sql_types::{Date, Time, Timestamp, Timestamptz};
+    use crate::test_helpers::connection;
+
+    use time::{
+        macros::{date, datetime},
+        Date as NaiveDate, Duration, OffsetDateTime, PrimitiveDateTime, Time as NaiveTime,
+    };
+
+    fn naive_now() -> PrimitiveDateTime {
+        let offset_now = OffsetDateTime::now_utc();
+        PrimitiveDateTime::new(offset_now.date(), offset_now.time())
+    }
+
+    #[test]
+    fn unix_epoch_encodes_correctly() {
+        let connection = &mut connection();
+        let time = datetime!(1970-1-1 0:00:00);
+        let query = select(sql::<Timestamp>("'1970-01-01'").eq(time));
+        assert!(query.get_result::<bool>(connection).unwrap());
+    }
+
+    #[test]
+    fn unix_epoch_encodes_correctly_with_utc_timezone() {
+        let connection = &mut connection();
+        let time = datetime!(1970-1-1 0:00:00 utc);
+        let query = select(sql::<Timestamptz>("'1970-01-01Z'::timestamptz").eq(time));
+        assert!(query.get_result::<bool>(connection).unwrap());
+    }
+
+    #[test]
+    fn unix_epoch_encodes_correctly_with_timezone() {
+        let connection = &mut connection();
+        let time = datetime!(1970-1-1 0:00:00 -1:00);
+        let query = select(sql::<Timestamptz>("'1970-01-01 01:00:00Z'::timestamptz").eq(time));
+        assert!(query.get_result::<bool>(connection).unwrap());
+    }
+
+    #[test]
+    fn unix_epoch_decodes_correctly() {
+        let connection = &mut connection();
+        let time = datetime!(1970-1-1 0:0:0);
+        let epoch_from_sql =
+            select(sql::<Timestamp>("'1970-01-01'::timestamp")).get_result(connection);
+        assert_eq!(Ok(time), epoch_from_sql);
+    }
+
+    #[test]
+    fn unix_epoch_decodes_correctly_with_timezone() {
+        let connection = &mut connection();
+        let time = datetime!(1970-1-1 0:00:00 utc);
+        let epoch_from_sql =
+            select(sql::<Timestamptz>("'1970-01-01Z'::timestamptz")).get_result(connection);
+        assert_eq!(Ok(time), epoch_from_sql);
+    }
+
+    #[test]
+    fn times_relative_to_now_encode_correctly() {
+        let connection = &mut connection();
+        let time = naive_now() + Duration::seconds(60);
+        let query = select(now.at_time_zone("utc").lt(time));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let time = naive_now() - Duration::seconds(60);
+        let query = select(now.at_time_zone("utc").gt(time));
+        assert!(query.get_result::<bool>(connection).unwrap());
+    }
+
+    #[test]
+    fn times_with_timezones_round_trip_after_conversion() {
+        let connection = &mut connection();
+        let time = datetime!(2016-1-2 1:00:00 +1);
+        let expected = datetime!(2016-1-1 20:0:0);
+        let query = select(time.into_sql::<Timestamptz>().at_time_zone("EDT"));
+        assert_eq!(Ok(expected), query.get_result(connection));
+    }
+
+    #[test]
+    fn times_of_day_encode_correctly() {
+        let connection = &mut connection();
+
+        let query = select(sql::<Time>("'00:00:00'::time").eq(NaiveTime::MIDNIGHT));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let noon = NaiveTime::from_hms(12, 0, 0).expect("noon is a legal time");
+        let query = select(sql::<Time>("'12:00:00'::time").eq(noon));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let roughly_half_past_eleven =
+            NaiveTime::from_hms_micro(23, 37, 4, 2200).expect("this is also a legal time");
+        let query = select(sql::<Time>("'23:37:04.002200'::time").eq(roughly_half_past_eleven));
+        assert!(query.get_result::<bool>(connection).unwrap());
+    }
+
+    #[test]
+    fn times_of_day_decode_correctly() {
+        let connection = &mut connection();
+        let query = select(sql::<Time>("'00:00:00'::time"));
+        let result: Result<NaiveTime, _> = query.get_result(connection);
+        assert_eq!(Ok(NaiveTime::MIDNIGHT), result);
+
+        let noon = NaiveTime::from_hms(12, 0, 0).expect("this time is legal");
+        let query = select(sql::<Time>("'12:00:00'::time"));
+        let result: Result<NaiveTime, _> = query.get_result(connection);
+        assert_eq!(Ok(noon), result);
+
+        let roughly_half_past_eleven =
+            NaiveTime::from_hms_micro(23, 37, 4, 2200).expect("this time is legal");
+        let query = select(sql::<Time>("'23:37:04.002200'::time"));
+        let result: Result<NaiveTime, _> = query.get_result(connection);
+        assert_eq!(Ok(roughly_half_past_eleven), result);
+    }
+
+    #[test]
+    fn dates_encode_correctly() {
+        let connection = &mut connection();
+        let january_first_2000 = date!(2000 - 1 - 1);
+        let query = select(sql::<Date>("'2000-1-1'").eq(january_first_2000));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let distant_past = date!(-398 - 4 - 11); // year 0 is 1 BC in this function
+        let query = select(sql::<Date>("'399-4-11 BC'").eq(distant_past));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let julian_epoch = date!(-4713 - 11 - 24);
+        let query = select(sql::<Date>("'J0'::date").eq(julian_epoch));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let max_date = NaiveDate::MAX;
+        let query = select(sql::<Date>("'9999-12-31'::date").eq(max_date));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let january_first_2018 = date!(2018 - 1 - 1);
+        let query = select(sql::<Date>("'2018-1-1'::date").eq(january_first_2018));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let distant_future = date!(9999 - 1 - 8);
+        let query = select(sql::<Date>("'9999-1-8'::date").eq(distant_future));
+        assert!(query.get_result::<bool>(connection).unwrap());
+    }
+
+    #[test]
+    fn dates_decode_correctly() {
+        let connection = &mut connection();
+        let january_first_2000 = date!(2000 - 1 - 1);
+        let query = select(sql::<Date>("'2000-1-1'::date"));
+        assert_eq!(
+            Ok(january_first_2000),
+            query.get_result::<NaiveDate>(connection)
+        );
+
+        let distant_past = date!(-398 - 4 - 11);
+        let query = select(sql::<Date>("'399-4-11 BC'::date"));
+        assert_eq!(Ok(distant_past), query.get_result::<NaiveDate>(connection));
+
+        let julian_epoch = date!(-4713 - 11 - 24);
+        let query = select(sql::<Date>("'J0'::date"));
+        assert_eq!(Ok(julian_epoch), query.get_result::<NaiveDate>(connection));
+
+        let max_date = NaiveDate::MAX;
+        let query = select(sql::<Date>("'9999-12-31'::date"));
+        assert_eq!(Ok(max_date), query.get_result::<NaiveDate>(connection));
+
+        let january_first_2018 = date!(2018 - 1 - 1);
+        let query = select(sql::<Date>("'2018-1-1'::date"));
+        assert_eq!(
+            Ok(january_first_2018),
+            query.get_result::<NaiveDate>(connection)
+        );
+
+        let distant_future = date!(9999 - 1 - 8);
+        let query = select(sql::<Date>("'9999-1-8'::date"));
+        assert_eq!(
+            Ok(distant_future),
+            query.get_result::<NaiveDate>(connection)
+        );
+    }
+}
diff --git a/diesel/src/pg/types/mod.rs b/diesel/src/pg/types/mod.rs
index 4e0632e0487e..e00522ad681e 100644
--- a/diesel/src/pg/types/mod.rs
+++ b/diesel/src/pg/types/mod.rs
@@ -56,12 +56,16 @@ pub mod sql_types {
     /// - [`PgTimestamp`]
     /// - [`chrono::NaiveDateTime`] with `feature = "chrono"`
     /// - [`chrono::DateTime`] with `feature = "chrono"`
+    /// - [`time::PrimitiveDateTime`] with `feature = "time"`
+    /// - [`time::OffsetDateTime`] with `feature = "time"`
     ///
     /// ### [`FromSql`] impls
     ///
     /// - [`PgTimestamp`]
     /// - [`chrono::NaiveDateTime`] with `feature = "chrono"`
     /// - [`chrono::DateTime`] with `feature = "chrono"`
+    /// - [`time::PrimitiveDateTime`] with `feature = "time"`
+    /// - [`time::OffsetDateTime`] with `feature = "time"`
     ///
     /// [`ToSql`]: crate::serialize::ToSql
     /// [`FromSql`]: crate::deserialize::FromSql
@@ -80,6 +84,22 @@ pub mod sql_types {
         not(feature = "chrono"),
         doc = " [`chrono::DateTime`]: https://docs.rs/chrono/0.4.19/chrono/struct.DateTime.html"
     )]
+    #[cfg_attr(
+        feature = "time",
+        doc = " [`time::PrimitiveDateTime`]: time::PrimitiveDateTime"
+    )]
+    #[cfg_attr(
+        not(feature = "time"),
+        doc = " [`time::PrimitiveDateTime`]: https://docs.rs/time/0.3.9/time/struct.PrimitiveDateTime.html"
+    )]
+    #[cfg_attr(
+        feature = "time",
+        doc = " [`time::OffsetDateTime`]: time::OffsetDateTime"
+    )]
+    #[cfg_attr(
+        not(feature = "time"),
+        doc = " [`time::OffsetDateTime`]: https://docs.rs/time/0.3.9/time/struct.OffsetDateTime.html"
+    )]
     #[cfg(feature = "postgres_backend")]
     #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)]
     #[diesel(postgres_type(oid = 1184, array_oid = 1185))]
diff --git a/diesel/src/sql_types/mod.rs b/diesel/src/sql_types/mod.rs
index 5dd33aaaa474..e8f7b666648a 100644
--- a/diesel/src/sql_types/mod.rs
+++ b/diesel/src/sql_types/mod.rs
@@ -272,12 +272,15 @@ pub type Bit = Binary;
 /// ### [`ToSql`](crate::serialize::ToSql) impls
 ///
 /// - [`chrono::NaiveDate`][NaiveDate] with `feature = "chrono"`
+/// - [`time::Date`][Date] with `feature = "time"`
 ///
 /// ### [`FromSql`](crate::deserialize::FromSql) impls
 ///
 /// - [`chrono::NaiveDate`][NaiveDate] with `feature = "chrono"`
+/// - [`time::Date`][Date] with `feature = "time"`
 ///
 /// [NaiveDate]: https://docs.rs/chrono/*/chrono/naive/struct.NaiveDate.html
+/// [Date]: https://docs.rs/time/0.3.9/time/struct.Date.html
 #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)]
 #[diesel(postgres_type(oid = 1082, array_oid = 1182))]
 #[diesel(sqlite_type(name = "Text"))]
@@ -307,12 +310,15 @@ pub struct Interval;
 /// ### [`ToSql`](crate::serialize::ToSql) impls
 ///
 /// - [`chrono::NaiveTime`][NaiveTime] with `feature = "chrono"`
+/// - [`time::Time`][Time] with `feature = "time"`
 ///
 /// ### [`FromSql`](crate::deserialize::FromSql) impls
 ///
 /// - [`chrono::NaiveTime`][NaiveTime] with `feature = "chrono"`
+/// - [`time::Time`][Time] with `feature = "time"`
 ///
 /// [NaiveTime]: /chrono/naive/time/struct.NaiveTime.html
+/// [Time]: /time/struct.Time.html
 #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)]
 #[diesel(postgres_type(oid = 1083, array_oid = 1183))]
 #[diesel(sqlite_type(name = "Text"))]
@@ -325,13 +331,15 @@ pub struct Time;
 ///
 /// - [`std::time::SystemTime`][SystemTime] (PG only)
 /// - [`chrono::NaiveDateTime`][NaiveDateTime] with `feature = "chrono"`
-/// - [`time::Timespec`][Timespec] with `feature = "deprecated-time"` (PG only)
+/// - [`time::PrimitiveDateTime`] with `feature = "time"`
+/// - [`time::OffsetDateTime`] with `feature = "time"`
 ///
 /// ### [`FromSql`](crate::deserialize::FromSql) impls
 ///
 /// - [`std::time::SystemTime`][SystemTime] (PG only)
 /// - [`chrono::NaiveDateTime`][NaiveDateTime] with `feature = "chrono"`
-/// - [`time::Timespec`][Timespec] with `feature = "deprecated-time"` (PG only)
+/// - [`time::PrimitiveDateTime`] with `feature = "time"`
+/// - [`time::OffsetDateTime`] with `feature = "time"`
 ///
 /// [SystemTime]: std::time::SystemTime
 #[cfg_attr(
@@ -342,6 +350,22 @@ pub struct Time;
     not(feature = "chrono"),
     doc = " [NaiveDateTime]: https://docs.rs/chrono/*/chrono/naive/struct.NaiveDateTime.html"
 )]
+#[cfg_attr(
+    feature = "time",
+    doc = " [`time::PrimitiveDateTime`]: time::PrimitiveDateTime"
+)]
+#[cfg_attr(
+    not(feature = "time"),
+    doc = " [`time::PrimitiveDateTime`]: https://docs.rs/time/0.3.9/time/struct.PrimitiveDateTime.html"
+)]
+#[cfg_attr(
+    feature = "time",
+    doc = " [`time::OffsetDateTime`]: time::OffsetDateTime"
+)]
+#[cfg_attr(
+    not(feature = "time"),
+    doc = " [`time::OffsetDateTime`]: https://docs.rs/time/0.3.9/time/struct.OffsetDateTime.html"
+)]
 /// [Timespec]: /time/struct.Timespec.html
 #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)]
 #[diesel(postgres_type(oid = 1114, array_oid = 1115))]
diff --git a/diesel/src/sqlite/types/date_and_time/chrono.rs b/diesel/src/sqlite/types/date_and_time/chrono.rs
index 5cbfab562d73..48a5f6e29dac 100644
--- a/diesel/src/sqlite/types/date_and_time/chrono.rs
+++ b/diesel/src/sqlite/types/date_and_time/chrono.rs
@@ -571,6 +571,11 @@ mod tests {
         let time: DateTime<Utc> = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 0, 1);
         let query = select(sql::<TimestamptzSqlite>("'1970-01-01 00:00:00.001+00:00'").eq(time));
         assert!(query.get_result::<bool>(connection).unwrap());
+
+        // and without millisecond
+        let time: DateTime<Utc> = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 0, 0);
+        let query = select(sql::<TimestamptzSqlite>("'1970-01-01 00:00:00+00:00'").eq(time));
+        assert!(query.get_result::<bool>(connection).unwrap());
     }
 
     #[test]
diff --git a/diesel/src/sqlite/types/date_and_time/mod.rs b/diesel/src/sqlite/types/date_and_time/mod.rs
index b52f87b8431a..98facfd4387c 100644
--- a/diesel/src/sqlite/types/date_and_time/mod.rs
+++ b/diesel/src/sqlite/types/date_and_time/mod.rs
@@ -6,6 +6,8 @@ use crate::sqlite::Sqlite;
 
 #[cfg(feature = "chrono")]
 mod chrono;
+#[cfg(feature = "time")]
+mod time;
 
 #[cfg(feature = "sqlite")]
 impl FromSql<sql_types::Date, Sqlite> for String {
diff --git a/diesel/src/sqlite/types/date_and_time/time.rs b/diesel/src/sqlite/types/date_and_time/time.rs
new file mode 100644
index 000000000000..3b6020b94df9
--- /dev/null
+++ b/diesel/src/sqlite/types/date_and_time/time.rs
@@ -0,0 +1,661 @@
+//! This module makes it possible to map `time` date and time values to sqlite `NUMERIC`
+//! fields. It is enabled with the `time` feature.
+
+extern crate time;
+
+use self::time::{
+    error::ComponentRange, format_description::FormatItem, macros::format_description,
+    Date as NaiveDate, OffsetDateTime, PrimitiveDateTime, Time as NaiveTime, UtcOffset,
+};
+
+use crate::backend;
+use crate::deserialize::{self, FromSql};
+use crate::serialize::{self, IsNull, Output, ToSql};
+use crate::sql_types::{Date, Time, Timestamp, TimestamptzSqlite};
+use crate::sqlite::Sqlite;
+
+const DATE_FORMAT: &[FormatItem<'_>] = format_description!("[year]-[month]-[day]");
+const ENCODE_TIME_FORMAT_WHOLE_SECOND: &[FormatItem<'_>] =
+    format_description!("[hour]:[minute]:[second]");
+const ENCODE_TIME_FORMAT_SUBSECOND: &[FormatItem<'_>] =
+    format_description!("[hour]:[minute]:[second].[subsecond digits:6]");
+
+const TIME_FORMATS: [&[FormatItem<'_>]; 9] = [
+    // Most likely
+    format_description!("[hour]:[minute]:[second].[subsecond]"),
+    // All other valid formats in order of increasing specificity
+    format_description!("[hour]:[minute]"),
+    format_description!("[hour]:[minute]Z"),
+    format_description!("[hour]:[minute][offset_hour sign:mandatory]:[offset_minute]"),
+    format_description!("[hour]:[minute]:[second]"),
+    format_description!("[hour]:[minute]:[second]Z"),
+    format_description!("[hour]:[minute]:[second][offset_hour sign:mandatory]:[offset_minute]"),
+    // here is where the most likely format would go according to the pattern
+    format_description!("[hour]:[minute]:[second].[subsecond]Z"),
+    format_description!(
+        "[hour]:[minute]:[second].[subsecond][offset_hour sign:mandatory]:[offset_minute]"
+    ),
+];
+
+const ENCODE_PRIMITIVE_DATETIME_FORMAT_WHOLE_SECOND: &[FormatItem<'_>] =
+    format_description!("[year]-[month]-[day] [hour]:[minute]:[second]");
+const ENCODE_PRIMITIVE_DATETIME_FORMAT_SUBSECOND: &[FormatItem<'_>] =
+    format_description!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond digits:6]");
+
+const ENCODE_DATETIME_FORMAT_WHOLE_SECOND: &[FormatItem<'_>] = format_description!(
+    "[year]-[month]-[day] [hour]:[minute]:[second][offset_hour sign:mandatory]:[offset_minute]"
+);
+const ENCODE_DATETIME_FORMAT_SUBSECOND: &[FormatItem<'_>] =
+    format_description!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond digits:3][offset_hour sign:mandatory]:[offset_minute]");
+
+const DATETIME_FORMATS: [&[FormatItem<'_>]; 18] = [
+    // Most likely format
+    format_description!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]"),
+    // Other formats in order of increasing specificity
+    format_description!("[year]-[month]-[day] [hour]:[minute]"),
+    format_description!("[year]-[month]-[day] [hour]:[minute]Z"),
+    format_description!("[year]-[month]-[day] [hour]:[minute][offset_hour sign:mandatory]:[offset_minute]"),
+    format_description!("[year]-[month]-[day] [hour]:[minute]:[second]"),
+    format_description!("[year]-[month]-[day] [hour]:[minute]:[second]Z"),
+    format_description!("[year]-[month]-[day] [hour]:[minute]:[second][offset_hour sign:mandatory]:[offset_minute]"),
+    // here is where the most likely format would go according to the pattern
+    format_description!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]Z"),
+    format_description!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond][offset_hour sign:mandatory]:[offset_minute]"),
+    // now the same thing, with T
+    format_description!("[year]-[month]-[day]T[hour]:[minute]"),
+    format_description!("[year]-[month]-[day]T[hour]:[minute]Z"),
+    format_description!("[year]-[month]-[day]T[hour]:[minute][offset_hour sign:mandatory]:[offset_minute]"),
+    format_description!("[year]-[month]-[day]T[hour]:[minute]:[second]"),
+    format_description!("[year]-[month]-[day]T[hour]:[minute]:[second]Z"),
+    format_description!("[year]-[month]-[day]T[hour]:[minute]:[second][offset_hour sign:mandatory]:[offset_minute]"),
+    format_description!("[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond]"),
+    format_description!("[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond]Z"),
+    format_description!("[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond][offset_hour sign:mandatory]:[offset_minute]"),
+];
+
+fn naive_utc(dt: OffsetDateTime) -> PrimitiveDateTime {
+    let dt = dt.to_offset(UtcOffset::UTC);
+    PrimitiveDateTime::new(dt.date(), dt.time())
+}
+
+fn parse_julian(julian_days: f64) -> Result<PrimitiveDateTime, ComponentRange> {
+    const EPOCH_IN_JULIAN_DAYS: f64 = 2_440_587.5;
+    const SECONDS_IN_DAY: f64 = 86400.0;
+    let timestamp = (julian_days - EPOCH_IN_JULIAN_DAYS) * SECONDS_IN_DAY;
+    OffsetDateTime::from_unix_timestamp_nanos((timestamp * 1E9) as i128)
+        .map(|timestamp| naive_utc(timestamp))
+}
+
+#[cfg(all(feature = "sqlite", feature = "time"))]
+impl FromSql<Date, Sqlite> for NaiveDate {
+    fn from_sql(value: backend::RawValue<'_, Sqlite>) -> deserialize::Result<Self> {
+        value
+            .parse_string(|s| Self::parse(s, DATE_FORMAT))
+            .map_err(Into::into)
+    }
+}
+
+#[cfg(all(feature = "sqlite", feature = "time"))]
+impl ToSql<Date, Sqlite> for NaiveDate {
+    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> serialize::Result {
+        out.set_value(self.format(DATE_FORMAT).map_err(|err| err.to_string())?);
+        Ok(IsNull::No)
+    }
+}
+
+#[cfg(all(feature = "sqlite", feature = "time"))]
+impl FromSql<Time, Sqlite> for NaiveTime {
+    fn from_sql(value: backend::RawValue<'_, Sqlite>) -> deserialize::Result<Self> {
+        value.parse_string(|text| {
+            for format in TIME_FORMATS {
+                if let Ok(time) = Self::parse(text, format) {
+                    return Ok(time);
+                }
+            }
+
+            Err(format!("Invalid time {}", text).into())
+        })
+    }
+}
+
+#[cfg(all(feature = "sqlite", feature = "time"))]
+impl ToSql<Time, Sqlite> for NaiveTime {
+    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> serialize::Result {
+        let format = if self.microsecond() == 0 {
+            ENCODE_TIME_FORMAT_WHOLE_SECOND
+        } else {
+            ENCODE_TIME_FORMAT_SUBSECOND
+        };
+        out.set_value(self.format(format).map_err(|err| err.to_string())?);
+        Ok(IsNull::No)
+    }
+}
+
+#[cfg(all(feature = "sqlite", feature = "time"))]
+impl FromSql<Timestamp, Sqlite> for PrimitiveDateTime {
+    fn from_sql(value: backend::RawValue<'_, Sqlite>) -> deserialize::Result<Self> {
+        value.parse_string(|text| {
+            for format in DATETIME_FORMATS {
+                if let Ok(dt) = Self::parse(text, format) {
+                    return Ok(dt);
+                }
+            }
+
+            if let Ok(julian_days) = text.parse::<f64>() {
+                if let Ok(timestamp) = parse_julian(julian_days) {
+                    return Ok(timestamp);
+                }
+            }
+
+            Err(format!("Invalid datetime {}", text).into())
+        })
+    }
+}
+
+#[cfg(all(feature = "sqlite", feature = "time"))]
+impl ToSql<Timestamp, Sqlite> for PrimitiveDateTime {
+    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> serialize::Result {
+        let format = if self.microsecond() == 0 {
+            ENCODE_PRIMITIVE_DATETIME_FORMAT_WHOLE_SECOND
+        } else {
+            ENCODE_PRIMITIVE_DATETIME_FORMAT_SUBSECOND
+        };
+        out.set_value(self.format(format).map_err(|err| err.to_string())?);
+        Ok(IsNull::No)
+    }
+}
+
+#[cfg(all(feature = "sqlite", feature = "time"))]
+impl FromSql<TimestamptzSqlite, Sqlite> for PrimitiveDateTime {
+    fn from_sql(value: backend::RawValue<'_, Sqlite>) -> deserialize::Result<Self> {
+        value.parse_string(|text| {
+            for format in DATETIME_FORMATS {
+                if let Ok(dt) = Self::parse(text, format) {
+                    return Ok(dt);
+                }
+            }
+
+            if let Ok(julian_days) = text.parse::<f64>() {
+                if let Ok(timestamp) = parse_julian(julian_days) {
+                    return Ok(timestamp);
+                }
+            }
+
+            Err(format!("Invalid datetime {}", text).into())
+        })
+    }
+}
+
+#[cfg(all(feature = "sqlite", feature = "time"))]
+impl ToSql<TimestamptzSqlite, Sqlite> for PrimitiveDateTime {
+    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> serialize::Result {
+        let format = if self.microsecond() == 0 {
+            ENCODE_PRIMITIVE_DATETIME_FORMAT_WHOLE_SECOND
+        } else {
+            ENCODE_PRIMITIVE_DATETIME_FORMAT_SUBSECOND
+        };
+        out.set_value(self.format(format).map_err(|err| err.to_string())?);
+        Ok(IsNull::No)
+    }
+}
+
+#[cfg(all(feature = "sqlite", feature = "time"))]
+impl FromSql<TimestamptzSqlite, Sqlite> for OffsetDateTime {
+    fn from_sql(value: backend::RawValue<'_, Sqlite>) -> deserialize::Result<Self> {
+        let primitive_date_time =
+            <PrimitiveDateTime as FromSql<TimestamptzSqlite, Sqlite>>::from_sql(value)?;
+        Ok(primitive_date_time.assume_utc())
+    }
+}
+
+#[cfg(all(feature = "sqlite", feature = "time"))]
+impl ToSql<TimestamptzSqlite, Sqlite> for OffsetDateTime {
+    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> serialize::Result {
+        let dt_utc = self.to_offset(UtcOffset::UTC);
+        let format = if self.millisecond() == 0 {
+            ENCODE_DATETIME_FORMAT_WHOLE_SECOND
+        } else {
+            ENCODE_DATETIME_FORMAT_SUBSECOND
+        };
+        out.set_value(dt_utc.format(format).map_err(|err| err.to_string())?);
+        Ok(IsNull::No)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    extern crate dotenvy;
+
+    use ::time::{
+        macros::{date, datetime},
+        Date as NaiveDate, Duration, OffsetDateTime, PrimitiveDateTime, Time as NaiveTime,
+    };
+
+    use super::naive_utc;
+
+    use crate::dsl::{now, sql};
+    use crate::prelude::*;
+    use crate::select;
+    use crate::sql_types::{Text, Time, Timestamp, TimestamptzSqlite};
+    use crate::test_helpers::connection;
+
+    sql_function!(fn datetime(x: Text) -> Timestamp);
+    sql_function!(fn time(x: Text) -> Time);
+    sql_function!(fn date(x: Text) -> Date);
+
+    #[test]
+    fn unix_epoch_encodes_correctly() {
+        let connection = &mut connection();
+        let time = datetime!(1970-1-1 0:0:0);
+        let query = select(datetime("1970-01-01 00:00:00.000000").eq(time));
+        assert_eq!(Ok(true), query.get_result(connection));
+    }
+
+    #[test]
+    fn unix_epoch_decodes_correctly_in_all_possible_formats() {
+        let connection = &mut connection();
+        let time = datetime!(1970-1-1 0:0:0);
+        let valid_epoch_formats = vec![
+            "1970-01-01 00:00",
+            "1970-01-01 00:00:00",
+            "1970-01-01 00:00:00.000",
+            "1970-01-01 00:00:00.000000",
+            "1970-01-01T00:00",
+            "1970-01-01T00:00:00",
+            "1970-01-01T00:00:00.000",
+            "1970-01-01T00:00:00.000000",
+            "1970-01-01 00:00Z",
+            "1970-01-01 00:00:00Z",
+            "1970-01-01 00:00:00.000Z",
+            "1970-01-01 00:00:00.000000Z",
+            "1970-01-01T00:00Z",
+            "1970-01-01T00:00:00Z",
+            "1970-01-01T00:00:00.000Z",
+            "1970-01-01T00:00:00.000000Z",
+            "1970-01-01 00:00+00:00",
+            "1970-01-01 00:00:00+00:00",
+            "1970-01-01 00:00:00.000+00:00",
+            "1970-01-01 00:00:00.000000+00:00",
+            "1970-01-01T00:00+00:00",
+            "1970-01-01T00:00:00+00:00",
+            "1970-01-01T00:00:00.000+00:00",
+            "1970-01-01T00:00:00.000000+00:00",
+            "1970-01-01 00:00+01:00",
+            "1970-01-01 00:00:00+01:00",
+            "1970-01-01 00:00:00.000+01:00",
+            "1970-01-01 00:00:00.000000+01:00",
+            "1970-01-01T00:00+01:00",
+            "1970-01-01T00:00:00+01:00",
+            "1970-01-01T00:00:00.000+01:00",
+            "1970-01-01T00:00:00.000000+01:00",
+            "1970-01-01T00:00-01:00",
+            "1970-01-01T00:00:00-01:00",
+            "1970-01-01T00:00:00.000-01:00",
+            "1970-01-01T00:00:00.000000-01:00",
+            "1970-01-01T00:00-01:00",
+            "1970-01-01T00:00:00-01:00",
+            "1970-01-01T00:00:00.000-01:00",
+            "1970-01-01T00:00:00.000000-01:00",
+            "2440587.5",
+        ];
+
+        for s in valid_epoch_formats {
+            let epoch_from_sql =
+                select(sql::<Timestamp>(&format!("'{}'", s))).get_result(connection);
+            assert_eq!(Ok(time), epoch_from_sql, "format {} failed", s);
+        }
+    }
+
+    #[test]
+    fn times_relative_to_now_encode_correctly() {
+        let connection = &mut connection();
+        let time = naive_utc(OffsetDateTime::now_utc()) + Duration::seconds(60);
+        let query = select(now.lt(time));
+        assert_eq!(Ok(true), query.get_result(connection));
+
+        let time = naive_utc(OffsetDateTime::now_utc()) - Duration::seconds(600);
+        let query = select(now.gt(time));
+        assert_eq!(Ok(true), query.get_result(connection));
+    }
+
+    #[test]
+    fn times_of_day_encode_correctly() {
+        let connection = &mut connection();
+
+        let midnight = NaiveTime::from_hms(0, 0, 0).unwrap();
+        let query = select(time("00:00:00.000000").eq(midnight));
+        assert_eq!(query.get_result::<bool>(connection).unwrap(), true);
+
+        let noon = NaiveTime::from_hms(12, 0, 0).unwrap();
+        let query = select(time("12:00:00.000000").eq(noon));
+        assert_eq!(query.get_result::<bool>(connection).unwrap(), true);
+
+        let roughly_half_past_eleven = NaiveTime::from_hms_micro(23, 37, 4, 2200).unwrap();
+        let query = select(sql::<Time>("'23:37:04.002200'").eq(roughly_half_past_eleven));
+        assert_eq!(query.get_result::<bool>(connection).unwrap(), true);
+    }
+
+    #[test]
+    fn times_of_day_decode_correctly() {
+        let connection = &mut connection();
+        let midnight = NaiveTime::from_hms(0, 0, 0).unwrap();
+        let valid_midnight_formats = &[
+            "00:00",
+            "00:00:00",
+            "00:00:00.000",
+            "00:00:00.000000",
+            "00:00Z",
+            "00:00:00Z",
+            "00:00:00.000Z",
+            "00:00:00.000000Z",
+            "00:00+00:00",
+            "00:00:00+00:00",
+            "00:00:00.000+00:00",
+            "00:00:00.000000+00:00",
+            "00:00+01:00",
+            "00:00:00+01:00",
+            "00:00:00.000+01:00",
+            "00:00:00.000000+01:00",
+            "00:00-01:00",
+            "00:00:00-01:00",
+            "00:00:00.000-01:00",
+            "00:00:00.000000-01:00",
+        ];
+        for format in valid_midnight_formats {
+            let query = select(sql::<Time>(&format!("'{}'", format)));
+            assert_eq!(
+                Ok(midnight),
+                query.get_result::<NaiveTime>(connection),
+                "format {} failed",
+                format
+            );
+        }
+
+        let noon = NaiveTime::from_hms(12, 0, 0).unwrap();
+        let query = select(sql::<Time>("'12:00:00'"));
+        assert_eq!(Ok(noon), query.get_result::<NaiveTime>(connection));
+
+        let roughly_half_past_eleven = NaiveTime::from_hms_micro(23, 37, 4, 2200).unwrap();
+        let query = select(sql::<Time>("'23:37:04.002200'"));
+        assert_eq!(
+            Ok(roughly_half_past_eleven),
+            query.get_result::<NaiveTime>(connection)
+        );
+    }
+
+    #[test]
+    fn dates_encode_correctly() {
+        let connection = &mut connection();
+        let january_first_2000 = date!(2000 - 1 - 1);
+        let query = select(date("2000-01-01").eq(january_first_2000));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let distant_past = date!(0 - 4 - 11);
+        let query = select(date("0000-04-11").eq(distant_past));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let january_first_2018 = date!(2018 - 1 - 1);
+        let query = select(date("2018-01-01").eq(january_first_2018));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let distant_future = date!(9999 - 1 - 8);
+        let query = select(date("9999-01-08").eq(distant_future));
+        assert!(query.get_result::<bool>(connection).unwrap());
+    }
+
+    #[test]
+    fn dates_decode_correctly() {
+        let connection = &mut connection();
+        let january_first_2000 = date!(2000 - 1 - 1);
+        let query = select(date("2000-01-01"));
+        assert_eq!(
+            Ok(january_first_2000),
+            query.get_result::<NaiveDate>(connection)
+        );
+
+        let distant_past = date!(0 - 4 - 11);
+        let query = select(date("0000-04-11"));
+        assert_eq!(Ok(distant_past), query.get_result::<NaiveDate>(connection));
+
+        let january_first_2018 = date!(2018 - 1 - 1);
+        let query = select(date("2018-01-01"));
+        assert_eq!(
+            Ok(january_first_2018),
+            query.get_result::<NaiveDate>(connection)
+        );
+
+        let distant_future = date!(9999 - 1 - 8);
+        let query = select(date("9999-01-08"));
+        assert_eq!(
+            Ok(distant_future),
+            query.get_result::<NaiveDate>(connection)
+        );
+    }
+
+    #[test]
+    fn datetimes_decode_correctly() {
+        let connection = &mut connection();
+        let january_first_2000 = datetime!(2000-1-1 1:1:1);
+        let query = select(datetime("2000-01-01 01:01:01.000000"));
+        assert_eq!(
+            Ok(january_first_2000),
+            query.get_result::<PrimitiveDateTime>(connection)
+        );
+
+        let distant_past = datetime!(0-4-11 2:2:2);
+        let query = select(datetime("0000-04-11 02:02:02.000000"));
+        assert_eq!(
+            Ok(distant_past),
+            query.get_result::<PrimitiveDateTime>(connection)
+        );
+
+        let january_first_2018 = date!(2018 - 1 - 1);
+        let query = select(date("2018-01-01"));
+        assert_eq!(
+            Ok(january_first_2018),
+            query.get_result::<NaiveDate>(connection)
+        );
+
+        let distant_future = datetime!(9999 - 1 - 8 23:59:59.0001);
+        let query = select(sql::<Timestamp>("'9999-01-08 23:59:59.000100'"));
+        assert_eq!(
+            Ok(distant_future),
+            query.get_result::<PrimitiveDateTime>(connection)
+        );
+    }
+
+    #[test]
+    fn datetimes_encode_correctly() {
+        let connection = &mut connection();
+        let january_first_2000 = datetime!(2000-1-1 0:0:0);
+        let query = select(datetime("2000-01-01 00:00:00.000000").eq(january_first_2000));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let distant_past = datetime!(0-4-11 20:00:20);
+        let query = select(datetime("0000-04-11 20:00:20.000000").eq(distant_past));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let january_first_2018 = datetime!(2018 - 1 - 1 12:00:00.0005);
+        let query = select(sql::<Timestamp>("'2018-01-01 12:00:00.000500'").eq(january_first_2018));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        let distant_future = datetime!(9999-1-8 0:0:0);
+        let query = select(datetime("9999-01-08 00:00:00.000000").eq(distant_future));
+        assert!(query.get_result::<bool>(connection).unwrap());
+    }
+
+    #[test]
+    fn insert_timestamptz_into_table_as_text() {
+        crate::table! {
+            #[allow(unused_parens)]
+            test_insert_timestamptz_into_table_as_text(id) {
+                id -> Integer,
+                timestamp_with_tz -> TimestamptzSqlite,
+            }
+        }
+        let conn = &mut connection();
+        crate::sql_query(
+            "CREATE TABLE test_insert_timestamptz_into_table_as_text(id INTEGER PRIMARY KEY, timestamp_with_tz TEXT);",
+        )
+        .execute(conn)
+        .unwrap();
+
+        let time: OffsetDateTime = datetime!(1970-1-1 0:0:0.0 utc);
+
+        crate::insert_into(test_insert_timestamptz_into_table_as_text::table)
+            .values(vec![(
+                test_insert_timestamptz_into_table_as_text::id.eq(1),
+                test_insert_timestamptz_into_table_as_text::timestamp_with_tz.eq(sql::<
+                    TimestamptzSqlite,
+                >(
+                    "'1970-01-01 00:00:00.000000+00:00'",
+                )),
+            )])
+            .execute(conn)
+            .unwrap();
+
+        let result = test_insert_timestamptz_into_table_as_text::table
+            .select(test_insert_timestamptz_into_table_as_text::timestamp_with_tz)
+            .get_result::<OffsetDateTime>(conn)
+            .unwrap();
+        assert_eq!(result, time);
+    }
+
+    #[test]
+    fn can_query_timestamptz_column_with_between() {
+        crate::table! {
+            #[allow(unused_parens)]
+            test_query_timestamptz_column_with_between(id) {
+                id -> Integer,
+                timestamp_with_tz -> TimestamptzSqlite,
+            }
+        }
+        let conn = &mut connection();
+        crate::sql_query(
+            "CREATE TABLE test_query_timestamptz_column_with_between(id INTEGER PRIMARY KEY, timestamp_with_tz TEXT);",
+        )
+        .execute(conn)
+        .unwrap();
+
+        crate::insert_into(test_query_timestamptz_column_with_between::table)
+            .values(vec![
+                (
+                    test_query_timestamptz_column_with_between::id.eq(1),
+                    test_query_timestamptz_column_with_between::timestamp_with_tz.eq(sql::<
+                        TimestamptzSqlite,
+                    >(
+                        "'1970-01-01 00:00:01.000000+00:00'",
+                    )),
+                ),
+                (
+                    test_query_timestamptz_column_with_between::id.eq(2),
+                    test_query_timestamptz_column_with_between::timestamp_with_tz.eq(sql::<
+                        TimestamptzSqlite,
+                    >(
+                        "'1970-01-01 00:00:02.000000+00:00'",
+                    )),
+                ),
+                (
+                    test_query_timestamptz_column_with_between::id.eq(3),
+                    test_query_timestamptz_column_with_between::timestamp_with_tz.eq(sql::<
+                        TimestamptzSqlite,
+                    >(
+                        "'1970-01-01 00:00:03.000000+00:00'",
+                    )),
+                ),
+                (
+                    test_query_timestamptz_column_with_between::id.eq(4),
+                    test_query_timestamptz_column_with_between::timestamp_with_tz.eq(sql::<
+                        TimestamptzSqlite,
+                    >(
+                        "'1970-01-01 00:00:04.000000+00:00'",
+                    )),
+                ),
+            ])
+            .execute(conn)
+            .unwrap();
+
+        let result = test_query_timestamptz_column_with_between::table
+            .select(test_query_timestamptz_column_with_between::timestamp_with_tz)
+            .filter(
+                test_query_timestamptz_column_with_between::timestamp_with_tz
+                    .gt(datetime!(1970-1-1 0:0:0.0 utc)),
+            )
+            .filter(
+                test_query_timestamptz_column_with_between::timestamp_with_tz
+                    .lt(datetime!(1970-1-1 0:0:4.0 utc)),
+            )
+            .count()
+            .get_result::<_>(conn);
+        assert_eq!(result, Ok(3));
+    }
+
+    #[test]
+    fn unix_epoch_encodes_correctly_with_timezone() {
+        let connection = &mut connection();
+        // West one hour is negative offset
+        let time = datetime!(1970-1-1 0:00:00.001 -1:00);
+        let query = select(sql::<TimestamptzSqlite>("'1970-01-01 01:00:00.001+00:00'").eq(time));
+        assert!(query.get_result::<bool>(connection).unwrap());
+    }
+
+    #[test]
+    fn unix_epoch_encodes_correctly_with_utc_timezone() {
+        let connection = &mut connection();
+        let time: OffsetDateTime = datetime!(1970-1-1 0:0:0.001 utc);
+        let query = select(sql::<TimestamptzSqlite>("'1970-01-01 00:00:00.001+00:00'").eq(time));
+        assert!(query.get_result::<bool>(connection).unwrap());
+
+        // and without millisecond
+        let time: OffsetDateTime = datetime!(1970-1-1 0:0:0 utc);
+        let query = select(sql::<TimestamptzSqlite>("'1970-01-01 00:00:00+00:00'").eq(time));
+        assert!(query.get_result::<bool>(connection).unwrap());
+    }
+
+    #[test]
+    fn unix_epoch_decodes_correctly_with_utc_timezone_in_all_possible_formats() {
+        let connection = &mut connection();
+        let time: OffsetDateTime = datetime!(1970-1-1 0:0:0 utc);
+        let valid_epoch_formats = vec![
+            "1970-01-01 00:00Z",
+            "1970-01-01 00:00:00Z",
+            "1970-01-01 00:00:00.000Z",
+            "1970-01-01 00:00:00.000000Z",
+            "1970-01-01T00:00Z",
+            "1970-01-01T00:00:00Z",
+            "1970-01-01T00:00:00.000Z",
+            "1970-01-01T00:00:00.000000Z",
+            "1970-01-01 00:00+00:00",
+            "1970-01-01 00:00:00+00:00",
+            "1970-01-01 00:00:00.000+00:00",
+            "1970-01-01 00:00:00.000000+00:00",
+            "1970-01-01T00:00+00:00",
+            "1970-01-01T00:00:00+00:00",
+            "1970-01-01T00:00:00.000+00:00",
+            "1970-01-01T00:00:00.000000+00:00",
+            "1970-01-01 00:00+01:00",
+            "1970-01-01 00:00:00+01:00",
+            "1970-01-01 00:00:00.000+01:00",
+            "1970-01-01 00:00:00.000000+01:00",
+            "1970-01-01T00:00+01:00",
+            "1970-01-01T00:00:00+01:00",
+            "1970-01-01T00:00:00.000+01:00",
+            "1970-01-01T00:00:00.000000+01:00",
+            "1970-01-01T00:00-01:00",
+            "1970-01-01T00:00:00-01:00",
+            "1970-01-01T00:00:00.000-01:00",
+            "1970-01-01T00:00:00.000000-01:00",
+            "1970-01-01T00:00-01:00",
+            "1970-01-01T00:00:00-01:00",
+            "1970-01-01T00:00:00.000-01:00",
+            "1970-01-01T00:00:00.000000-01:00",
+            "2440587.5",
+        ];
+
+        for s in valid_epoch_formats {
+            let epoch_from_sql =
+                select(sql::<TimestamptzSqlite>(&format!("'{}'", s))).get_result(connection);
+            assert_eq!(Ok(time), epoch_from_sql, "format {} failed", s);
+        }
+    }
+}
diff --git a/diesel/src/sqlite/types/mod.rs b/diesel/src/sqlite/types/mod.rs
index 28c7c68c09dd..c6214d44daae 100644
--- a/diesel/src/sqlite/types/mod.rs
+++ b/diesel/src/sqlite/types/mod.rs
@@ -147,11 +147,15 @@ impl ToSql<sql_types::Double, Sqlite> for f64 {
 ///
 /// - [`chrono::NaiveDateTime`] with `feature = "chrono"`
 /// - [`chrono::DateTime`] with `feature = "chrono"`
+/// - [`time::PrimitiveDateTime`] with `feature = "time"`
+/// - [`time::OffsetDateTime`] with `feature = "time"`
 ///
 /// ### [`FromSql`] impls
 ///
 /// - [`chrono::NaiveDateTime`] with `feature = "chrono"`
 /// - [`chrono::DateTime`] with `feature = "chrono"`
+/// - [`time::PrimitiveDateTime`] with `feature = "time"`
+/// - [`time::OffsetDateTime`] with `feature = "time"`
 ///
 /// [`ToSql`]: crate::serialize::ToSql
 /// [`FromSql`]: crate::deserialize::FromSql
@@ -168,6 +172,22 @@ impl ToSql<sql_types::Double, Sqlite> for f64 {
     not(feature = "chrono"),
     doc = " [`chrono::DateTime`]: https://docs.rs/chrono/0.4.19/chrono/struct.DateTime.html"
 )]
+#[cfg_attr(
+    feature = "time",
+    doc = " [`time::PrimitiveDateTime`]: time::PrimitiveDateTime"
+)]
+#[cfg_attr(
+    not(feature = "time"),
+    doc = " [`time::PrimitiveDateTime`]: https://docs.rs/time/0.3.9/time/struct.PrimitiveDateTime.html"
+)]
+#[cfg_attr(
+    feature = "time",
+    doc = " [`time::OffsetDateTime`]: time::OffsetDateTime"
+)]
+#[cfg_attr(
+    not(feature = "time"),
+    doc = " [`time::OffsetDateTime`]: https://docs.rs/time/0.3.9/time/struct.OffsetDateTime.html"
+)]
 #[derive(Debug, Clone, Copy, Default, QueryId, SqlType)]
 #[diesel(sqlite_type(name = "Text"))]
 #[cfg(feature = "sqlite")]
diff --git a/diesel/src/type_impls/date_and_time.rs b/diesel/src/type_impls/date_and_time.rs
index e0f31b398d6b..b189fc275e1e 100644
--- a/diesel/src/type_impls/date_and_time.rs
+++ b/diesel/src/type_impls/date_and_time.rs
@@ -50,3 +50,42 @@ mod chrono {
     #[cfg_attr(feature = "sqlite", diesel(sql_type = crate::sql_types::TimestamptzSqlite))]
     struct DateTimeProxy<Tz: TimeZone>(DateTime<Tz>);
 }
+
+#[cfg(feature = "time")]
+mod time {
+    use time::{Date as NaiveDate, OffsetDateTime, PrimitiveDateTime, Time as NaiveTime};
+
+    use crate::deserialize::FromSqlRow;
+    use crate::expression::AsExpression;
+    use crate::sql_types::{Date, Time, Timestamp};
+
+    #[derive(AsExpression, FromSqlRow)]
+    #[diesel(foreign_derive)]
+    #[diesel(sql_type = Date)]
+    struct NaiveDateProxy(NaiveDate);
+
+    #[derive(AsExpression, FromSqlRow)]
+    #[diesel(foreign_derive)]
+    #[diesel(sql_type = Time)]
+    struct NaiveTimeProxy(NaiveTime);
+
+    #[derive(AsExpression, FromSqlRow)]
+    #[diesel(foreign_derive)]
+    #[diesel(sql_type = Timestamp)]
+    #[cfg_attr(
+        feature = "postgres_backend",
+        diesel(sql_type = crate::sql_types::Timestamptz)
+    )]
+    #[cfg_attr(feature = "mysql_backend", diesel(sql_type = crate::sql_types::Datetime))]
+    struct NaiveDateTimeProxy(PrimitiveDateTime);
+
+    #[derive(AsExpression, FromSqlRow)]
+    #[diesel(foreign_derive)]
+    #[cfg_attr(
+        feature = "postgres_backend",
+        diesel(sql_type = crate::sql_types::Timestamptz)
+    )]
+    #[cfg_attr(feature = "sqlite", diesel(sql_type = crate::sql_types::TimestamptzSqlite))]
+    #[cfg_attr(feature = "mysql_backend", diesel(sql_type = crate::sql_types::Datetime))]
+    struct DateTimeProxy(OffsetDateTime);
+}
diff --git a/diesel_cli/Cargo.toml b/diesel_cli/Cargo.toml
index b5edc6196897..83da82ce05a5 100644
--- a/diesel_cli/Cargo.toml
+++ b/diesel_cli/Cargo.toml
@@ -26,7 +26,7 @@ dotenvy = "0.15"
 heck = "0.4.0"
 serde = { version = "1.0.0", features = ["derive"] }
 toml = "0.5"
-url = { version = "2.1.0", optional = true }
+url = { version = "2.2.2", optional = true }
 libsqlite3-sys = { version = ">=0.17.2, <0.26.0", optional = true }
 diffy = "0.2.0"
 regex = "1.0.6"
diff --git a/diesel_cli/src/print_schema.rs b/diesel_cli/src/print_schema.rs
index 0e59f4846069..98239b799758 100644
--- a/diesel_cli/src/print_schema.rs
+++ b/diesel_cli/src/print_schema.rs
@@ -245,6 +245,7 @@ impl CustomTypeList {
     }
 }
 
+#[allow(clippy::print_in_format_impl)]
 impl Display for CustomTypeList {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         if self.types_sorted.is_empty() {
diff --git a/examples/mysql/all_about_inserts/Cargo.toml b/examples/mysql/all_about_inserts/Cargo.toml
index 8611e4be8b4e..e6f4ce22c685 100644
--- a/examples/mysql/all_about_inserts/Cargo.toml
+++ b/examples/mysql/all_about_inserts/Cargo.toml
@@ -2,6 +2,7 @@
 name = "all_about_inserts_mysql"
 version = "0.1.0"
 edition = "2018"
+publish = false
 
 [dependencies]
 diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["mysql", "chrono"] }
diff --git a/examples/mysql/getting_started_step_1/Cargo.toml b/examples/mysql/getting_started_step_1/Cargo.toml
index 63c718d25cf2..ff78e1d10148 100644
--- a/examples/mysql/getting_started_step_1/Cargo.toml
+++ b/examples/mysql/getting_started_step_1/Cargo.toml
@@ -2,6 +2,7 @@
 name = "diesel_demo_step_1_mysql"
 version = "0.1.0"
 edition = "2018"
+publish = false
 
 [dependencies]
 diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["mysql"] }
diff --git a/examples/mysql/getting_started_step_2/Cargo.toml b/examples/mysql/getting_started_step_2/Cargo.toml
index bbb3c0934d0f..30f05bcb8ded 100644
--- a/examples/mysql/getting_started_step_2/Cargo.toml
+++ b/examples/mysql/getting_started_step_2/Cargo.toml
@@ -2,6 +2,7 @@
 name = "diesel_demo_step_2_mysql"
 version = "0.1.0"
 edition = "2018"
+publish = false
 
 [dependencies]
 diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["mysql"] }
diff --git a/examples/mysql/getting_started_step_3/Cargo.toml b/examples/mysql/getting_started_step_3/Cargo.toml
index 9ca8a7ff059c..70df33d425ac 100644
--- a/examples/mysql/getting_started_step_3/Cargo.toml
+++ b/examples/mysql/getting_started_step_3/Cargo.toml
@@ -2,6 +2,7 @@
 name = "diesel_demo_step_3_mysql"
 version = "0.1.0"
 edition = "2018"
+publish = false
 
 [dependencies]
 diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["mysql"] }
diff --git a/examples/postgres/advanced-blog-cli/Cargo.toml b/examples/postgres/advanced-blog-cli/Cargo.toml
index 13d4810ae164..fdf456e0a01b 100644
--- a/examples/postgres/advanced-blog-cli/Cargo.toml
+++ b/examples/postgres/advanced-blog-cli/Cargo.toml
@@ -2,6 +2,7 @@
 name = "advanced-blog-cli"
 version = "0.1.0"
 edition = "2018"
+publish = false
 
 [dependencies]
 bcrypt = "0.10.1"
diff --git a/examples/postgres/all_about_inserts/Cargo.toml b/examples/postgres/all_about_inserts/Cargo.toml
index 2314c79859aa..23b92fe138fe 100644
--- a/examples/postgres/all_about_inserts/Cargo.toml
+++ b/examples/postgres/all_about_inserts/Cargo.toml
@@ -2,6 +2,7 @@
 name = "all_about_inserts"
 version = "0.1.0"
 edition = "2018"
+publish = false
 
 [dependencies]
 diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["postgres"] }
diff --git a/examples/postgres/all_about_updates/Cargo.toml b/examples/postgres/all_about_updates/Cargo.toml
index f48c952f51fb..c776926b58f0 100644
--- a/examples/postgres/all_about_updates/Cargo.toml
+++ b/examples/postgres/all_about_updates/Cargo.toml
@@ -2,6 +2,7 @@
 name = "all_about_updates"
 version = "0.1.0"
 edition = "2018"
+publish = false
 
 [dependencies]
 diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["postgres"] }
diff --git a/examples/postgres/custom_types/Cargo.toml b/examples/postgres/custom_types/Cargo.toml
index ee8a2104711f..ccedb6a8f26f 100644
--- a/examples/postgres/custom_types/Cargo.toml
+++ b/examples/postgres/custom_types/Cargo.toml
@@ -2,6 +2,7 @@
 name = "custom-types"
 version = "0.1.0"
 edition = "2018"
+publish = false
 
 [dependencies]
 diesel = { path = "../../../diesel", version = "2.0.0-rc.1", features = ["postgres"] }
diff --git a/examples/postgres/getting_started_step_1/Cargo.toml b/examples/postgres/getting_started_step_1/Cargo.toml
index 36ecf2524226..f280826f0cf0 100644
--- a/examples/postgres/getting_started_step_1/Cargo.toml
+++ b/examples/postgres/getting_started_step_1/Cargo.toml
@@ -2,6 +2,7 @@
 name = "diesel_demo_step_1_pg"
 version = "0.1.0"
 edition = "2018"
+publish = false
 
 [dependencies]
 diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["postgres"] }
diff --git a/examples/postgres/getting_started_step_2/Cargo.toml b/examples/postgres/getting_started_step_2/Cargo.toml
index 67fb736aee96..fd836da7e11c 100644
--- a/examples/postgres/getting_started_step_2/Cargo.toml
+++ b/examples/postgres/getting_started_step_2/Cargo.toml
@@ -2,6 +2,7 @@
 name = "diesel_demo_step_2_pg"
 version = "0.1.0"
 edition = "2018"
+publish = false
 
 [dependencies]
 diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["postgres"] }
diff --git a/examples/postgres/getting_started_step_3/Cargo.toml b/examples/postgres/getting_started_step_3/Cargo.toml
index d585af312688..8fcd6d08fa9c 100644
--- a/examples/postgres/getting_started_step_3/Cargo.toml
+++ b/examples/postgres/getting_started_step_3/Cargo.toml
@@ -2,6 +2,7 @@
 name = "diesel_demo_step_3_pg"
 version = "0.1.0"
 edition = "2018"
+publish = false
 
 [dependencies]
 diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["postgres"] }
diff --git a/examples/sqlite/all_about_inserts/Cargo.toml b/examples/sqlite/all_about_inserts/Cargo.toml
index 8598b3ae89cc..f46ed6c326f6 100644
--- a/examples/sqlite/all_about_inserts/Cargo.toml
+++ b/examples/sqlite/all_about_inserts/Cargo.toml
@@ -2,6 +2,7 @@
 name = "all_about_inserts_sqlite"
 version = "0.1.0"
 edition = "2018"
+publish = false
 
 [dependencies]
 diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["sqlite", "chrono"] }
diff --git a/examples/sqlite/getting_started_step_1/Cargo.toml b/examples/sqlite/getting_started_step_1/Cargo.toml
index 113039dddace..7f0b126fff8e 100644
--- a/examples/sqlite/getting_started_step_1/Cargo.toml
+++ b/examples/sqlite/getting_started_step_1/Cargo.toml
@@ -4,6 +4,7 @@ version = "0.1.0"
 license = "MIT OR Apache-2.0"
 authors = ["Taryn Hill <taryn@phrohdoh.com>"]
 edition = "2018"
+publish = false
 
 [dependencies]
 diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["sqlite"] }
diff --git a/examples/sqlite/getting_started_step_2/Cargo.toml b/examples/sqlite/getting_started_step_2/Cargo.toml
index 04dd56514893..4783b2c8dae0 100644
--- a/examples/sqlite/getting_started_step_2/Cargo.toml
+++ b/examples/sqlite/getting_started_step_2/Cargo.toml
@@ -3,6 +3,7 @@ name = "diesel_demo_step_2_sqlite"
 version = "0.1.0"
 license = "MIT OR Apache-2.0"
 edition = "2018"
+publish = false
 
 [dependencies]
 diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["sqlite"] }
diff --git a/examples/sqlite/getting_started_step_3/Cargo.toml b/examples/sqlite/getting_started_step_3/Cargo.toml
index 553fa0741cfd..f412fd373f11 100644
--- a/examples/sqlite/getting_started_step_3/Cargo.toml
+++ b/examples/sqlite/getting_started_step_3/Cargo.toml
@@ -3,6 +3,7 @@ name = "diesel_demo_step_3_sqlite"
 version = "0.1.0"
 license = "MIT OR Apache-2.0"
 edition = "2018"
+publish = false
 
 [dependencies]
 diesel = { version = "2.0.0-rc.1", path = "../../../diesel", features = ["sqlite"] }
diff --git a/rust-toolchain b/rust-toolchain
index 3ebf789f5a8d..b77a81dcb12a 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1,1 +1,1 @@
-1.56.0
+1.62.1


Test patch:
diff --git a/diesel_compile_tests/Cargo.lock b/diesel_compile_tests/Cargo.lock
index 502c4cfe96a6..4a8f2b1935a9 100644
--- a/diesel_compile_tests/Cargo.lock
+++ b/diesel_compile_tests/Cargo.lock
@@ -70,6 +70,7 @@ dependencies = [
  "pq-sys",
  "r2d2",
  "serde_json",
+ "time",
  "url",
  "uuid",
 ]
@@ -235,6 +236,15 @@ dependencies = [
  "autocfg",
 ]
 
+[[package]]
+name = "num_threads"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "parking_lot"
 version = "0.11.2"
@@ -421,6 +431,24 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "time"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd"
+dependencies = [
+ "itoa 1.0.1",
+ "libc",
+ "num_threads",
+ "time-macros",
+]
+
+[[package]]
+name = "time-macros"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792"
+
 [[package]]
 name = "tinyvec"
 version = "1.5.1"
diff --git a/diesel_tests/Cargo.toml b/diesel_tests/Cargo.toml
index c9206f559ebc..4cd1ec98ee1d 100644
--- a/diesel_tests/Cargo.toml
+++ b/diesel_tests/Cargo.toml
@@ -6,6 +6,7 @@ license = "MIT OR Apache-2.0"
 autotests = false
 autobenches = false
 edition = "2018"
+publish = false
 
 [dependencies]
 assert_matches = "1.0.1"
diff --git a/diesel_tests/tests/errors.rs b/diesel_tests/tests/errors.rs
index 4a683e34fc54..2a13d9b0e432 100644
--- a/diesel_tests/tests/errors.rs
+++ b/diesel_tests/tests/errors.rs
@@ -188,12 +188,11 @@ fn isolation_errors_are_detected() {
 #[test]
 #[cfg(not(feature = "sqlite"))]
 fn read_only_errors_are_detected() {
+    use diesel::connection::SimpleConnection;
     use diesel::result::DatabaseErrorKind::ReadOnlyTransaction;
 
     let conn = &mut connection_without_transaction();
-    diesel::sql_query("START TRANSACTION READ ONLY")
-        .execute(conn)
-        .unwrap();
+    conn.batch_execute("START TRANSACTION READ ONLY").unwrap();
 
     let result = users::table.for_update().load::<User>(conn);