1 /*
2 * Copyright 2017, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Akshay Agarwal <agarwal.akshay.akshay8@gmail.com>
7 */
8
9
10 #include <unicode/uversion.h>
11 #include <RelativeDateTimeFormat.h>
12
13 #include <stdlib.h>
14 #include <time.h>
15
16 #include <unicode/gregocal.h>
17 #include <unicode/reldatefmt.h>
18 #include <unicode/utypes.h>
19
20 #include <ICUWrapper.h>
21
22 #include <Language.h>
23 #include <Locale.h>
24 #include <LocaleRoster.h>
25 #include <TimeUnitFormat.h>
26
27
28 U_NAMESPACE_USE
29
30
31 static const URelativeDateTimeUnit kTimeUnitToRelativeDateTime[] = {
32 UDAT_REL_UNIT_YEAR,
33 UDAT_REL_UNIT_MONTH,
34 UDAT_REL_UNIT_WEEK,
35 UDAT_REL_UNIT_DAY,
36 UDAT_REL_UNIT_HOUR,
37 UDAT_REL_UNIT_MINUTE,
38 UDAT_REL_UNIT_SECOND,
39 };
40
41
42 static const UCalendarDateFields kTimeUnitToICUDateField[] = {
43 UCAL_YEAR,
44 UCAL_MONTH,
45 UCAL_WEEK_OF_MONTH,
46 UCAL_DAY_OF_WEEK,
47 UCAL_HOUR_OF_DAY,
48 UCAL_MINUTE,
49 UCAL_SECOND,
50 };
51
52
BRelativeDateTimeFormat()53 BRelativeDateTimeFormat::BRelativeDateTimeFormat()
54 : Inherited()
55 {
56 Locale icuLocale(fLanguage.Code());
57 UErrorCode icuStatus = U_ZERO_ERROR;
58
59 fFormatter = new RelativeDateTimeFormatter(icuLocale, icuStatus);
60 if (fFormatter == NULL) {
61 fInitStatus = B_NO_MEMORY;
62 return;
63 }
64
65 fCalendar = new GregorianCalendar(icuStatus);
66 if (fCalendar == NULL) {
67 fInitStatus = B_NO_MEMORY;
68 return;
69 }
70
71 if (!U_SUCCESS(icuStatus))
72 fInitStatus = B_ERROR;
73 }
74
75
BRelativeDateTimeFormat(const BLanguage & language,const BFormattingConventions & conventions)76 BRelativeDateTimeFormat::BRelativeDateTimeFormat(const BLanguage& language,
77 const BFormattingConventions& conventions)
78 : Inherited(language, conventions)
79 {
80 Locale icuLocale(fLanguage.Code());
81 UErrorCode icuStatus = U_ZERO_ERROR;
82
83 fFormatter = new RelativeDateTimeFormatter(icuLocale, icuStatus);
84 if (fFormatter == NULL) {
85 fInitStatus = B_NO_MEMORY;
86 return;
87 }
88
89 fCalendar = new GregorianCalendar(icuStatus);
90 if (fCalendar == NULL) {
91 fInitStatus = B_NO_MEMORY;
92 return;
93 }
94
95 if (!U_SUCCESS(icuStatus))
96 fInitStatus = B_ERROR;
97 }
98
99
BRelativeDateTimeFormat(const BRelativeDateTimeFormat & other)100 BRelativeDateTimeFormat::BRelativeDateTimeFormat(const BRelativeDateTimeFormat& other)
101 : Inherited(other),
102 fFormatter(other.fFormatter != NULL
103 ? new RelativeDateTimeFormatter(*other.fFormatter) : NULL),
104 fCalendar(other.fCalendar != NULL
105 ? new GregorianCalendar(*other.fCalendar) : NULL)
106 {
107 if ((fFormatter == NULL && other.fFormatter != NULL)
108 || (fCalendar == NULL && other.fCalendar != NULL))
109 fInitStatus = B_NO_MEMORY;
110 }
111
112
~BRelativeDateTimeFormat()113 BRelativeDateTimeFormat::~BRelativeDateTimeFormat()
114 {
115 delete fFormatter;
116 delete fCalendar;
117 }
118
119
120 status_t
Format(BString & string,const time_t timeValue) const121 BRelativeDateTimeFormat::Format(BString& string,
122 const time_t timeValue) const
123 {
124 if (fFormatter == NULL)
125 return B_NO_INIT;
126
127 time_t currentTime = time(NULL);
128
129 UErrorCode icuStatus = U_ZERO_ERROR;
130 fCalendar->setTime((UDate)currentTime * 1000, icuStatus);
131 if (!U_SUCCESS(icuStatus))
132 return B_ERROR;
133
134 UDate UTimeValue = (UDate)timeValue * 1000;
135
136 int delta = 0;
137 int offset = 1;
138 URelativeDateTimeUnit unit = UDAT_REL_UNIT_SECOND;
139
140 for (int timeUnit = 0; timeUnit <= B_TIME_UNIT_LAST; ++timeUnit) {
141 delta = fCalendar->fieldDifference(UTimeValue,
142 kTimeUnitToICUDateField[timeUnit], icuStatus);
143
144 if (!U_SUCCESS(icuStatus))
145 return B_ERROR;
146
147 if (abs(delta) >= offset) {
148 unit = kTimeUnitToRelativeDateTime[timeUnit];
149 break;
150 }
151 }
152
153 UnicodeString unicodeResult;
154
155 // Note: icu::RelativeDateTimeFormatter::formatNumeric() is a part of ICU Draft API
156 // and may be changed in the future versions and was introduced in ICU 57.
157 fFormatter->formatNumeric(delta, unit, unicodeResult, icuStatus);
158
159 if (!U_SUCCESS(icuStatus))
160 return B_ERROR;
161
162 BStringByteSink byteSink(&string);
163 unicodeResult.toUTF8(byteSink);
164
165 return B_OK;
166 }
167