1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *****************************************************************************
5 * Copyright (C) 2014-2016, International Business Machines Corporation and
6 * others.
7 * All Rights Reserved.
8 *****************************************************************************
9 *
10 * File RELDATEFMT.H
11 *****************************************************************************
12 */
13 
14 #ifndef __RELDATEFMT_H
15 #define __RELDATEFMT_H
16 
17 #include "unicode/utypes.h"
18 #include "unicode/uobject.h"
19 #include "unicode/udisplaycontext.h"
20 #include "unicode/ureldatefmt.h"
21 #include "unicode/locid.h"
22 
23 /**
24  * \file
25  * \brief C++ API: Formats relative dates such as "1 day ago" or "tomorrow"
26  */
27 
28 #if !UCONFIG_NO_FORMATTING
29 
30 /**
31  * Represents the unit for formatting a relative date. e.g "in 5 days"
32  * or "in 3 months"
33  * @stable ICU 53
34  */
35 typedef enum UDateRelativeUnit {
36 
37     /**
38      * Seconds
39      * @stable ICU 53
40      */
41     UDAT_RELATIVE_SECONDS,
42 
43     /**
44      * Minutes
45      * @stable ICU 53
46      */
47     UDAT_RELATIVE_MINUTES,
48 
49     /**
50      * Hours
51      * @stable ICU 53
52      */
53     UDAT_RELATIVE_HOURS,
54 
55     /**
56      * Days
57      * @stable ICU 53
58      */
59     UDAT_RELATIVE_DAYS,
60 
61     /**
62      * Weeks
63      * @stable ICU 53
64      */
65     UDAT_RELATIVE_WEEKS,
66 
67     /**
68      * Months
69      * @stable ICU 53
70      */
71     UDAT_RELATIVE_MONTHS,
72 
73     /**
74      * Years
75      * @stable ICU 53
76      */
77     UDAT_RELATIVE_YEARS,
78 
79 #ifndef U_HIDE_DEPRECATED_API
80     /**
81      * One more than the highest normal UDateRelativeUnit value.
82      * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
83      */
84     UDAT_RELATIVE_UNIT_COUNT
85 #endif  // U_HIDE_DEPRECATED_API
86 } UDateRelativeUnit;
87 
88 /**
89  * Represents an absolute unit.
90  * @stable ICU 53
91  */
92 typedef enum UDateAbsoluteUnit {
93 
94     // Days of week have to remain together and in order from Sunday to
95     // Saturday.
96     /**
97      * Sunday
98      * @stable ICU 53
99      */
100     UDAT_ABSOLUTE_SUNDAY,
101 
102     /**
103      * Monday
104      * @stable ICU 53
105      */
106     UDAT_ABSOLUTE_MONDAY,
107 
108     /**
109      * Tuesday
110      * @stable ICU 53
111      */
112     UDAT_ABSOLUTE_TUESDAY,
113 
114     /**
115      * Wednesday
116      * @stable ICU 53
117      */
118     UDAT_ABSOLUTE_WEDNESDAY,
119 
120     /**
121      * Thursday
122      * @stable ICU 53
123      */
124     UDAT_ABSOLUTE_THURSDAY,
125 
126     /**
127      * Friday
128      * @stable ICU 53
129      */
130     UDAT_ABSOLUTE_FRIDAY,
131 
132     /**
133      * Saturday
134      * @stable ICU 53
135      */
136     UDAT_ABSOLUTE_SATURDAY,
137 
138     /**
139      * Day
140      * @stable ICU 53
141      */
142     UDAT_ABSOLUTE_DAY,
143 
144     /**
145      * Week
146      * @stable ICU 53
147      */
148     UDAT_ABSOLUTE_WEEK,
149 
150     /**
151      * Month
152      * @stable ICU 53
153      */
154     UDAT_ABSOLUTE_MONTH,
155 
156     /**
157      * Year
158      * @stable ICU 53
159      */
160     UDAT_ABSOLUTE_YEAR,
161 
162     /**
163      * Now
164      * @stable ICU 53
165      */
166     UDAT_ABSOLUTE_NOW,
167 
168 #ifndef U_HIDE_DEPRECATED_API
169     /**
170      * One more than the highest normal UDateAbsoluteUnit value.
171      * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
172      */
173     UDAT_ABSOLUTE_UNIT_COUNT
174 #endif  // U_HIDE_DEPRECATED_API
175 } UDateAbsoluteUnit;
176 
177 /**
178  * Represents a direction for an absolute unit e.g "Next Tuesday"
179  * or "Last Tuesday"
180  * @stable ICU 53
181  */
182 typedef enum UDateDirection {
183 
184     /**
185      * Two before. Not fully supported in every locale.
186      * @stable ICU 53
187      */
188     UDAT_DIRECTION_LAST_2,
189 
190     /**
191      * Last
192      * @stable ICU 53
193      */
194     UDAT_DIRECTION_LAST,
195 
196     /**
197      * This
198      * @stable ICU 53
199      */
200     UDAT_DIRECTION_THIS,
201 
202     /**
203      * Next
204      * @stable ICU 53
205      */
206     UDAT_DIRECTION_NEXT,
207 
208     /**
209      * Two after. Not fully supported in every locale.
210      * @stable ICU 53
211      */
212     UDAT_DIRECTION_NEXT_2,
213 
214     /**
215      * Plain, which means the absence of a qualifier.
216      * @stable ICU 53
217      */
218     UDAT_DIRECTION_PLAIN,
219 
220 #ifndef U_HIDE_DEPRECATED_API
221     /**
222      * One more than the highest normal UDateDirection value.
223      * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
224      */
225     UDAT_DIRECTION_COUNT
226 #endif  // U_HIDE_DEPRECATED_API
227 } UDateDirection;
228 
229 #if !UCONFIG_NO_BREAK_ITERATION
230 
231 U_NAMESPACE_BEGIN
232 
233 class BreakIterator;
234 class RelativeDateTimeCacheData;
235 class SharedNumberFormat;
236 class SharedPluralRules;
237 class SharedBreakIterator;
238 class NumberFormat;
239 class UnicodeString;
240 
241 /**
242  * Formats simple relative dates. There are two types of relative dates that
243  * it handles:
244  * <ul>
245  *   <li>relative dates with a quantity e.g "in 5 days"</li>
246  *   <li>relative dates without a quantity e.g "next Tuesday"</li>
247  * </ul>
248  * <p>
249  * This API is very basic and is intended to be a building block for more
250  * fancy APIs. The caller tells it exactly what to display in a locale
251  * independent way. While this class automatically provides the correct plural
252  * forms, the grammatical form is otherwise as neutral as possible. It is the
253  * caller's responsibility to handle cut-off logic such as deciding between
254  * displaying "in 7 days" or "in 1 week." This API supports relative dates
255  * involving one single unit. This API does not support relative dates
256  * involving compound units,
257  * e.g "in 5 days and 4 hours" nor does it support parsing.
258  * <p>
259  * This class is mostly thread safe and immutable with the following caveats:
260  * 1. The assignment operator violates Immutability. It must not be used
261  *    concurrently with other operations.
262  * 2. Caller must not hold onto adopted pointers.
263  * <p>
264  * This class is not intended for public subclassing.
265  * <p>
266  * Here are some examples of use:
267  * <blockquote>
268  * <pre>
269  * UErrorCode status = U_ZERO_ERROR;
270  * UnicodeString appendTo;
271  * RelativeDateTimeFormatter fmt(status);
272  * // Appends "in 1 day"
273  * fmt.format(
274  *     1, UDAT_DIRECTION_NEXT, UDAT_RELATIVE_DAYS, appendTo, status);
275  * // Appends "in 3 days"
276  * fmt.format(
277  *     3, UDAT_DIRECTION_NEXT, UDAT_RELATIVE_DAYS, appendTo, status);
278  * // Appends "3.2 years ago"
279  * fmt.format(
280  *     3.2, UDAT_DIRECTION_LAST, UDAT_RELATIVE_YEARS, appendTo, status);
281  * // Appends "last Sunday"
282  * fmt.format(UDAT_DIRECTION_LAST, UDAT_ABSOLUTE_SUNDAY, appendTo, status);
283  * // Appends "this Sunday"
284  * fmt.format(UDAT_DIRECTION_THIS, UDAT_ABSOLUTE_SUNDAY, appendTo, status);
285  * // Appends "next Sunday"
286  * fmt.format(UDAT_DIRECTION_NEXT, UDAT_ABSOLUTE_SUNDAY, appendTo, status);
287  * // Appends "Sunday"
288  * fmt.format(UDAT_DIRECTION_PLAIN, UDAT_ABSOLUTE_SUNDAY, appendTo, status);
289  *
290  * // Appends "yesterday"
291  * fmt.format(UDAT_DIRECTION_LAST, UDAT_ABSOLUTE_DAY, appendTo, status);
292  * // Appends "today"
293  * fmt.format(UDAT_DIRECTION_THIS, UDAT_ABSOLUTE_DAY, appendTo, status);
294  * // Appends "tomorrow"
295  * fmt.format(UDAT_DIRECTION_NEXT, UDAT_ABSOLUTE_DAY, appendTo, status);
296  * // Appends "now"
297  * fmt.format(UDAT_DIRECTION_PLAIN, UDAT_ABSOLUTE_NOW, appendTo, status);
298  *
299  * </pre>
300  * </blockquote>
301  * <p>
302  * In the future, we may add more forms, such as abbreviated/short forms
303  * (3 secs ago), and relative day periods ("yesterday afternoon"), etc.
304  *
305  * The RelativeDateTimeFormatter class is not intended for public subclassing.
306  *
307  * @stable ICU 53
308  */
309 class U_I18N_API RelativeDateTimeFormatter : public UObject {
310 public:
311 
312     /**
313      * Create RelativeDateTimeFormatter with default locale.
314      * @stable ICU 53
315      */
316     RelativeDateTimeFormatter(UErrorCode& status);
317 
318     /**
319      * Create RelativeDateTimeFormatter with given locale.
320      * @stable ICU 53
321      */
322     RelativeDateTimeFormatter(const Locale& locale, UErrorCode& status);
323 
324     /**
325      * Create RelativeDateTimeFormatter with given locale and NumberFormat.
326      *
327      * @param locale the locale
328      * @param nfToAdopt Constructed object takes ownership of this pointer.
329      *   It is an error for caller to delete this pointer or change its
330      *   contents after calling this constructor.
331      * @status Any error is returned here.
332      * @stable ICU 53
333      */
334     RelativeDateTimeFormatter(
335         const Locale& locale, NumberFormat *nfToAdopt, UErrorCode& status);
336 
337     /**
338      * Create RelativeDateTimeFormatter with given locale, NumberFormat,
339      * and capitalization context.
340      *
341      * @param locale the locale
342      * @param nfToAdopt Constructed object takes ownership of this pointer.
343      *   It is an error for caller to delete this pointer or change its
344      *   contents after calling this constructor. Caller may pass NULL for
345      *   this argument if they want default number format behavior.
346      * @param style the format style. The UDAT_RELATIVE bit field has no effect.
347      * @param capitalizationContext A value from UDisplayContext that pertains to
348      * capitalization.
349      * @status Any error is returned here.
350      * @stable ICU 54
351      */
352     RelativeDateTimeFormatter(
353             const Locale& locale,
354             NumberFormat *nfToAdopt,
355             UDateRelativeDateTimeFormatterStyle style,
356             UDisplayContext capitalizationContext,
357             UErrorCode& status);
358 
359     /**
360      * Copy constructor.
361      * @stable ICU 53
362      */
363     RelativeDateTimeFormatter(const RelativeDateTimeFormatter& other);
364 
365     /**
366      * Assignment operator.
367      * @stable ICU 53
368      */
369     RelativeDateTimeFormatter& operator=(
370             const RelativeDateTimeFormatter& other);
371 
372     /**
373      * Destructor.
374      * @stable ICU 53
375      */
376     virtual ~RelativeDateTimeFormatter();
377 
378     /**
379      * Formats a relative date with a quantity such as "in 5 days" or
380      * "3 months ago"
381      * @param quantity The numerical amount e.g 5. This value is formatted
382      * according to this object's NumberFormat object.
383      * @param direction NEXT means a future relative date; LAST means a past
384      * relative date. If direction is anything else, this method sets
385      * status to U_ILLEGAL_ARGUMENT_ERROR.
386      * @param unit the unit e.g day? month? year?
387      * @param appendTo The string to which the formatted result will be
388      *  appended
389      * @param status ICU error code returned here.
390      * @return appendTo
391      * @stable ICU 53
392      */
393     UnicodeString& format(
394             double quantity,
395             UDateDirection direction,
396             UDateRelativeUnit unit,
397             UnicodeString& appendTo,
398             UErrorCode& status) const;
399 
400     /**
401      * Formats a relative date without a quantity.
402      * @param direction NEXT, LAST, THIS, etc.
403      * @param unit e.g SATURDAY, DAY, MONTH
404      * @param appendTo The string to which the formatted result will be
405      *  appended. If the value of direction is documented as not being fully
406      *  supported in all locales then this method leaves appendTo unchanged if
407      *  no format string is available.
408      * @param status ICU error code returned here.
409      * @return appendTo
410      * @stable ICU 53
411      */
412     UnicodeString& format(
413             UDateDirection direction,
414             UDateAbsoluteUnit unit,
415             UnicodeString& appendTo,
416             UErrorCode& status) const;
417 
418     /**
419      * Format a combination of URelativeDateTimeUnit and numeric offset
420      * using a numeric style, e.g. "1 week ago", "in 1 week",
421      * "5 weeks ago", "in 5 weeks".
422      *
423      * @param offset    The signed offset for the specified unit. This
424      *                  will be formatted according to this object's
425      *                  NumberFormat object.
426      * @param unit      The unit to use when formatting the relative
427      *                  date, e.g. UDAT_REL_UNIT_WEEK,
428      *                  UDAT_REL_UNIT_FRIDAY.
429      * @param appendTo  The string to which the formatted result will be
430      *                  appended.
431      * @param status    ICU error code returned here.
432      * @return          appendTo
433      * @stable ICU 57
434      */
435     UnicodeString& formatNumeric(
436             double offset,
437             URelativeDateTimeUnit unit,
438             UnicodeString& appendTo,
439             UErrorCode& status) const;
440 
441     /**
442      * Format a combination of URelativeDateTimeUnit and numeric offset
443      * using a text style if possible, e.g. "last week", "this week",
444      * "next week", "yesterday", "tomorrow". Falls back to numeric
445      * style if no appropriate text term is available for the specified
446      * offset in the object's locale.
447      *
448      * @param offset    The signed offset for the specified unit.
449      * @param unit      The unit to use when formatting the relative
450      *                  date, e.g. UDAT_REL_UNIT_WEEK,
451      *                  UDAT_REL_UNIT_FRIDAY.
452      * @param appendTo  The string to which the formatted result will be
453      *                  appended.
454      * @param status    ICU error code returned here.
455      * @return          appendTo
456      * @stable ICU 57
457      */
458     UnicodeString& format(
459             double offset,
460             URelativeDateTimeUnit unit,
461             UnicodeString& appendTo,
462             UErrorCode& status) const;
463 
464     /**
465      * Combines a relative date string and a time string in this object's
466      * locale. This is done with the same date-time separator used for the
467      * default calendar in this locale.
468      *
469      * @param relativeDateString the relative date, e.g 'yesterday'
470      * @param timeString the time e.g '3:45'
471      * @param appendTo concatenated date and time appended here
472      * @param status ICU error code returned here.
473      * @return appendTo
474      * @stable ICU 53
475      */
476     UnicodeString& combineDateAndTime(
477             const UnicodeString& relativeDateString,
478             const UnicodeString& timeString,
479             UnicodeString& appendTo,
480             UErrorCode& status) const;
481 
482     /**
483      * Returns the NumberFormat this object is using.
484      *
485      * @stable ICU 53
486      */
487     const NumberFormat& getNumberFormat() const;
488 
489     /**
490      * Returns the capitalization context.
491      *
492      * @stable ICU 54
493      */
494     UDisplayContext getCapitalizationContext() const;
495 
496     /**
497      * Returns the format style.
498      *
499      * @stable ICU 54
500      */
501     UDateRelativeDateTimeFormatterStyle getFormatStyle() const;
502 
503 private:
504     const RelativeDateTimeCacheData* fCache;
505     const SharedNumberFormat *fNumberFormat;
506     const SharedPluralRules *fPluralRules;
507     UDateRelativeDateTimeFormatterStyle fStyle;
508     UDisplayContext fContext;
509     const SharedBreakIterator *fOptBreakIterator;
510     Locale fLocale;
511     void init(
512             NumberFormat *nfToAdopt,
513             BreakIterator *brkIter,
514             UErrorCode &status);
515     void adjustForContext(UnicodeString &) const;
516 };
517 
518 U_NAMESPACE_END
519 
520 #endif /* !UCONFIG_NO_BREAK_ITERATION */
521 #endif /* !UCONFIG_NO_FORMATTING */
522 #endif /* __RELDATEFMT_H */
523