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
46using namespace KMime;
47
48//@cond PRIVATE
49int DateFormatter::mDaylight = -1;
50//@endcond
51DateFormatter::DateFormatter( FormatType ftype )
52 : mFormat( ftype ), mTodayOneSecondBeforeMidnight( 0 )
53{
54}
55
56DateFormatter::~DateFormatter()
57{
58}
59
60DateFormatter::FormatType DateFormatter::format() const
61{
62 return mFormat;
63}
64
65void DateFormatter::setFormat( FormatType ftype )
66{
67 mFormat = ftype;
68}
69
70QString 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
96QString 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
102QString 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
115QString 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
135void DateFormatter::setCustomFormat( const QString &format )
136{
137 mCustomFormat = format;
138 mFormat = Custom;
139}
140
141QString DateFormatter::customFormat() const
142{
143 return mCustomFormat;
144}
145
146QByteArray 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
207time_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
220QString 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
261QString 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
281QString DateFormatter::cTime( time_t t ) const
282{
283 return QString::fromLatin1( ctime( &t ) ).trimmed();
284}
285
286QString 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
293void DateFormatter::reset()
294{
295 mTodayOneSecondBeforeMidnight = 0;
296}
297
298QString 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
309QString 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
319bool 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