在QTimeZone内统一Qt::TimeSpec

Qt6.5对QDateTime的API进行了改进,统一了QTimeZone中的时间规范,消除了重复的构造函数和方法。这一改变使得处理QDateTime实例时无需再进行复杂的Qt::TimeSpec转换,简化了客户端代码,并为QDateTimeEdit支持更多时区铺平了道路。
摘要由CSDN通过智能技术生成

Unifying Qt::TimeSpec within QTimeZone

在QTimeZone内统一Qt::TimeSpec

April 25, 2023 by Eddy | Comments

​2023年4月25日Eddy | 评论

Qt 6.5 sees a quiet revolution in QDateTime's API, built on one in QTimeZone's.

Qt6.5见证了QDateTime的API在QTimeZone的API基础上的一场悄无声息的革命。

Previously

先前

QDateTime had an overload pair of constructors that looked like:

QDateTime有一对重载构造函数,看起来像:

QDateTime(QDate date, QTime time, Qt::TimeSpec spec = Qt::LocalTime, int offsetSeconds = 0);
#if QT_CONFIG(timezone)
    QDateTime(QDate date, QTime time, const QTimeZone &timeZone);
#endif // timezone
which, in turn, implied a similar duplication in various methods of QDateTime and QDate that returned a new QDateTime object.

这反过来意味着QDateTime和QDate的各种方法中存在类似的重复,返回了一个新的QDateTime对象。

class Q_CORE_EXPORT QDate
{
    // …
    QDateTime startOfDay(Qt::TimeSpec spec = Qt::LocalTime, int offsetSeconds = 0) const;
    QDateTime endOfDay(Qt::TimeSpec spec = Qt::LocalTime, int offsetSeconds = 0) const;
#if QT_CONFIG(timezone)
    QDateTime startOfDay(const QTimeZone &zone) const;
    QDateTime endOfDay(const QTimeZone &zone) const;
#endif
    // …
};

// …

class Q_CORE_EXPORT QDateTime
{
    // …
    void setTimeSpec(Qt::TimeSpec spec);
    void setOffsetFromUtc(int offsetSeconds);
#if QT_CONFIG(timezone)
    void setTimeZone(const QTimeZone &toZone);
#endif // timezone
    // … similar for s/set/to/ …

    static QDateTime fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec = Qt::LocalTime,
                                         int offsetFromUtc = 0);
    static QDateTime fromSecsSinceEpoch(qint64 secs, Qt::TimeSpec spec = Qt::LocalTime,
                                        int offsetFromUtc = 0);

#if QT_CONFIG(timezone)
    static QDateTime fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone);
    static QDateTime fromSecsSinceEpoch(qint64 secs, const QTimeZone &timeZone);
#endif

    // …
};

Any future new methods or constructors were doomed to repeat this duplication, complete with its #if-ery (on a feature that's only defined on most platforms).  So it wasn't a nice API to try to grow or evolve.  But that's my problem, as a developer working on it; how about client code ?

任何未来的新方法或构造函数都注定要重复这种重复,包括#if-ery(在大多数平台上定义的功能上)。因此,它不是一个很好的API来尝试增长或发展。但这是我的问题,作为一名开发人员;客户端代码如何?

Client code's problem

客户端代码的问题

Code that needed to manipulate QDateTime instances had, in some cases, to switch on the Qt::TimeSpec of one of them.  For example, if your code has a QDateTime active that it wants all the others it manipulates to use the same time spec as, it ended up needing a time-spec converter, for any received QDateTime datetime that looked like

在某些情况下,需要操作QDateTime实例的代码必须打开其中一个实例的Qt::TimeSpec。例如,如果您的代码有一个激活的QDateTime,它希望它操纵的所有其他代码使用相同的时间规范,那么它最终需要一个时间规范转换器,用于任何接收到的QDateTime-datetime

   

    switch (active.timeSpec()) {
    case Qt::UTC:
        return datetime.toUTC();
    case Qt::LocalTime:
        return datetime.toLocalTime();
    case Qt::OffsetFromUTC:
        return datetime.toOffsetFromUtc(active.offsetFromUtc());
    case Qt::TimeZone:
#if QT_CONFIG(timezone)
        return datetime.toTimeZone(active.timeZone());
#else
        qWarning("Enable timezone feature to support Qt::TimeZone");
        return datetime; // Failed to convert.
#endif
    }
    Q_UNREACHABLE();

The extra complexity of such changes is one factor in why QDateTimeEdit still only supports UTC and local time; see QTBUG-80417.

​这些变化的额外复杂性是QDateTimeEdit仍然只支持UTC和当地时间的原因之一;参见QTBUG-80417。

The solution

解决方案

The initial version of this was called QTimeSystem but Thiago persuaded me to roll it into QTimeZone, which did make a whole lot of sense, although the implementation had some trickiness to it.  (Thanks to Ville and Marc for help with working out how to do that.)  So now QTimeZone can be either

它的最初版本被称为QTimeSystem,但Thiago说服我将其引入QTimeZone,这确实很有意义,尽管实现过程中有一些棘手之处(感谢Ville和Marc的帮助。)所以现在QTimeZone可以是

  • an actual backend-backed time-zone object, as before, or

  • 实际的后端支持的时区对象,与以前一样,或者

  • a lightweight time representation.

  • 轻量级的时间表示。

Only the former is pimpled; the latter inhabits the space its d-ptr would occupy, with the least significant bits of that being an enum to tell it what it is; 0 means pimpled, of course.

只有前者是多余的;后者占据了d-ptr将占据的空间,其中最不重要的部分是一个枚举来告诉它它是什么;0当然意味着多余。

A lightweight time representation, then, is just a Qt::TimeSpec packaged, when necessary, with the offset it needs to carry around with it. When the Qt::TimeSpec is Qt::TimeZone, we're in the pimpled side of the union and using the same old back-end as ever, subject to the same old #if-ery on feature timezone.  The rest of the class is now freed of that #if-ery and the header no longer does a QT_REQUIRE_CONFIG(timezone); so it can always be included.

因此,轻量级的时间表示只是一个Qt::TimeSpec封装,必要时带有它需要携带的偏移量。当Qt:::TimeSpec是Qt::TimeZone时,我们处于联合的粉刺侧,使用一如既往的旧后端,在功能时区上受相同的旧#if-ery约束。类的其余部分现在已经摆脱了#if-ery,并且头不再执行QT_REQUIRE_CONFIG(timezone);所以它总是可以被包括在内。

6.5 APIs

The changed QTimeZone API now only conditions the backend-based aspects on feature timezone; all the rest is always present.

​更改后的QTimeZone API现在只在功能时区上限制基于后端的方面;其余的总是当前的。

The changed QDateTime API now prefers to go via QTimeZone, obtained from QDateTime::timeRepresentation() – the name timeZone() being already taken; it could now be implemented as timeRepresentation().asBackendZone().  That client code converter for time-spec becomes a one-liner, converting to the time-zone of the active value:

​更改后的QDateTime API现在更倾向于通过QTimeZone,它是从QDateTime::timeRepresentation()获得的,名称timeZone()已经被使用;它现在可以实现为timeRepresentation().asBackendZone()。时间规范的客户端代码转换器变成了一个单行,转换为活动值的时区:

    return datetime.toTimeZone(active.timeRepresentation());

and passing a QTimeZone to functions returning a QDateTime is now the uniform way to call relevant functions.  Qt::TimeSpec should now almost never need to be seen in public any more.

将QTimeZone传递给返回QDateTime的函数现在是调用相关函数的统一方式。Qt::TimeSpec现在几乎不需要再公开露面了。

The one frustrating detail is that, to avoid mutual inclusion issues, qdatetime.h can't #include <QTimeZone> so the methods there taking a QTimeZone parameter can't pass QTimeZone::LocalTime as default, obliging them to still have an overload without the QTimeZone parameter, for backwards compatibility – but you should never need to use these.

一个令人沮丧的细节是,为了避免相互包含的问题,qdatetime.h不能#include<QTimeZone>,因此采用QTimeZone参数的方法不能将QTimeZone::LocalTime作为默认值传递,这迫使它们在没有QTimeZone参数的情况下仍有重载,以实现向后兼容性,但您永远不应该使用这些方法。

The usual extent of change needed in existing code, to minimally adapt to the coming deprecations, is to replace the Qt prefix with QTimeZone in all uses of Qt::UTC and Qt::LocalTime (which are easy to search for).  Further changes to make the most of the new API can follow at leisure.

为了最低限度地适应即将到来的弃用,现有代码中通常需要进行的更改是在Qt::UTC和Qt:::LocalTime(很容易搜索)的所有使用中用QTimeZone替换Qt前缀。为了充分利用新的API,可以随时进行进一步的更改。

As a result, QTBUG-80417 is now more or less at the point where we just need to change the API of QDateTimeEdit to access the internals which just got simpler while becoming able to support any time-zone, as soon as the public API exposes that.

因此,QTBUG-80417现在或多或少已经到了我们只需要更改QDateTimeEdit的API来访问内部组件的时候了,只要公开的API暴露出来,内部组件就会变得更简单,同时能够支持任何时区。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值