見出し画像

Notes C API探訪: 世界時計

前回までの記事で、コンバート関数をシミュレーションするダイアログを作りましたが、動作確認のために、途中で世界時計を作成しました。今回は、番外編としてこの世界時計をご紹介します。

UI自体はとてもシンプルです。

スクリーンショット 2021-09-27 16.13.50

基準となる日時(日本のOSなので日本時間)を設定する日時エディタ、世界時計の計算を開始する Show ボタン、結果を表示するテーブルビューの3つです。

ヘッダーファイルは以下の通りです。

#ifndef WORLDCLOCKDIALOG_H
#define WORLDCLOCKDIALOG_H

#include <QDialog>
#include <QStandardItemModel>

namespace Ui {
class WorldClockDialog;
}

class WorldClockDialog : public QDialog
{
 Q_OBJECT

public:
 explicit WorldClockDialog(QWidget *parent = nullptr);
 ~WorldClockDialog();

 void initialize();

public slots:
 void showClock();

private:
 Ui::WorldClockDialog *ui_;
 QStandardItemModel *pModel_;
};

#endif // WORLDCLOCKDIALOG_H

Show ボタンに対応するスロット関数 showClock と、テーブルビューに対応するモデル(QStandardItemModel *pModel_)が定義されています。

ソースコードは以下の通りです。

#include "worldclockdialog.h"
#include "ui_worldclockdialog.h"
#include <QTimeZone>
#include <nxpp/qt/nxpp_qt_timedate.hpp>
#include <nxpp/qt/nxpp_qt_lmbcs.hpp>

WorldClockDialog::WorldClockDialog(QWidget *parent) :
 QDialog(parent),
 ui_(new Ui::WorldClockDialog)
{
 ui_->setupUi(this);

 pModel_ = new QStandardItemModel(this);
 ui_->tableView->setModel(pModel_);

 QDateTime now = QDateTime::currentDateTime();
 ui_->dateTimeEdit->setDateTime(now);

 connect(
       ui_->showButton, &QPushButton::clicked,
       this, &WorldClockDialog::showClock
       );

 initialize();
}

WorldClockDialog::~WorldClockDialog()
{
 delete ui_;
}

/**
* @brief テーブルを初期化
*/
void WorldClockDialog::initialize() {
 pModel_->clear();
 pModel_->setHorizontalHeaderLabels(
       QStringList()
       << tr("TimeZone ID")
       << tr("UTC(Qt)")
       << tr("UTC(Notes)")
       << tr("Daylight time")
       << tr("QDateTime")
       << tr("nxpp::TimeDate")
       );
}

void WorldClockDialog::showClock() {
 // テーブルを初期化
 initialize();

 // QTimeZoneの有効なタイムゾーンIDリスト
 QByteArrayList list = QTimeZone::availableTimeZoneIds();

 // 現在設定されている日時(Qt)
 QDateTime dateTime = ui_->dateTimeEdit->dateTime();

 // Notes日時に変換
 TIMEDATE now = nxpp::qt::toTIMEDATE(dateTime);

 // タイムゾーンIDリストを巡回
 foreach (QByteArray ianaId, list) {

   // タイムゾーンIDからタイムゾーンを取得
   QTimeZone timeZone(ianaId);

   // 設定日時の時、UTCからの夏時間を含むオフセット時間(秒)を取得
   int offsetSec = timeZone.offsetFromUtc(dateTime);

   // 設定日時の時、そのタイムゾーンでは夏時間を使用しているか
   bool isDTS = timeZone.isDaylightTime(dateTime);

   // 設定日時からそのタイムゾーンでのローカル時間を取得
   auto dt2 = dateTime.toTimeZone(timeZone);

   // Notes時間をnxpp::TimeDateでラップ
   nxpp::TimeDate timeDate(now);

   // Notes時間からそのタイムゾーンでのローカル時間を取得
   TIMEDATE td2 = timeDate.toTimeZone(offsetSec, isDTS);

   // オフセット秒と夏時間の有無でTIME::zone値を取得
   int zone = nxpp::Time::offsetSecondsToZone(offsetSec, isDTS);

   // デフォルトINTLFORMATを取得
   auto intlSettings = std::make_shared<nxpp::intl::Settings>();

   // INTLFORMATをカスタマイズ
   intlSettings->setTimeZone(zone);
   intlSettings->setDaylightSavings(isDTS);

   // デフォルトTFMTを取得
   auto format = std::make_shared<nxpp::TimeFormat>();

   // タイムゾーンを常に表示に設定
   format->setZone(TZFMT_ALWAYS);

   // 日時からテキストに変換するコンバーターを生成
   nxpp::TimeDateToTextConverter converter(intlSettings, format);

   // コンバーターで日時をテキストに変換
   nxpp::Lmbcs data = converter(&td2);

   // 1列目/タイムゾーンID
   auto item0 = new QStandardItem(QString::fromLatin1(ianaId));
   item0->setEditable(false);

   // 2列目/UTCからのオフセット時間
   int min = offsetSec / 60;
   int hour = min / 60;
   min = abs(min % 60);
   auto item1 = new QStandardItem(
         QString("%1:%2")
         .arg(hour, 2, 10, QChar('0'))
         .arg(min, 2, 10, QChar('0'))
         );
   item1->setEditable(false);

   // 3列名/UTCオフセット(Notes,TIME::zone)
   auto item2 = new QStandardItem(QString("%1").arg(zone));
   item2->setEditable(false);

   // 4列目/夏時間の有無
   auto item3 = new QStandardItem(QString(isDTS ? "true" : "false"));
   item3->setEditable(false);

   // 5列目/ローカル時間(Qt)
   auto item4 = new QStandardItem(dt2.toString("yyyy/MM/dd HH:mm:ss t"));
   item4->setEditable(false);

   // 6列目/ローカル日時(Notes)
   QString dataq = fromLmbcsQ(data);
   auto item5 = new QStandardItem(dataq);
   item5->setEditable(false);

   QList<QStandardItem*> items;
   items
       << item0
       << item1
       << item2
       << item3
       << item4
       << item5
          ;
   pModel_->appendRow(items);
 }
 ui_->tableView->resizeColumnsToContents();
}

テーブルビューの列は、以下の通りです。

1列目: タイムゾーンID(Qtで利用できるIANAタイムゾーンID)
2列目: UTCオフセット時間(Qt)
3列目: UTCオフセット時間(Notes)
4列目: 夏時間の有無
5列目: QDateTimeでローカル時間に変換した日時
6列目: TIMEDATEをNotes C APIでローカル時間に変換した日時

1列目のタイムゾーンIDは、Qtが提供してくれるタイムゾーンIDリスト(QTimeZone::availableTimeZoneIds())を活用しています。

このダイアログを起動すると、以下のように表示されます。

スクリーンショット 2021-09-27 16.18.31

例えばここで、Show ボタンをクリックすると、

スクリーンショット 2021-09-27 16.19.40

このように500ほどのタイムゾーンIDを元に、Qt、Notes、両方でUTCオフセット時間やローカル時間を計算して表示します。UTCオフセットがプラスマイナス反対なのもおわかりいただけると思います。なお、QtのUTCオフセットは夏時間込みですが、Notes C APIのUTCオフセットは標準時のみです。

例えば、ここで基準の日付を12月に設定を変えると、以下のように表示内容(特にDaylight time)が変わります。

スクリーンショット 2021-09-27 16.22.32

ちなみに、14行目の「Africa/Casablanca」の夏時間が有効なままですが、調べたらモロッコでは2018年から「通年サマータイム」を採用しているそうです。

まとめ

Notes独特のUTCオフセットの定義方法も、これで確認できます。「UTC(Notes)」が4桁で表示されているものを列挙してみます。

スクリーンショット 2021-09-27 16.47.01

スクリーンショット 2021-09-27 16.48.11

スクリーンショット 2021-09-27 16.48.54

スクリーンショット 2021-09-27 16.49.43

スクリーンショット 2021-09-27 16.50.20

スクリーンショット 2021-09-27 16.51.04

スクリーンショット 2021-09-27 16.51.44

スクリーンショット 2021-09-27 16.52.21

スクリーンショット 2021-09-27 16.53.03

スクリーンショット 2021-09-27 16.53.30

スクリーンショット 2021-09-27 16.54.03

スクリーンショット 2021-09-27 16.55.00

スクリーンショット 2021-09-27 16.55.33

スクリーンショット 2021-09-27 16.56.10

1時間以下の時差を千と百の位で表現するなんて、やはりクセの強い考え方です。

この記事が気に入ったらサポートをしてみませんか?