之前使用ESP32写了一个闹钟,免得我老是把手机闹钟给滑了就不知该起床了
原本想用标准库解决的,但是这个时间一直不准,逼得用 SNTP 获取了步进单位为(second)的时间戳,然后使用 GPtimer 来维持时间戳才算是把精准计时给解决了
废话不多说,直接上代码
typedef struct
{
int year;
int month;
int day;
int hour;
int minute;
int second;
} My_tm;
/// @brief 判断是否是闰年
/// @param year 年份
/// @return
static int isLeapYear(int year)
{
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
{
return 1; // 是闰年
}
return 0; // 不是闰年
}
/// @brief 时间戳转换成My_tm结构体
/// @param timestamp 时间戳
/// @param my_tm 结构体指针
/// @param timezone_offset_hours 时区偏移量
void convertTimestamp(time_t timestamp, My_tm *my_tm, const int timezone_offset_hours)
{
// 计算每个时间单位的秒数
const long secondsPerMinute = 60;
const long secondsPerHour = 3600;
const long secondsPerDay = 86400;
// 调整为指定时区
timestamp += timezone_offset_hours * secondsPerHour;
// 初始化结构体
my_tm->year = 1970;
my_tm->month = 1;
my_tm->day = 1;
my_tm->hour = 0;
my_tm->minute = 0;
my_tm->second = 0;
// 计算累积天数
int totalDays = timestamp / secondsPerDay;
// 跳过1970年前的天数
int currentYear = 1970;
while (totalDays >= 365)
{
if (isLeapYear(currentYear))
{
if (totalDays >= 366)
{
totalDays -= 366;
currentYear++;
}
else
{
break;
}
}
else
{
totalDays -= 365;
currentYear++;
}
}
// 设置年份
my_tm->year = currentYear;
// 跳过月份的天数
static const int daysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int monthIndex = 0;
while (totalDays >= daysPerMonth[monthIndex])
{
if (monthIndex == 1 && isLeapYear(currentYear))
{
if (totalDays >= 29)
{
totalDays -= 29;
monthIndex++;
}
else
{
break;
}
}
else
{
totalDays -= daysPerMonth[monthIndex];
monthIndex++;
}
}
// 设置月份和日期
my_tm->month = monthIndex + 1;
my_tm->day = totalDays + 1;
// 计算剩余时间
int remainingSeconds = timestamp % secondsPerDay;
my_tm->hour = remainingSeconds / secondsPerHour;
remainingSeconds %= secondsPerHour;
my_tm->minute = remainingSeconds / secondsPerMinute;
my_tm->second = remainingSeconds % secondsPerMinute;
}
/**
* 将整数转换为字符串,格式为“(整数值)”
*
* @param number 待转换的整数
* @param str 用于存储转换结果的字符数组
* @param size 字符数组 str 的大小
*
* 注意:调用者必须确保 str 的大小足够存储转换后的字符串,包括终止空字符
*/
void intToString(int number, char *str, size_t size)
{
// 使用 sprintf 将整数转换为字符串
// 注意:str 必须有足够的空间来存储转换后的字符串
// %d 是整数的格式化标识符
// 返回值是写入的字符数,不包括终止空字符
snprintf(str, size, "%d", number);
}
/// @brief 获取本地时间戳将其转换成字符串
/// @param timezone_offset_hours 时区偏移量
/// @param TimeStr 时间字符串(字符串要接入的位置)
/// @param TimeStrLen 时间字符串长度(传入的字符串长度要>=26)
/// @return 时间字符串"yyyy-mm-dd hh:mm:ss.ms"
char *User_tmToStrings(const int timezone_offset_hours, char *TimeStr, size_t TimeStrLen)
{
if (TimeStr == NULL || TimeStrLen < 26)
return NULL;
static My_tm User_tm; // My_tm结构体
time_t timestamp;
size_t str_len = TimeStrLen, pos = 0;
GetTimestamp();// 获取本地时间戳
memset((void *)TimeStr, 0, str_len);
convertTimestamp(timestamp, &User_tm, timezone_offset_hours);
TimeStr[pos++] = '\"';
// 填充年份
intToString(User_tm.year, TimeStr + pos, str_len);
pos = strlen(TimeStr);
TimeStr[pos++] = '-'; // 目前写入了6个字符, |"yyyy-|
// 填充月份
switch (User_tm.month)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9: // 月份小于10前面补0
TimeStr[pos++] = '0';
intToString(User_tm.month, TimeStr + pos, str_len - pos);
pos += strlen(TimeStr + pos); // 计算已经写入的字符数
break;
default:
intToString(User_tm.month, TimeStr + pos, str_len - pos);
pos += strlen(TimeStr + pos);
break;
}
TimeStr[pos++] = '-'; // 目前写入了9个字符, |"yyyy-mm-|
// 填充日期
switch (User_tm.day)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9: // 日期小于10前面补0
TimeStr[pos++] = '0';
intToString(User_tm.day, TimeStr + pos, str_len - pos);
pos += strlen(TimeStr + pos);
break;
default:
intToString(User_tm.day, TimeStr + pos, str_len - pos);
pos += strlen(TimeStr + pos);
break;
}
TimeStr[pos++] = ' '; // 目前写入了12个字符, |"yyyy-mm-dd |
// 填充小时
switch (User_tm.hour)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9: // 小时小于10前面补0
TimeStr[pos++] = '0';
intToString(User_tm.hour, TimeStr + pos, str_len - pos);
pos += strlen(TimeStr + pos);
break;
default:
intToString(User_tm.hour, TimeStr + pos, str_len - pos);
pos += strlen(TimeStr + pos);
break;
}
TimeStr[pos++] = ':'; // 目前写入了15个字符, |"yyyy-mm-dd hh:|
// 填充分钟
switch (User_tm.minute)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9: // 分钟小于10前面补0
TimeStr[pos++] = '0';
intToString(User_tm.minute, TimeStr + pos, str_len - pos);
pos += strlen(TimeStr + pos);
break;
default:
intToString(User_tm.minute, TimeStr + pos, str_len - pos);
pos += strlen(TimeStr + pos);
break;
}
TimeStr[pos++] = ':'; // 目前写入了18个字符, |"yyyy-mm-dd- hh:mm:|
// 填充秒数
switch (User_tm.second)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9: // 秒数小于10前面补0
TimeStr[pos++] = '0';
intToString(User_tm.second, TimeStr + pos, str_len - pos);
pos += strlen(TimeStr + pos);
break;
default:
intToString(User_tm.second, TimeStr + pos, str_len - pos);
pos += strlen(TimeStr + pos);
break;
}
TimeStr[pos++] = '.'; // 目前写入了21个字符, |"yyyy-mm-dd- hh:mm:ss.|
// 填充毫秒数
TimeStr[pos++] = '0';
TimeStr[pos++] = '0';
TimeStr[pos++] = '0';
// UserStrcat(TimeStr, "000", strlen("000"), pos);
// strcat(TimeStr + pos, "000"); // 毫秒数, 由于获取的时间时间戳是unit: s, 所以直接加3个0
// pos += 3; // 目前写入了25个字符, "yyyy-mm-dd- hh:mm:ss.000"
switch (timezone_offset_hours)
{
case 0:
TimeStr[pos++] = 'Z';
TimeStr[pos++] = '\"';
TimeStr[pos++] = '\0';
while (TimeStr[pos] != ' ')
{
pos--;
}
TimeStr[pos] = 'T';
return TimeStr;
default:
TimeStr[pos++] = '\"';
break;
}
return TimeStr;
}
标签:case,自定义,++,TimeStr,pos,C语言,unix,tm,User
From: https://www.cnblogs.com/JPW-2024/p/18453576