#define ARRAYSIZE(_arr) (sizeof(_arr) / sizeof(_arr[0])) #define GMT_TOKYO (9*60*60) #define SECONDS_IN_A_DAY (24*60*60) #define EPOCH_DAY (1969*365L + 1969/4 - 1969/100 + 1969/400 + 306) // days from 0000/03/01 to 1970/01/01 #define UNIX_EPOCH_DAY EPOCH_DAY #define YEAR_ONE 365 #define YEAR_FOUR (YEAR_ONE * 4 + 1) // it is YEAR_ONE*4+1 so the maximum reminder of day / YEAR_FOUR is YEAR_ONE * 4 and it occurs only on 2/29 #define YEAR_100 (YEAR_FOUR * 25 - 1) #define YEAR_400 (YEAR_100*4 + 1) // it is YEAR_100*4+1 so the maximum reminder of day / YEAR_400 is YEAR_100 * 4 and it occurs only on 2/29 void ConvertUnixTimeToTokyoTime(uint64_t unixtime, uint32_t *pyear, uint8_t *pmonth, uint8_t *pday, uint8_t *phour, uint8_t *pminute, uint8_t *psecond) { uint32_t unixday; uint16_t year = 0; uint8_t leap = 0; uint32_t n; uint8_t month, day, weekday; uint8_t hour, minute, second; static const uint16_t monthday[] = { 0,31,61,92,122,153,184,214,245,275,306,337 }; unixtime += GMT_TOKYO; second = unixtime % 60; minute = (unixtime / 60) % 60; hour = (unixtime / 3600) % 24; unixday = (uint32_t)(unixtime / SECONDS_IN_A_DAY); weekday = (uint8_t)((unixday + 3) % 7); // because the unix epoch day is thursday unixday += UNIX_EPOCH_DAY; // days from 0000/03/01 to 1970/01/01 year += 400 * (unixday / YEAR_400); unixday %= YEAR_400; n = unixday / YEAR_100; year += n * 100; unixday %= YEAR_100; if (n == 4){ leap = 1; } else { year += 4 * (unixday / YEAR_FOUR); unixday %= YEAR_FOUR; n = unixday / YEAR_ONE; year += n; unixday %= YEAR_ONE; if (n == 4) { leap = 1; } } if (leap != 0) { month = 2; day = 29; } else { month = (unixday * 5 + 2) / 153; day = unixday - monthday[month] + 1; // month += 3; if (month > 12) { ++year; month -= 12; } } *psecond = second; *pminute = minute; *phour = hour; *pyear = year; *pmonth = month; *pday = day; }
理解せぬコピペはバグが出るとお手上げです。以下解説を試みます。
unixtime += GMT_TOKYO;
second = unixtime % 60; minute = (unixtime/60) % 60; hour = (unixtime/3600) % 24;
unixday = (uint32_t)(unixtime / SECONDS_IN_A_DAY);
weekday = (uint8_t)((unixday + 3) % 7);
unixday += UNIX_EPOCH_DAY;
365日×4+1 | ||||
365日 | 365日 | 365日 | 365日 |
100年×4+1 | ||||
100年 | 100年 | 100年 | 100年 |
400年がいくつある、100年がいくつある、4年がいくつある、1年がいくつある。
これを合算すればよいのです。
そして、100年と1年の計算で4が出てきたら割り切れるので、そこで計算を打ち切って大丈夫です。
year += 400 * (unixday / YEAR_400); unixday %= YEAR_400; n = unixday / YEAR_100; year += n * 100; unixday %= YEAR_100; if (n == 4){ leap = 1; } else { year += 4 * (unixday / YEAR_FOUR); unixday %= YEAR_FOUR; n = unixday / YEAR_ONE; year += n; unixday %= YEAR_ONE; if (n == 4) { leap = 1; } }
month = (unixday / 153) * 5; unixday %= 153; month += (unixday / 61) * 2; month += ((unixday % 61) / 31);
month = (unixday * 5 + 2) / 153;
月 | 日数 | 累積 |
---|---|---|
3 | 31 | 31 |
4 | 30 | 61 |
5 | 31 | 92 |
6 | 30 | 122 |
7 | 31 | 153 |
8 | 31 | 184 |
9 | 30 | 214 |
10 | 31 | 245 |
11 | 30 | 275 |
12 | 31 | 306 |
1 | 31 | 337 |
2 | 28 | 365 |
月 | 月初 | (月初日*5)/153 | 月末日 | (月末日*5)/153 |
---|---|---|---|---|
3 | 0 | 0.0 | 30 | 0.980392157 |
4 | 31 | 1.013071895 | 60 | 1.960784314 |
5 | 61 | 1.993464052 | 91 | 2.973856209 |
6 | 92 | 3.006535948 | 121 | 3.954248366 |
7 | 122 | 3.986928105 | 152 | 4.967320261 |
month = ((unixday + ?) * 5) / 153;
月 | 月末日 | 30.6日の月末 | マージン |
---|---|---|---|
3 | 30 | 30.6 | 0.6 |
4 | 60 | 61.2 | 1.2 |
5 | 91 | 91.8 | 0.8 |
6 | 121 | 122.4 | 1.4 |
7 | 152 | 153.0 | 1.0 |
月 | 月初日 | 30.6日の月初 | 不足日数 |
---|---|---|---|
3 | 0 | 0 | 0.0 |
4 | 31 | 30.6 | 0 |
5 | 61 | 61.2 | 0.2 |
6 | 92 | 91.8 | 0 |
7 | 122 | 122.4 | 0.4 |
month = ((unixday + 0.4) * 5) / 153;
month = ((unixday * 5) + 2) / 153;
月 | 月初 | (月初日*5+2)/153 | 月末日 | (月末日*5+2)/153 |
---|---|---|---|---|
3 | 0 | 0 | 30 | 0 |
4 | 31 | 1 | 60 | 1 |
5 | 61 | 2 | 91 | 2 |
6 | 92 | 3 | 121 | 3 |
7 | 122 | 4 | 152 | 4 |
8 | 153 | 5 | 183 | 5 |
9 | 184 | 6 | 213 | 6 |
10 | 214 | 7 | 244 | 7 |
11 | 245 | 8 | 274 | 8 |
12 | 275 | 9 | 305 | 9 |
1 | 306 | 10 | 336 | 10 |
2 | 337 | 11 | 355 | 11 |
static const uint16_t monthday[] = { 0,31,61,92,122,153,184,214,245,275,306,337 };
if (leap != 0) { month = 2; day = 29; } else { month = (unixday * 5 + 2) / 153; day = unixday - monthday[month] + 1; // 日は0日からじゃないので+1 month += 3; if (month > 12) { ++year; month -= 12; } }