Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,24 @@ LIBRARIES = check glib-2.0
all: test example
@echo "+++ All good."""

test: tests/test-parser
test: tests/test-parser tests/test-timegm
@echo "+++ Running parser test suite."
tests/test-parser
@echo "+++ Running at-timegm test suite."
tests/test-timegm

clean:
$(RM) src/example-at src/example-sim800 tests/test-parser
$(RM) src/example-at src/example-sim800 tests/test-parser tests/test-timegm
$(RM) src/*.o src/modem/*.o tests/*.o

PARSER = include/attentive/parser.h
AT = include/attentive/at.h include/attentive/at-unix.h $(PARSER)
CELLULAR = include/attentive/cellular.h $(AT)
CELLULAR = include/attentive/cellular.h include/attentive/at-timegm.h $(AT)
MODEM = src/modem/common.h $(CELLULAR)

src/parser.o: src/parser.c $(PARSER)
src/at-unix.o: src/at-unix.c $(AT)
src/at-timegm.o: src/at-timegm.c
src/cellular.o: src/cellular.c $(CELLULAR)
src/modem/common.o: src/modem/common.c $(MODEM)
src/modem/generic.o: src/modem/generic.c $(MODEM)
Expand All @@ -37,8 +40,9 @@ src/example-at.o: src/example-at.c $(AT)
src/example-sim800.o: src/example-sim800.c $(CELLULAR)

tests/test-parser: tests/test-parser.o src/parser.o
tests/test-timegm: tests/test-timegm.o src/at-timegm.o

src/example-at: src/example-at.o src/parser.o src/at-unix.o
src/example-sim800: src/example-sim800.o src/modem/sim800.o src/modem/common.o src/cellular.o src/at-unix.o src/parser.o
src/example-at: src/example-at.o src/parser.o src/at-unix.o src/at-timegm.o
src/example-sim800: src/example-sim800.o src/modem/sim800.o src/modem/common.o src/cellular.o src/at-unix.o src/at-timegm.o src/parser.o

.PHONY: all test clean
19 changes: 19 additions & 0 deletions include/attentive/at-timegm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright © 2025 Zyax AB
* This program is free software. It comes without any warranty, to the extent
* permitted by applicable law. You can redistribute it and/or modify it under
* the terms of the Do What The Fuck You Want To Public License, Version 2, as
* published by Sam Hocevar. See the COPYING file for more details.
*/

#ifndef ATTENTIVE_AT_UNIX_H
#define ATTENTIVE_AT_UNIX_H

#include <time.h>
#include <stdint.h>

time_t at_timegm(const struct tm *tm);

#endif

/* vim: set ts=4 sw=4 et: */
62 changes: 62 additions & 0 deletions src/at-timegm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include <attentive/at-timegm.h>

static int is_leap_year(int year)
{
return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
}

static int days_in_month(int year, int month)
{
static const int days[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
if (month == 1 && is_leap_year(year)) {
return 29;
}
return days[month];
}

time_t at_timegm(const struct tm *tm)
{
int year = tm->tm_year + 1900;
int month = tm->tm_mon;
int day = tm->tm_mday;
int hour = tm->tm_hour;
int minute = tm->tm_min;
int second = tm->tm_sec;

// Normalize month and year
if (month > 11) {
year += month / 12;
month %= 12;
} else if (month < 0) {
int years_diff = (11 - month) / 12;
year -= years_diff;
month += 12 * years_diff;
}

// Days since Unix epoch
int64_t days = 0;

// Years to days
for (int y = 1970; y < year; ++y) {
days += is_leap_year(y) ? 366 : 365;
}
for (int y = year; y < 1970; ++y) {
days -= is_leap_year(y) ? 366 : 365;
}

// Months to days
for (int m = 0; m < month; ++m) {
days += days_in_month(year, m);
}

// Days
days += (day - 1);

// Total seconds
int64_t total_seconds = days * 86400
+ hour * 3600
+ minute * 60
+ second;

return (time_t)total_seconds;
}
3 changes: 2 additions & 1 deletion src/modem/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

#include <attentive/cellular.h>
#include <attentive/at-timegm.h>

#include <stdio.h>
#include <string.h>
Expand Down Expand Up @@ -135,7 +136,7 @@ int cellular_op_clock_gettime(struct cellular *modem, struct timespec *ts)
/* Adjust values and perform conversion. */
tm.tm_year += 2000 - 1900;
tm.tm_mon -= 1;
time_t unix_time = timegm(&tm);
time_t unix_time = at_timegm(&tm);
if (unix_time == -1) {
errno = EINVAL;
return -1;
Expand Down
3 changes: 2 additions & 1 deletion src/modem/telit2.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

#include <attentive/cellular.h>
#include <attentive/at-timegm.h>

#include <stdio.h>
#include <string.h>
Expand Down Expand Up @@ -159,7 +160,7 @@ static int telit2_op_clock_gettime(struct cellular *modem, struct timespec *ts)
/* Adjust values and perform conversion. */
tm.tm_year += 2000 - 1900;
tm.tm_mon -= 1;
time_t unix_time = timegm(&tm);
time_t unix_time = at_timegm(&tm);
if (unix_time == -1) {
errno = EINVAL;
return -1;
Expand Down
2 changes: 2 additions & 0 deletions tests/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
test-parser
test-timegm

64 changes: 64 additions & 0 deletions tests/test-timegm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright © 2015 Zyax AB
* This program is free software. It comes without any warranty, to the extent
* permitted by applicable law. You can redistribute it and/or modify it under
* the terms of the Do What The Fuck You Want To Public License, Version 2, as
* published by Sam Hocevar. See the COPYING file for more details.
*/

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <check.h>
#include <glib.h>

#include <attentive/at-timegm.h>


START_TEST(test_timegm)
{
printf(":: test_timegm\n");

struct tm tmg = {
.tm_sec = 7,
.tm_min = 14,
.tm_hour = 3,
.tm_mday = 19,
.tm_mon = 0,
.tm_year = 138,
.tm_wday = 2,
.tm_yday = 18,
.tm_isdst = 0
};

time_t t = at_timegm(&tmg);
ck_assert_int_eq(t, 0x7fffffff);
}
END_TEST

Suite *attentive_suite(void)
{
Suite *s = suite_create("attentive");
TCase *tc;

tc = tcase_create("timegm");
tcase_add_test(tc, test_timegm);
suite_add_tcase(s, tc);

return s;
}

int main()
{
int number_failed;
Suite *s = attentive_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

/* vim: set ts=4 sw=4 et: */