File indexing completed on 2024-04-21 16:06:16

0001 /*
0002   kmime_dateformatter.cpp
0003 
0004   KMime, the KDE Internet mail/usenet news message library.
0005   SPDX-FileCopyrightText: 2001 the KMime authors.
0006   See file AUTHORS for details
0007 
0008   SPDX-License-Identifier: LGPL-2.0-or-later
0009 */
0010 /**
0011   @file
0012   This file is part of the API for handling @ref MIME data and
0013   defines the DateFormatter class.
0014 
0015   @brief
0016   Defines the DateFormatter class.
0017 
0018   @authors the KMime authors (see AUTHORS file)
0019 */
0020 
0021 #include "kmime_dateformatter.h"
0022 
0023 #include <KLocalizedString>
0024 
0025 using namespace KMime;
0026 
0027 namespace KMime {
0028 
0029 class DateFormatterPrivate {
0030 public:
0031     DateFormatterPrivate()
0032     {}
0033 
0034     /**
0035       Returns a QString containing the specified time @p t formatted
0036       using the #Fancy #FormatType.
0037 
0038       @param t is the time to use for formatting.
0039     */
0040     QString fancy(const QDateTime &t);
0041 
0042     /**
0043       Returns a QString containing the specified time @p t formatted
0044       using the #Localized #FormatType.
0045 
0046       @param t is the time to use for formatting.
0047       @param shortFormat if true, create the short version of the date string.
0048       @param lang is a QString containing the language to use.
0049     */
0050     static QString localized(const QDateTime &t, bool shortFormat = true, const QString &lang = QString());
0051 
0052     /**
0053       Returns a QString containing the specified time @p t formatted
0054       with the ctime() function.
0055 
0056       @param t is the time to use for formatting.
0057     */
0058     static QString cTime(const QDateTime &t);
0059 
0060     /**
0061       Returns a QString containing the specified time @p t formatted
0062       with a previously specified custom format.
0063 
0064       @param t time used for formatting
0065     */
0066     QString custom(const QDateTime &t) const;
0067 
0068     /**
0069       Returns a QString that identifies the timezone (eg."-0500")
0070       of the specified time @p t.
0071 
0072       @param t time to compute timezone from.
0073     */
0074     static QByteArray zone(const QDateTime &t);
0075 
0076     DateFormatter::FormatType mFormat;
0077     QDateTime mTodayOneSecondBeforeMidnight;
0078     QString mCustomFormat;
0079 };
0080 
0081 }
0082 
0083 DateFormatter::DateFormatter(FormatType ftype) :
0084     d(new DateFormatterPrivate)
0085 {
0086     d->mFormat = ftype;
0087 }
0088 
0089 DateFormatter::~DateFormatter() = default;
0090 
0091 DateFormatter::FormatType DateFormatter::format() const
0092 {
0093     return d->mFormat;
0094 }
0095 
0096 void DateFormatter::setFormat(FormatType ftype)
0097 {
0098     d->mFormat = ftype;
0099 }
0100 
0101 QString DateFormatter::dateString(const QDateTime &dt, const QString &lang, bool shortFormat) const
0102 {
0103     switch (d->mFormat) {
0104     case Fancy:
0105         return d->fancy(dt);
0106     case Localized:
0107         return d->localized(dt, shortFormat, lang);
0108     case CTime:
0109         return d->cTime(dt);
0110     case Custom:
0111         return d->custom(dt);
0112     }
0113     return {};
0114 }
0115 
0116 QString DateFormatterPrivate::custom(const QDateTime &t) const
0117 {
0118     if (mCustomFormat.isEmpty()) {
0119       return {};
0120     }
0121 
0122     int z = mCustomFormat.indexOf(QLatin1Char('Z'));
0123     QDateTime dt;
0124     QString ret = mCustomFormat;
0125 
0126     if (z != -1) {
0127       ret.replace(z, 1, QLatin1StringView(zone(t)));
0128     }
0129 
0130     ret = t.toString(ret);
0131 
0132     return ret;
0133 }
0134 
0135 void DateFormatter::setCustomFormat(const QString &format)
0136 {
0137     d->mCustomFormat = format;
0138     d->mFormat = Custom;
0139 }
0140 
0141 QString DateFormatter::customFormat() const
0142 {
0143     return d->mCustomFormat;
0144 }
0145 
0146 QByteArray DateFormatterPrivate::zone(const QDateTime &t)
0147 {
0148     const auto secs = t.offsetFromUtc();
0149     const auto hours = std::abs(secs / 3600);
0150     const auto mins  = std::abs((secs - hours * 3600) / 60);
0151 
0152     QByteArray ret(6, 0);
0153     qsnprintf(ret.data(), ret.size(), "%c%.2d%.2d", (secs < 0) ? '-' : '+', hours, mins);
0154     ret.chop(1);
0155     return ret;
0156 }
0157 
0158 QString DateFormatterPrivate::fancy(const QDateTime &t)
0159 {
0160     if (!t.isValid()) {
0161         return i18nc("invalid time specified", "unknown");
0162     }
0163 
0164     if (!mTodayOneSecondBeforeMidnight.isValid()) {
0165         // determine time of today 23:59:59
0166         mTodayOneSecondBeforeMidnight = QDateTime(QDate::currentDate(), QTime(23, 59, 59));
0167     }
0168 
0169     QDateTime old(t);
0170 
0171     if (mTodayOneSecondBeforeMidnight >= t) {
0172         const auto diff = t.secsTo(mTodayOneSecondBeforeMidnight);
0173         if (diff < 7 * 24 * 60 * 60) {
0174             if (diff < 24 * 60 * 60) {
0175                 return i18n("Today %1",
0176                             QLocale().toString(old.time(), QLocale::ShortFormat));
0177             }
0178             if (diff < 2 * 24 * 60 * 60) {
0179                 return i18n("Yesterday %1",
0180                             QLocale().toString(old.time(), QLocale::ShortFormat));
0181             }
0182             for (int i = 3; i < 8; i++) {
0183                 if (diff < i * 24 * 60 * 60) {
0184                     return i18nc("1. weekday, 2. time", "%1 %2" ,
0185                                  QLocale().dayName(old.date().dayOfWeek(), QLocale::LongFormat),
0186                                  QLocale().toString(old.time(), QLocale::ShortFormat));
0187                 }
0188             }
0189         }
0190     }
0191 
0192     return QLocale().toString(old, QLocale::ShortFormat);
0193 }
0194 
0195 QString DateFormatterPrivate::localized(const QDateTime &t, bool shortFormat, const QString &lang)
0196 {
0197     QString ret;
0198 
0199     if (!lang.isEmpty()) {
0200         ret = QLocale(lang).toString(t, (shortFormat ? QLocale::ShortFormat : QLocale::LongFormat));
0201     } else {
0202         ret = QLocale().toString(t, (shortFormat ? QLocale::ShortFormat : QLocale::LongFormat));
0203     }
0204 
0205     return ret;
0206 }
0207 
0208 QString DateFormatterPrivate::cTime(const QDateTime &t)
0209 {
0210     return t.toString(QStringLiteral("ddd MMM dd hh:mm:ss yyyy"));
0211 }
0212 
0213 QString DateFormatter::formatDate(FormatType ftype, const QDateTime &t,
0214                                   const QString &data, bool shortFormat)
0215 {
0216     DateFormatter f(ftype);
0217     if (ftype == Custom) {
0218         f.setCustomFormat(data);
0219     }
0220     return f.dateString(t, data, shortFormat);
0221 }
0222 
0223 QString DateFormatter::formatCurrentDate(FormatType ftype, const QString &data, bool shortFormat)
0224 {
0225     DateFormatter f(ftype);
0226     if (ftype == Custom) {
0227         f.setCustomFormat(data);
0228     }
0229     return f.dateString(QDateTime::currentDateTime(), data, shortFormat);
0230 }