1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// @docImport 'time_picker.dart';
6library;
7
8import 'package:flutter/services.dart';
9import 'package:flutter/widgets.dart';
10
11import 'debug.dart';
12import 'material_localizations.dart';
13
14/// Whether the [TimeOfDay] is before or after noon.
15enum DayPeriod {
16 /// Ante meridiem (before noon).
17 am,
18
19 /// Post meridiem (after noon).
20 pm,
21}
22
23/// A value representing a time during the day, independent of the date that
24/// day might fall on or the time zone.
25///
26/// The time is represented by [hour] and [minute] pair. Once created, both
27/// values cannot be changed.
28///
29/// You can create TimeOfDay using the constructor which requires both hour and
30/// minute or using [DateTime] object.
31/// Hours are specified between 0 and 23, as in a 24-hour clock.
32///
33/// {@tool snippet}
34///
35/// ```dart
36/// TimeOfDay now = TimeOfDay.now();
37/// const TimeOfDay releaseTime = TimeOfDay(hour: 15, minute: 0); // 3:00pm
38/// TimeOfDay roomBooked = TimeOfDay.fromDateTime(DateTime.parse('2018-10-20 16:30:04Z')); // 4:30pm
39/// ```
40/// {@end-tool}
41///
42/// See also:
43///
44/// * [showTimePicker], which returns this type.
45/// * [MaterialLocalizations], which provides methods for formatting values of
46/// this type according to the chosen [Locale].
47/// * [DateTime], which represents date and time, and is subject to eras and
48/// time zones.
49@immutable
50class TimeOfDay implements Comparable<TimeOfDay> {
51 /// Creates a time of day.
52 ///
53 /// The [hour] argument must be between 0 and 23, inclusive. The [minute]
54 /// argument must be between 0 and 59, inclusive.
55 const TimeOfDay({required this.hour, required this.minute});
56
57 /// Creates a time of day based on the given time.
58 ///
59 /// The [hour] is set to the time's hour and the [minute] is set to the time's
60 /// minute in the timezone of the given [DateTime].
61 TimeOfDay.fromDateTime(DateTime time) : hour = time.hour, minute = time.minute;
62
63 /// Creates a time of day based on the current time.
64 ///
65 /// The [hour] is set to the current hour and the [minute] is set to the
66 /// current minute in the local time zone.
67 TimeOfDay.now() : this.fromDateTime(DateTime.now());
68
69 /// The number of hours in one day, i.e. 24.
70 static const int hoursPerDay = 24;
71
72 /// The number of hours in one day period (see also [DayPeriod]), i.e. 12.
73 static const int hoursPerPeriod = 12;
74
75 /// The number of minutes in one hour, i.e. 60.
76 static const int minutesPerHour = 60;
77
78 /// Returns a new TimeOfDay with the hour and/or minute replaced.
79 TimeOfDay replacing({int? hour, int? minute}) {
80 assert(hour == null || (hour >= 0 && hour < hoursPerDay));
81 assert(minute == null || (minute >= 0 && minute < minutesPerHour));
82 return TimeOfDay(hour: hour ?? this.hour, minute: minute ?? this.minute);
83 }
84
85 /// The selected hour, in 24 hour time from 0..23.
86 final int hour;
87
88 /// The selected minute.
89 final int minute;
90
91 /// Whether this time of day is before or after noon.
92 DayPeriod get period => hour < hoursPerPeriod ? DayPeriod.am : DayPeriod.pm;
93
94 /// Which hour of the current period (e.g., am or pm) this time is.
95 ///
96 /// For 12AM (midnight) and 12PM (noon) this returns 12.
97 int get hourOfPeriod => hour == 0 || hour == 12 ? 12 : hour - periodOffset;
98
99 /// The hour at which the current period starts.
100 int get periodOffset => period == DayPeriod.am ? 0 : hoursPerPeriod;
101
102 /// Returns the localized string representation of this time of day.
103 ///
104 /// This is a shortcut for [MaterialLocalizations.formatTimeOfDay].
105 String format(BuildContext context) {
106 assert(debugCheckHasMediaQuery(context));
107 assert(debugCheckHasMaterialLocalizations(context));
108 final MaterialLocalizations localizations = MaterialLocalizations.of(context);
109 return localizations.formatTimeOfDay(
110 this,
111 alwaysUse24HourFormat: MediaQuery.alwaysUse24HourFormatOf(context),
112 );
113 }
114
115 /// Whether this [TimeOfDay] occurs earlier than [other].
116 ///
117 /// Does not account for day or sub-minute differences. This means
118 /// that "00:00" of the next day is still before "23:00" of this day.
119 bool isBefore(TimeOfDay other) => compareTo(other) < 0;
120
121 /// Whether this [TimeOfDay] occurs later than [other].
122 ///
123 /// Does not account for day or sub-minute differences. This means
124 /// that "00:00" of the next day is still before "23:00" of this day.
125 bool isAfter(TimeOfDay other) => compareTo(other) > 0;
126
127 /// Whether this [TimeOfDay] occurs at the same time as [other].
128 ///
129 /// Does not account for day or sub-minute differences. This means
130 /// that "00:00" of the next day is still before "23:00" of this day.
131 bool isAtSameTimeAs(TimeOfDay other) => compareTo(other) == 0;
132
133 /// Compares this [TimeOfDay] object to [other] independent of date.
134 ///
135 /// Does not account for day or sub-minute differences. This means
136 /// that "00:00" of the next day is still before "23:00" of this day.
137 ///
138 /// A [compareTo] function returns:
139 /// * a negative value if this TimeOfDay [isBefore] [other].
140 /// * `0` if this DateTime [isAtSameTimeAs] [other], and
141 /// * a positive value otherwise (when this TimeOfDay [isAfter] [other]).
142 @override
143 int compareTo(TimeOfDay other) {
144 final int hourComparison = hour.compareTo(other.hour);
145 return hourComparison == 0 ? minute.compareTo(other.minute) : hourComparison;
146 }
147
148 @override
149 bool operator ==(Object other) {
150 return other is TimeOfDay && other.hour == hour && other.minute == minute;
151 }
152
153 @override
154 int get hashCode => Object.hash(hour, minute);
155
156 @override
157 String toString() {
158 String addLeadingZeroIfNeeded(int value) {
159 if (value < 10) {
160 return '0$value';
161 }
162 return value.toString();
163 }
164
165 final String hourLabel = addLeadingZeroIfNeeded(hour);
166 final String minuteLabel = addLeadingZeroIfNeeded(minute);
167
168 return '$TimeOfDay($hourLabel:$minuteLabel)';
169 }
170}
171
172/// A [RestorableValue] that knows how to save and restore [TimeOfDay].
173///
174/// {@macro flutter.widgets.RestorableNum}.
175class RestorableTimeOfDay extends RestorableValue<TimeOfDay> {
176 /// Creates a [RestorableTimeOfDay].
177 ///
178 /// {@macro flutter.widgets.RestorableNum.constructor}
179 RestorableTimeOfDay(TimeOfDay defaultValue) : _defaultValue = defaultValue;
180
181 final TimeOfDay _defaultValue;
182
183 @override
184 TimeOfDay createDefaultValue() => _defaultValue;
185
186 @override
187 void didUpdateValue(TimeOfDay? oldValue) {
188 assert(debugIsSerializableForRestoration(value.hour));
189 assert(debugIsSerializableForRestoration(value.minute));
190 notifyListeners();
191 }
192
193 @override
194 TimeOfDay fromPrimitives(Object? data) {
195 final List<Object?> timeData = data! as List<Object?>;
196 return TimeOfDay(minute: timeData[0]! as int, hour: timeData[1]! as int);
197 }
198
199 @override
200 Object? toPrimitives() => <int>[value.minute, value.hour];
201}
202
203/// Determines how the time picker invoked using [showTimePicker] formats and
204/// lays out the time controls.
205///
206/// The time picker provides layout configurations optimized for each of the
207/// enum values.
208enum TimeOfDayFormat {
209 /// Corresponds to the ICU 'HH:mm' pattern.
210 ///
211 /// This format uses 24-hour two-digit zero-padded hours. Controls are always
212 /// laid out horizontally. Hours are separated from minutes by one colon
213 /// character.
214 HH_colon_mm,
215
216 /// Corresponds to the ICU 'HH.mm' pattern.
217 ///
218 /// This format uses 24-hour two-digit zero-padded hours. Controls are always
219 /// laid out horizontally. Hours are separated from minutes by one dot
220 /// character.
221 HH_dot_mm,
222
223 /// Corresponds to the ICU "HH 'h' mm" pattern used in Canadian French.
224 ///
225 /// This format uses 24-hour two-digit zero-padded hours. Controls are always
226 /// laid out horizontally. Hours are separated from minutes by letter 'h'.
227 frenchCanadian,
228
229 /// Corresponds to the ICU 'H:mm' pattern.
230 ///
231 /// This format uses 24-hour non-padded variable-length hours. Controls are
232 /// always laid out horizontally. Hours are separated from minutes by one
233 /// colon character.
234 H_colon_mm,
235
236 /// Corresponds to the ICU 'h:mm a' pattern.
237 ///
238 /// This format uses 12-hour non-padded variable-length hours with a day
239 /// period. Controls are laid out horizontally in portrait mode. In landscape
240 /// mode, the day period appears vertically after (consistent with the ambient
241 /// [TextDirection]) hour-minute indicator. Hours are separated from minutes
242 /// by one colon character.
243 h_colon_mm_space_a,
244
245 /// Corresponds to the ICU 'a h:mm' pattern.
246 ///
247 /// This format uses 12-hour non-padded variable-length hours with a day
248 /// period. Controls are laid out horizontally in portrait mode. In landscape
249 /// mode, the day period appears vertically before (consistent with the
250 /// ambient [TextDirection]) hour-minute indicator. Hours are separated from
251 /// minutes by one colon character.
252 a_space_h_colon_mm,
253}
254
255/// Describes how hours are formatted.
256enum HourFormat {
257 /// Zero-padded two-digit 24-hour format ranging from "00" to "23".
258 HH,
259
260 /// Non-padded variable-length 24-hour format ranging from "0" to "23".
261 H,
262
263 /// Non-padded variable-length hour in day period format ranging from "1" to
264 /// "12".
265 h,
266}
267
268/// The [HourFormat] used for the given [TimeOfDayFormat].
269HourFormat hourFormat({required TimeOfDayFormat of}) {
270 switch (of) {
271 case TimeOfDayFormat.h_colon_mm_space_a:
272 case TimeOfDayFormat.a_space_h_colon_mm:
273 return HourFormat.h;
274 case TimeOfDayFormat.H_colon_mm:
275 return HourFormat.H;
276 case TimeOfDayFormat.HH_dot_mm:
277 case TimeOfDayFormat.HH_colon_mm:
278 case TimeOfDayFormat.frenchCanadian:
279 return HourFormat.HH;
280 }
281}
282

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com