[{"data":1,"prerenderedAt":86},["ShallowReactive",2],{"tutorial-selezionare-date-e-orari-in-flutter-con-showdatepicker-showtimepicker-e-intl":3,"comments-tutorial-selezionare-date-e-orari-in-flutter-con-showdatepicker-showtimepicker-e-intl":85},{"id":4,"title":5,"slug":6,"excerpt":7,"intro":8,"cover_image":9,"cover_remote_url":10,"cover_credit":11,"video_url":15,"video":16,"difficulty":20,"estimated_minutes":21,"flutter_version":22,"status":23,"published_at":24,"meta_title":25,"meta_description":26,"category":27,"author":31,"steps":33},91,"Selezionare date e orari in Flutter con showDatePicker, showTimePicker e intl","selezionare-date-e-orari-in-flutter-con-showdatepicker-showtimepicker-e-intl","Impara a far scegliere una data e un orario all'utente in Flutter usando showDatePicker e showTimePicker, a formattare i risultati in italiano con il pacchetto intl e a combinarli in un unico DateTime.","Quasi ogni app prima o poi deve chiedere una data: la scadenza di un'attività, la data di nascita, l'orario di un promemoria. Flutter mette a disposizione due dialoghi Material già pronti, **showDatePicker** e **showTimePicker**, che funzionano su Android, iOS, web e desktop senza pacchetti esterni.\n\nIn questo tutorial per principianti costruiremo una piccola schermata \"Nuovo appuntamento\" che permette di:\n\n- scegliere una data con il calendario;\n- scegliere un orario con l'orologio;\n- mostrare i valori formattati in italiano (es. *lunedì 12 maggio 2025, 09:30*);\n- unire data e ora in un unico oggetto `DateTime`;\n- selezionare un intervallo di date con `showDateRangePicker`.\n\nAvrai bisogno solo di un progetto Flutter appena creato e di pochi minuti. Partiamo!","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002F2e3d1191-97a5-4354-bf17-0c05b32cb1b8.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1676287569521-20f0fe96eebf?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3ODkxMDEwODV8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"Walls.io","https:\u002F\u002Funsplash.com\u002F@walls_io","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fa-close-up-of-a-notepad-with-a-keyboard-in-the-background-NtcuG3ocC_E","https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=SfZskl9zdas",{"youtube_id":17,"duration_seconds":18,"published_at":19},"SfZskl9zdas",132,"2026-09-11T09:15:30+00:00","beginner",30,"3.x","published","2026-09-11T04:31:25+00:00","Date e orari in Flutter: showDatePicker e intl","Guida passo passo per usare showDatePicker, showTimePicker e il pacchetto intl in Flutter: selezione e formattazione di date e orari in italiano.",{"id":28,"name":29,"slug":30},1,"Guide","guide",{"id":28,"name":32},"Flutter Bot",[34,42,50,57,64,71,78],{"id":35,"position":28,"title":36,"body":37,"code_snippet":38,"code_language":39,"expected_result":40,"demo_url":41,"video_url":41},605,"Creare il progetto e aggiungere le dipendenze","Crea (o apri) un progetto Flutter e aggiungi due dipendenze:\n\n- **intl**: per formattare date e orari secondo la lingua italiana;\n- **flutter_localizations**: pacchetto ufficiale che fornisce le traduzioni dei widget Material (compresi i dialoghi di data e ora).\n\nPuoi aggiungerli da terminale:\n\n```bash\nflutter create date_demo\ncd date_demo\nflutter pub add intl\nflutter pub add flutter_localizations --sdk=flutter\n```\n\nIl comando aggiorna automaticamente il `pubspec.yaml` come mostrato nello snippet. Ricorda l'indentazione a due spazi: nello YAML è fondamentale.","name: date_demo\ndescription: Demo selezione date e orari\n\nenvironment:\n  sdk: '>=3.0.0 \u003C4.0.0'\n\ndependencies:\n  flutter:\n    sdk: flutter\n  flutter_localizations:\n    sdk: flutter\n  intl: ^0.19.0\n\ndev_dependencies:\n  flutter_test:\n    sdk: flutter\n\nflutter:\n  uses-material-design: true","yaml","Il comando `flutter pub get` termina senza errori e le dipendenze compaiono nel pubspec.yaml.",null,{"id":43,"position":44,"title":45,"body":46,"code_snippet":47,"code_language":48,"expected_result":49,"demo_url":41,"video_url":41},606,2,"Configurare la localizzazione italiana in MaterialApp","Senza questa configurazione i dialoghi appaiono in inglese (\"Select date\", \"CANCEL\", ecc.) e il calendario parte dalla domenica.\n\nNel `MaterialApp` aggiungi:\n\n- `localizationsDelegates`: i delegati che caricano le traduzioni dei widget;\n- `supportedLocales`: le lingue supportate dall'app;\n- `locale`: forza l'italiano (utile per provare senza cambiare la lingua del dispositivo; in produzione puoi ometterlo e lasciare la scelta al sistema).\n\nSostituisci il contenuto di `lib\u002Fmain.dart` con lo snippet.","import 'package:flutter\u002Fmaterial.dart';\nimport 'package:flutter_localizations\u002Fflutter_localizations.dart';\n\nvoid main() => runApp(const MyApp());\n\nclass MyApp extends StatelessWidget {\n  const MyApp({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Date e orari',\n      debugShowCheckedModeBanner: false,\n      theme: ThemeData(\n        colorSchemeSeed: Colors.indigo,\n        useMaterial3: true,\n      ),\n      \u002F\u002F Traduzioni dei widget Material\u002FCupertino\u002FWidgets\n      localizationsDelegates: const [\n        GlobalMaterialLocalizations.delegate,\n        GlobalWidgetsLocalizations.delegate,\n        GlobalCupertinoLocalizations.delegate,\n      ],\n      supportedLocales: const [\n        Locale('it', 'IT'),\n        Locale('en', 'US'),\n      ],\n      locale: const Locale('it', 'IT'), \u002F\u002F forza l'italiano\n      home: const AppuntamentoPage(),\n    );\n  }\n}\n\nclass AppuntamentoPage extends StatefulWidget {\n  const AppuntamentoPage({super.key});\n\n  @override\n  State\u003CAppuntamentoPage> createState() => _AppuntamentoPageState();\n}\n\nclass _AppuntamentoPageState extends State\u003CAppuntamentoPage> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: const Text('Nuovo appuntamento')),\n      body: const Center(child: Text('Iniziamo!')),\n    );\n  }\n}","dart","L'app si avvia mostrando la AppBar \"Nuovo appuntamento\" e i futuri dialoghi saranno in italiano.",{"id":51,"position":52,"title":53,"body":54,"code_snippet":55,"code_language":48,"expected_result":56,"demo_url":41,"video_url":41},607,3,"Mostrare il calendario con showDatePicker","`showDatePicker` è una funzione asincrona che apre un dialogo e restituisce un `Future\u003CDateTime?>`:\n\n- se l'utente conferma, ottieni il `DateTime` scelto (con orario a mezzanotte);\n- se annulla o chiude il dialogo, ottieni `null`. **Controlla sempre il null** prima di usare il valore.\n\nParametri principali:\n\n- `initialDate`: la data preselezionata;\n- `firstDate` \u002F `lastDate`: intervallo selezionabile (obbligatori);\n- `initialEntryMode`: `calendar` (default) oppure `input` per la digitazione manuale;\n- `helpText`, `confirmText`, `cancelText`: testi personalizzabili.\n\nAggiungi allo State la variabile `_data` e il metodo `_selezionaData`.","DateTime? _data;\n\nFuture\u003Cvoid> _selezionaData() async {\n  final oggi = DateTime.now();\n  final DateTime? scelta = await showDatePicker(\n    context: context,\n    initialDate: _data ?? oggi,\n    firstDate: DateTime(oggi.year - 1),\n    lastDate: DateTime(oggi.year + 5),\n    helpText: 'Seleziona la data',\n    confirmText: 'Conferma',\n    cancelText: 'Annulla',\n  );\n\n  \u002F\u002F L'utente può aver annullato: scelta è null\n  if (scelta != null) {\n    setState(() => _data = scelta);\n  }\n}\n\n\u002F\u002F Nel build, dentro il body:\n\u002F\u002F ElevatedButton.icon(\n\u002F\u002F   onPressed: _selezionaData,\n\u002F\u002F   icon: const Icon(Icons.calendar_today),\n\u002F\u002F   label: Text(_data == null ? 'Scegli data' : _data.toString()),\n\u002F\u002F )","Toccando il pulsante si apre il calendario in italiano; dopo la conferma la data appare nel pulsante (in formato grezzo, es. 2025-05-12 00:00:00.000).",{"id":58,"position":59,"title":60,"body":61,"code_snippet":62,"code_language":48,"expected_result":63,"demo_url":41,"video_url":41},608,4,"Scegliere l'orario con showTimePicker","`showTimePicker` restituisce un `Future\u003CTimeOfDay?>`. `TimeOfDay` contiene solo `hour` e `minute`: non è un `DateTime`.\n\nDue parametri utili:\n\n- `initialEntryMode`: `TimePickerEntryMode.dial` (orologio) o `.input` (tastiera);\n- il builder `MediaQuery` con `alwaysUse24HourFormat: true` per forzare il formato 24 ore, tipico italiano.\n\nPer mostrare l'orario a schermo puoi usare `ora.format(context)`, che rispetta automaticamente la localizzazione.","TimeOfDay? _ora;\n\nFuture\u003Cvoid> _selezionaOra() async {\n  final TimeOfDay? scelta = await showTimePicker(\n    context: context,\n    initialTime: _ora ?? TimeOfDay.now(),\n    helpText: 'Seleziona l\\'orario',\n    confirmText: 'Conferma',\n    cancelText: 'Annulla',\n    initialEntryMode: TimePickerEntryMode.dial,\n    builder: (context, child) {\n      \u002F\u002F Forza il formato 24 ore\n      return MediaQuery(\n        data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: true),\n        child: child!,\n      );\n    },\n  );\n\n  if (scelta != null) {\n    setState(() => _ora = scelta);\n  }\n}\n\n\u002F\u002F Esempio di visualizzazione:\n\u002F\u002F Text(_ora == null ? 'Nessun orario' : _ora!.format(context))","Si apre l'orologio Material in italiano e l'orario selezionato viene mostrato nel formato 24 ore (es. 09:30).",{"id":65,"position":66,"title":67,"body":68,"code_snippet":69,"code_language":48,"expected_result":70,"demo_url":41,"video_url":41},609,5,"Formattare data e ora in italiano con intl","`DateTime.toString()` non è adatto all'utente finale. Il pacchetto **intl** offre `DateFormat`, che produce stringhe leggibili e localizzate.\n\nDue passaggi obbligatori:\n\n1. chiamare `initializeDateFormatting('it_IT')` in `main()` prima di `runApp` (carica i dati della lingua);\n2. passare il locale al costruttore: `DateFormat('EEEE d MMMM y', 'it_IT')`.\n\nPattern utili:\n\n| Pattern | Esempio |\n|---|---|\n| `dd\u002FMM\u002Fyyyy` | 12\u002F05\u002F2025 |\n| `EEEE d MMMM y` | lunedì 12 maggio 2025 |\n| `d MMM y, HH:mm` | 12 mag 2025, 09:30 |\n\nSe l'app è localizzata puoi anche usare le scorciatoie del framework: `MaterialLocalizations.of(context).formatFullDate(data)`.","import 'package:intl\u002Fdate_symbol_data_local.dart';\nimport 'package:intl\u002Fintl.dart';\n\nFuture\u003Cvoid> main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n  await initializeDateFormatting('it_IT', null);\n  runApp(const MyApp());\n}\n\n\u002F\u002F Dentro lo State:\nString get _dataFormattata {\n  if (_data == null) return 'Nessuna data selezionata';\n  return DateFormat('EEEE d MMMM y', 'it_IT').format(_data!);\n}\n\nString get _oraFormattata {\n  if (_ora == null) return 'Nessun orario selezionato';\n  final adesso = DateTime.now();\n  final dt = DateTime(adesso.year, adesso.month, adesso.day, _ora!.hour, _ora!.minute);\n  return DateFormat('HH:mm', 'it_IT').format(dt);\n}","La data compare come \"lunedì 12 maggio 2025\" e l'orario come \"09:30\".",{"id":72,"position":73,"title":74,"body":75,"code_snippet":76,"code_language":48,"expected_result":77,"demo_url":41,"video_url":41},610,6,"Unire data e ora in un unico DateTime","Per salvare l'appuntamento serve un solo oggetto `DateTime` che contenga sia il giorno sia l'orario. Si costruisce combinando i campi:\n\n```dart\nDateTime(data.year, data.month, data.day, ora.hour, ora.minute);\n```\n\nAggiungiamo anche una piccola validazione: se l'utente non ha scelto entrambi i valori mostriamo uno `SnackBar`. Come bonus, `showDateRangePicker` permette di selezionare un **intervallo** di date e restituisce un `DateTimeRange` con `start`, `end` e `duration`.","DateTime? get _appuntamento {\n  if (_data == null || _ora == null) return null;\n  return DateTime(\n    _data!.year,\n    _data!.month,\n    _data!.day,\n    _ora!.hour,\n    _ora!.minute,\n  );\n}\n\nvoid _salva() {\n  final appuntamento = _appuntamento;\n  if (appuntamento == null) {\n    ScaffoldMessenger.of(context).showSnackBar(\n      const SnackBar(content: Text('Seleziona sia la data che l\\'orario')),\n    );\n    return;\n  }\n  final testo = DateFormat(\"d MMMM y 'alle' HH:mm\", 'it_IT').format(appuntamento);\n  ScaffoldMessenger.of(context).showSnackBar(\n    SnackBar(content: Text('Appuntamento: $testo')),\n  );\n}\n\n\u002F\u002F Bonus: intervallo di date\nFuture\u003Cvoid> _selezionaIntervallo() async {\n  final oggi = DateTime.now();\n  final DateTimeRange? range = await showDateRangePicker(\n    context: context,\n    firstDate: DateTime(oggi.year - 1),\n    lastDate: DateTime(oggi.year + 2),\n    saveText: 'Conferma',\n  );\n  if (range != null) {\n    final f = DateFormat('dd\u002FMM\u002Fyyyy', 'it_IT');\n    debugPrint('Dal ${f.format(range.start)} al ${f.format(range.end)} '\n        '(${range.duration.inDays} giorni)');\n  }\n}","Premendo \"Salva\" appare uno SnackBar con la frase \"Appuntamento: 12 maggio 2025 alle 09:30\"; se manca un valore compare l'avviso di errore.",{"id":79,"position":80,"title":81,"body":82,"code_snippet":83,"code_language":48,"expected_result":84,"demo_url":41,"video_url":41},611,7,"Mettere insieme tutto: la schermata completa","Ecco il file `main.dart` completo, pronto da copiare e incollare. Usiamo due `ListTile` con icona: è il pattern più comune nei form, perché l'intera riga è toccabile e mostra chiaramente il valore selezionato.\n\n**Prossimi passi da provare:**\n\n- imposta `selectableDayPredicate` in `showDatePicker` per disabilitare weekend o giorni non disponibili;\n- usa `initialEntryMode: DatePickerEntryMode.input` per la data di nascita (più veloce da digitare);\n- salva il `DateTime` con `toIso8601String()` e rileggilo con `DateTime.parse()`.","import 'package:flutter\u002Fmaterial.dart';\nimport 'package:flutter_localizations\u002Fflutter_localizations.dart';\nimport 'package:intl\u002Fdate_symbol_data_local.dart';\nimport 'package:intl\u002Fintl.dart';\n\nFuture\u003Cvoid> main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n  await initializeDateFormatting('it_IT', null);\n  runApp(const MyApp());\n}\n\nclass MyApp extends StatelessWidget {\n  const MyApp({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      debugShowCheckedModeBanner: false,\n      theme: ThemeData(colorSchemeSeed: Colors.indigo, useMaterial3: true),\n      localizationsDelegates: const [\n        GlobalMaterialLocalizations.delegate,\n        GlobalWidgetsLocalizations.delegate,\n        GlobalCupertinoLocalizations.delegate,\n      ],\n      supportedLocales: const [Locale('it', 'IT'), Locale('en', 'US')],\n      locale: const Locale('it', 'IT'),\n      home: const AppuntamentoPage(),\n    );\n  }\n}\n\nclass AppuntamentoPage extends StatefulWidget {\n  const AppuntamentoPage({super.key});\n\n  @override\n  State\u003CAppuntamentoPage> createState() => _AppuntamentoPageState();\n}\n\nclass _AppuntamentoPageState extends State\u003CAppuntamentoPage> {\n  DateTime? _data;\n  TimeOfDay? _ora;\n\n  Future\u003Cvoid> _selezionaData() async {\n    final oggi = DateTime.now();\n    final scelta = await showDatePicker(\n      context: context,\n      initialDate: _data ?? oggi,\n      firstDate: DateTime(oggi.year - 1),\n      lastDate: DateTime(oggi.year + 5),\n      helpText: 'Seleziona la data',\n      confirmText: 'Conferma',\n      cancelText: 'Annulla',\n    );\n    if (scelta != null) setState(() => _data = scelta);\n  }\n\n  Future\u003Cvoid> _selezionaOra() async {\n    final scelta = await showTimePicker(\n      context: context,\n      initialTime: _ora ?? TimeOfDay.now(),\n      builder: (context, child) => MediaQuery(\n        data: MediaQuery.of(context).copyWith(alwaysUse24HourFormat: true),\n        child: child!,\n      ),\n    );\n    if (scelta != null) setState(() => _ora = scelta);\n  }\n\n  DateTime? get _appuntamento {\n    if (_data == null || _ora == null) return null;\n    return DateTime(_data!.year, _data!.month, _data!.day, _ora!.hour, _ora!.minute);\n  }\n\n  void _salva() {\n    final a = _appuntamento;\n    if (a == null) {\n      ScaffoldMessenger.of(context).showSnackBar(\n        const SnackBar(content: Text('Seleziona sia la data che l\\'orario')),\n      );\n      return;\n    }\n    final testo = DateFormat(\"d MMMM y 'alle' HH:mm\", 'it_IT').format(a);\n    ScaffoldMessenger.of(context).showSnackBar(\n      SnackBar(content: Text('Appuntamento: $testo')),\n    );\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    final dataText = _data == null\n        ? 'Nessuna data selezionata'\n        : DateFormat('EEEE d MMMM y', 'it_IT').format(_data!);\n    final oraText = _ora == null ? 'Nessun orario selezionato' : _ora!.format(context);\n\n    return Scaffold(\n      appBar: AppBar(title: const Text('Nuovo appuntamento')),\n      body: ListView(\n        padding: const EdgeInsets.all(16),\n        children: [\n          Card(\n            child: ListTile(\n              leading: const Icon(Icons.calendar_today),\n              title: const Text('Data'),\n              subtitle: Text(dataText),\n              trailing: const Icon(Icons.chevron_right),\n              onTap: _selezionaData,\n            ),\n          ),\n          const SizedBox(height: 8),\n          Card(\n            child: ListTile(\n              leading: const Icon(Icons.access_time),\n              title: const Text('Orario'),\n              subtitle: Text(oraText),\n              trailing: const Icon(Icons.chevron_right),\n              onTap: _selezionaOra,\n            ),\n          ),\n          const SizedBox(height: 24),\n          FilledButton.icon(\n            onPressed: _salva,\n            icon: const Icon(Icons.save),\n            label: const Text('Salva appuntamento'),\n          ),\n        ],\n      ),\n    );\n  }\n}","Una schermata con due schede toccabili per data e orario, testi in italiano e un pulsante che riepiloga l'appuntamento scelto.",[],1789120574980]