From 47d29e8fb9143756c156fcfbf0f581b0dfdad51d Mon Sep 17 00:00:00 2001 From: Thomas Beutlich Date: Sat, 11 Apr 2020 22:48:09 +0200 Subject: [PATCH] Rewrite using external functions from ModelicaTime.c * Rewrite DateTime.'constructor'.fromEpoch to utilize ModelicaTime_localtime * Rewrite DateTime.'String'.formatted to utilize ModelicaTime_strftime * Rewrite DateTime.epoch to utilize ModelicaTime_difftime * Add DateTime.'constructor'.fromString utilizing ModelicaTime_strptime ModelicaTime.[ch] need to be integrated to ModelicaExternalC for later distribution. During development ModelicaTime.c is directly included by the external function declaration. --- .../BuildProjects/autotools/Makefile.am | 2 +- Modelica/Resources/BuildProjects/gcc/Makefile | 6 +- Modelica/Resources/C-Sources/ModelicaTime.c | 210 +++++++ Modelica/Resources/C-Sources/ModelicaTime.h | 96 +++ Modelica/Resources/C-Sources/readme.txt | 3 +- Modelica/Resources/C-Sources/strptime.h | 557 ++++++++++++++++++ .../Licenses/LICENSE_ModelicaTime.txt | 27 + .../Resources/Licenses/LICENSE_strptime.txt | 26 + Modelica/Utilities/Internal.mo | 38 +- Modelica/Utilities/Time.mo | 166 ++---- 10 files changed, 998 insertions(+), 133 deletions(-) create mode 100644 Modelica/Resources/C-Sources/ModelicaTime.c create mode 100644 Modelica/Resources/C-Sources/ModelicaTime.h create mode 100644 Modelica/Resources/C-Sources/strptime.h create mode 100644 Modelica/Resources/Licenses/LICENSE_ModelicaTime.txt create mode 100644 Modelica/Resources/Licenses/LICENSE_strptime.txt diff --git a/Modelica/Resources/BuildProjects/autotools/Makefile.am b/Modelica/Resources/BuildProjects/autotools/Makefile.am index 2fa142a3c90..e2f903934fc 100644 --- a/Modelica/Resources/BuildProjects/autotools/Makefile.am +++ b/Modelica/Resources/BuildProjects/autotools/Makefile.am @@ -1,5 +1,5 @@ lib_LTLIBRARIES = libzlib.la libModelicaExternalC.la libModelicaMatIO.la libModelicaIO.la libModelicaStandardTables.la -libModelicaExternalC_la_SOURCES = ../../C-Sources/ModelicaFFT.c ../../C-Sources/ModelicaInternal.c ../../C-Sources/ModelicaRandom.c ../../C-Sources/ModelicaStrings.c +libModelicaExternalC_la_SOURCES = ../../C-Sources/ModelicaFFT.c ../../C-Sources/ModelicaInternal.c ../../C-Sources/ModelicaRandom.c ../../C-Sources/ModelicaStrings.c ../../C-Sources/ModelicaTime.c libModelicaExternalC_la_LIBADD = @LIBMATH@ libModelicaIO_la_SOURCES = ../../C-Sources/ModelicaIO.c libModelicaIO_la_LIBADD = libModelicaMatIO.la diff --git a/Modelica/Resources/BuildProjects/gcc/Makefile b/Modelica/Resources/BuildProjects/gcc/Makefile index 31f6dafbb57..78ad9351fa7 100644 --- a/Modelica/Resources/BuildProjects/gcc/Makefile +++ b/Modelica/Resources/BuildProjects/gcc/Makefile @@ -11,7 +11,8 @@ EXTC_OBJS = \ ModelicaFFT.o \ ModelicaInternal.o \ ModelicaRandom.o \ - ModelicaStrings.o + ModelicaStrings.o \ + ModelicaTime.o TABLES_OBJS = \ ModelicaStandardTables.o \ @@ -93,6 +94,9 @@ ModelicaRandom.o: ../../C-Sources/ModelicaRandom.c ModelicaStrings.o: ../../C-Sources/ModelicaStrings.c $(CC) $(CPPFLAGS) $(CFLAGS) $(INC) -c -o $@ $< +ModelicaTime.o: ../../C-Sources/ModelicaTime.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(INC) -c -o $@ $< + %.o: ../../C-Sources/zlib/%.c $(CC) $(CPPFLAGS) $(CFLAGS) $(INC) -c -o $@ $< diff --git a/Modelica/Resources/C-Sources/ModelicaTime.c b/Modelica/Resources/C-Sources/ModelicaTime.c new file mode 100644 index 00000000000..d31208e7e61 --- /dev/null +++ b/Modelica/Resources/C-Sources/ModelicaTime.c @@ -0,0 +1,210 @@ +/* ModelicaTime.c - External functions for Modelica.Utilities.Time + + Copyright (C) 2020, Modelica Association and contributors + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// TODO: Remove when ModelicaTime.c will become part of ModelicaExternalC +#if defined(DYMOSIM) +#pragma once +#endif + +#include "ModelicaTime.h" + +#include +#include +#include +#include "ModelicaUtilities.h" +#if !defined(__APPLE_CC__) +#include "strptime.h" +#endif + +#if !defined(NO_TIME) +time_t epoch(int sec, int min, int hour, int mday, int mon, int year) { + struct tm tlocal; + time_t calendarTime; + + memset(&tlocal, 0, sizeof(struct tm)); + tlocal.tm_sec = sec; + tlocal.tm_min = min; + tlocal.tm_hour = hour; + tlocal.tm_mday = mday; + tlocal.tm_mon = mon - 1; + tlocal.tm_year = year - 1900; + + calendarTime = mktime(&tlocal); + if (-1 == calendarTime) { + ModelicaFormatError("Not possible to convert \"%4i-%02i-%02i %02i:%02i:%02i\" " + "to time_t type in local time zone.\n", year, mon, mday, hour, min, sec); + } + return calendarTime; +} +#endif + +double ModelicaTime_difftime(int sec, int min, int hour, int mday, int mon, + int year, int refYear) { + /* Get elapsed seconds w.r.t. reference year */ +#if defined(NO_TIME) + return 0.0; +#else + const time_t endTime = epoch(sec, min, hour, mday, mon, year); + if (1970 == refYear) { + /* Avoid calling mktime for New Year 1970 in local time zone */ + const time_t startTime = epoch(0, 0, 0, 2, 1, 1970); + return difftime(endTime, startTime) + 86400.0; + } + else { + const time_t startTime = epoch(0, 0, 0, 1, 1, refYear); + return difftime(endTime, startTime); + } +#endif +} + +void ModelicaTime_localtime(_Out_ int* ms, _Out_ int* sec, _Out_ int* min, + _Out_ int* hour, _Out_ int* mday, _Out_ int* mon, + _Out_ int* year, double seconds, int refYear) { + /* Convert elapsed seconds w.r.t. reference year */ +#if defined(NO_TIME) + *ms = 0; + *sec = 0; + *min = 0; + *hour = 0; + *mday = 0; + *mon = 0; + *year = 0; +#else + struct tm* tlocal; + time_t calendarTime; + double intPartOfSeconds; + double fracPartOfSeconds; +#if defined(_POSIX_) || (defined(_MSC_VER) && _MSC_VER >= 1400) + struct tm tres; +#endif + + fracPartOfSeconds = modf(seconds, &intPartOfSeconds); + calendarTime = (time_t)intPartOfSeconds; + + if (1970 == refYear) { + /* Avoid calling mktime for New Year 1970 in local time zone */ + calendarTime = calendarTime + epoch(0, 0, 0, 2, 1, 1970) - (time_t)86400; + } + else { + calendarTime = calendarTime + epoch(0, 0, 0, 1, 1, refYear); + } + +#if defined(_POSIX_) + tlocal = localtime_r(&calendarTime, &tres); /* Time fields in local time zone */ +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + localtime_s(&tres, &calendarTime); /* Time fields in local time zone */ + tlocal = &tres; +#else + tlocal = localtime(&calendarTime); /* Time fields in local time zone */ +#endif + + /* Do not memcpy as you do not know which sizes are in the struct */ + *ms = (int)(fracPartOfSeconds*1000.0 + 0.5); + *sec = tlocal->tm_sec; + *min = tlocal->tm_min; + *hour = tlocal->tm_hour; + *mday = tlocal->tm_mday; + *mon = 1 + tlocal->tm_mon; /* Correct for month starting at 1 */ + *year = 1900 + tlocal->tm_year; /* Correct for 4-digit year */ +#endif +} + +_Ret_z_ const char* ModelicaTime_strftime(int sec, int min, int hour, int mday, int mon, + int year, _In_z_ const char* format, int _maxSize) { + /* Formatted time to string conversion */ +#if defined(NO_TIME) + return ""; +#else + size_t retLen; + struct tm* tlocal; + const size_t maxSize = (size_t)_maxSize; + char* timePtr = ModelicaAllocateString(maxSize); + time_t calendarTime = epoch(sec, min, hour, mday, mon, year); +#if defined(_POSIX_) || (defined(_MSC_VER) && _MSC_VER >= 1400) + struct tm tres; +#endif + +#if defined(_POSIX_) + tlocal = localtime_r(&calendarTime, &tres); /* Time fields in local time zone */ +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + localtime_s(&tres, &calendarTime); /* Time fields in local time zone */ + tlocal = &tres; +#else + tlocal = localtime(&calendarTime); /* Time fields in local time zone */ +#endif + + retLen = strftime(timePtr, maxSize, format, tlocal); + if (retLen > 0 && retLen <= maxSize) { + return (const char*)timePtr; + } + else { + return ""; + } +#endif +} + +void ModelicaTime_strptime(_Out_ int* ms, _Out_ int* sec, _Out_ int* min, + _Out_ int* hour, _Out_ int* mday, _Out_ int* mon, + _Out_ int* year, _In_z_ const char* buf, + _In_z_ const char* format) { + /* Formatted string to time conversion */ +#if defined(NO_TIME) + *ms = 0; + *sec = 0; + *min = 0; + *hour = 0; + *mday = 0; + *mon = 0; + *year = 0; +#else + struct tm tlocal; + + memset(&tlocal, 0, sizeof(struct tm)); + if (strptime(buf, format, &tlocal)) { + /* Do not memcpy as you do not know which sizes are in the struct */ + *sec = tlocal.tm_sec; + *min = tlocal.tm_min; + *hour = tlocal.tm_hour; + *mday = tlocal.tm_mday; + *mon = 1 + tlocal.tm_mon; /* Correct for month starting at 1 */ + *year = 1900 + tlocal.tm_year; /* Correct for 4-digit year */ + } + else { + *sec = 0; + *min = 0; + *hour = 0; + *mday = 0; + *mon = 0; + *year = 0; + } + *ms = 0; +#endif +} diff --git a/Modelica/Resources/C-Sources/ModelicaTime.h b/Modelica/Resources/C-Sources/ModelicaTime.h new file mode 100644 index 00000000000..f6390b96b23 --- /dev/null +++ b/Modelica/Resources/C-Sources/ModelicaTime.h @@ -0,0 +1,96 @@ +/* ModelicaTime.h - External functions for Modelica.Utilities.Time + + Copyright (C) 2020, Modelica Association and contributors + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* The following #define's are available. + + NO_TIME : Functions localtime and mktime are not present + MODELICA_EXPORT: Prefix used for function calls. If not defined, blank is used + Useful definition: + - "__declspec(dllexport)" if included in a DLL and the + functions shall be visible outside of the DLL +*/ + +#ifndef MODELICA_TIME_H_ +#define MODELICA_TIME_H_ + +#if !defined(MODELICA_EXPORT) +#if defined(__cplusplus) +#define MODELICA_EXPORT extern "C" +#else +#define MODELICA_EXPORT +#endif +#endif + +/* + * Non-null pointers and esp. null-terminated strings need to be passed to + * external functions. + * + * The following macros handle nonnull attributes for GNU C and Microsoft SAL. + */ +#undef MODELICA_NONNULLATTR +#undef MODELICA_RETURNNONNULLATTR +#if defined(__GNUC__) +#define MODELICA_NONNULLATTR __attribute__((nonnull)) +#if defined(__GNUC_MINOR__) && (__GNUC__ > 3 && __GNUC_MINOR__ > 8) +#define MODELICA_RETURNNONNULLATTR __attribute__((returns_nonnull)) +#else +#define MODELICA_RETURNNONNULLATTR +#endif +#elif defined(__ATTR_SAL) +#define MODELICA_NONNULLATTR +#define MODELICA_RETURNNONNULLATTR _Ret_z_ /* _Ret_notnull_ and null-terminated */ +#else +#define MODELICA_NONNULLATTR +#define MODELICA_RETURNNONNULLATTR +#endif +#if !defined(__ATTR_SAL) +#undef _In_z_ +#undef _Out_ +#undef _Ret_z_ +#define _In_z_ +#define _Out_ +#define _Ret_z_ +#endif + +MODELICA_EXPORT double ModelicaTime_difftime(int sec, int min, int hour, + int mday, int mon, int year, int refYear); +MODELICA_EXPORT void ModelicaTime_localtime(_Out_ int* ms, _Out_ int* sec, + _Out_ int* min, _Out_ int* hour, _Out_ int* mday, _Out_ int* mon, + _Out_ int* year, double seconds, int refYear) MODELICA_NONNULLATTR; +MODELICA_EXPORT MODELICA_RETURNNONNULLATTR const char* ModelicaTime_strftime( + int sec, int min, int hour, int mday, int mon, int year, + _In_z_ const char* format, int _maxSize) MODELICA_NONNULLATTR; +MODELICA_EXPORT void ModelicaTime_strptime(_Out_ int* ms, _Out_ int* sec, + _Out_ int* min, _Out_ int* hour, _Out_ int* mday, _Out_ int* mon, + _Out_ int* year, _In_z_ const char* buf, + _In_z_ const char* format) MODELICA_NONNULLATTR; + +#endif diff --git a/Modelica/Resources/C-Sources/readme.txt b/Modelica/Resources/C-Sources/readme.txt index 8103e467158..2fe1b74e09e 100644 --- a/Modelica/Resources/C-Sources/readme.txt +++ b/Modelica/Resources/C-Sources/readme.txt @@ -6,6 +6,7 @@ to the following object libraries ModelicaInternal.c ModelicaRandom.c ModelicaStrings.c + ModelicaTime.c win32_dirent.c (for Visual C++ on Windows) - ModelicaIO (.lib, .dll, .a, .so, depending on tool and OS) containing: @@ -53,4 +54,4 @@ Additionally, a tool vendor has to provide library "lapack" and this library should be used in the linker when a model is compiled that uses this library in its library annotation. -January 05, 2018. +April 11, 2020. diff --git a/Modelica/Resources/C-Sources/strptime.h b/Modelica/Resources/C-Sources/strptime.h new file mode 100644 index 00000000000..0c2d048814c --- /dev/null +++ b/Modelica/Resources/C-Sources/strptime.h @@ -0,0 +1,557 @@ +/*- + * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code was contributed to The NetBSD Foundation by Klaus Klein. + * Heavily optimised by David Laight + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#ifdef _MSC_VER +#define strncasecmp _strnicmp +#define strcasecmp _stricmp +#endif + +/* + * We do not implement alternate representations. However, we always + * check whether a given modifier is allowed for a certain conversion. + */ +#define ALT_E 0x01 +#define ALT_O 0x02 +#define LEGAL_ALT(x) { if (alt_format & ~(x)) return NULL; } + +static char gmt[] = { "GMT" }; +#ifdef TM_ZONE +static char utc[] = { "UTC" }; +#endif + +/* RFC-822/RFC-2822 */ +static const char * const nast[5] = { + "EST", "CST", "MST", "PST", "\0\0\0" +}; +static const char * const nadt[5] = { + "EDT", "CDT", "MDT", "PDT", "\0\0\0" +}; + +#define TM_YEAR_BASE 1900 + +static const char *day[7] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" +}; +static const char *abday[7] = { + "Sun","Mon","Tue","Wed","Thu","Fri","Sat" +}; +static const char *mon[12] = { + "January", "February", "March", "April", "May", "June", "July", + "August", "September", "October", "November", "December" +}; +static const char *abmon[12] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; +static const char *am_pm[2] = { + "AM", "PM" +}; + +static const unsigned char *conv_num (const unsigned char *, int *, + unsigned int, unsigned int); +static const unsigned char *find_string (const unsigned char *, int *, const char * const *, + const char * const *, int); + + +static const char * +strptime (const char *buf, const char *fmt, struct tm *tm) +{ + unsigned char c; + const unsigned char *bp, *ep; + int alt_format, i, split_year = 0, neg = 0, offs; + const char *new_fmt; + + bp = (const unsigned char *)buf; + + while (bp != NULL && (c = *fmt++) != '\0') { + /* Clear 'alternate' modifier prior to new conversion. */ + alt_format = 0; + i = 0; + + /* Eat up white-space. */ + if (isspace(c)) { + while (isspace(*bp)) + bp++; + continue; + } + + if (c != '%') + goto literal; + + +again: + switch (c = *fmt++) { + case '%': /* "%%" is converted to "%". */ +literal: + if (c != *bp++) + return NULL; + LEGAL_ALT(0); + continue; + + /* + * "Alternative" modifiers. Just set the appropriate flag + * and start over again. + */ + case 'E': /* "%E?" alternative conversion modifier. */ + LEGAL_ALT(0); + alt_format |= ALT_E; + goto again; + + case 'O': /* "%O?" alternative conversion modifier. */ + LEGAL_ALT(0); + alt_format |= ALT_O; + goto again; + + /* + * "Complex" conversion rules, implemented through recursion. + */ + case 'c': /* Date and time, using the locale's format. */ + new_fmt = "%x %X"; + goto recurse; + + case 'D': /* The date as "%m/%d/%y". */ + new_fmt = "%m/%d/%y"; + LEGAL_ALT(0); + goto recurse; + + case 'F': /* The date as "%Y-%m-%d". */ + new_fmt = "%Y-%m-%d"; + LEGAL_ALT(0); + goto recurse; + + case 'R': /* The time as "%H:%M". */ + new_fmt = "%H:%M"; + LEGAL_ALT(0); + goto recurse; + + case 'r': /* The time in 12-hour clock representation. */ + new_fmt = "%I:%M:%S %p"; + LEGAL_ALT(0); + goto recurse; + + case 'T': /* The time as "%H:%M:%S". */ + new_fmt = "%H:%M:%S"; + LEGAL_ALT(0); + goto recurse; + + case 'X': /* The time, using the locale's format. */ + new_fmt = "%H:%M:%S"; + goto recurse; + + case 'x': /* The date, using the locale's format. */ + new_fmt = "%m/%d/%y"; + recurse: + bp = (const unsigned char *)strptime((const char *)bp, new_fmt, tm); + LEGAL_ALT(ALT_E); + continue; + + /* + * "Elementary" conversion rules. + */ + case 'A': /* The day of week, using the locale's form. */ + case 'a': + bp = find_string(bp, &tm->tm_wday, day, abday, 7); + LEGAL_ALT(0); + continue; + + case 'B': /* The month, using the locale's form. */ + case 'b': + case 'h': + bp = find_string(bp, &tm->tm_mon, mon, abmon, 12); + LEGAL_ALT(0); + continue; + + case 'C': /* The century number. */ + i = 20; + bp = conv_num(bp, &i, 0, 99); + + i = i * 100 - TM_YEAR_BASE; + if (split_year) + i += tm->tm_year % 100; + split_year = 1; + tm->tm_year = i; + LEGAL_ALT(ALT_E); + continue; + + case 'd': /* The day of month. */ + case 'e': + bp = conv_num(bp, &tm->tm_mday, 1, 31); + LEGAL_ALT(ALT_O); + continue; + + case 'k': /* The hour (24-hour clock representation). */ + LEGAL_ALT(0); + /* FALLTHROUGH */ + case 'H': + bp = conv_num(bp, &tm->tm_hour, 0, 23); + LEGAL_ALT(ALT_O); + continue; + + case 'l': /* The hour (12-hour clock representation). */ + LEGAL_ALT(0); + /* FALLTHROUGH */ + case 'I': + bp = conv_num(bp, &tm->tm_hour, 1, 12); + if (tm->tm_hour == 12) + tm->tm_hour = 0; + LEGAL_ALT(ALT_O); + continue; + + case 'j': /* The day of year. */ + i = 1; + bp = conv_num(bp, &i, 1, 366); + tm->tm_yday = i - 1; + LEGAL_ALT(0); + continue; + + case 'M': /* The minute. */ + bp = conv_num(bp, &tm->tm_min, 0, 59); + LEGAL_ALT(ALT_O); + continue; + + case 'm': /* The month. */ + i = 1; + bp = conv_num(bp, &i, 1, 12); + tm->tm_mon = i - 1; + LEGAL_ALT(ALT_O); + continue; + + case 'p': /* The locale's equivalent of AM/PM. */ + bp = find_string(bp, &i, am_pm, NULL, 2); + if (tm->tm_hour > 11) + return NULL; + tm->tm_hour += i * 12; + LEGAL_ALT(0); + continue; + + case 'S': /* The seconds. */ + bp = conv_num(bp, &tm->tm_sec, 0, 61); + LEGAL_ALT(ALT_O); + continue; + + case 'U': /* The week of year, beginning on sunday. */ + case 'W': /* The week of year, beginning on monday. */ + /* + * XXX This is bogus, as we can not assume any valid + * information present in the tm structure at this + * point to calculate a real value, so just check the + * range for now. + */ + bp = conv_num(bp, &i, 0, 53); + LEGAL_ALT(ALT_O); + continue; + + case 'w': /* The day of week, beginning on sunday. */ + bp = conv_num(bp, &tm->tm_wday, 0, 6); + LEGAL_ALT(ALT_O); + continue; + + case 'u': /* The day of week, monday = 1. */ + bp = conv_num(bp, &i, 1, 7); + tm->tm_wday = i % 7; + LEGAL_ALT(ALT_O); + continue; + + case 'g': + /* The year corresponding to the ISO week + * number but without the century. + */ + bp = conv_num(bp, &i, 0, 99); + continue; + + case 'G': + /* The year corresponding to the ISO week + * number with century. + */ + do + bp++; + while (isdigit(*bp)); + continue; + + case 'V': /* The ISO 8601:1988 week number as decimal */ + bp = conv_num(bp, &i, 0, 53); + continue; + + case 'Y': /* The year. */ + i = TM_YEAR_BASE; /* just for data sanity... */ + bp = conv_num(bp, &i, 0, 9999); + tm->tm_year = i - TM_YEAR_BASE; + LEGAL_ALT(ALT_E); + continue; + + case 'y': /* The year within 100 years of the epoch. */ + /* LEGAL_ALT(ALT_E | ALT_O); */ + bp = conv_num(bp, &i, 0, 99); + + if (split_year) + /* preserve century */ + i += (tm->tm_year / 100) * 100; + else { + split_year = 1; + if (i <= 68) + i = i + 2000 - TM_YEAR_BASE; + else + i = i + 1900 - TM_YEAR_BASE; + } + tm->tm_year = i; + continue; + + case 'Z': + if (strncmp((const char *)bp, gmt, 3) == 0) { + tm->tm_isdst = 0; +#ifdef TM_GMTOFF + tm->TM_GMTOFF = 0; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = gmt; +#endif + bp += 3; + } else { +#if defined(_TM_DEFINED) && !defined(_WIN32_WCE) + _tzset(); + ep = find_string(bp, &i, + (const char * const *)tzname, + NULL, 2); + if (ep != NULL) { + tm->tm_isdst = i; +#ifdef TM_GMTOFF + tm->TM_GMTOFF = -(timezone); +#endif +#ifdef TM_ZONE + tm->TM_ZONE = tzname[i]; +#endif + } + bp = ep; +#endif + } + continue; + + case 'z': + /* + * We recognize all ISO 8601 formats: + * Z = Zulu time/UTC + * [+-]hhmm + * [+-]hh:mm + * [+-]hh + * We recognize all RFC-822/RFC-2822 formats: + * UT|GMT + * North American : UTC offsets + * E[DS]T = Eastern : -4 | -5 + * C[DS]T = Central : -5 | -6 + * M[DS]T = Mountain: -6 | -7 + * P[DS]T = Pacific : -7 | -8 + * Military + * [A-IL-M] = -1 ... -9 (J not used) + * [N-Y] = +1 ... +12 + */ + while (isspace(*bp)) + bp++; + + switch (*bp++) { + case 'G': + if (*bp++ != 'M') + return NULL; + /*FALLTHROUGH*/ + case 'U': + if (*bp++ != 'T') + return NULL; + /*FALLTHROUGH*/ + case 'Z': + tm->tm_isdst = 0; +#ifdef TM_GMTOFF + tm->TM_GMTOFF = 0; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = utc; +#endif + continue; + case '+': + neg = 0; + break; + case '-': + neg = 1; + break; + default: + --bp; + ep = find_string(bp, &i, nast, NULL, 4); + if (ep != NULL) { +#ifdef TM_GMTOFF + tm->TM_GMTOFF = -5 - i; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = __UNCONST(nast[i]); +#endif + bp = ep; + continue; + } + ep = find_string(bp, &i, nadt, NULL, 4); + if (ep != NULL) { + tm->tm_isdst = 1; +#ifdef TM_GMTOFF + tm->TM_GMTOFF = -4 - i; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = __UNCONST(nadt[i]); +#endif + bp = ep; + continue; + } + + if ((*bp >= 'A' && *bp <= 'I') || + (*bp >= 'L' && *bp <= 'Y')) { +#ifdef TM_GMTOFF + /* Argh! No 'J'! */ + if (*bp >= 'A' && *bp <= 'I') + tm->TM_GMTOFF = + ('A' - 1) - (int)*bp; + else if (*bp >= 'L' && *bp <= 'M') + tm->TM_GMTOFF = 'A' - (int)*bp; + else if (*bp >= 'N' && *bp <= 'Y') + tm->TM_GMTOFF = (int)*bp - 'M'; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = NULL; /* XXX */ +#endif + bp++; + continue; + } + return NULL; + } + offs = 0; + for (i = 0; i < 4; ) { + if (isdigit(*bp)) { + offs = offs * 10 + (*bp++ - '0'); + i++; + continue; + } + if (i == 2 && *bp == ':') { + bp++; + continue; + } + break; + } + switch (i) { + case 2: + offs *= 100; + break; + case 4: + i = offs % 100; + if (i >= 60) + return NULL; + /* Convert minutes into decimal */ + offs = (offs / 100) * 100 + (i * 50) / 30; + break; + default: + return NULL; + } + if (neg) + offs = -offs; + tm->tm_isdst = 0; /* XXX */ +#ifdef TM_GMTOFF + tm->TM_GMTOFF = offs; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = NULL; /* XXX */ +#endif + continue; + + /* + * Miscellaneous conversions. + */ + case 'n': /* Any kind of white-space. */ + case 't': + while (isspace(*bp)) + bp++; + LEGAL_ALT(0); + continue; + + + default: /* Unknown/unsupported conversion. */ + return NULL; + } + } + + return ((const char *)bp); +} + + +static const unsigned char * +conv_num (const unsigned char *buf, int *dest, + unsigned int llim, unsigned int ulim) +{ + unsigned int result = 0; + unsigned char ch; + + /* The limit also determines the number of valid digits. */ + unsigned int rulim = ulim; + + ch = *buf; + if (ch < '0' || ch > '9') + return NULL; + + do { + result *= 10; + result += ch - '0'; + rulim /= 10; + ch = *++buf; + } while ((result * 10 <= ulim) && rulim && ch >= '0' && ch <= '9'); + + if (result < llim || result > ulim) + return NULL; + + *dest = result; + return buf; +} + +static const unsigned char * +find_string (const unsigned char *bp, int *tgt, const char * const *n1, + const char * const *n2, int c) +{ + int i; + unsigned int len; + + /* check full name - then abbreviated ones */ + for (; n1 != NULL; n1 = n2, n2 = NULL) { + for (i = 0; i < c; i++, n1++) { + len = (unsigned int) strlen(*n1); + if (strncasecmp(*n1, (const char *)bp, len) == 0) { + *tgt = i; + return bp + len; + } + } + } + + /* Nothing matched */ + return NULL; +} diff --git a/Modelica/Resources/Licenses/LICENSE_ModelicaTime.txt b/Modelica/Resources/Licenses/LICENSE_ModelicaTime.txt new file mode 100644 index 00000000000..41416704360 --- /dev/null +++ b/Modelica/Resources/Licenses/LICENSE_ModelicaTime.txt @@ -0,0 +1,27 @@ +Copyright (C) 2020, Modelica Association and contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Modelica/Resources/Licenses/LICENSE_strptime.txt b/Modelica/Resources/Licenses/LICENSE_strptime.txt new file mode 100644 index 00000000000..0fdae1e4201 --- /dev/null +++ b/Modelica/Resources/Licenses/LICENSE_strptime.txt @@ -0,0 +1,26 @@ +Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. +All rights reserved. + +This code was contributed to The NetBSD Foundation by Klaus Klein. +Heavily optimised by David Laight + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/Modelica/Utilities/Internal.mo b/Modelica/Utilities/Internal.mo index f758590155b..144b1a0bed2 100644 --- a/Modelica/Utilities/Internal.mo +++ b/Modelica/Utilities/Internal.mo @@ -252,7 +252,7 @@ end FileSystem; output Integer day "Day"; output Integer mon "Month"; output Integer year "Year"; - external "C" ModelicaInternal_getTime(ms,sec,min,hour,day,mon,year) + external "C" ModelicaInternal_getTime(ms, sec, min, hour, day, mon, year) annotation(Library="ModelicaExternalC"); annotation (Documentation(info="

Syntax

@@ -322,6 +322,42 @@ All returned values are of type Integer and have the following meaning: ")); end getTime; + pure function localTime "Retrieve the local time (in the local time zone) from elapsed seconds since reference year" + extends Modelica.Icons.Function; + input Real seconds "Elapsed seconds since epoch_year"; + input Integer epoch_year = 1970 "Reference year"; + output Integer ms "Millisecond"; + output Integer sec "Second"; + output Integer min "Minute"; + output Integer hour "Hour"; + output Integer day "Day"; + output Integer mon "Month"; + output Integer year "Year"; + external "C90" ModelicaTime_localtime(ms, sec, min, hour, day, mon, year, seconds, epoch_year) + annotation (IncludeDirectory="modelica://Modelica/Resources/C-Sources", Include="#include \"ModelicaTime.c\""); + annotation (Documentation(info=" +TODO +")); + end localTime; + + pure function stringToTime "Retrieve the local time (in the local time zone) from formatted string" + extends Modelica.Icons.Function; + input String str "Formatted data and time string"; + input String format = "%Y-%m-%d %H:%M:%S" "Format string passed to strptime"; + output Integer ms "Millisecond"; + output Integer sec "Second"; + output Integer min "Minute"; + output Integer hour "Hour"; + output Integer day "Day"; + output Integer mon "Month"; + output Integer year "Year"; + external "C99" ModelicaTime_strptime(ms, sec, min, hour, day, mon, year, str, format) + annotation (IncludeDirectory="modelica://Modelica/Resources/C-Sources", Include="#include \"ModelicaTime.c\""); + annotation (Documentation(info=" +TODO +")); + end stringToTime; + function dayOfWeek "Return day of week for given date" extends Modelica.Icons.Function; input Integer year "Year"; diff --git a/Modelica/Utilities/Time.mo b/Modelica/Utilities/Time.mo index 115727b0753..e26ef460ad1 100644 --- a/Modelica/Utilities/Time.mo +++ b/Modelica/Utilities/Time.mo @@ -215,14 +215,12 @@ days = leapDays(2000, 2020) // = 5 leap days in range [2000, 2019] algorithm (millisecond, second, minute, hour, day, month, year) := getTime(); - dt :=DateTime(millisecond=millisecond, second=second, minute=minute, hour=hour, day=day, month=month, year=year); + dt := DateTime(millisecond=millisecond, second=second, minute=minute, hour=hour, day=day, month=month, year=year); end fromSystemTime; function fromEpoch "Create DateTime from elapsed seconds since reference year" - import Modelica.Math.nearestInteger; - import Modelica.Utilities.Time.isLeapYear; - import Modelica.Utilities.Time.daysInYear; + import Modelica.Utilities.Internal.Time.localTime; extends Function; input Real seconds "Elapsed seconds since epoch_year"; @@ -230,12 +228,6 @@ days = leapDays(2000, 2020) // = 5 leap days in range [2000, 2019] output DateTime dt "Date and time"; protected - Integer[2,12] days_passed = {{31,59,90,120,151,181,212,243,273,304,334,365}, - {31,60,91,121,152,182,213,244,274,305,335,366}}; - Real rem; - Integer days, day_of_year, counted_days; - Integer i, j; - Integer millisecond "Millisecond"; Integer second "Second"; Integer minute "Minute"; @@ -246,62 +238,34 @@ days = leapDays(2000, 2020) // = 5 leap days in range [2000, 2019] algorithm - // get milliseconds - millisecond := nearestInteger(mod(abs(seconds),1)*1000); - - // get seconds - second :=nearestInteger(mod(seconds,60)); - - // get minutes - rem :=seconds - second; - minute :=nearestInteger(mod(rem/60, 60)); - - // get hours - rem :=rem - minute*60; - hour :=nearestInteger(mod(rem/3600, 24)); - - // get number of days since epoch year - rem := rem - hour*3600; - days := nearestInteger(rem/(24*3600)); - - // get year - if days >= 0 then - // time is after reference year: count how many years must pass from reference year until 'days' is reached - year := epoch_year; - counted_days := 0; - while counted_days + daysInYear(year) <= days loop - counted_days := counted_days + daysInYear(year); - year :=year + 1; - end while; - else - // time is before reference year: count years downwards - year := epoch_year - 1; - counted_days := -daysInYear(year); - while counted_days > days loop - year := year - 1; - counted_days := counted_days - daysInYear(year); - end while; - end if; + (millisecond, second, minute, hour, day, month, year) := localTime(seconds, epoch_year); + dt := DateTime(millisecond=millisecond, second=second, minute=minute, hour=hour, day=day, month=month, year=year); - // compute day in current year - day_of_year := days - counted_days + 1; + end fromEpoch; - // get month - // use correct column depending on leap and regular year - j := if isLeapYear(year) then 2 else 1; - for i in 1:12 loop - if days_passed[j,i] >= day_of_year then - month := i; - break; - end if; - end for; + function fromString "Create DateTime from formatted string" + import Modelica.Utilities.Internal.Time.stringToTime; + extends Function; + + input String str "Formatted data and time string"; + input String format = "%Y-%m-%d %H:%M:%S" "Format string passed to strptime"; + output DateTime dt "Date and time"; - // get day - day := if month > 1 then day_of_year - days_passed[j,month-1] else day_of_year; + protected + Integer millisecond "Millisecond"; + Integer second "Second"; + Integer minute "Minute"; + Integer hour "Hour"; + Integer day "Day"; + Integer month "Month"; + Integer year "Year"; + algorithm + + (millisecond, second, minute, hour, day, month, year) := stringToTime(str, format); dt := DateTime(millisecond=millisecond, second=second, minute=minute, hour=hour, day=day, month=month, year=year); - end fromEpoch; + end fromString; annotation (Documentation(info="

Here the constructor operator(s) is/are defined.

"), Icon( @@ -324,52 +288,24 @@ days = leapDays(2000, 2020) // = 5 leap days in range [2000, 2019] encapsulated operator 'String' "Convert DateTime to string" import Modelica.Utilities.Time.DateTime; - import Modelica.Utilities.Strings.replace; import Modelica.Icons.Function; - function formatted "Use a subset of C strftime() conversion specifiers to format a DateTime record as string" + pure function formatted "Use strftime conversion to format a DateTime record as string" extends Function; - import Modelica.Utilities.Internal.Time.dayOfWeek; - import Modelica.Utilities.Time.weekDays; - import Modelica.Utilities.Time.shortWeekDays; - import Modelica.Utilities.Time.months; - import Modelica.Utilities.Time.shortMonths; - input DateTime dt "Date and time"; - input String format = "%Y-%m-%d %H:%M:%S"; + input String format = "%Y-%m-%d %H:%M:%S" "Format string passed to strftime"; + input Integer maxSize = 128 "Maximal length of formatted string"; output String str "Formatted data and time string"; - - protected - encapsulated function string0 "Create string with minimum length, filled with 0" - import Modelica.Utilities.Strings.replace; - input Integer i; - input Integer l; - output String s0; - algorithm - s0 := replace(String(i, minimumLength=l, leftJustified=false), " ", "0"); - end string0; - - algorithm - str := replace(format, "%%", "%"); - str := replace(str, "%y", string0(mod(dt.year, 100), l=2)); - str := replace(str, "%Y", string0(dt.year, l=4)); - str := replace(str, "%m", string0(dt.month, l=2)); - str := replace(str, "%d", string0(dt.day, l=2)); - str := replace(str, "%H", string0(dt.hour, l=2)); - str := replace(str, "%M", string0(dt.minute, l=2)); - str := replace(str, "%S", string0(dt.second, l=2)); - str := replace(str, "%L", string0(dt.millisecond, l=3)); - str := replace(str, "%a", shortWeekDays[dayOfWeek(dt.year, dt.month, dt.day)]); - str := replace(str, "%A", weekDays[dayOfWeek(dt.year, dt.month, dt.day)]); - str := replace(str, "%b", shortMonths[dt.month]); - str := replace(str, "%B", months[dt.month]); + external "C99" str = ModelicaTime_strftime(dt.second, dt.minute, dt.hour, dt.day, dt.month, dt.year, format, maxSize) + annotation (IncludeDirectory="modelica://Modelica/Resources/C-Sources", Include="#include \"ModelicaTime.c\""); annotation (Documentation(info="

Syntax

 String(dt)
 String(dt, format)
+String(dt, format, maxSize)
 
@@ -664,45 +600,17 @@ String(dt, format=\"%%b\") // Should give \"%b\", but gives \"Dec.\" instead points={{-50,0},{50,0}})})); end '-'; - encapsulated function epoch "Convert DateTime to elapsed seconds since custom epoch year" + encapsulated pure function epoch "Convert DateTime to elapsed seconds since custom epoch year" import Modelica.Utilities.Time.DateTime; - import Modelica.Utilities.Time.isLeapYear; import Modelica.Icons.Function; extends Function; - input DateTime dt; + input DateTime dt "Date and time"; input Integer epoch_year = 1970 "Reference year"; - output Real seconds "Elapsed seconds since epoch_year"; - - protected - Integer[2,12] days_passed = {{0,31,59,90,120,151,181,212,243,273,304,334}, - {0,31,60,91,121,152,182,213,244,274,305,335}}; - Integer leap_days, day_of_year; - Integer leap_years_til_epoch; - Integer j; - - // Aux variables for shorter access in code - Integer millisecond=dt.millisecond "Millisecond"; - Integer second=dt.second "Second"; - Integer minute=dt.minute "Minute"; - Integer hour=dt.hour "Hour"; - Integer day=dt.day "Day"; - Integer month=dt.month "Month"; - Integer year=dt.year "Year"; - - algorithm - // get leap years from year 0 until the chosen epoch year - leap_years_til_epoch := integer(epoch_year/4) - integer((epoch_year)/100) + integer((epoch_year)/400); - - // get leap days of passed years since epoch year - leap_days := integer((year-1)/4) - integer((year-1)/100) + integer((year-1)/400) - leap_years_til_epoch; - - // get current day of year and consider leap day if current year is leap year and February has passed - j := if isLeapYear(year) then 2 else 1; - day_of_year := day + days_passed[j,month]; - - seconds := millisecond/1000 + second + 60*(minute + 60*(hour + 24*(day_of_year-1 + leap_days + 365*(year-epoch_year)))); + output Real seconds "Elapsed seconds since epoch_year in the current time zone"; + external "C" seconds = ModelicaTime_difftime(dt.second, dt.minute, dt.hour, dt.day, dt.month, dt.year, epoch_year) + annotation (IncludeDirectory="modelica://Modelica/Resources/C-Sources", Include="#include \"ModelicaTime.c\""); end epoch; encapsulated function now "Get current system date and time as DateTime" @@ -1398,7 +1306,7 @@ String(d, format=\"%%days\") // Should give \"%days\", but gives \"1\" instead output Real totalSeconds "Elapsed seconds"; algorithm - totalSeconds :=d.milliseconds/1000 + d.seconds + 60*(d.minutes + 60*(d.hours + 24*d.days)); + totalSeconds := d.milliseconds/1000 + d.seconds + 60*(d.minutes + 60*(d.hours + 24*d.days)); end inSeconds; @@ -1413,7 +1321,7 @@ String(d, format=\"%%days\") // Should give \"%days\", but gives \"1\" instead algorithm - d_norm :=Duration(totalSeconds=Duration.inSeconds(d)); + d_norm := Duration(totalSeconds=Duration.inSeconds(d)); end normalize;