Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qttemporalpattern.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4#include "private/qttemporalpattern_p.h"
5
6#include "private/qlocale_p.h"
7#include "private/qtparseqttemporalformat_p.h"
8#if QT_CONFIG(datetimeparser)
9# include "private/qtparsetemporal_p.h"
10#endif
11
12#include <bitset>
13
14QT_BEGIN_NAMESPACE
15
17/*!
18 \internal
19 \since 6.12
20 \namespace QtTemporalPattern
21 \brief Supporting types and functions for temporal patterns.
22
23 Temporal patterns describe how a date, time or datetime may be serialized as
24 text or parsed from text. This namespace provides the common tools used by
25 the classes describing such patterns: \l QDateTimePattern, \l QTimePattern
26 and \l QDatePattern.
27*/
28
29/* Note (QTBUG-70516): For now (Qt 6.12) it suffices to cover everything that
30 the existing Qt datetime format strings are capable of. However, the intent
31 is to eventually expand this to fully support CLDR's datetime formats so that
32 we can switch from converting those to Qt formats when we scan CLDR to
33 actually storing the CLDR format in the qlocale_data_p.h tables and
34 constructing our Q(Date|Time)+Pattern objects from those formats. See comment
35 in header for a link to the relevant parts of LDML.
36*/
37
38/*!
39 \enum QtTemporalPattern::TemporalFieldCategory
40
41 This enumeration characterizes the information supplied by a field.
42
43 For the details of how that information is conveyed, see \l
44 {QtTemporalPattern::}{TemporalFieldFlag}. For the classification of fields
45 by whether they specify date, time or zone, see \l
46 {QtTemporalPattern::}{DateTimePart}.
47
48 \value Literal Describes a text fragment that frames the data, such as
49 separators and delimiters.
50 \value TimeZone Identifies the timezone or offset from UTC of a datetime.
51 \value SecondFraction The fraction of a second (an optional time field).
52 \value Second The second within the minute (an optional time field).
53 \value Minute The minute within the hour (a time field).
54 \value PeriodInDay A subdivision of the day, such as before noon vs after
55 noon (a time field). May serve to disambiguate the hour
56 when specified only modulo 12. (Currently only the am/pm
57 distinction is supported.)
58 \value HourMod12 The hour in the range 1 through 12 (a time field). May be
59 ambiguous on its own.
60 \value Hour The hour in the range from 0 through 23 (a time field).
61
62 \value DayOfWeek The day within the week (a date field). Usually specified
63 by name. Some locales may use numbers for their Narrow
64 Verbal and/or Standalone forms. No form is supported for
65 Numeric | DayOfWeek.
66 \value DayOfMonth The day number within the month (a date field). Runs from
67 1 for the first day of the month up to the length of the
68 month. Always numeric, regardless of field flags.
69
70 \value Month The month within the year (a date field). When specified
71 numerically, the first month of the year is numbered 1; there
72 is no month 0. Some locales may use numbers for their Narrow
73 Verbal form.
74
75 \value YearWithinCentury The two-digit year number (a date field). Widely
76 used in date formats, despite its potential for
77 ambiguity. May be disambiguated by other fields or
78 by specifying base year for the hundred years
79 presumed when only two digits are given and other
80 fields don't disambiguate.
81 \value Year The full year number (a date field).
82
83 Fields identified as numbers, along with hour, minute, second and fraction
84 of second, are always given in numeric form (regardless of Numeric, Verbal
85 or Standalone flags).
86
87 The SecondFraction field describes the digits immediately following the
88 fractional-part separator. Leading zeros are significant and not considered
89 to be padding: trailing zeros are understood as padding. QTime and QDateTime
90 only handle times to millisecond precision, so if more than three digits are
91 found when parsing a SecondFraction field, the excess are used only to round
92 to the nearest millisecond. (If fewer than three digits are parsed, the
93 value is implicitly extended on the right with zeros to obtain milliseconds
94 precision. Whether such a field is accepted will depend on the setting of
95 the \c width of the field and the absence of \c ZeroPad from its
96 \c{options}, in the usual ways.) If more than three digits are specified
97 when serializing, the digits after the first three shall all be zeros (and
98 are omitted if the \c ZeroPad option is not specified).
99
100 \note For negative years, the YearWithinCentury will be understood as the
101 number of completed years since the start of the most recent year that is a
102 multiple of 100. Thus year -1 (which Qt understands, when using the
103 Gregorian calendar, to mean 1 BCE) has a YearWithinCentury value of 99,
104 since the last year that's a multiple of 100 is -100 (for Gregorian, 100
105 BCE).
106
107 \omitvalue EndCategories
108
109 \sa {QtTemporalPattern::}{TemporalFieldFlag}, {QtTemporalPattern::}{DateTimePart}
110*/
111
112/* For numbers as narrow days of the week, at least three different numberings
113 are used, all of which are used in locales whose "first day of the week" is
114 Monday. (Furthermore, some locales with digits as narrow names only do that
115 for some days, with letters for others.) So there is no way to determine how
116 days of the week are numbered from one locale to the next, except in so far
117 as their narrow Verbal or Standalone forms use digits. A Numeric version of
118 the day of the week field would thus either not know what to do for most
119 locales, be inconsistent between locales or be inconsistent, for some
120 locales, between Narrow Verbal / Standalone formats and Numeric format.
121 Hence the lack of a meaning of Numeric for DayOfWeek.
122
123 Some locales use month numbers for the narrow format of months; but none are
124 known to do so inconsistently with the usual month numbering (although Pashto
125 does this only partially, using non-numeric narrow standalone forms for the
126 first two months). This does still conflict with the numeric form of months,
127 at least in some cases, that use ASCII digits for narrow forms of month
128 numbers but locale-appropriate digits for their numeric forms. However, the
129 conflict is only in how the numbers are represented, not in the numeric
130 values used for months.
131*/
132
133/*!
134 \internal
135 \namespace QtTemporalPattern::FieldGroup
136 \brief Masks identifying mutually-exclusive families of options.
137
138 Each constant in this namespace is of type \l {QtTemporalPattern::}
139 {TemporalFieldFlags} and combines a mutually-exclusive family of \l
140 {QtTemporalPattern::} {TemporalFieldFlag} values into a mask by which to
141 identify that family. Within each such family, if none of the flags is
142 specified, any of them may be applied but if any of them are specified then
143 only one of those specified may be applied.
144
145 \value FormMask The three general forms of a field: numeric, verbal and
146 standalone.
147 \value WidthMask The four field widths: wide, short, abbreviated, and
148 narrow.
149 \value UtcPrefixMask The two options for prefixes on offset forms of
150 timezones, with and without a UTC prefix.
151 \value PaddingMask The two padding options for when fields don't fill the
152 width allotted to them: spaces and zeros.
153 \value SeasonMask The three perspectives from which to describe a timezone:
154 the generic, regardless of the time of year, the standard,
155 and how it's described when exercising daylight-saving
156 time (if it does at all).
157*/
158/* Namespace QtParseCommon has helper functions, defined in qtparsetimezone_p.h,
159 to apply the above rule related to these masks.
160*/
161
162/*!
163 \enum QtTemporalPattern::TemporalFieldFlag
164
165 This enumeration describes how datetime fields are expressed in text.
166
167 A combination of these flags is used to qualify a \l {QtTemporalPattern::}
168 {TemporalFieldCategory}, indicating whether it is conveyed by words or
169 numbers, how tersely or in which terms, depending on the field
170 category. Interpretation of a flag in this enumeration varies with the field
171 category it is qualifying and with other flags combined with it.
172
173 Some flags, such as the four width options, are mutually exclusive. For each
174 group of mutually-exclusive flags, a mask constant is defined in namespace
175 QtTemporalPattern::FieldGroup, of type \l {QtTemporalPattern::}
176 {TemporalFieldFlags}, that combines the members of that group. If no member
177 of such a group is set in a flags variable, it is treated as if all members
178 of that group were set. When serializing, the behavior when two or more
179 conflicting flags, in a group relevant to the field, are combined is
180 unspecified. It may depend on other fields or variables passed to the
181 serialization function. When parsing, such conflicting flags allow the
182 parser to match any of the conflicting options specified. If this leads to
183 ambiguity, parsing prefers the option that consumes more of the text to
184 parse.
185
186 Unless otherwise indicated, fields are localized. For example, ZeroPad pads
187 with, and Numeric uses, locale-appropriate digits when localized, and the
188 names of months, days of the week and timezones are translated into the
189 appropriate language (if possible).
190
191 The primary distinction in how fields are expressed is the form of the
192 field. These first three options are mutually incompatible and are grouped
193 together as the \l {QtTemporalPattern::FieldGroup::} {FormMask} constant:
194
195 \value Numeric Express the field numerically as a series of digits.
196 \value Verbal Name the field value in its usual in-format grammatical form.
197 \value Standalone Name the field value in its stand-alone grammatical form.
198
199 Next comes the width of the field. The meanings of these fields depends on
200 other flags and the field category, where relevant. Some field categories
201 may ignore these entirely, others may draw fewer distinctions and use the
202 same meaning for some widths. These four options are mutually exclusive and
203 grouped together as the \l {QtTemporalPattern::FieldGroup::} {WidthMask}
204 constant:
205
206 \value Narrow Use a the narrowest supported form for the field. In some
207 locales, the Narrow Verbal forms of some fields may use
208 numbers, potentially conflicting with one of its Numeric
209 forms.
210 \value Abbreviated Use an abbreviated form of the field.
211 \value Short Use a short form of the field.
212 \value Wide Use a wide form of the field.
213
214 Where a \c width is specified for a field but the field's value is naturally
215 shorter, it is necessary to indicate how to pad it to the desired width.
216 These two options are mutually exclusive and grouped together as the \l
217 {QtTemporalPattern::FieldGroup::} {PaddingMask} constant:
218
219 \value ZeroPad Only for numeric fields: pad to \c width with zeros. When
220 parsing, accept zeros that don't affect value, reject fields
221 that are narrower than their specified \c width.
222 \value SpacePad For a field with a positive \c width, pad to that \c width
223 with spaces. When parsing, allow leading and trailing
224 spacing characters.
225
226 If neither form of padding is indicated, the natural representation of a
227 value is used even if it fails to reach the \c width specified and parsing
228 will accept a narrower field (although it will prefer a match with full
229 width). In a \l {QtTemporalPattern::TemporalFieldCategory} {TimeZone} field
230 (see below) using an offset form, SpacePad is ignored and ZeroPad or its
231 absence only has its usual meaning for hour fields, while controlling the
232 presence of zero minute and second offsets following the hour field.
233
234 Where a text to be matched (for example, a literal or the name of a month or
235 day of the week) contains spaces, by default plain space (ASCII SPACE,
236 U+0020) and the various Unicode spacing characters outside the ASCII range
237 (of various widths, some of them non-breaking) are all accepted as matches
238 for one another, while the number and placement of such short horizontal
239 spaces must match. Other spacing characters (newline, tab, etc.) must match
240 exactly. Since users commonly do not distinguish the short horizontal
241 spaces, this default usually suffices. In some cases, there may be reason to
242 insist on exact matching of spaces, without treating short horizontal spaces
243 as equivalent. Where the text to be parsed is taken from a larger text,
244 however, it's also possible that this larger text has been flowed, as a
245 paragraph, which may have turned some spaces into line breaks, possibly with
246 added indentation, or the text may be split across a page boundary. Coping
247 with such cases is supported by the options
248
249 \value FlexSpace Where a field to be matched contains spacing characters, or
250 a run of them, any spacing character or run of them will be
251 accepted as matching. A character is deemed to be a spacing
252 character if \l QChar::isSpace() is true for it.
253 \value StrictSpace Spacing characters must be matched exactly.
254 Ignored if FlexSpace is also set.
255
256 The following options are only relevant to Verbal and Standalone
257 fields. They are not treated as a group or descrbed by a mask, as the locale
258 provides relevant fields with the appropriate (possibly mixed) case for the
259 lcoale. By default, the locale's form is used when serializing and matched
260 (case-sensitively) when parsing. The first two of these are mutually
261 exclusive. They change that default, forcing the case when serializing and
262 requiring the specified case (or one of the specified cases) when
263 parsing. The third has no effect when serializing and overrides the other
264 two, if either is present, when parsing.
265
266 \value LowerCase When serializing, force lower-case.
267 \value UpperCase When serializing, force upper-case.
268 \value IgnoreCase When parsing, match the field case-insensitively.
269
270 Modern revisions of ISO 8601 permit years outside the range from 0 through
271 9999 but require that they have a sign. By default a + sign on a positive
272 year is allowed and silently ignored (without counting towards its \c
273 width), but the YearSignIso8601 applies a modified version of the ISO rule:
274 the year field will only match a text with more digits than its specified \c
275 width if that text starts with a sign. When the field's \c width is 4, this
276 implements the ISO rule, but it can be applied to other widths, if needed.
277
278 In contrast to ISO's use of year 0000 to indicate 1 BCE, with negative year
279 values representing successively earlier years, where the calendar in use
280 has no year zero, Qt describes the year before year 1 as year -1, skipping
281 over 0 and treating 0 as an invalid value for the year. In particular, this
282 applies to the Gregorian calendar, which is used by default: 1 CE is
283 represented as year 1, with 1 BC as year -1. If the calendar in use reports
284 \c true from \l {QCalendar::} {hasYearZero()}, Qt duly accepts a year 0
285 between years -1 and +1. ISO also specifies that years before 1583 (the
286 first full year after the Gregorian calendar came into play) or after 9999
287 should not be used except by prior agreement between the producer and
288 consumer of the serialized date or datetime. Qt leaves such agreement as a
289 matter between the user and those they communicate with, simply accepting
290 any year number within the range of QDate or QDateTime, as appropriate.
291
292 \section2 Timezone representation
293
294 The following options are only relevant to timezones. If used with other
295 categories of field, they are ignored. By default, when the other fields of
296 a timestamp determine a datetime, the zone's localized name in effect at
297 that datetime is used when serializing and matched when parsing.
298
299 There are both localized and international standard formats available. The
300 following pair of options select which of those to use. They are grouped
301 together as the \l {QtTemporalPattern::FieldGroup::} {LocalizationMask}
302 constant:
303
304 \value LocalizedZone For a TimeZone, use localized forms.
305 \value Iso8601 For a TimeZone, use an ISO 8601 offset format.
306
307 When both are specified, or neither is, localized forms are preferred. See
308 \l {Locale-independent offset forms}, below, for details of the ISO
309 8601-based formats. See \c{Standalone | Short} below for the IANA DB and
310 \l{Local time} for a system-dependent form, both of which ignore the choice
311 between LocalizedZone and Iso8601.
312
313 The following three options, selecting seasonal variations, are mutually
314 exclusive and only relevant to Verbal or Standalone forms. They are
315 independent of the choice between LocalizedZone and Iso8601. They are
316 grouped together as the \l {QtTemporalPattern::FieldGroup::} {SeasonMask}
317 constant:
318
319 \value GenericTime For a non-Numeric TimeZone, use its generic name.
320 \value StandardTime For a non-Numeric TimeZone, use its standard-time name.
321 \value DaylightSavingTime For a non-Numeric TimeZone, use its
322 daylight-saving name.
323
324 For localized timezones, Numeric selects a basic offset format or an offset
325 format with a base prefix (typically a localized form of UTC or GMT), Verbal
326 selects a form of the zone's name, and Standalone selects the IANA ID or a
327 localized name based on a city that serves as exemplar for the zone (for the
328 given locale). The effects of the width options above then depend on which
329 of these is used. When LocalizedZone is set, the following forms are
330 available:
331
332 \list
333 \li For Numeric, the timezone offset is used:
334 \list
335 \li Wide uses the hour, minute and second, as for Short, but when
336 parsing it will accept a fractional part of the seconds (following
337 the locale-appropriate separator, after the whole number part of
338 the seconds), if present. As Qt only supports whole numbers of
339 seconds as offsets, this fractional part's only effect is to round
340 up the second part if it is at least a half second. (See note on
341 rounding in the next section.)
342 \li Short uses the hour, minute and second, rounding to the nearest
343 second if the offset is not a whole number of seconds.
344 \li Abbreviated uses the hour and minute, rounding to the nearest
345 minute if the offset is not a whole number of minutes.
346 \li Narrow uses the hour, rounding to nearest if the actual offset is
347 not a whole number of hours.
348 \endlist
349 \li For Verbal, the zone name is used:
350 \list
351 \li Wide uses the full name of the zone, e.g. "Pacific Time", "Pacific
352 Standard Time" or "Pacific Daylight Time", depending on season.
353 \li Short is treated as Wide.
354 \li Abbreviated uses the zone abbreviation, e.g. "PT", "PST" or "PDT".
355 Note that these cannot be reliably parsed.
356 \li Narrow is treated as Abbreviated.
357 \endlist
358 \li For Standalone, the city name:
359 \list
360 \li Wide uses the locale's generic location format, such as "Los
361 Angeles Time".
362 \li Short uses the full IANA ID, such as America/Los_Angeles.
363 This is not localized (the LocalizedZone flag is ignored).
364 \li Abbreviated just gives the localized exemplar city, e.g. "Los
365 Angeles".
366 \li Narrow is treated as Abbreviated.
367 \endlist
368 \endlist
369
370 Where a timezone is specified simply in terms of an offset from UTC, it does
371 not necessarily have an associated city or a name other than its offset
372 representations. For such zones, when serializing, Verbal and Standalone are
373 treated as Numeric, with the exception of \c{Staldalone | Short}, as the
374 IANA ID is not localized and this form, like an IANA ID, is accepted by the
375 QTimeZone(QByteArray) constructor. (Note that these do not include ZeroPad:
376 see the next section for its effect on offset forms.) When parsing,
377 therefore, these offset formats are accepted for the Verbal and Standalone
378 forms that would map to them for offset zones. This applies to \l
379 {QTimeZone::fromDurationAheadOfUtc()} lightweight time representations (for
380 which \l {QTimeZone::}{isUtcOrFixedOffset()} is true) as well as to those,
381 with a UTC-offset backend, constructed by QTimeZone(int) or, with an ID of
382 form \c{"UTC"} or \c{"UTC±HH:mm"}, by QTimeZone(QByteArray),
383
384 \section3 Offset modifiers
385
386 In the various timezone offset formats (both above and below), there are
387 potentially hour, minute and second parts of the offset, depending on the
388 width option selected. The minute and second parts, when present, always use
389 two digits, rendering the usual meaning of ZeroPad redundant. Instead, for
390 these parts, ZeroPad controls whether trailing zero parts are included.
391 When ZeroPad is set they are included when serializing and required to be
392 present when parsing. When ZeroPad is not set, they are omitted when
393 serializing and, if trailng parts are missing when parsing, they are taken
394 to have value zero. Zero parts are always accepted when parsing, even when
395 ZeroPad is not set.
396
397 The hour part of an offset is never omitted when serializing and is always
398 required when parsing. When ZeroPad is not set, when parsing offset formats
399 with separators between parts, a single-digit hour is accepted. (For the
400 localized offset formats above, whether there are separators between parts
401 depends on the locale.) When ZeroPad is not set, serialization only produces
402 a single-digit hour if there are no later parts (typically because they were
403 all zero, hence omitted). Otherwise, the hour part is always serialized with
404 two digits and parsing requires it to have two digits.
405
406 As ever, if more than one width is specified, any given is allowed. On
407 serializing, narrower formats are preferred unless they lose precision in
408 the offset that an allowed longer format would include. Thus \c{Narrow |
409 Short} would include only the hours for a whole-hour offset, but would
410 include hours, minutes and seconds for an hour-and-a-half offset (albeit
411 omitting the zero seconds unless ZeroPad is set). Where the width thus
412 selected requires rounding due to omitting a part of the offset that isn't
413 zero, exact halves round away from zero. On parsing, the longest allowed
414 form for which a match is found will be used.
415
416 Offset formats may also include a prefix (localized in the forms above) that
417 identifies the offset as being relative to UTC or GMT. The following pair of
418 mutually exclusive options control whether that is omitted or included.
419 They are grouped together as the \l {QtTemporalPattern::FieldGroup::}
420 {UtcPrefixMask} constant:
421
422 \value AcceptUtcPrefix Include a UTC prefix on offsets when serializing and
423 require it when parsing.
424 \value NeedNoUtcPrefix Leave off the UTC prefix when serializing and reject
425 it when parsing.
426
427 If neither or both of these are specified, serializing omits the prefix and
428 parsing permits it but does not require it.
429
430 \section3 Locale-independent offset forms
431
432 In addition to these localized forms, a timestamp may also represent its
433 zone in a locale-independent offset form. In effect, this use the C locale,
434 with ASCII digits 0 through 9, the ASCII + and - as signs, and the ASCII
435 colon as separator (where relevant). These are selected by the \c Iso8601
436 flag.
437
438 \value AllowZSuffix Modifies Iso8601 to allow use of a \c{Z} suffix to
439 denote a zero UTC offset. See RFC 9557 note below.
440
441 If AllowZSuffix is set and ZeroPad is not, serialization will use \c{Z} to
442 represent a zero offset. When ZeroPad is set, serialization ignores
443 AllowZSuffix. If AllowZSufix is set, regardless of ZeroPad, parsing will
444 accept a \c{Z} suffix as meaning zero offset.
445
446 The Iso8601 format is modified by other flags as follows (when not using
447 \c{Z} to represent a zero offset):
448 \list
449 \li With Numeric it uses a basic format (with no separators), with Verbal
450 or Standalone it uses separators between hours, minutes and seconds,
451 in so far as these appear.
452 \li The width options Wide, Short, Abbreviated and Narrow have the same
453 meanings as for Numeric localized offset formats, modified by the
454 ZeroPad option, as described above.
455 \endlist
456
457 \note In some contexts, notably where \l
458 {https://www.rfc-editor.org/rfc/rfc9557.html} {RFC 9557} is used, a zone
459 indicator on a timestamp may be understood as giving context to the
460 information in which it appears, as opposed to only indicating the zone with
461 respect to which the timestamp itself is expressed. In such contexts, a
462 \c{Z} suffix, applied by \c AllowZSuffix, only indicates that the timestamp
463 itself is given with respect to UTC and does not give any context to the
464 information in which it appears. For contrast, in such contexts, a +00:00
465 suffix does indicate not only that the timestamp is given in UTC but also
466 that UTC is the relevant zone for the context of the information. Prior to
467 RFC 9557, some RFCs (incompatibly with ISO 8601) proposed using -00:00 to
468 indicate what RFC 9557 has specified as the meaning for a \c{Z}
469 suffix. Nothing in Qt attends to this distinction.
470
471 \section3 Local time
472
473 Where Qt can determine how the local system describes its local time, Qt has
474 no control over the form in which the system supplies it, nor does Qt know
475 whether, or how, it is localized, with the result that this representation
476 is system-dependent. As another system may be using a different local time,
477 or representing it differently, there is no guarantee that what one system
478 supplies for local time can be successfully understood on another system. To
479 opt in to using this system-dependent representation of local time, supply
480 the following option. Even then, when serializing, if the options given
481 permit any other available representation of the timezone, that is preferred
482 over this.
483
484 \value LocalTimeName Allow the system-supplied local time name to describe
485 the system's local time.
486
487 The system local time may come in separate forms for standard time and
488 daylight-saving time. When it does, the options above for selecting between
489 these affect LocalTimeName as usual, with GenericTime ignored.
490
491 \sa {QtTemporalPattern::}{TemporalFieldCategory}, {QtTemporalPattern::}{TemporalFieldFlags}
492*/
493// RFC 9557: see QTBUG-114172
494
495// TemporalFieldFlags and DateTimeParts: docs taken care of automagically by
496// QDoc, recognizing QFLAG() usage.
497
498/*!
499 \fn constexpr bool QtTemporalPattern::matchesFlagWithin(QtTemporalPattern::TemporalFieldFlags flags, QtTemporalPattern::TemporalFieldFlag sought, QtTemporalPattern::TemporalFieldFlags group)
500
501 Tests \a flags for a \a sought flag within a \a group.
502
503 Implements the per-flag check for a single TemporalFieldFlag with respect to
504 its FieldGroup entry. If no flag in a group is given in \a flags, then all
505 flags in the group are allowed; otherwise, only the given flags in the group
506 match.
507*/
508
509/*!
510 \fn constexpr bool QtTemporalPattern::matchesFlagsWithin(QtTemporalPattern::TemporalFieldFlags flags, QtTemporalPattern::TemporalFieldFlags sought, QtTemporalPattern::TemporalFieldFlags group)
511
512 Similar to \l matchesFlagWithin(), but if any of those \a sought is found in
513 \a flags, or if none of group are, it's counted as a match.
514
515 In some contexts, some flags are treated as equivalent, so to check for what
516 they represent pass the equivalent flags |-joined as \a sought.
517*/
518
519
520/*!
521 \enum QtTemporalPattern::DateTimePart
522 \brief This enumeraction classifies the various field categories.
523
524 The classification addresses which parts of a datetime a field contributes
525 data to.
526
527 \value None A literal field contributes no data.
528 \value Date Various fields contribute to the date.
529 \value Time Various fields contribute to the time.
530 \value Zone Only the \l {QtTemporalPattern::TemporalFieldFlag::}{TimeZone}
531 field contributes information about the timezone.
532
533 These may be combined in a \l {QtTemporalPattern::}{DateTimeParts} to
534 express a set of parts that a set of fields might suffice to describe,
535 whether fully or only in part.
536
537 \sa {QtTemporalPattern::}{TemporalFieldCategory}, {QtTemporalPattern::}{supports()}
538*/
539
540/*!
541 \fn QtTemporalPattern::classify(QtTemporalPattern::TemporalFieldCategory category) noexcept
542 \brief Classify a field category according to the part of a datetime it contributes to.
543
544 This maps a \l {QtTemporalPattern::}{TemporalFieldCategory} to the \l
545 {QtTemporalPattern::}{DateTimePart} for which it supplies data.
546*/
547
548/*!
549 \class QtTemporalPattern::TemporalField
550 \brief Describes one field in a temporal pattern.
551
552 A single field is characterized by its \l
553 {QtTemporalPattern::TemporalFieldCategory}{category}, some \l
554 {QtTemporalPattern::TemporalFieldFlags}{options} identifying how the field
555 is to be expressed and, where relevant, a datum. For a Literal field, the
556 datum is the string to be matched.
557
558 For numeric fields, a width may optionally be specified, indicating
559 the expected number of digits in the field. If options specifies
560 zero-padding, this is a minimum number of digits; otherwise, shorter fields
561 are accepted. In any case, longer values are accepted, where the resulting
562 numeric value is valid for the field. A zero width does not mean an empty
563 field will be accepted: it is effectively equivalent to a width of 1.
564
565 \note in some locales, the digits may require surrogate pairs to encode, so
566 the UTF-16 length of the field may exceed the number of digits. In a year
567 field with a sign, the sign does not count towards the width of the
568 field. The width only counts digits. The width is, in any case, a lower
569 bound: more digits may be read, if present and not consumed by some later
570 field. The \c endIndex of any parse result is the only reliable source of
571 truth on the UTF-16 end of the text parsed.
572*/
573// TODO: should we support digit grouping in year numbers, at least with > 4 digits ?
574
575/*!
576 \fn QtTemporalPattern::hasFieldsFor(QSpan<const QtTemporalPattern::TemporalField> range)
577 \brief Identify the parts to which the given fields contribute data.
578
579 Takes a \a range of TemporalField instances and returns a \l
580 {QtTemporalPattern::}{DateTimeParts} indicating which parts \l classify()
581 says any of the fields contribute to. Note that this only tessts for
582 contribution to a part, not for full coverage of the part. See \l supports()
583 for that.
584
585 \sa classify(), supports()
586*/
587
588/*!
589 \enum QtTemporalPattern::SupportType
590 \brief This enumeration identifies how well some fields describe requested datetime parts.
591
592 The fields of a pattern may contain partial or complete data on each of the
593 \l {QtTemporalPattern::TemporalFieldPart}{parts of} a datetime. When parsing
594 or serializing only a date or only a time, fields for the other or for
595 timezone are extraneous, making the pattern unable to serialize just the
596 intended type, as it lacks the data for those fields. It would also, when
597 parsing, be obliged discard some of the data it parses, as the type it
598 returns cannot express it.
599
600 When serializing a datetime, if the fields present do not suffice to fully
601 encode the date or time, it will not be possible for a reader of the
602 resulting text to unambiguously determine the datetime. If timezone is not
603 specified, it is possible to convert the datetime to some specific choice of
604 zone: provided both ends of the communication use the same zone, it is then
605 possible to recover the exact point in time, albeit without knowing the
606 timezone originally used to encode it.
607
608 Where data is partially supplied, it is possible that the partial data
609 suffices to meet the readers needs, although this typically involves the
610 reader in making some default assumptions about the missing fields. For
611 example, a two-digit year may need some assumptions about the century
612 (possibly aided by information about the date and day of the week) to
613 determine what year to presume the sender intended.
614
615 \value None No fields were found.
616 \value HasStrays Some field not relevant to the requested parts was present.
617 \value Partial Either some requested part is present and some other is
618 missing or some fields for a requested part are present but
619 not enough to fully describe that part.
620 \value Clear Enough fields of the requested parts were found to fully
621 determine them and no fields of unwanted parts were present.
622
623 Where partial fields for the requested parts were found along with fields
624 for unwanted parts, HasStrays is used in preference to Partial, as it is
625 considered a more significant defect.
626
627 \sa {QtTemporalPattern::}{TemporalFieldPart}, {QtTemporalPattern::}{supports()}
628*/
629
630/*!
631 \fn QtTemporalPattern::supports(QtTemporalPattern::DateTimeParts wanted, QSpan<QtTemporalPattern::TemporalField> range, bool hasBaseYear) noexcept
632 \brief Assess how well the given fields support the \a wanted parts.
633
634 If any field in \a range belongs to a part not included in \a wanted,
635 returns \l {SupportType::}{HasStrays}. Otherwise,
636
637 \list
638 \li If no fields are present, aside from \l
639 {TemporalFieldCategory::}{Literal} ones, returns \l
640 {SupportType::}{None}.
641 \li If the fields present completely specify all parts in \a wanted,
642 returns \l {SupportType::}{Clear}.
643 \li If some fields are specified but some \a wanted part is inadequately
644 specified, or entirely unspecified, returns \l
645 {SupportType::}{Partial}.
646 \endlist
647
648 For these purposes,
649
650 \list
651 \li The \l {DateTimePart::}{Zone} part is specified by the \l
652 {TemporalFieldCategory::}{TimeZone}.
653 \li The \l {DateTimePart::}{Time} part is specified by any combination of
654 fields that identify the hour and minute. If the \l
655 {TemporalFieldCategory::}{SecondFractions} field is present, the part is
656 considered incompletely specified unless the \l
657 {TemporalFieldCategory::}{Seconds} field is also present.
658 \li The \l {DateTimePart::}{Date} part is specified by any combination of
659 fields that identify a date. This usually means \l
660 {TemporalFieldCategory::}{Year}, \l {TemporalFieldCategory::}{Month}
661 and \l {TemporalFieldCategory::}{DayOfMonth} although Year may be
662 indirectly specified by \l
663 {TemporalFieldCategory::}{YearWithinCentury} if the presence of \l
664 {TemporalFieldCategory::}{DayOfWeek} enables disambiguation among
665 centuries close to the present, given the other date fields.
666 \endlist
667*/
668
669template <typename Enum, size_t Size>
671{
672 std::bitset<Size> bits;
673 static size_t map(Enum cat) { return qToUnderlying(cat); }
674public:
675 void set(Enum cat) { bits[map(cat)] = true; }
676 bool test(Enum cat) const { return bits[map(cat)]; }
677};
678
679SupportType supports(DateTimeParts wanted, QSpan<const TemporalField> range,
680 bool hasBaseYear) noexcept
681{
682 // TODO: may need to take into account calendar (and perhaps locale).
683 SupportType support = SupportType::HasStrays;
684 SupportType zone = SupportType::None;
685 EnumIndexedBitSet<TemporalFieldCategory, EndTemporalFieldCategories> categories;
686 for (const TemporalField &field : range) {
687 const DateTimePart part = field.part();
688 switch (part) {
689 case DateTimePart::None: // Literal contributes no data.
690 continue;
691 case DateTimePart::Date:
692 case DateTimePart::Time:
693 categories.set(field.category);
694 break;
695 case DateTimePart::Zone:
696 if (field.options.testAnyFlags(TemporalFieldFlag::Wide | TemporalFieldFlag::Short)
697 || field.options.testAnyFlags(TemporalFieldFlag::Numeric
698 | TemporalFieldFlag::Standalone
699 | TemporalFieldFlag::Iso8601)) {
700 zone = SupportType::Clear;
701 } else if (zone == SupportType::None) {
702 // Zone name abbreviation: does not uniquely identify zone.
703 zone = SupportType::Partial;
704 }
705 break;
706 }
707 if (!wanted.testFlag(part))
708 return support;
709 }
710
711 bool partsSeen = wanted.testFlag(DateTimePart::Zone);
712 support = partsSeen ? zone : SupportType::None;
713
714 constexpr auto join = [](SupportType lhs, SupportType rhs) -> SupportType {
715 Q_PRE(lhs != SupportType::HasStrays);
716 Q_PRE(rhs != SupportType::HasStrays);
717 // For combining SupportTypes from different Parts to determine support
718 // for their composite. Simplest case is when they're the same:
719 if (lhs == rhs)
720 return lhs;
721 // Every combination of distinct values among the other three is partial:
722 return SupportType::Partial;
723 };
724
725#define CHECK(field) (categories.test(TemporalFieldCategory::field))
726
727 if (wanted.testFlag(DateTimePart::Date)) {
728 const SupportType hasDate = [&] {
729 // if (CHECK(JulianDay)) return SupportType::Clear;
730 int fields = 0;
731 bool partial = false;
732 if (CHECK(Year)) {
733 ++fields;
734 } else if (CHECK(YearWithinCentury)) {
735 if (hasBaseYear) {
736 ++fields;
737 // } else if (CHECK(Century)) { ++fields;
738 } else if (CHECK(DayOfWeek) && CHECK(DayOfMonth) && CHECK(Month)) {
739 // We can infer century from those three by assuming it's
740 // close to the present.
741 ++fields;
742 } else {
743 partial = true;
744 }
745 // } else if (CHECK(Century)) { partial = true;
746 }
747 if (CHECK(Month))
748 ++fields;
749 if (CHECK(DayOfMonth))
750 ++fields;
751 else if (CHECK(DayOfWeek))
752 partial = true;
753 if (fields == 3 && !partial)
754 return SupportType::Clear;
755 if (fields || partial)
756 return SupportType::Partial;
757 return SupportType::None;
758 }();
759 support = partsSeen ? join(support, hasDate) : hasDate;
760 partsSeen = true;
761 }
762
763 if (wanted.testFlag(DateTimePart::Time)) {
764 const SupportType hasTime = [&] {
765 // if (CHECK(MillisecondInDay)) return SupportType::Clear;
766 int fields = 0;
767 bool partial = false;
768 if (CHECK(Hour)) {
769 ++fields;
770 } else if (CHECK(HourMod12)) {
771 if (CHECK(PeriodInDay))
772 ++fields;
773 else
774 partial = true;
775 } else if (CHECK(PeriodInDay)) {
776 partial = true;
777 }
778 if (CHECK(Minute))
779 ++fields;
780 // Hour and minute are required, but seconds and later are optional;
781 // however, having a finer field without an coarser one leaves a gap => Partial.
782 if (CHECK(Second))
783 partial = fields < 2;
784 else if (CHECK(SecondFraction))
785 partial = true;
786 if (fields == 2 && !partial)
787 return SupportType::Clear;
788 if (fields || partial)
789 return SupportType::Partial;
790 return SupportType::None;
791 }();
792 support = partsSeen ? join(support, hasTime) : hasTime;
793 partsSeen = true;
794 }
795
796#undef CHECK
797
798 // Shall still be None if we've seen no fields:
799 Q_ASSERT(partsSeen || support == SupportType::None);
800 return support;
801}
802
803} // namespace QtTemporalPattern
804
805/*!
806 \internal
807 \since 6.12
808 \class QDateTimePattern
809 \brief A description of a serialization format for a datetime
810*/
811
812/*!
813 \fn QDateTimePattern::forLocale(const QLocale &locale, QLocale::FormatType format)
814 Construct a QDateTimePattern appropriate to the given \a locale.
815
816 The \a format can be used to select how compact or expansive the pattern is.
817
818 \sa fromQtFormat
819*/
820
821/*
822//! [is-valid]
823 Returns \c true if this pattern can be used to reliably transmit {\1}s.
824
825 Returns \c false if there is unresolved ambiguity in the texts it will
826 produce when serializing or the texts that will match it when parsing.
827 Some apparent ambiguities may be resolved by interactions between other
828 fields or the \c{defaults} parameter to \l{parse()}.
829//! [is-valid]
830*/
831
832// TODO: currently (see supports(), above) doesn't take locale or calendar into account.
833/*!
834 \fn QDateTimePattern::isValid() const noexcept
835
836 \include qttemporalpattern.cpp {is-valid} {datetime}
837 \include qttemporalpattern.cpp base-year-disambiguates
838
839 Timezone abbreviations are ambiguous.
840*/
841
842/*!
843 \fn QDateTimePattern::setLocale(const QLocale &loc) noexcept
844
845//! [set-locale]
846 Sets the locale, for use for fields whose representation depends on locale,
847 to \a loc. By default the application's current default locale is used.
848
849 \sa QLocale::setDefault()
850//! [set-locale]
851*/
852
853/*!
854 \fn QDateTimePattern::locale() const noexcep
855
856 Returns the current locale in use by this pattern.
857
858 \sa setLocale()
859*/
860
861/*!
862 \fn QDateTimePattern::setCalendar(QCalendar calendar) noexcept
863
864 \include qttemporalpattern.cpp set-calendar
865*/
866
867/*!
868 \fn QDateTimePattern::calendar(QCalendar calendar) const noexcept
869
870 Returns the current calendar in use by this pattern.
871
872 \sa setCalendar()
873*/
874
875/*!
876 \fn QDateTimePattern::setBaseYear(int centuryStart) noexcept
877
878 \include qttemporalpattern.cpp set-base-year
879*/
880
881/*!
882 \fn QDateTimePattern::clearBaseYear() noexcept
883
884 \include qttemporalpattern.cpp clear-base-year
885*/
886
887/*!
888 \fn QDateTimePattern::baseYear() const noexcept
889
890 \include qttemporalpattern.cpp get-base-year
891*/
892
893/*!
894 Parse and return the datetime represented by \a text.
895
896//! [parser-defaults]
897 If \a defaults is provided and valid, any fields the format described by
898 this pattern does not provide will be copied from \a defaults to construct
899 the returned value.
900//! [parser-defaults]
901*/
902
903QtTemporalPattern::ParseResult<QDateTime>
904QDateTimePattern::parse(QStringView text, const QDateTime &defaults) const
905{
906#if QT_CONFIG(datetimeparser)
907 const auto seen = QtParseTemporal::prefix(text, m_fields, m_locale, m_calendar, m_baseYear);
908 if (!m_fields.isEmpty() && !seen) // Failed to parse.
909 return {};
910
911 const QDate date = seen.date(m_calendar, defaults.date());
912 const QTime time = seen.time(defaults.time());
913
914 if (QDateTime result(date, time, seen.zone, seen.resolveType()); result.isValid())
915 return {std::move(result), seen.size()};
916 // Fall back to default transition resolution:
917 return {QDateTime(date, time, seen.zone), seen.size()};
918#else
919 Q_UNUSED(text);
920 Q_UNUSED(defaults);
921 return {};
922#endif // datetimeparser
923}
924
925/*!
926 Serialize the given \a datetime to a string representation.
927*/
928
929QString QDateTimePattern::serialize(const QDateTime &datetime) const
930{
931 Q_UNUSED(datetime);
932 return {};
933}
934
935/*!
936 Construct a QDateTimePattern described by the given \a format string.
937
938 \sa forLocale()
939*/
940
941QDateTimePattern QDateTimePattern::fromQtFormat(QStringView format)
942{
943 using namespace QtTemporalPattern;
944 constexpr DateTimeParts form = DateTimePart::Date | DateTimePart::Time | DateTimePart::Zone;
945 const auto qt = QtParseQtTemporalFormat::prefix(format, form);
946 if (qt.size() == format.size())
947 return QDateTimePattern(qt.fields);
948 return QDateTimePattern({});
949}
950
951/*!
952 \internal
953 \since 6.12
954 \class QTimePattern
955 \brief A description of a serialization format for a time
956*/
957
958/*!
959 \fn QTimePattern::forLocale(const QLocale &locale, QLocale::FormatType format)
960 Construct a QTimePattern appropriate to the given \a locale.
961
962 The \a format can be used to select how compact or expansive the pattern is.
963
964 \sa fromQtFormat
965*/
966
967/*!
968 \fn QTimePattern::isValid() const noexcept
969
970 \include qttemporalpattern.cpp {is-valid} {time}
971*/
972
973/*!
974 \fn QTimePattern::setLocale(const QLocale &loc) noexcept
975
976 \include qttemporalpattern.cpp set-locale
977*/
978
979/*!
980 \fn QTimePattern::locale() const noexcep
981
982 Returns the current locale in use by this pattern.
983
984 \sa setLocale()
985*/
986
987/*!
988 Parse and return the time represented by \a text.
989
990 \include qttemporalpattern.cpp parser-defaults
991*/
992
993QtTemporalPattern::ParseResult<QTime>
994QTimePattern::parse(QStringView text, QTime defaults) const
995{
996#if QT_CONFIG(datetimeparser)
997 const auto seen = QtParseTemporal::prefix(text, m_fields, m_locale, QCalendar());
998 if (!m_fields.isEmpty() && !seen) // Failed to parse.
999 return {};
1000 return {seen.time(defaults), seen.size()};
1001#else
1002 Q_UNUSED(text);
1003 Q_UNUSED(defaults);
1004 return {};
1005#endif // datetimeparser
1006}
1007
1008/*!
1009 Serialize the given \a time to a string representation.
1010*/
1011
1012QString QTimePattern::serialize(const QTime &time) const
1013{
1014 Q_UNUSED(time);
1015 return {};
1016}
1017
1018/*!
1019 Construct a QTimePattern described by the given \a format string.
1020
1021 \sa forLocale()
1022*/
1023
1024QTimePattern QTimePattern::fromQtFormat(QStringView format)
1025{
1026 using namespace QtTemporalPattern;
1027 constexpr DateTimeParts form{DateTimePart::Time};
1028 const auto qt = QtParseQtTemporalFormat::prefix(format, form);
1029 if (qt.size() == format.size())
1030 return QTimePattern(qt.fields);
1031 return QTimePattern({});
1032}
1033
1034/*!
1035 \internal
1036 \since 6.12
1037 \class QDatePattern
1038 \brief A description of a serialization format for a date
1039*/
1040
1041/*!
1042 \fn QDatePattern::forLocale(const QLocale &locale, QLocale::FormatType format)
1043 Construct a QDatePattern appropriate to the given \a locale.
1044
1045 The \a format can be used to select how compact or expansive the pattern is.
1046
1047 \sa fromQtFormat
1048*/
1049
1050/*!
1051 \fn QDatePattern::isValid() const noexcept
1052
1053 \include qttemporalpattern.cpp {is-valid} {date}
1054
1055//! [base-year-disambiguates]
1056 The ambiguity of two-digit years may be resolved by configuring the hundred
1057 years among which to select a matching years.
1058//! [base-year-disambiguates]
1059
1060 \sa setBaseYear()
1061*/
1062
1063/*!
1064 \fn QDatePattern::setLocale(const QLocale &loc) noexcept
1065
1066 \include qttemporalpattern.cpp set-locale
1067*/
1068
1069/*!
1070 \fn QDatePattern::locale() const noexcep
1071
1072 Returns the current locale in use by this pattern.
1073
1074 \sa setLocale()
1075*/
1076
1077/*!
1078 \fn QDatePattern::setCalendar(QCalendar calendar) noexcept
1079
1080//! [set-calendar]
1081 Sets the calendar used by this pattern. This influences the names and
1082 lengths of months and how these vary from year to year. In some cases it may
1083 also influence the number of months in the year or even the pattern and
1084 names of days of the week.
1085
1086 By default the Gregorian calendar is used.
1087
1088 \sa getCalendar(), QCalendar
1089//! [set-calendar]
1090*/
1091
1092/*!
1093 \fn QDatePattern::calendar(QCalendar calendar) const noexcept
1094
1095 Returns the current calendar in use by this pattern.
1096
1097 \sa setCalendar()
1098*/
1099
1100/*!
1101 \fn QDatePattern::setBaseYear(int centuryStart) noexcept
1102
1103//! [set-base-year]
1104 Configures the handling of two-digit years, if any are present in the pattern.
1105
1106 If a two-digit year is present, the year ending in those two digits in the
1107 range from \a centuryStart to \c {centuryStart + 99} shall be its default
1108 interpretation. This may be amended if the month, day of the month and day
1109 of the week indicate some other nearby century.
1110
1111 \note the years here, including \a centuryStart, are expressed with respect
1112 to \c{calendar()}, whose year numbering need not match that of the Gregorian
1113 calendar.
1114
1115 Calling this method makes no difference unless the pattern does in fact use
1116 a two-digit year, nor does it affect serialization.
1117
1118 \sa clearBaseYear()
1119//! [set-base-year]
1120*/
1121
1122// TODO: should the default state be clear or some specific year ?
1123// That year could depend on the present, e.g. present minus 49 years.
1124
1125/*!
1126 \fn QDatePattern::clearBaseYear() noexcept
1127
1128//! [clear-base-year]
1129 Leaves the handling of two-digit years to other fields to disambiguate.
1130
1131 This is the default state, so has no effect unless \l setBaseYear() has
1132 previously been called.
1133
1134 If a two-digit year is present, this leaves unspecified which hundred years
1135 to presume it lies within. If a two-digit year is present and other fields
1136 of the pattern do not suffice to make clear which hundred years to select
1137 based on the given last two digits, the text produced when serializing with
1138 this format shall generally be ambiguous. While readers of the text may be
1139 able to disambiguate the year anyway, there is scope for misunderstanding if
1140 their heuristics for doing so do not match your expectation. On parsing, the
1141 pattern may deliver a result that is off by some whole number of centuries
1142 from what the parsed text's author intended.
1143
1144 \sa setBaseYear(), isValid()
1145//! [clear-base-year]
1146*/
1147
1148/*!
1149 \fn QDatePattern::baseYear() const noexcept
1150
1151//! [get-base-year]
1152
1153 Returns the current base year, with respect to \c{calendar()}, used by this
1154 pattern if it needs to resolve a two-digit year. The result is \c
1155 {std::nullopt} when no base year is set, which is the default state.
1156
1157 \sa setBaseYear()
1158//! [get-base-year]
1159*/
1160
1161/*!
1162 Parse and return the date represented by \a text.
1163
1164 \include qttemporalpattern.cpp parser-defaults
1165*/
1166
1167QtTemporalPattern::ParseResult<QDate>
1168QDatePattern::parse(QStringView text, QDate defaults) const
1169{
1170#if QT_CONFIG(datetimeparser)
1171 const auto seen = QtParseTemporal::prefix(text, m_fields, m_locale, m_calendar, m_baseYear);
1172 if (!m_fields.isEmpty() && !seen) // Failed to parse.
1173 return {};
1174 return {seen.date(m_calendar, defaults), seen.size()};
1175#else
1176 Q_UNUSED(text);
1177 Q_UNUSED(defaults);
1178 return {};
1179#endif // datetimeparser
1180}
1181
1182/*!
1183 Serialize the given \a date to a string representation.
1184
1185 \sa parse()
1186*/
1187
1188QString QDatePattern::serialize(const QDate &date) const
1189{
1190 Q_UNUSED(date);
1191 return {};
1192}
1193
1194/*!
1195 Construct a QDatePattern described by the given \a format string.
1196
1197 \sa forLocale()
1198*/
1199
1200QDatePattern QDatePattern::fromQtFormat(QStringView format)
1201{
1202 using namespace QtTemporalPattern;
1203 constexpr DateTimeParts form{DateTimePart::Date};
1204 const auto qt = QtParseQtTemporalFormat::prefix(format, form);
1205 if (qt.size() == format.size())
1206 return QDatePattern(qt.fields);
1207 return QDatePattern({});
1208}
1209
1210QT_END_NAMESPACE
Supporting types and functions for temporal patterns.
SupportType supports(DateTimeParts wanted, QSpan< const TemporalField > range, bool hasBaseYear) noexcept
#define CHECK(cvref)