date and time (local time instead of UTC) (Maxima)

481 views Asked by At

These lines give the date and time in UTC:

t:timedate(absolute_real_time() - (10*3600));
t0:substring(t,1,20);
t1:concat(substring(t,12,17), " ", substring(t,9,11), "/", substring(t,6,8), "/", substring(t,1,5));
t2:concat(substring(t,1,5), substring(t,6,8), substring(t,9,11), substring(t,12,14), substring(t,15,17), substring(t,18,20));

I know that '?\*autoconf\-version\*;' can give the Maxima version number, so maybe there is some undocumented way to get the local time.

Otherwise are there any ready-made functions that can convert UTC time to local time given conditions for start/end of daylight saving time e.g. UTC time to UK time (which is GMT/BST depending on the time of year)?

3

There are 3 answers

0
vafylec On BEST ANSWER

To clarify the problem, before revealing the solution: these are the steps that I take in Maxima v5.30 to get the time in UTC, in a readable format:

Note: When I use Maxima v5.30 (in the UK), for some unknown reason, the time is always UTC adjusted by 10 hours, and does not adjust for DST.

/* 1st Jan 2017 12 noon: */
timedate(3692260800); /* "2017-01-01 22:00:00+10:00" */
timedate(3692260800-10*3600); /* "2017-01-01 12:00:00+10:00" */
substring(timedate(3692260800-10*3600),1,20); /* "2017-01-01 12:00:00" */

Note: timedate works better/differently in later versions of Maxima, but some institutions recommend installing a specific version of Maxima.

Sometimes I want the date in the form: 'yyyyMMddHHmmss'. A function for this is:

SecUTCToDate(vSec,vHour):=
block([d1,d2],
d1:timedate(vSec+vHour*3600),
d2:concat(substring(d1,1,5), substring(d1,6,8), substring(d1,9,11), substring(d1,12,14), substring(d1,15,17), substring(d1,18,20)),
parse_string(d2)
);

Note: [d1,d2] keeps those variables local to within the block, and not global.

To get the local time I have to add on hours based on my time zone (0 in the UK), and DST. To calculate whether a time is within the DST period requires an individual function per time zone: in the UK, and many European countries, one such function is:

/* correct for the years 1900-2200 inclusive */
SecUTCIsDSTUK(vSec):=
block([vLeap,vDaysMar25,vDaysOct25,vWDayMar25,vWDayOct25,vRange1,vRange2],
vYear : parse_string(substring(timedate(vSec),1,5)),
vLeap : floor((vYear-1900)/4), if (vYear>=2100) then vLeap : vLeap-1,
vDaysMar25 : (vYear-1900)*365 + vLeap + 83,
vDaysOct25 : vDaysMar25 + 214,
vWDayMar25 : mod(vDaysMar25+1,7),
vWDayOct25 : mod(vDaysOct25+1,7),
vRange1 : (vDaysMar25+mod(-vWDayMar25,7))*86400 + 3600,
vRange2 : (vDaysOct25+mod(-vWDayOct25,7))*86400 + 3600,
if ((vSec >= vRange1) and (vSec < vRange2)) then 1 else 0);

You can create a mac file with such a function, and call up the the function when needed, e.g.:

load("C:\\MyFolder\\MyFile.mac");
SecUTCIsDSTUK(absolute_real_time());
SecUTCIsDSTUK(absolute_real_time()+86400*180);
10
vafylec On

thank you for your helpful response,

results (v. 5.39.0) (works fine, param 2 omitted gives local time, param 2 as 0 gives UTC):

t:3691202499;
timedate (t);
timedate (t + 6*30.25*24*3600);
timedate (t + 6*30*24*3600);
timedate (t, 0);
timedate (t + 6*30.25*24*3600, 0);
timedate (t + 6*30*24*3600, 0);
:lisp (decode-universal-time 3691202499)
:lisp (decode-universal-time 3691202499 0)
:lisp (decode-universal-time 3706754499)
:lisp (decode-universal-time 3706754499 0)

3691202499
"2016-12-20 06:01:39+00:00"
"2017-06-19 19:01:39+01:00"
"2017-06-18 07:01:39+01:00"
"2016-12-20 06:01:39+00:00"
"2017-06-19 18:01:39+00:00"
"2017-06-18 06:01:39+00:00"
39 1 6 20 12 2016 1 NIL 0
39 1 6 20 12 2016 1 NIL 0
39 1 7 18 6 2017 6 T 0
39 1 6 18 6 2017 6 NIL 0

results (v. 5.30.0) (it seems param 2 omitted gives UTC+10, with no daylight saving time):
(if this is true, I would have to find another way to get local time, possibly by Common LISP commands)

t:3691202499;
timedate (t);
timedate (t + 6*30.25*24*3600);
timedate (t + 6*30*24*3600);
:lisp (decode-universal-time 3691202499)
:lisp (decode-universal-time 3691202499 0)
:lisp (decode-universal-time 3706754499)
:lisp (decode-universal-time 3706754499 0)

3691202499
"2016-12-20 16:01:39+10:00"
"2017-06-20 04:01:39.0+10:00"
"2017-06-18 16:01:39+10:00"
39 1 16 20 12 2016 1 NIL -10
39 1 6 20 12 2016 1 NIL 0
39 1 16 18 6 2017 6 NIL -10
39 1 6 18 6 2017 6 NIL 0

(I can see that the timedate and decode-universal-time functions have key differences between Maxima versions)

thank you for the website mention,
CLHS: Section The Environment Dictionary
http://clhs.lisp.se/Body/c_enviro.htm

is there a list of LISP commands that work in Maxima?

the main reason for the datestamp concerns:
to produce datestamps for filenames such as 'z title yyyymmddhhmmss.txt', or for friendly dates inside those files such as 'hh:mm dd/mm/yyyy', the string manipulation method was the simplest method that I could successfully code (I don't explicitly need to extract individual d m y etc)

0
Robert Dodier On

It's not clear to me exactly what you need, but perhaps the following helps. By the way, do you really need to extract the parts (year, month, day, etc)? If so, it might be more convenient to work directly in Lisp. See DECODE-UNIVERSAL-TIME at the Common Lisp Hyperspec (a web search will find it).

The timedate now (in the just-released Maxima 5.39) accepts an optional argument which is the time zone offset, in hours (plus or minus). The time zone offset may be noninteger (e.g. 2.5). Offset 0 indicates UTC. If the offset is omitted, the time is formatted in the local time zone.

(%i5) t:absolute_real_time();
(%o5)                             3691202499
(%i6) timedate (t, 0);
(%o6)                      2016-12-20 06:01:39+00:00
(%i7) timedate (t);
(%o7)                      2016-12-19 22:01:39-08:00

Note that the daylight saving time flag is applied at the "time of the time". Here is a time from next summer, when daylight saving time is in effect.

(%i8) timedate (t + 6*30.25*24*3600);
(%o8)                      2017-06-19 11:01:39-07:00

The parse_timedate function has also been (in Maxima 5.39) updated to recognize time zone offsets.

(%i9) parse_timedate ("2016-12-19 22:01:39-08:00");
(%o9)                             3691202499

As with timedate if the offset is omitted, it is assumed to be in the local time zone.

(%i10) parse_timedate ("2016-12-19 22:01:39");
(%o10)                            3691202499

Note also that Maxima does not recognize any symbolic time zone indicators such as "UTC", "GMT", "EDT", "America/New_York", etc., only numerical time zone offsets.