How to use 24 hour clock when invoking showTimePicker() in Flutter?

The above answers didn't work for me. Maybe for the new flutter or dart version. I fixed it by -

 final newTime = await showTimePicker(
        context: context,
        initialTime: TimeOfDay.now(),
        builder: (context, child) {
          return MediaQuery(
            data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: true),
          child: child ?? Container(),
          );
        },
      );

Before reading this answer, you need to know how MediaQuery.of() works. Essentially, there is a tree of widgets in any given page. The widgets each have a Context which you can think of as a node in the tree. When you call MediaQuery.of(context), it basically traces up the tree until it finds (or doesn't find) a MediaQuery widget, and then returns the data associated with the widget.

What you want to do is possible, but you have to be slightly careful about how you do it. See below for a minimal code example:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      builder: (context, child) =>
          MediaQuery(data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: true), child: child),
      home: new Container(
        color: Colors.white,
        child: Center(
          child: Builder(
            builder: (context) => FlatButton(
                  onPressed: () => showTimePicker(context: context, initialTime: TimeOfDay.now()),
                  child: Text("Show Time Picker"),
                ),
          ),
        ),
      ),
    );
  }
}

There are a couple of things of note here. First is that I'm creating a new MediaQueryData from the old one in the builder for MaterialApp. This is because you can't modify the properites of a MaterialQueryData.

The second is that I'm wrapping the child in the builder for MaterialApp with a new MediaQuery. This is necessary so that all 'pages' in the navigator (which is part of material app in this instance) read this new MediaQueryData with MediaQuery.of().

The third is that I use a Builder around the FlatButton. If I didn't do that, the context that it would be using would be the context of MyApp, rather than a context under the MaterialApp. If you made your own class to enclose the 'page', that wouldn't be necessary.

The MediaQuery has to be put where it is now, because if you make it within your 'page' (anywhere under the container), it won't actually be read by the TimePicker widget. This is because the TimePicker is actually inserting itself as the top element of the navigation stack which lives under the Navigator (and MaterialApp), rather than being embedded under your page. If this wasn't the case, it would be much more difficult to use a time picker.

I don't know that I did a very good job of explaining that, so here's a diagram:

MyApp  <------ Context (the one that would have been used without the builder)
  MaterialApp
    MediaQuery (from flutter)
      MediaQuery copy (that was made in the builder)
        Navigator (implicit - built as part of MaterialApp)
         |- Container
         |    Center
         |      Builder     <----\ Context (used to showTimePicker)
         |        FlatButton ----/ 
         \- TimePicker

Taking in consideration @rmtmckenzie answer, you can actually simplify what he told you. You don't need to set the alwaysUse24HourFormat: true within your MyApp context.

This will do the trick

void inputTimeSelect() async {
    final TimeOfDay picked = await showTimePicker(
      context: context,
      initialTime: TimeOfDay.now(),
      builder: (BuildContext context, Widget child) {
        return MediaQuery(
          data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: true),
          child: child,
        );
      },
    );
}

And the widget tree can be whatever you want.

Tags:

Dart

Flutter