1 | /* |
2 | kmime_dateformatter.cpp |
3 | |
4 | KMime, the KDE Internet mail/usenet news message library. |
5 | Copyright (c) 2001 the KMime authors. |
6 | See file AUTHORS for details |
7 | |
8 | This library is free software; you can redistribute it and/or |
9 | modify it under the terms of the GNU Library General Public |
10 | License as published by the Free Software Foundation; either |
11 | version 2 of the License, or (at your option) any later version. |
12 | |
13 | This library is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | Library General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU Library General Public License |
19 | along with this library; see the file COPYING.LIB. If not, write to |
20 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
21 | Boston, MA 02110-1301, USA. |
22 | */ |
23 | /** |
24 | @file |
25 | This file is part of the API for handling @ref MIME data and |
26 | defines the DateFormatter class. |
27 | |
28 | @brief |
29 | Defines the DateFormatter class. |
30 | |
31 | @authors the KMime authors (see AUTHORS file) |
32 | */ |
33 | |
34 | #include "kmime_dateformatter.h" |
35 | |
36 | #include <config-kmime.h> |
37 | |
38 | #include <stdlib.h> // for abs() |
39 | |
40 | #include <QtCore/QTextStream> |
41 | |
42 | #include <kglobal.h> |
43 | #include <klocalizedstring.h> |
44 | #include <kcalendarsystem.h> |
45 | |
46 | using namespace KMime; |
47 | |
48 | //@cond PRIVATE |
49 | int DateFormatter::mDaylight = -1; |
50 | //@endcond |
51 | DateFormatter::DateFormatter( FormatType ftype ) |
52 | : mFormat( ftype ), mTodayOneSecondBeforeMidnight( 0 ) |
53 | { |
54 | } |
55 | |
56 | DateFormatter::~DateFormatter() |
57 | { |
58 | } |
59 | |
60 | DateFormatter::FormatType DateFormatter::format() const |
61 | { |
62 | return mFormat; |
63 | } |
64 | |
65 | void DateFormatter::setFormat( FormatType ftype ) |
66 | { |
67 | mFormat = ftype; |
68 | } |
69 | |
70 | QString DateFormatter::dateString( time_t t , const QString &lang , |
71 | bool shortFormat, bool includeSecs ) const |
72 | { |
73 | switch ( mFormat ) { |
74 | case Fancy: |
75 | return fancy( t ); |
76 | break; |
77 | case Localized: |
78 | return localized( t, shortFormat, includeSecs, lang ); |
79 | break; |
80 | case CTime: |
81 | return cTime( t ); |
82 | break; |
83 | case Iso: |
84 | return isoDate( t ); |
85 | break; |
86 | case Rfc: |
87 | return rfc2822( t ); |
88 | break; |
89 | case Custom: |
90 | return custom( t ); |
91 | break; |
92 | } |
93 | return QString(); |
94 | } |
95 | |
96 | QString DateFormatter::dateString( const QDateTime &dt, const QString &lang, |
97 | bool shortFormat, bool includeSecs ) const |
98 | { |
99 | return dateString( qdateToTimeT( dt ), lang, shortFormat, includeSecs ); |
100 | } |
101 | |
102 | QString DateFormatter::rfc2822( time_t t ) const |
103 | { |
104 | QDateTime tmp; |
105 | QString ret; |
106 | |
107 | tmp.setTime_t( t ); |
108 | |
109 | ret = tmp.toString( QLatin1String( "ddd, dd MMM yyyy hh:mm:ss " ) ); |
110 | ret += QLatin1String( zone( t ) ); |
111 | |
112 | return ret; |
113 | } |
114 | |
115 | QString DateFormatter::custom( time_t t ) const |
116 | { |
117 | if ( mCustomFormat.isEmpty() ) { |
118 | return QString(); |
119 | } |
120 | |
121 | int z = mCustomFormat.indexOf( QLatin1Char( 'Z' ) ); |
122 | QDateTime d; |
123 | QString ret = mCustomFormat; |
124 | |
125 | d.setTime_t( t ); |
126 | if ( z != -1 ) { |
127 | ret.replace( z, 1, QLatin1String( zone( t ) ) ); |
128 | } |
129 | |
130 | ret = d.toString( ret ); |
131 | |
132 | return ret; |
133 | } |
134 | |
135 | void DateFormatter::setCustomFormat( const QString &format ) |
136 | { |
137 | mCustomFormat = format; |
138 | mFormat = Custom; |
139 | } |
140 | |
141 | QString DateFormatter::customFormat() const |
142 | { |
143 | return mCustomFormat; |
144 | } |
145 | |
146 | QByteArray DateFormatter::zone( time_t t ) const |
147 | { |
148 | #if defined(HAVE_TIMEZONE) || defined(HAVE_TM_GMTOFF) |
149 | struct tm *local = localtime( &t ); |
150 | #endif |
151 | |
152 | #if defined(HAVE_TIMEZONE) |
153 | |
154 | //hmm, could make hours & mins static |
155 | int secs = abs( timezone ); |
156 | int neg = ( timezone > 0 ) ? 1 : 0; |
157 | int hours = secs / 3600; |
158 | int mins = ( secs - hours * 3600 ) / 60; |
159 | |
160 | // adjust to daylight |
161 | if ( local->tm_isdst > 0 ) { |
162 | mDaylight = 1; |
163 | if ( neg ) { |
164 | --hours; |
165 | } else { |
166 | ++hours; |
167 | } |
168 | } else { |
169 | mDaylight = 0; |
170 | } |
171 | |
172 | #elif defined(HAVE_TM_GMTOFF) |
173 | |
174 | int secs = abs( local->tm_gmtoff ); |
175 | int neg = ( local->tm_gmtoff < 0 ) ? 1 : 0; |
176 | int hours = secs / 3600; |
177 | int mins = ( secs - hours * 3600 ) / 60; |
178 | |
179 | if ( local->tm_isdst > 0 ) { |
180 | mDaylight = 1; |
181 | } else { |
182 | mDaylight = 0; |
183 | } |
184 | |
185 | #else |
186 | |
187 | QDateTime d1 = QDateTime::fromString( QString::fromLatin1( asctime( gmtime( &t ) ) ) ); |
188 | QDateTime d2 = QDateTime::fromString( QString::fromLatin1( asctime( localtime( &t ) ) ) ); |
189 | int secs = d1.secsTo( d2 ); |
190 | int neg = ( secs < 0 ) ? 1 : 0; |
191 | secs = abs( secs ); |
192 | int hours = secs / 3600; |
193 | int mins = ( secs - hours * 3600 ) / 60; |
194 | // daylight should be already taken care of here |
195 | |
196 | #endif /* HAVE_TIMEZONE */ |
197 | |
198 | QByteArray ret; |
199 | QTextStream s( &ret, QIODevice::WriteOnly ); |
200 | s << ( neg ? '-' : '+' ) |
201 | << qSetFieldWidth( 2 ) << qSetPadChar( QLatin1Char( '0' ) ) << right << hours << mins; |
202 | //old code: ret.sprintf( "%c%.2d%.2d", (neg) ? '-' : '+', hours, mins ); |
203 | |
204 | return ret; |
205 | } |
206 | |
207 | time_t DateFormatter::qdateToTimeT( const QDateTime &dt ) const |
208 | { |
209 | QDateTime epoch( QDate( 1970, 1, 1 ), QTime( 00, 00, 00 ) ); |
210 | time_t t; |
211 | time( &t ); |
212 | |
213 | QDateTime d1 = QDateTime::fromString( QLatin1String( asctime( gmtime( &t ) ) ) ); |
214 | QDateTime d2 = QDateTime::fromString( QLatin1String( asctime( localtime( &t ) ) ) ); |
215 | time_t drf = epoch.secsTo( dt ) - d1.secsTo( d2 ); |
216 | |
217 | return drf; |
218 | } |
219 | |
220 | QString DateFormatter::fancy( time_t t ) const |
221 | { |
222 | KLocale *locale = KGlobal::locale(); |
223 | |
224 | if ( t <= 0 ) { |
225 | return i18nc( "invalid time specified" , "unknown" ); |
226 | } |
227 | |
228 | if ( mTodayOneSecondBeforeMidnight < time( 0 ) ) { |
229 | // determine time_t value of today 23:59:59 |
230 | const QDateTime today( QDate::currentDate(), QTime( 23, 59, 59 ) ); |
231 | mTodayOneSecondBeforeMidnight = today.toTime_t(); |
232 | } |
233 | |
234 | QDateTime old; |
235 | old.setTime_t( t ); |
236 | |
237 | if ( mTodayOneSecondBeforeMidnight >= t ) { |
238 | const time_t diff = mTodayOneSecondBeforeMidnight - t; |
239 | if ( diff < 7 * 24 * 60 * 60 ) { |
240 | if ( diff < 24 * 60 * 60 ) { |
241 | return i18n( "Today %1" , |
242 | locale->formatTime( old.time(), true ) ); |
243 | } |
244 | if ( diff < 2 * 24 * 60 * 60 ) { |
245 | return i18n( "Yesterday %1" , |
246 | locale->formatTime( old.time(), true ) ); |
247 | } |
248 | for ( int i = 3; i < 8; i++ ) { |
249 | if ( diff < i * 24 * 60 * 60 ) { |
250 | return i18nc( "1. weekday, 2. time" , "%1 %2" , |
251 | locale->calendar()->weekDayName( old.date() ) , |
252 | locale->formatTime( old.time(), true ) ); |
253 | } |
254 | } |
255 | } |
256 | } |
257 | |
258 | return locale->formatDateTime( old ); |
259 | } |
260 | |
261 | QString DateFormatter::localized( time_t t, bool shortFormat, bool includeSecs, |
262 | const QString &lang ) const |
263 | { |
264 | QDateTime tmp; |
265 | QString ret; |
266 | KLocale *locale = KGlobal::locale(); |
267 | |
268 | tmp.setTime_t( t ); |
269 | |
270 | if ( !lang.isEmpty() ) { |
271 | locale = new KLocale( lang, lang, lang ); |
272 | ret = locale->formatDateTime( tmp, ( shortFormat ? KLocale::ShortDate : KLocale::LongDate ), includeSecs ); |
273 | delete locale; |
274 | } else { |
275 | ret = locale->formatDateTime( tmp, ( shortFormat ? KLocale::ShortDate : KLocale::LongDate ), includeSecs ); |
276 | } |
277 | |
278 | return ret; |
279 | } |
280 | |
281 | QString DateFormatter::cTime( time_t t ) const |
282 | { |
283 | return QString::fromLatin1( ctime( &t ) ).trimmed(); |
284 | } |
285 | |
286 | QString DateFormatter::isoDate( time_t t ) const |
287 | { |
288 | char cstr[64]; |
289 | strftime( cstr, 63, "%Y-%m-%d %H:%M:%S" , localtime( &t ) ); |
290 | return QLatin1String( cstr ); |
291 | } |
292 | |
293 | void DateFormatter::reset() |
294 | { |
295 | mTodayOneSecondBeforeMidnight = 0; |
296 | } |
297 | |
298 | QString DateFormatter::formatDate( FormatType ftype, time_t t, |
299 | const QString &data, bool shortFormat, |
300 | bool includeSecs ) |
301 | { |
302 | DateFormatter f( ftype ); |
303 | if ( ftype == Custom ) { |
304 | f.setCustomFormat( data ); |
305 | } |
306 | return f.dateString( t, data, shortFormat, includeSecs ); |
307 | } |
308 | |
309 | QString DateFormatter::formatCurrentDate( FormatType ftype, const QString &data, |
310 | bool shortFormat, bool includeSecs ) |
311 | { |
312 | DateFormatter f( ftype ); |
313 | if ( ftype == Custom ) { |
314 | f.setCustomFormat( data ); |
315 | } |
316 | return f.dateString( time( 0 ), data, shortFormat, includeSecs ); |
317 | } |
318 | |
319 | bool DateFormatter::isDaylight() |
320 | { |
321 | if ( mDaylight == -1 ) { |
322 | time_t ntime = time( 0 ); |
323 | struct tm *local = localtime( &ntime ); |
324 | if ( local->tm_isdst > 0 ) { |
325 | mDaylight = 1; |
326 | return true; |
327 | } else { |
328 | mDaylight = 0; |
329 | return false; |
330 | } |
331 | } else if ( mDaylight != 0 ) { |
332 | return true; |
333 | } else { |
334 | return false; |
335 | } |
336 | } |
337 | |