【问题标题】:working with dates and times (struct tm) on arm embedded system using Zephyr RTOS使用 Zephyr RTOS 在 arm 嵌入式系统上处理日期和时间(struct tm)
【发布时间】:2020-01-02 21:59:17
【问题描述】:

我正在尝试在我的 arm 微处理器板上获取当前日期时间并执行一些简单的数学运算(从 GMT 更改为 EST,然后转换为日历时间)。

我已经能够通过 AT 命令获得准确的网络 GMT 时间。它以以下格式返回:“20/01/02,16:31:07-20”。我已经解析了这个 char 数组并将相关值分配给 tm struct。我可以很好地打印单个值,但是当我尝试使用strftime 打印时,应用程序就会停止。一旦我开始工作,我将如何将其转换为日历时间(从纪元开始的秒数)我认为mktime 应该可以解决问题,但我认为同样的原因也会失败。任何人都有任何想法。这是代码和输出

    char datetime[] = "20/01/02,16:31:07-20";
    //just hardcoded for now to get formatting and math done properly
    char sep[] = " ,.-:/";
    char str[30];
    strcpy(str,datetime);
    struct tm *timekeeper;
    char* token = strtok (str, sep);
    int tempyear = atoi(token);
    if(tempyear < 100){
          timekeeper->tm_year = 2000 + tempyear;
          printk("year= %i\n",timekeeper->tm_year);
    }
    else{
          timekeeper->tm_year = tempyear;
    }
    token = strtok(NULL, sep);
    //months are set from 0 to 11 so -1 is needed to adjust
    timekeeper->tm_mon = atoi(token) - 1;
    printk("tm_mon= %i\n",timekeeper->tm_mon);
    token = strtok(NULL, sep);
    timekeeper->tm_mday = atoi(token);
    printk("tm_day= %i\n",timekeeper->tm_mday);
    token = strtok(NULL, sep);
    timekeeper->tm_hour = atoi(token);
    printk("tm_hour= %i\n",timekeeper->tm_hour);
    token = strtok(NULL, sep);
    timekeeper->tm_min = atoi(token);
    printk("tm_min= %i\n",timekeeper->tm_min);
    token = strtok(NULL, sep);
    timekeeper->tm_sec = atoi(token);
    timekeeper->tm_isdst = 0;
    printk("tm_sec= %i\n",timekeeper->tm_sec);
    char buffer[40];
    //strftime(buffer, 26, "%Y-%m-%d %H:%M:%S", timekeeper);
    //int secondsfromepoch = mktime(timekeeper);
    strftime(buffer, 40, "%A", timekeeper);
    printk("test\n");
    printk("date and time= %s\n",buffer);

尝试了新代码:


     timekeeper->tm_year = 120; 
     timekeeper->tm_mon = 1; 
     timekeeper->tm_mday = 1; 
     timekeeper->tm_hour = 10; 
     timekeeper->tm_min = 10; 
     timekeeper->tm_sec = 10; 
     timekeeper->tm_isdst = 0; 
     char buffer[40]; 
     printk("year= %i\n",timekeeper->tm_year); 
     printk("tm_mon= %i\n",timekeeper->tm_mon); 
     printk("tm_day= %i\n",timekeeper->tm_mday); 
     printk("tm_hour= %i\n",timekeeper->tm_hour); 
     printk("tm_min= %i\n",timekeeper->tm_min); 
     printk("tm_sec= %i\n",timekeeper->tm_sec);

输出:

year= 2020
tm_mon= 0
tm_day= 2
tm_hour= 16
tm_min= 31
tm_sec= 7

新代码尝试输出:

year= 120 
tm_mon= 1 
tm_day= 1 
tm_hour= 10 
tm_min= 10 
tm_sec= 10 

【问题讨论】:

  • 请注意Zephyr C library 是最小的,您的构建可能使用不同的 C 库。如果您使用CONFIG_NEWLIB_LIBC 选项,它将使用Newlib。那是您的问题取决于您使用的 C 库,而不是 Zephyr RTOS。

标签: c datetime embedded


【解决方案1】:

struct tmyear 字段需要 year - 1900 的值。

所以在你的情况下,它应该包含值120,而不是2020

另外,指针timekeeper 永远不会被设置。因此,当您尝试通过 -&gt; 运算符取消引用该未初始化指针时,您调用了 undefined behavior

timekeeper 更改为struct tm 的实例而不是指针:

struct tm timekeeper;

并将其上的 -&gt; 运算符的任何实例调整为 .

【讨论】:

  • 我试了一下,但得到了相同的结果。我尝试手动输入数据组件,但仍然失败。
  • 它运行良好,我可以从 tm 结构手动获取值,但这条线不起作用 strftime(buffer, 40, "%A", timekeeper);
  • 计时员->tm_year = 120;计时器->tm_mon = 1;计时员->tm_mday = 1;计时器->tm_hour = 10;计时器->tm_min = 10;计时器->tm_sec = 10;计时器->tm_isdst = 0;字符缓冲区[40]; printk("year= %i\n",timekeeper->tm_year); printk("tm_mon= %i\n",timekeeper->tm_mon); printk("tm_day= %i\n",timekeeper->tm_mday); printk("tm_hour= %i\n",timekeeper->tm_hour); printk("tm_min= %i\n",timekeeper->tm_min); printk("tm_sec= %i\n",timekeeper->tm_sec);
  • 这是输出
  • 这里是输出 year= 120 tm_mon= 1 tm_day= 1 tm_hour= 10 tm_min= 10 tm_sec= 10
【解决方案2】:

struct tm 纪元年是 1900 年而不是零:

    if(tempyear < 100)
    {
          timekeeper->tm_year = 100 + tempyear;
    }
    else
    {
          timekeeper->tm_year = tempyear - 1900;
    }

    printk( "year= %i\n", timekeeper->tm_year + 1900 ) ;

或者,因为它是您可能更喜欢的简单条件赋值:

timekeeper->tm_year = (tempyear < 100) ? 100 + tempyear : 
                                         tempyear - 1900 ;
printk( "year= %i\n", timekeeper->tm_year + 1900 ) ;

【讨论】: