Add utc format to formula parser. Test date conversions to from utc.

pull/780/head
Fredrik Öhrström 2022-12-31 11:38:28 +01:00
rodzic 08ca21e7b9
commit c2e1127caa
6 zmienionych plików z 144 dodań i 3 usunięć

Wyświetl plik

@ -227,7 +227,8 @@ double Token::val(const string &s)
else if (type == TokenType::DATETIME)
{
struct tm time {};
strptime(v.c_str(), "'%Y-%m-%d %H:%M:%S'", &time);
char *ok = strptime(v.c_str(), "'%Y-%m-%d %H:%M:%S'", &time);
if (!ok) ok = strptime(v.c_str(), "'%Y-%m-%dT%H:%M:%SZ'", &time);
time_t epoch = mktime(&time);
double result = (double)epoch;
return result;
@ -320,7 +321,8 @@ size_t FormulaImplementation::findNumber(size_t i)
size_t FormulaImplementation::findDateTime(size_t i)
{
// A datetime is converted into a unix timestamp.
// Patterns: '2222-22-22 11:11:00'
// Patterns: '2022-12-30T09:32:45Z'
// '2222-22-22 11:11:00'
// '2222-22-22 11:11'
// '2222-22-22'
@ -329,6 +331,12 @@ size_t FormulaImplementation::findDateTime(size_t i)
const char *end;
memset(&time, 0, sizeof(time));
if (i+21 < formula_.length())
{
end = strptime(start, "'%Y-%m-%dT%H:%M:%SZ'", &time);
if (distance(start, end) == 22) return 22;
}
if (i+20 < formula_.length())
{
end = strptime(start, "'%Y-%m-%d %H:%M:%S'", &time);

Wyświetl plik

@ -860,7 +860,10 @@ string MeterCommonImplementation::datetimeOfUpdateRobot()
char datetime[40];
memset(datetime, 0, sizeof(datetime));
// This is the date time in the Greenwich timezone (Zulu time), dont get surprised!
strftime(datetime, sizeof(datetime), "%FT%TZ", gmtime(&datetime_of_update_));
time_t d = datetime_of_update_;
struct tm ts;
gmtime_r(&d, &ts);
strftime(datetime, sizeof(datetime), "%FT%TZ", &ts);
return string(datetime);
}
@ -1184,6 +1187,13 @@ bool checkPrintableField(string *buf, string desired_field_name, Meter *m, Teleg
*buf += c;
return true;
}
else if (fi.displayUnit() == Unit::DateTimeUTC)
{
double d = m->getNumericValue(&fi, Unit::DateTimeUTC);
*buf += strTimestampUTC(d);
*buf += c;
return true;
}
else
{
// Default unit.
@ -1767,6 +1777,10 @@ string FieldInfo::renderJson(Meter *m, DVEntry *dve)
{
s += "\""+field_name+"_"+display_unit_s+"\":\""+strdatetime(m->getNumericValue(field_name, Unit::DateTimeLT))+"\"";
}
else if (displayUnit() == Unit::DateTimeUTC)
{
s += "\""+field_name+"_"+display_unit_s+"\":\""+strTimestampUTC(m->getNumericValue(field_name, Unit::DateTimeUTC))+"\"";
}
else
{
// All numeric values.

Wyświetl plik

@ -2405,3 +2405,14 @@ int strlen_utf8(const char *s)
for (; *s; ++s) if ((*s & 0xC0) != 0x80) ++len;
return len;
}
string strTimestampUTC(double v)
{
char datetime[40];
memset(datetime, 0, sizeof(datetime));
time_t d = v;
struct tm ts;
gmtime_r(&d, &ts);
strftime(datetime, sizeof(datetime), "%FT%TZ", &ts);
return string(datetime);
}

Wyświetl plik

@ -82,6 +82,8 @@ std::string strdatetime(double v);
// Return for example: 2010-03-21 15:22:03
std::string strdatetimesec(struct tm *date);
std::string strdatetimesec(double v);
// Return UTC timestamp:
std::string strTimestampUTC(double v);
void addMonths(struct tm* date, int m);
double addMonths(double t, int m);

Wyświetl plik

@ -93,6 +93,9 @@ if [ "$?" != "0" ]; then RC="1"; fi
tests/test_formulas.sh $PROG
if [ "$?" != "0" ]; then RC="1"; fi
tests/test_calculate_dates.sh $PROG
if [ "$?" != "0" ]; then RC="1"; fi
tests/test_fields.sh $PROG
if [ "$?" != "0" ]; then RC="1"; fi

Wyświetl plik

@ -0,0 +1,103 @@
#!/bin/sh
PROG="$1"
rm -rf testoutput
mkdir -p testoutput
TEST=testoutput
TESTNAME="Test date calculations"
TESTRESULT="ERROR"
HEX="5E44A51139259471410D7A720050052F2F0C06742400008C1006000000000C13823522008C2013494400000B3B0000000C2B000000000A5A22030A5E91020AA61800004C0619130000CC100600000000426CDF252F2F2F2F2F2F2F2F2F2F2F"
cat > $TEST/test_expected.txt <<EOF
"set_date":"2022-05-31",
"set_1_fromd_utc":"2022-12-22T01:00:00Z",
"set_2_fromdhm_utc":"2022-12-22T13:12:00Z",
"set_3_fromdhms_utc":"2022-12-22T13:12:12Z",
"set_4_fromdhmsz_utc":"2022-12-22T13:12:12Z",
"set_5_fromdut_utc":"2022-12-22T12:12:12Z",
"set_6_from_setdate_utc":"2022-05-31T01:00:00Z",
"set_7_fromd_datetime":"2022-12-22 00:00",
"set_8_fromdhm_datetime":"2022-12-22 12:12",
"set_9_fromdhms_datetime":"2022-12-22 12:12",
"set_10_fromdhmsz_datetime":"2022-12-22 12:12",
"set_11_fromdhmsz_datetime":"2022-12-22 11:12",
"set_12_from_setdate_datetime":"2022-05-31 00:00",
"set_13_fromd_date":"2022-12-22",
"set_14_fromdhm_date":"2022-12-22",
"set_15_fromdhms_date":"2022-12-22",
"set_16_fromdhmsz_date":"2022-12-22",
"set_17_fromdhmsz_date":"2022-12-22",
"set_18_from_setdate_date":"2022-05-31",
"set_19_fromd_ut":1671670800,
"set_20_fromdhm_ut":1671714720,
"set_21_fromdhms_ut":1671714732,
"set_22_fromdhmsz_ut":1671714732,
"set_23_fromdhmsz_ut":1671711132,
"set_24_from_setdate_ut":1653958800,
"set_25_fromd_datetime":"2023-01-22 00:00",
"set_26_fromdhm_datetime":"2023-01-22 12:12",
"set_27_fromdhms_datetime":"2023-01-22 12:12",
"set_28_fromdhmsz_datetime":"2023-01-22 12:12",
"set_29_fromdhmsz_datetime":"2023-01-22 11:12",
"set_30_from_setdate_datetime":"2022-06-30 00:00",
EOF
# TZ=UTC+1 date --date 2022-12-22T12:12:12Z +%s --> 1671711132 # UTC time
# TZ=UTC+1 date --date '2022-12-22 12:12:12' +%s --> 1671714732 # Local time in UTC+1 ie Stockholm no daylight savings.
# TZ=UTC+1 date --date '2022-12-22 12:12' +%s --> 1671714720
# TZ=UTC+1 date --date '2022-12-22' +%s --> 1671670800
# Test using a fixed timezone without daylight savings
# This is necessary to have the utc conversion be stable for testing.
TZ=UTC+1 $PROG --format=json --ppjson \
--calculate_set_1_fromd_utc="'2022-12-22'" \
--calculate_set_2_fromdhm_utc="'2022-12-22 12:12'" \
--calculate_set_3_fromdhms_utc="'2022-12-22 12:12:12'" \
--calculate_set_4_fromdhmsz_utc="'2022-12-22T12:12:12Z'" \
--calculate_set_5_fromdut_utc='1671711132 ut' \
--calculate_set_6_from_setdate_utc=set_date \
\
--calculate_set_7_fromd_datetime="'2022-12-22'" \
--calculate_set_8_fromdhm_datetime="'2022-12-22 12:12'" \
--calculate_set_9_fromdhms_datetime="'2022-12-22 12:12:12'" \
--calculate_set_10_fromdhmsz_datetime="'2022-12-22T12:12:12Z'" \
--calculate_set_11_fromdhmsz_datetime='1671711132 ut'\
--calculate_set_12_from_setdate_datetime=set_date \
\
--calculate_set_13_fromd_date="'2022-12-22'" \
--calculate_set_14_fromdhm_date="'2022-12-22 12:12'" \
--calculate_set_15_fromdhms_date="'2022-12-22 12:12:12'" \
--calculate_set_16_fromdhmsz_date="'2022-12-22T12:12:12Z'" \
--calculate_set_17_fromdhmsz_date='1671711132 ut'\
--calculate_set_18_from_setdate_date=set_date \
\
--calculate_set_19_fromd_ut="'2022-12-22'" \
--calculate_set_20_fromdhm_ut="'2022-12-22 12:12'" \
--calculate_set_21_fromdhms_ut="'2022-12-22 12:12:12'" \
--calculate_set_22_fromdhmsz_ut="'2022-12-22T12:12:12Z'" \
--calculate_set_23_fromdhmsz_ut='1671711132 ut'\
--calculate_set_24_from_setdate_ut=set_date \
\
--calculate_set_25_fromd_datetime="'2022-12-22' + 1 month" \
--calculate_set_26_fromdhm_datetime="'2022-12-22 12:12' + 1 month" \
--calculate_set_27_fromdhms_datetime="'2022-12-22 12:12:12' + 1 month" \
--calculate_set_28_fromdhmsz_datetime="'2022-12-22T12:12:12Z' + 1 month" \
--calculate_set_29_fromdhmsz_datetime='1671711132 ut + 1 month'\
--calculate_set_30_from_setdate_datetime='set_date + 1 month'\
"$HEX" \
GURKA sharky774 71942539 NOKEY | grep \"set_ > $TEST/test_output.txt
if [ "$?" = "0" ]
then
diff $TEST/test_expected.txt $TEST/test_output.txt
if [ "$?" = "0" ]
then
echo "OK: $TESTNAME"
TESTRESULT="OK"
fi
fi
if [ "$TESTRESULT" = "ERROR" ]; then echo ERROR: $TESTNAME; exit 1; fi