LCOV - code coverage report
Current view: top level - src/datetime - datetime.c (source / functions) Coverage Total Hit
Test: colopresso Coverage Report Lines: 93.2 % 103 96
Test Date: 2026-11-09 10:50:48 Functions: 100.0 % 14 14
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-or-later
       3              :  *
       4              :  * This file is part of colopresso
       5              :  *
       6              :  * Copyright (C) 2025-2026 COLOPL, Inc.
       7              :  *
       8              :  * Author: Go Kudo <g-kudo@colopl.co.jp>
       9              :  * Developed with AI (LLM) code assistance. See `NOTICE` for details.
      10              :  */
      11              : 
      12              : #include <stdbool.h>
      13              : #include <stdio.h>
      14              : #include <stdlib.h>
      15              : 
      16              : #include <time.h>
      17              : 
      18              : #include <colopresso/datetime.h>
      19              : #include <colopresso/portable.h>
      20              : 
      21              : struct _cpres_datetime_t {
      22              :     uint16_t year;
      23              :     uint8_t month;
      24              :     uint8_t day;
      25              :     uint8_t hour;
      26              :     uint8_t min;
      27              :     uint8_t sec;
      28              : };
      29              : 
      30            2 : extern cpres_datetime_timestamp_t cpres_datetime_timestamp(void)
      31              : {
      32              :     time_t tm;
      33              : 
      34            2 :     tm = time(NULL);
      35            2 :     if (tm == -1) {
      36            0 :         return 0;
      37              :     }
      38              : 
      39            2 :     return (cpres_datetime_timestamp_t)tm;
      40              : }
      41              : 
      42           12 : extern void cpres_datetime_destroy(cpres_datetime_t *pdt)
      43              : {
      44           12 :     if (!pdt) {
      45            1 :         return;
      46              :     }
      47              : 
      48           11 :     free(pdt);
      49              : }
      50              : 
      51           11 : extern cpres_datetime_t *cpres_datetime_create_from_timestamp(cpres_datetime_timestamp_t timestamp)
      52              : {
      53              :     cpres_datetime_t *pdt;
      54              :     time_t t;
      55              :     struct tm tm;
      56              : 
      57           11 :     t = (time_t)timestamp;
      58           11 :     if (!gmtime_r(&t, &tm)) {
      59            0 :         return NULL;
      60              :     }
      61              : 
      62           11 :     pdt = (cpres_datetime_t *)malloc(sizeof(cpres_datetime_t));
      63           11 :     if (!pdt) {
      64            0 :         return NULL;
      65              :     }
      66              : 
      67           11 :     pdt->year = (uint16_t)(tm.tm_year + 1900);
      68           11 :     pdt->month = (uint8_t)tm.tm_mon + 1;
      69           11 :     pdt->day = (uint8_t)tm.tm_mday;
      70           11 :     pdt->hour = (uint8_t)tm.tm_hour;
      71           11 :     pdt->min = (uint8_t)tm.tm_min;
      72           11 :     pdt->sec = (uint8_t)tm.tm_sec;
      73              : 
      74           11 :     return pdt;
      75              : }
      76              : 
      77            1 : extern cpres_datetime_t *cpres_datetime_create(void)
      78              : {
      79            1 :     return cpres_datetime_create_from_timestamp(cpres_datetime_timestamp());
      80              : }
      81              : 
      82            3 : extern cpres_datetime_timestamp_t cpres_datetime_get_timestamp(const cpres_datetime_t *pdt)
      83              : {
      84            3 :     struct tm tm = {0}, gmt_tm;
      85              :     time_t local_time, gmt_time;
      86              : 
      87            3 :     if (!pdt) {
      88            2 :         return 0;
      89              :     }
      90              : 
      91            1 :     tm.tm_year = pdt->year - 1900;
      92            1 :     tm.tm_mon = pdt->month - 1;
      93            1 :     tm.tm_mday = pdt->day;
      94            1 :     tm.tm_hour = pdt->hour;
      95            1 :     tm.tm_min = pdt->min;
      96            1 :     tm.tm_sec = pdt->sec;
      97            1 :     tm.tm_isdst = -1;
      98            1 :     colopresso_tm_set_gmt_offset(&tm);
      99              : 
     100            1 :     local_time = mktime(&tm);
     101            1 :     if (local_time == -1) {
     102            0 :         return 0;
     103              :     }
     104              : 
     105            1 :     gmtime_r(&local_time, &gmt_tm);
     106            1 :     gmt_time = mktime(&gmt_tm);
     107              : 
     108            1 :     return (cpres_datetime_timestamp_t)local_time + (local_time - gmt_time);
     109              : }
     110              : 
     111            5 : extern uint16_t cpres_datetime_get_year(const cpres_datetime_t *pdt)
     112              : {
     113            5 :     if (!pdt) {
     114            2 :         return 0;
     115              :     }
     116              : 
     117            3 :     return pdt->year;
     118              : }
     119              : 
     120            4 : extern uint8_t cpres_datetime_get_mon(const cpres_datetime_t *pdt)
     121              : {
     122            4 :     if (!pdt) {
     123            2 :         return 0;
     124              :     }
     125              : 
     126            2 :     return pdt->month;
     127              : }
     128              : 
     129            4 : extern uint8_t cpres_datetime_get_day(const cpres_datetime_t *pdt)
     130              : {
     131            4 :     if (!pdt) {
     132            2 :         return 0;
     133              :     }
     134              : 
     135            2 :     return pdt->day;
     136              : }
     137              : 
     138            3 : extern uint8_t cpres_datetime_get_hour(const cpres_datetime_t *pdt)
     139              : {
     140            3 :     if (!pdt) {
     141            2 :         return 0;
     142              :     }
     143              : 
     144            1 :     return pdt->hour;
     145              : }
     146              : 
     147            3 : extern uint8_t cpres_datetime_get_min(const cpres_datetime_t *pdt)
     148              : {
     149            3 :     if (!pdt) {
     150            2 :         return 0;
     151              :     }
     152              : 
     153            1 :     return pdt->min;
     154              : }
     155              : 
     156            3 : extern uint8_t cpres_datetime_get_sec(const cpres_datetime_t *pdt)
     157              : {
     158            3 :     if (!pdt) {
     159            2 :         return 0;
     160              :     }
     161              : 
     162            1 :     return pdt->sec;
     163              : }
     164              : 
     165              : /**
     166              :  * 32bit buildtime structure
     167              :  *
     168              :  * - UTC only.
     169              :  * - Theses are not supported:
     170              :  *   - summer time
     171              :  *   - time zone
     172              :  *
     173              :  *  year   (Y) : 12bit => 2^12-1 = 4095 use: ALL
     174              :  *  month  (M) : 4bit  => 2^4-1  = 15   use: 1-12
     175              :  *  day    (D) : 5bit  => 2^5-1  = 31   use: 1-31
     176              :  *  hour   (H) : 5bit  => 2^5-1  = 31   use: 0-23
     177              :  *  minute (M) : 6bit  => 2^6-1  = 63   use: 0-59
     178              :  *
     179              :  * HIGH                             LOW
     180              :  *  |--------------------------------|
     181              :  *  |YYYYYYYYYYYYMMMMDDDDDHHHHHMMMMMM|
     182              :  *  |--------------------------------|
     183              :  *  32           20  16   11   6     0
     184              :  *
     185              :  * e.g.
     186              :  * - Min: 0000-01-01 00:00 => 00000000000000010000100000000000 => 0x0010800
     187              :  * - Max: 4095-12-31 23:59 => 11111111111111001111110111111011 => 0xFFFCFDFB
     188              :  */
     189              : extern cpres_datetime_buildtime_t
     190            4 : cpres_datetime_encode_buildtime(cpres_datetime_timestamp_t timestamp)
     191              : {
     192              :     cpres_datetime_t *pdt;
     193              :     cpres_datetime_buildtime_t bt;
     194              : 
     195            4 :     pdt = cpres_datetime_create_from_timestamp(timestamp);
     196            4 :     if (!pdt) {
     197            0 :         return 0;
     198              :     }
     199              : 
     200            4 :     bt = 0;
     201            4 :     bt |= ((cpres_datetime_buildtime_t)(pdt->year) & 0xFFF) << 20;
     202            4 :     bt |= ((cpres_datetime_buildtime_t)(pdt->month) & 0xF) << 16;
     203            4 :     bt |= ((cpres_datetime_buildtime_t)(pdt->day) & 0x1F) << 11;
     204            4 :     bt |= ((cpres_datetime_buildtime_t)(pdt->hour) & 0x1F) << 6;
     205            4 :     bt |= ((cpres_datetime_buildtime_t)(pdt->min) & 0x3F);
     206              : 
     207            4 :     cpres_datetime_destroy(pdt);
     208              : 
     209            4 :     return bt;
     210              : }
     211              : 
     212              : extern cpres_datetime_timestamp_t
     213            4 : cpres_datetime_decode_buildtime(cpres_datetime_buildtime_t buildtime)
     214              : {
     215            4 :     struct tm t = {0}, gmt_tm;
     216              :     time_t local_time, gmt_time;
     217              : 
     218            4 :     t.tm_year = ((buildtime >> 20) & 0xFFF) - 1900;
     219            4 :     t.tm_mon = ((buildtime >> 16) & 0xF) - 1;
     220            4 :     t.tm_mday = (buildtime >> 11) & 0x1F;
     221            4 :     t.tm_hour = (buildtime >> 6) & 0x1F;
     222            4 :     t.tm_min = buildtime & 0x3F;
     223            4 :     t.tm_sec = 0;
     224            4 :     t.tm_isdst = -1;
     225            4 :     colopresso_tm_set_gmt_offset(&t);
     226              : 
     227            4 :     local_time = mktime(&t);
     228            4 :     if (local_time == -1) {
     229            0 :         return 0;
     230              :     }
     231              : 
     232            4 :     gmtime_r(&local_time, &gmt_tm);
     233            4 :     gmt_time = mktime(&gmt_tm);
     234              : 
     235            4 :     return (cpres_datetime_timestamp_t)local_time + (local_time - gmt_time);
     236              : }
     237              : 
     238            2 : extern bool cpres_datetime_buildtime2str(cpres_datetime_buildtime_t buildtime,
     239              :                                          cpres_datetime_buildtime_str_t str)
     240              : {
     241              :     cpres_datetime_t *pdt;
     242              : 
     243            2 :     pdt = cpres_datetime_create_from_timestamp(cpres_datetime_decode_buildtime(buildtime));
     244            2 :     if (pdt == NULL) {
     245            0 :         return false;
     246              :     }
     247              : 
     248            2 :     snprintf(str, CPRES_DT_BUILDTIME_LENGTH, "%04u-%02u-%02u %02u:%02u UTC", pdt->year, pdt->month,
     249            2 :              pdt->day, pdt->hour, pdt->min);
     250              : 
     251            2 :     cpres_datetime_destroy(pdt);
     252              : 
     253            2 :     return true;
     254              : }
        

Generated by: LCOV version 2.0-1