【问题标题】:Unix Time stamp creation in C from custom data fields从自定义数据字段在 C 中创建 Unix 时间戳
【发布时间】:2020-06-21 06:57:33
【问题描述】:

我希望创建一个 Unix 时间戳。我有一个带有 ble 连接的微控制器,我通过 GATT 连接将当前时间发送到该连接。我收到了几个整数的数据。

这些是年、月、日、时、分和秒。例如:

  • 年 = 2020,月 = 3,日 = 9,小时 = 10,分钟 = 10,秒 = 10。

我想将其转换为 Unix 时间,这样我就可以通过基于中断的计时器每秒递增该值。因此,将这些数据组合在一起形成 Unix 时间的正确方法是什么。我的假设如下:

创建一个足够大的整数值来存储称为 unix 时间的值,并从相应的时间分量(年、月等)中添加等效秒数。

这些是以秒为单位的值

  • Year_in_seconds = 31,556,952
  • Month_in_seconds = 2,630,000
  • Day_in_seconds = 86,400
  • Hour_in_seconds = 3,600
  • Minute_in_seconds = 60

因此,Unix 时间 =

  • (nYears * Year_in_seconds)+(nMonths * Month_in_seconds)+(nDays * Days_in_seconds)+(nHours * Hour_in_seconds)+(nMinutes * Minute_in_seconds)+(nSeconds * 1)

我的假设有什么问题吗?

我不知道 unix 时间如何处理一个月中不同的天数,因为不同的月份有不同的长度。还有闰年。那么我需要另一个查找表或其他东西来使这个准确吗?

或者从我的数据集中获取 unix 时间的正确方法是什么?

【问题讨论】:

  • @PaulR 听起来有点像他的微控制器没有全套可用的 posix 功能,因此副本在这里可能没有多大用处。投票重新开放。
  • 我可以做的一件事是将发送的数据更改为 unix 值。这来自我使用日历库的手机。然后在我的微控制器上每秒增加一次。我想这会奏效。然后反向传输只会将 unix 时间发送回去。然后将使用我手机上的日历库再次处理时间戳。我没有直接要求在我的微型计算机上获得准确的 readbale 时间。只需要确保记录数据的时间是正确的。
  • 这些是当地时间还是什么?因为当地时间不一定每天有 86,400 秒。 /// Re "我不知道 unix 时间如何处理一个月中不同的天数,因为不同的月份有不同的长度。",Unix 时间是自 1970-01 以来的秒数-01T00:00:00Z(Z 表示 UTC)。每月或每年的秒数不是恒定的,因此该过程要复杂得多。
  • 你没有提到夏令时。这是您可能应该关心的其他事情。
  • Julian day article on Wikipedia 具有将日、月、年转换为天数的公式。您可以以此为基础将年、月、日、小时、分钟、秒(时区、夏令时?)转换为 unix 时间戳。

标签: c time unix-timestamp data-conversion


【解决方案1】:

这应该精确到 2100:

unsigned int tounix (int year, int month, int day, int hour, int min, int sec) {
    unsigned int epoch = 0;
    // These are the number of days in the year up to the corresponding month
    static const unsigned int monthdays[] = { 0, 31, 59, 90, 120, 151, 181, 211, 242, 272, 303, 333 };
    epoch = (year-1970)*86400*365u +    // Account the years
            ((year-1968)/4)*86400 +    // leap years
            monthdays[month-1]*86400 + // days in past full month
            (day-1)*86400u + hour*3600 + min*60 + sec; // days, hours, mins, secs

    if (!(year%4)&&month < 3) // Correct 1 day if in leap year before Feb-29
        epoch -= 86400;

    return epoch;
}

输入应为:

  • 年份:1970 - 2099
  • 月:1 - 12
  • 天:1 - 31
  • 时、分、秒:照常;)

【讨论】:

  • 如果您输入今天的日期,您是否对此进行了测试以确认日期是否正确?
  • @ThomasMorris 我总是测试我的代码,除非我明确写 untested
  • 嗯,y=2028 之后,(year-1970)*86400*365 开始溢出 32 位 int 数学导致 UB。最好使用unsignedconstants/math。
  • @pmg 是的,这是将年份限制为 1970-2100 的两个原因之一。另一个是,它不适合 unsigned int 否则可能 µc 不支持更长的整数。
  • @Ctx 效果很好,谢谢。 2020,3,9,12,43,30通过,得到1583757810。这是正确的。非常感谢。
【解决方案2】:

时间戳只是从 1970 年 1 月 1 日到任何特定实例的经过时间。

通过这个逻辑,让我们看看实现从日期时间获取时间戳的方法的步骤。

这些是问题本身中提到的以秒为单位的值
Day_in_seconds = 86400
Hour_in_seconds = 3600
Minute_in_seconds = 60

1。首先计算您想要秒的年份的秒数:

int yearInSeconds = (year - 1970)*365*86400 + // assume all year has only 365 day and multiple 365 * 86400(seconds in a day)
                    (year - 1968)/4 * 86400 // now here we are adding 1 day seconds for all the leaps which comes once in every 4 years from the first leap 1972 to till date

要查看闰年,您可以参考tool

2。给定月份的秒数计算:

因为一个月可以有以下可能的日子 [28, 30, 31] // 不包括闰年 2 月。 让我们创建一个累积月份数组,其中包含任何特定月份的完整月份天数

const int daysInMonth[] = { 0, 31, 59, 90, 120, 151, 181, 211, 242, 272, 303, 333 };

一个月的秒数 = daysInMonth[month-1] * 86400 // daysInMonth[month-1] 给出完整月份的天数并乘以 86400(一天中的秒数)

3。计算给定日、时、分和秒的秒数:

// seconds of given day, hour, minutes and second as totalSeconds
int totalSeconds = day*86400 + hour*3600 + minute*60 + second; // multipling the given data with the above mentioned constants for day, hour and minute.

4。现在让我们来处理查询闰日的特殊情况。

在第一步中,我们为所有闰年添加了 1 天秒数,如果您的查询是闰年,其中一个月是 2 月或之前的一个月,这意味着我们没有超过 2 月 29 日。

为此,我们需要从最终结果中减去天秒数。

if(!(year%4) && month <= 2) {
  result = result - 1*86400;
}

最终代码如下:

int getUnixTimestamp(int year, int month, int day, int hour, int minute, int second) {
    const int daysInMonth[] = {
        0,
        31,
        59,
        90,
        120,
        151,
        181,
        211,
        242,
        272,
        303,
        333
    };
    int unixtime = (year - 1970) * 86400 * 365 +
        ((year - 1968) / 4) * 86400 +
        daysInMonth[month - 1] * 86400 +
        (day - 1) * 86400 +
        hour * 3600 +
        minute * 60 +
        second;
    if (!(year % 4) && month <= 2) {
        unixtime -= 86400;
    }
    return unixtime;
}

此代码将一直有效到 2100 年,有关更多信息或检查时间转换,您可以使用此tool

【讨论】:

    猜你喜欢
    • 2016-12-13
    • 1970-01-01
    • 1970-01-01
    • 2021-03-02
    • 2022-07-11
    • 1970-01-01
    • 1970-01-01
    • 2023-02-02
    • 2015-02-20
    相关资源
    最近更新 更多