| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter/services.dart'; |
| import 'package:flutter/widgets.dart'; |
| |
| import 'debug.dart'; |
| import 'material_localizations.dart'; |
| |
| |
| /// Whether the [TimeOfDay] is before or after noon. |
| enum DayPeriod { |
| /// Ante meridiem (before noon). |
| am, |
| |
| /// Post meridiem (after noon). |
| pm, |
| } |
| |
| /// A value representing a time during the day, independent of the date that |
| /// day might fall on or the time zone. |
| /// |
| /// The time is represented by [hour] and [minute] pair. Once created, both |
| /// values cannot be changed. |
| /// |
| /// You can create TimeOfDay using the constructor which requires both hour and |
| /// minute or using [DateTime] object. |
| /// Hours are specified between 0 and 23, as in a 24-hour clock. |
| /// |
| /// {@tool snippet} |
| /// |
| /// ```dart |
| /// TimeOfDay now = TimeOfDay.now(); |
| /// const TimeOfDay releaseTime = TimeOfDay(hour: 15, minute: 0); // 3:00pm |
| /// TimeOfDay roomBooked = TimeOfDay.fromDateTime(DateTime.parse('2018-10-20 16:30:04Z')); // 4:30pm |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [showTimePicker], which returns this type. |
| /// * [MaterialLocalizations], which provides methods for formatting values of |
| /// this type according to the chosen [Locale]. |
| /// * [DateTime], which represents date and time, and is subject to eras and |
| /// time zones. |
| @immutable |
| class TimeOfDay { |
| /// Creates a time of day. |
| /// |
| /// The [hour] argument must be between 0 and 23, inclusive. The [minute] |
| /// argument must be between 0 and 59, inclusive. |
| const TimeOfDay({ required this.hour, required this.minute }); |
| |
| /// Creates a time of day based on the given time. |
| /// |
| /// The [hour] is set to the time's hour and the [minute] is set to the time's |
| /// minute in the timezone of the given [DateTime]. |
| TimeOfDay.fromDateTime(DateTime time) |
| : hour = time.hour, |
| minute = time.minute; |
| |
| /// Creates a time of day based on the current time. |
| /// |
| /// The [hour] is set to the current hour and the [minute] is set to the |
| /// current minute in the local time zone. |
| factory TimeOfDay.now() { return TimeOfDay.fromDateTime(DateTime.now()); } |
| |
| /// The number of hours in one day, i.e. 24. |
| static const int hoursPerDay = 24; |
| |
| /// The number of hours in one day period (see also [DayPeriod]), i.e. 12. |
| static const int hoursPerPeriod = 12; |
| |
| /// The number of minutes in one hour, i.e. 60. |
| static const int minutesPerHour = 60; |
| |
| /// Returns a new TimeOfDay with the hour and/or minute replaced. |
| TimeOfDay replacing({ int? hour, int? minute }) { |
| assert(hour == null || (hour >= 0 && hour < hoursPerDay)); |
| assert(minute == null || (minute >= 0 && minute < minutesPerHour)); |
| return TimeOfDay(hour: hour ?? this.hour, minute: minute ?? this.minute); |
| } |
| |
| /// The selected hour, in 24 hour time from 0..23. |
| final int hour; |
| |
| /// The selected minute. |
| final int minute; |
| |
| /// Whether this time of day is before or after noon. |
| DayPeriod get period => hour < hoursPerPeriod ? DayPeriod.am : DayPeriod.pm; |
| |
| /// Which hour of the current period (e.g., am or pm) this time is. |
| /// |
| /// For 12AM (midnight) and 12PM (noon) this returns 12. |
| int get hourOfPeriod => hour == 0 || hour == 12 ? 12 : hour - periodOffset; |
| |
| /// The hour at which the current period starts. |
| int get periodOffset => period == DayPeriod.am ? 0 : hoursPerPeriod; |
| |
| /// Returns the localized string representation of this time of day. |
| /// |
| /// This is a shortcut for [MaterialLocalizations.formatTimeOfDay]. |
| String format(BuildContext context) { |
| assert(debugCheckHasMediaQuery(context)); |
| assert(debugCheckHasMaterialLocalizations(context)); |
| final MaterialLocalizations localizations = MaterialLocalizations.of(context); |
| return localizations.formatTimeOfDay( |
| this, |
| alwaysUse24HourFormat: MediaQuery.of(context).alwaysUse24HourFormat, |
| ); |
| } |
| |
| @override |
| bool operator ==(Object other) { |
| return other is TimeOfDay |
| && other.hour == hour |
| && other.minute == minute; |
| } |
| |
| @override |
| int get hashCode => Object.hash(hour, minute); |
| |
| @override |
| String toString() { |
| String addLeadingZeroIfNeeded(int value) { |
| if (value < 10) { |
| return '0$value'; |
| } |
| return value.toString(); |
| } |
| |
| final String hourLabel = addLeadingZeroIfNeeded(hour); |
| final String minuteLabel = addLeadingZeroIfNeeded(minute); |
| |
| return '$TimeOfDay($hourLabel:$minuteLabel)'; |
| } |
| } |
| |
| /// A [RestorableValue] that knows how to save and restore [TimeOfDay]. |
| /// |
| /// {@macro flutter.widgets.RestorableNum}. |
| class RestorableTimeOfDay extends RestorableValue<TimeOfDay> { |
| /// Creates a [RestorableTimeOfDay]. |
| /// |
| /// {@macro flutter.widgets.RestorableNum.constructor} |
| RestorableTimeOfDay(TimeOfDay defaultValue) : _defaultValue = defaultValue; |
| |
| final TimeOfDay _defaultValue; |
| |
| @override |
| TimeOfDay createDefaultValue() => _defaultValue; |
| |
| @override |
| void didUpdateValue(TimeOfDay? oldValue) { |
| assert(debugIsSerializableForRestoration(value.hour)); |
| assert(debugIsSerializableForRestoration(value.minute)); |
| notifyListeners(); |
| } |
| |
| @override |
| TimeOfDay fromPrimitives(Object? data) { |
| final List<Object?> timeData = data! as List<Object?>; |
| return TimeOfDay( |
| minute: timeData[0]! as int, |
| hour: timeData[1]! as int, |
| ); |
| } |
| |
| @override |
| Object? toPrimitives() => <int>[value.minute, value.hour]; |
| } |
| |
| /// Determines how the time picker invoked using [showTimePicker] formats and |
| /// lays out the time controls. |
| /// |
| /// The time picker provides layout configurations optimized for each of the |
| /// enum values. |
| enum TimeOfDayFormat { |
| /// Corresponds to the ICU 'HH:mm' pattern. |
| /// |
| /// This format uses 24-hour two-digit zero-padded hours. Controls are always |
| /// laid out horizontally. Hours are separated from minutes by one colon |
| /// character. |
| HH_colon_mm, |
| |
| /// Corresponds to the ICU 'HH.mm' pattern. |
| /// |
| /// This format uses 24-hour two-digit zero-padded hours. Controls are always |
| /// laid out horizontally. Hours are separated from minutes by one dot |
| /// character. |
| HH_dot_mm, |
| |
| /// Corresponds to the ICU "HH 'h' mm" pattern used in Canadian French. |
| /// |
| /// This format uses 24-hour two-digit zero-padded hours. Controls are always |
| /// laid out horizontally. Hours are separated from minutes by letter 'h'. |
| frenchCanadian, |
| |
| /// Corresponds to the ICU 'H:mm' pattern. |
| /// |
| /// This format uses 24-hour non-padded variable-length hours. Controls are |
| /// always laid out horizontally. Hours are separated from minutes by one |
| /// colon character. |
| H_colon_mm, |
| |
| /// Corresponds to the ICU 'h:mm a' pattern. |
| /// |
| /// This format uses 12-hour non-padded variable-length hours with a day |
| /// period. Controls are laid out horizontally in portrait mode. In landscape |
| /// mode, the day period appears vertically after (consistent with the ambient |
| /// [TextDirection]) hour-minute indicator. Hours are separated from minutes |
| /// by one colon character. |
| h_colon_mm_space_a, |
| |
| /// Corresponds to the ICU 'a h:mm' pattern. |
| /// |
| /// This format uses 12-hour non-padded variable-length hours with a day |
| /// period. Controls are laid out horizontally in portrait mode. In landscape |
| /// mode, the day period appears vertically before (consistent with the |
| /// ambient [TextDirection]) hour-minute indicator. Hours are separated from |
| /// minutes by one colon character. |
| a_space_h_colon_mm, |
| } |
| |
| /// Describes how hours are formatted. |
| enum HourFormat { |
| /// Zero-padded two-digit 24-hour format ranging from "00" to "23". |
| HH, |
| |
| /// Non-padded variable-length 24-hour format ranging from "0" to "23". |
| H, |
| |
| /// Non-padded variable-length hour in day period format ranging from "1" to |
| /// "12". |
| h, |
| } |
| |
| /// The [HourFormat] used for the given [TimeOfDayFormat]. |
| HourFormat hourFormat({ required TimeOfDayFormat of }) { |
| switch (of) { |
| case TimeOfDayFormat.h_colon_mm_space_a: |
| case TimeOfDayFormat.a_space_h_colon_mm: |
| return HourFormat.h; |
| case TimeOfDayFormat.H_colon_mm: |
| return HourFormat.H; |
| case TimeOfDayFormat.HH_dot_mm: |
| case TimeOfDayFormat.HH_colon_mm: |
| case TimeOfDayFormat.frenchCanadian: |
| return HourFormat.HH; |
| } |
| } |