Skip to content

bcddatetime

askn37 edited this page Oct 18, 2023 · 5 revisions

bcddatetime BCD時間表現とMJD通日可換支援

このライブラリは BCD関連の構造体と関連関数、MJD変換関数を提供する。 7セグメントLEDや、外部RTC(カレンダー)の年月日レジスタ制御、アラーム設定に使用できる。 型変換では地域時差を加減しない。 整数乗除算を使用する。

可換単位

修正ユリウス通日(MJD)

修正ユリウス通日(MJD)の元期は グレゴリオ暦 1858-11-17 正子 に置く。 これは天文学や宇宙航法などで使われる、長い日数を加減算するのに便利な単位である。

MJD-BCD-UNIX Epoch の関係性は以下の通り。

MJD       0 == BCD 1858-11-17                                  MJD 元期
MJD   15020 == BCD 1900-01-01                                  20世紀元旦
MJD   40587 == BCD 1970-01-01 == Epoch 0x0                     UNIX Epoch 元期
MJD   51544 == BCD 2000-01-01 == Epoch 0x386D4380 (+10957 day) 21世紀元旦
MJD   65442 == BCD 2038-01-19 == Epoch 0x7FFFD280 (+24855 day) Epoch 31bit幅上限到達日
MJD   65535 == BCD 2038-04-22 == Epoch 0x8079EF70 (+24948 day) MJD 16bit幅表現上限到達日
MJD   90297 == BCD 2106-02-07 == Epoch 0xFFFFA500 (+49710 day) Epoch 32bit幅上限到達日
MJD  106122 == BCD 2149-06-06                     (+65535 day) Epoch 相対日数16bit幅上限
MJD  161116 == BCD 2299-12-31                                  23世紀大晦日
MJD 2973483 == BCD 9999-12-31                                  西暦4桁BCD上限
                                                               (MJD=0x2D5F2B なので22bit範囲)

UNIX Epoch の元期は 1970-01-01 00:00:00 に置くが、自由に再解釈して構わない。(地域時として)

MJD にも Y2038問題がありうることに注意

曜日表現

幾つかの関数を除き、曜日桁は解釈も算出もしない。 算出した場合の表現は0:日(Sun)6:土(Sat)とする。

グレゴリウス歴の定義から、いわゆる万年カレンダーは400年周期で ちょうど年月日〜曜日対応の関係性が循環する。

400年 × 365日 + 閏日97日 == 146097日 == 20871週 × 7日(端数なし)

この性質から年を下位2桁しか保持できないカレンダーICでも曜日が保持できるなら、 400年範囲内の特定の西暦上位2桁を推測して(センチュリービット機能がなくても)求めることが出来る。

例えば 20世紀元旦 1900-01-01 から 23世紀大晦日 2299-12-31 まで等 (Still alive the YAMATO)

これについては [XRTC_PCF85063A リファレンス] が詳しい。

12時間表現

カレンダーICを12時間表現設定とした場合、 20時台に位置するビット(0x20)が0=午前1=午後を表すようになり 0時は12時と表される。 従って24時間表現との相互対応は次のようになる。

24h 0x00 0x01-0x11 0x12 0x13-0x23
12h 0x12 0x01-0x11 0x32 0x21-0x31
23:00:00 <-> 31:00:00 (11:00:00 p.m.) (30:59:59の次)
00:00:00 <-> 12:00:00 (12:00:00 a.m.) (31:59:59の次)
01:00:00 <-> 01:00:00 (01:00:00 a.m.) (12:59:59の次)
--
11:00:00 <-> 11:00:00 (11:00:00 a.m.) (10:59:59の次)
12:00:00 <-> 32:00:00 (12:00:00 p.m.) (11:59:59の次)
13:00:00 <-> 21:00:00 (01:00:00 p.m.) (32:59:59の次)

<bcddatetime.h>

依存性: <inttypes.h> <stddef.h>

定義される関数はすべて標準C関数(グローバル名前空間)である。

型定義と変換補助

typedef uint32_t time_t

Epoch型の型宣言。単位は秒。主に UNIX Epoch を格納する。

time_t X = 951782400; // 2000-02-29 00:00:00

他の先行するヘッダで定義されているならそれが優先される。 (signed long等価の場合がありうる)

typedef uint32_t date_t

MJD日付型の型宣言。単位は日。 主に修正ユリウス通日(MJD)を格納する。

date_t X = 51603; // 2000-02-29

typedef uint32_t bcdtime_t

8桁のパックドBCDによる時刻型の型宣言。(予約2桁:時2桁:分2桁:秒2桁)
最上位2桁は予約領域で普通無視されるが、 日数(非BCD 0-255)や曜日(0-7)を保持することが出来る。

bcdtime_t X = 0x03012345;

typedef uint32_t bcddate_t

8桁のパックドBCDによる日付型の型宣言。(年4桁-月2桁-日2桁)
年2桁しか保持できないカレンダーICでは、最上位2桁に0x20を補うのが普通。

bcddate_t X = 0x20221220;

カレンダーICにセンチュリービット機能がある場合は0x190x21を補う。

struct bcddatetime_t

BCD時刻型 と BCD日付型 の構造体宣言。(リトルエンディアン)

bcddatetime_t X = {0x03012345, 0x20221220};
bcddate_t _date = X.date;
bcdtime_t _time = X.time;

struct datetime_t

size_t時刻型 と date_t日付型 の構造体宣言。(リトルエンディアン)

datetime_t X = {0x012345, 51890};
time_t _time = X.time; // 0x012345
date_t _date = X.date; // 51890

#define _WB(p) ((wbyte_t*)(&p))

右辺左辺両方で使える型変換支援。ワード型の各桁を読み書きする。(リトルエンディアン)

uint16_t X;
_WB(X)->word = 0x1234;
uint8_t  A = _WB(X)->bytes[0]; // 0x34
uint8_t  B = _WB(X)->bytes[1]; // 0x12

#define _BCDDT(p) ((bcddt_t*)&(p))

右辺左辺両方で使える型変換支援。bcddatetime_t型の各桁を読み書きする。

bcddatetime_t X; // = {0x03012345, 0x20221220};
_BCDDT(X)->bcd.time = 0x03012345;        //        == _BCDDT(X)->dwords[0]
_BCDDT(X)->bcd.date = 0x20221220;        //        == _BCDDT(X)->dwords[1]
uint8_t  second = _BCDDT(X)->col.second; // 0x45   == _BCDDT(X)->bytes[0]
uint8_t  minute = _BCDDT(X)->col.minute; // 0x23   == _BCDDT(X)->bytes[1]
uint8_t  hour   = _BCDDT(X)->col.hour;   // 0x01   == _BCDDT(X)->bytes[2]
uint8_t  wday   = _BCDDT(X)->col.wday;   // 0x03   == _BCDDT(X)->bytes[3]
uint8_t  day    = _BCDDT(X)->col.day;    // 0x20   == _BCDDT(X)->bytes[4]
uint8_t  month  = _BCDDT(X)->col.month;  // 0x12   == _BCDDT(X)->bytes[5]
uint16_t year   = _BCDDT(X)->col.year;   // 0x2022 == _BCDDT(X)->words[3]

#define _BCDT(p) ((bcdt_t*)&(p))

右辺左辺両方で使える型変換支援。bcdtime_t型の各桁を読み書きする。

bcdtime_t X; // = 0x03012345;
_BCDT(X)->time  = 0x03012345;           //        == _BCDT(X)->dword
uint8_t  second = _BCDT(X)->col.second; // 0x45   == _BCDT(X)->bytes[0]
uint8_t  minute = _BCDT(X)->col.minute; // 0x23   == _BCDT(X)->bytes[1]
uint8_t  hour   = _BCDT(X)->col.hour;   // 0x01   == _BCDT(X)->bytes[2]
uint8_t  wday   = _BCDT(X)->col.wday;   // 0x03   == _BCDT(X)->bytes[3]

#define _BCDD(p) ((bcdd_t*)&(p))

右辺左辺両方で使える型変換支援。bcddate_t型の各桁を読み書きする。

bcddate_t X; // = 0x20221220;
_BCDD(X)->date  = 0x20221220;           //        == _BCDD(X)->dword
uint8_t  day    = _BCDD(X)->col.day;    // 0x20   == _BCDD(X)->bytes[0]
uint8_t  month  = _BCDD(X)->col.month;  // 0x12   == _BCDD(X)->bytes[1]
uint16_t year   = _BCDD(X)->col.year;   // 0x2022 == _BCDD(X)->words[1]

uint8_t dtob (const uint8_t)

整数を2桁のパックドBCDにして返す。 btodの逆変換。

//      0x23 <- 23
uint8_t Y = dtob(X);

uint8_t btod (const uint8_t)

2桁のパックドBCDを整数にして返す。 dtobの逆変換。

//      23 <- 0x23
uint8_t Y = btob(X);

uint16_t wdtob (const uint16_t dint)

整数を4桁のパックドBCDにして返す。 wbtodの逆変換。

//    0x1234 <- 1234
uint16_t Y = wdtob(X);

uint16_t wbtod (const uint16_t bcd)

4桁のパックドBCDを整数にして返す。 wdtobの逆変換。

//    1234 <- 0x1234
uint16_t Y = wbtod(X);

BCD日時構造体から

time_t bcdToEpoch (const bcddate_t bcd_date, const bcdtime_t bcd_time)

BCD日付型 と BCD時刻型 から Epoch を求める。 逆変換には epochToBcdDateTime あるいは epochToBcdDateepochToBcdTime を用いる。

// 951782400 <- 2000-02-29 00:00:00
bcddate_t BCDDATE = 0x20000229;
bcdtime_t BCDTIME = 0x00000000;
time_t EPOCH = bcdToEpoch(DATE, TIME);

time_t bcdDateTimeToEpoch (const bcddatetime_t bcddatetime)

BCD日時構造体から Epoch を求める。 epochToBcdDateTimeの逆変換。

// 951782400 <- 2000-02-29 00:00:00
bcddatetime_t BCDDATETIME = {0x000000, 0x20000229};
time_t EPOCH = bcdDateTimeToEpoch(BCDDATETIME);

bcddatetime_t bcdDateTime24to12 (const bcddatetime_t bcd_datetime)

BCD日時構造体を、24時間表現 から 12時間表現 形式に変換する。 bcdDateTime12to24の逆変換。

// 2022-12-31  31:59:59 (11:59:59 p.m.) <- 2022-12-31 23:59:59
bcddatetime_t BCDDATETIME = {0x235959, 0x20221231};
bcddatetime_t AMPMDATETIME = bcdDateTime24to12(BCDDATETIME);

bcddatetime_t bcdDateTime12to24 (const bcddatetime_t bcd_datetime)

12時間表現の BCD日時構造体を、24時間表現 に変換する。 bcdDateTime24to12の逆変換。

// 2022-12-31 23:59:59 <- 2022-12-31 31:59:59 (11:59:59 p.m.)
bcddatetime_t AMPMDATETIME = {0x315959, 0x20221231};
bcddatetime_t BCDDATETIME = bcdDateTime12to24(AMPMDATETIME);

datetime_t bcdDateTimeToDateTime (const bcddatetime_t bcd_datetime)

bcddatetime_t型からdatetime_t型を求める。 dateTimeToBcdDateTimeの逆変換。

datetime_t t_dt = bcdDateTimeToDateTime(t_bcd);

BCD日付型から

date_t bcdDateToMjd (const bcddate_t bcd_date)

BCD日付型 から 修正ユリウス通日(MJD)を求める。 mjdToBcdDateの逆変換。

// MJD:51603 <- 2000-02-29
bcddate_t BCDDATE = 0x20000229;
date_t MJD = bcdDateToMjd(BCDDATE);

uint8_t bcdDateToWeekday (const bcddate_t bcd_date)

BCD日付型 から 曜日 を求める。表現は0:日(Sun)6:土(Sat)とする。

// WDAY:2 <- 2000-02-29
bcddate_t BCDDATE = 0x20000229;
uint8_t WDAY = bcdDateToWeekday(BCDDATE);

BCD時刻型から

time_t bcdTimeToEpoch (const bcdtime_t bcd_time)

BCD時刻型 から Epoch を求める。 BCD 00:23:59:59 からは 整数 86399 と求まる。 bcd_timeの最上位2桁は無視される。 epochToBcdDayTimeの逆変換。

// EPOCH:86399 <- 23:59:59
bcdtime_t BCDTIME = 0x235959;
time_t EPOCH = bcdTimeToEpoch(BCDTIME);

time_t bcdTimeToSeconds (const bcdtime_t bcd_time)

BCD時刻型 から Epoch を求める。 BCD 00:23:59:59 からは 整数 86399 と求まる。 最上位2桁は BCD ではなく 1バイト幅整数と見なし、 これを丸めないので 256日未満の通算秒数が得られる。 epochToBcdDayTimeの逆変換。

// EPOCH:172799 <- 1:23:59:59
bcdtime_t BCDTIME = 0x01235959;
time_t EPOCH = bcdTimeToSeconds(BCDTIME);

bcdtime_t bcdTime24to12 (const bcdtime_t bcd_time)

BCD時刻型を、24時間表現 から 12時間表現 形式に変換する。 bcdTime12to24の逆変換。

// 31:59:59 (11:59:59 p.m.) <- 23:59:59
bcdtime_t BCDTIME = 0x235959;
bcdtime_t AMPMTIME = bcdTime24to12(BCDTIME);

bcdtime_t bcdTime12to24 (const bcdtime_t bcd_time)

12時間表現の BCD時刻型を、24時間表現に変換する。 bcdTime24to12の逆変換。

// 23:59:59 <- 31:59:59 (11:59:59 p.m.)
bcdtime_t AMPMTIME = 0x315959;
bcdtime_t BCDTIME = bcdTime12to24(AMPMTIME);

MJD通日から

bcddate_t mjdToBcdDate (const date_t mjd)

修正ユリウス通日(MJD)から BCD日付型 を求める。 bcdDateToMjdの逆変換。

// 2000-02-29 <- MJD:51603
date_t MJD = 51603
bcddate_t BCDDATE = mjdToBcdDate(MJD);

uint8_t mjdToWeekday (const date_t mjd)

修正ユリウス通日(MJD)から 曜日 を求める。表現は0:日(Sun)6:土(Sat)とする。

// WDAY:2 <- 2000-02-29 <- MJD:51603
date_t MJD = 51603
uint8_t WDAY = mjdToWeekday(MJD);

time_t mjdToEpoch (const date_t mjd)

修正ユリウス通日(MJD)から Epoch を求める。 時分秒は含まないので結果は 86400 の倍整数になる。 表現範囲は 1970-01-01 から 2106-02-07 未満まで。 epochToMjdの逆変換。

// EPOCH:951782400 <- 2000-02-29 00:00:00 <- MJD:51603
date_t MJD = 51603
time_t EPOCH = mjdToEpoch(MJD);

datetime_t型から

define time_t dateTimeToEpoch (const datetime_t t_dt)

datetime_t型つまりMJDEpochの組からtime_tを求める。 epochToDateTimeの逆変換。 Epoch86400進数と見做してその過不足をMJD項に加減算する。

time_t t_time dateTimeToEpoch((const datetime_t){86400 * -7, 51890});
// t_time = 51883 * 86400;

bcddatetime_t dateTimeToBcdDateTime (const datetime_t t_dt)

datetime_t型からbcddatetime_t型を求める。 bcdDateTimeToDateTimeの逆変換。

bcddatetime_t t_bcd = dateTimeToBcdDateTime(t_dt);

Epoch通算秒から

date_t epochToMjd (const time_t t_epoch)

Epoch から 修正ユリウス通日(MJD)を求める。 mjdToEpochの逆変換。

// MJD:51603 <- 2000-02-29 00:00:00 <- EPOCH:951782400
time_t EPOCH = 951782400;
date_t MJD = epochToMjd(EPOCH);

bcddatetime_t epochToBcdDateTime (const time_t t_epoch)

Epoch から BCD日時構造体 を求める。 bcdDateTimeToEpochの逆変換。

// 2000-02-29 00:00:00 <- EPOCH:951782400
time_t EPOCH = 951782400;
bcddatetime_t BCDDATETIME = epochToBcdDateTime(EPOCH);

bcddate_t epochToBcdDate (const time_t t_epoch)

Epoch から BCD日付型 を求める。 逆変換にはbcdToEpochを用いる。

// 2000-02-29 <- 2000-02-29 00:00:00 <- EPOCH:951782400
time_t EPOCH = 951782400;
bcddate_t BCDDATE = epochToBcdDate(EPOCH);

bcdtime_t epochToBcdTime (const time_t t_epoch)

Epoch から BCD時刻型 を求める。 逆変換にはbcdToEpochを用いる。

// 00:00:00 <- 2000-02-29 00:00:00 <- EPOCH:951782400
time_t EPOCH = 951782400;
bcdtime_t BCDTIME = epochToBcdTime(EPOCH);

bcdtime_t epochToBcdDayTime (const time_t t_epoch)

Epoch から BCD時刻型 を求めるが、通算日も含める。 bcdTimeToSecondsの逆変換。
最上位2桁は BCD ではなく1バイト幅の整数。(0-255)

// 1:23:59:59 <- EPOCH:172799
time_t EPOCH = 172799;
bcdtime_t BCDTIME = epochToBcdDayTime(EPOCH);

datetime_t epochToDateTime (const time_t t_epoch)

time_t型からdatetime_t型つまりMJDEpochの組を求める。 dateTimeToEpochの逆変換。

datetime_t t_dt = epochToDateTime(7 * 86400 + 1234);
// t_dt = {1234, 7};

uint8_t epochToWeekday (const time_t t_epoch)

Epoch から 曜日 を求める。表現は0:日(Sun)6:土(Sat)とする。

// WDAY:2 <- 2000-02-29 00:00:00 <- EPOCH:951782400
time_t EPOCH = 951782400;
uint8_t WDAY = epochToWeekday(EPOCH);

LINKS

multix.jp/てくにかるむ(休眠中)
Multix Zinnia Product SDK [*AVR]
AVR.JP(日本語訳)
AVR-LIBC(日本語訳)

Clone this wiki locally