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